La cible du matin devient une energie a couvrir, plus un palier
La regle classait le lendemain en trois paliers a partir de son TOTAL (>= 18 kWh -> 35 %, >= 10 -> 55 %, sinon 85 %) et ignorait donc l heure d arrivee de l energie. Le 03/09 demain annoncait 33,9 kWh — donc "fort", donc 35 % — avec un matin creux (0,03 kWh a 7 h, 0,77 a 8 h) et un croisement a 9 h. Meme defaut que le plancher du soir, a l autre bout de la nuit. Releve de la nuit 02-03/09, requis contre reel : 00:30 62,4 / 53 ; 03:00 50,4 / 45 ; 04:30 41,7 / 37 ; 06:00 37,1 / 22 — cible fixe a 35 tout du long. Le required_soc decroit proprement avec la nuit qui se consomme (6,1 -> 0 kWh a couvrir), la batterie est restee sous la ligne toute la nuit, et le bilan le savait des 00:30. A 03:00 EDF a ete relache cinq points sous la ligne ; le reseau est revenu de 07:24 a 10:33 au plein tarif, 1,49 kWh. La cible vaut desormais min(90, max(palier ou advisor, required_soc)). Sens unique delibere : la direction corrigee est celle de l echec observe, et le principe unificateur des deux cablages est que le bilan ne pousse jamais dans le sens "couvre moins bien la nuit". Plafond 90 parce qu au-dela la batterie cesse d etre un puits et evince la production du matin, et parce que le bilan publie sans ecretage des valeurs superieures a 100 — sans ce plafond la cible serait inatteignable et EDF resterait allume toute la nuit. C est deja la borne du chemin advisor, aucune constante nouvelle. Pas d oscillateur : required_soc decroit de facon monotone pendant la nuit et la passe unique de recovery reste en place. Gardes et repli identiques au plancher du soir, kill-switch existant. Golden 70 -> 75. Quatre mutations font tomber chacune exactement un scenario different. Un cinquieme scenario fige une LIMITE CONNUE, mesuree par sonde : la passe unique de recovery latche le relachement pour toute la session, donc la cible dynamique n ameliore que la premiere passe. §26 avait deja designe le bon critere de re-engagement — un budget d energie restant a couvrir, qui appartient au bilan ; la suite touche la machine a etats de la nuit et fera l objet d un chantier propre. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
This commit is contained in:
102
HANDOFF.md
102
HANDOFF.md
@@ -2821,3 +2821,105 @@ pas, et c'est tout l'interet.
|
||||
|
||||
---
|
||||
*Document mis a jour le : 03/09/2026 (~22:25) — plancher du soir issu du bilan energetique, golden 70/70, deploye*
|
||||
|
||||
## 39. Session du 03/09/2026 (suite) — La cible du matin devient une energie
|
||||
|
||||
### Le defaut, symetrique de la §38
|
||||
La regle historique classe le lendemain en trois paliers a partir de son TOTAL :
|
||||
`>= 18 kWh -> 35 %`, `>= 10 -> 55 %`, sinon 85 %. Elle est donc aveugle a
|
||||
**l'heure d'arrivee** de l'energie. Le 03/09, demain annoncait 33,9 kWh — donc
|
||||
« fort », donc 35 % — mais avec un matin creux (0,03 kWh a 7 h, 0,77 a 8 h,
|
||||
1,81 a 9 h) et un croisement a 9 h. C'est le meme defaut que le plancher du soir
|
||||
de la §38, a l'autre bout de la nuit.
|
||||
|
||||
### Le releve qui a motive le cablage (nuit 02-03/09)
|
||||
| heure | requis (bilan) | SOC reel | cible fixe |
|
||||
|---|---:|---:|---:|
|
||||
| 00:30 | 62,4 | 53 | 35 |
|
||||
| 03:00 | **50,4** | **45** | 35 |
|
||||
| 04:30 | 41,7 | 37 | 35 |
|
||||
| 06:00 | 37,1 | 22 | 35 |
|
||||
|
||||
`required_soc` decroit proprement avec la nuit qui se consomme (6,1 -> 0 kWh a
|
||||
couvrir) : c'est une cible instantanee, pas une constante deguisee. **La
|
||||
batterie est restee sous la ligne toute la nuit, et le bilan le savait des
|
||||
00:30.** A 03:00 EDF a ete relache cinq points sous la ligne ; la batterie est
|
||||
tombee a 20 % vers 06:30 et le reseau est revenu de 07:24 a 10:33 —
|
||||
**1,49 kWh AU PLEIN TARIF**.
|
||||
|
||||
### Le correctif (deploye 03/09 22:50, golden 75/75)
|
||||
Dans `WINDOWS_SOURCEV2.js` :
|
||||
|
||||
```js
|
||||
batteryMorningTargetPct = balanceApplique
|
||||
? Math.min(90, Math.max(batteryMorningTargetBasePct, params.balanceRequiredSocPct))
|
||||
: batteryMorningTargetBasePct;
|
||||
```
|
||||
|
||||
`batteryMorningTargetBasePct` = advisor si son toggle est actif, sinon les
|
||||
paliers. L'ordre est donc : paliers ou advisor d'abord, puis le bilan ne peut
|
||||
que RELEVER.
|
||||
|
||||
**SENS UNIQUE**, comme en §38 : la direction corrigee est celle de l'echec
|
||||
observe — cible trop basse, batterie a plat avant le croisement, reseau au
|
||||
plein tarif le matin. L'abaisser ouvrirait un risque neuf que rien n'a valide.
|
||||
Principe unificateur des deux cablages : **le bilan ne pousse jamais dans le
|
||||
sens « couvre moins bien la nuit »**.
|
||||
|
||||
**PLAFOND 90 %** : au-dela la batterie cesse d'etre un puits et la production du
|
||||
matin se fait evincer (mesures du 31/08). Charger au reseau au-dela de 90
|
||||
echangerait un kWh bon marche cette nuit contre plusieurs kWh censures demain.
|
||||
C'est deja la borne du chemin advisor : aucune constante nouvelle. Le bilan
|
||||
publie sans ecretage des valeurs > 100 (voulu, §26 : signal de dimensionnement),
|
||||
donc ce plafond n'est pas cosmetique — sans lui la cible serait inatteignable
|
||||
et EDF resterait allume toute la nuit.
|
||||
|
||||
**PAS D'OSCILLATEUR** : `required_soc` decroit de facon monotone pendant la nuit,
|
||||
et la passe unique de recovery (§26) reste en place.
|
||||
|
||||
**Gardes et repli** identiques a la §38 (fraicheur 30 min, statut `ok`, valeur
|
||||
finie ; kill-switch `evcs_balance_enabled` deja existant). Trace logbook :
|
||||
`Nuit EVCS: target=X% (BILAN)`.
|
||||
|
||||
### Golden 70 → 75
|
||||
| scenario | attendu |
|
||||
|---|---|
|
||||
| `cible-bilan-tient-le-reseau` (releve 03:00, SOC 45, requis 50,4) | reseau MAINTENU |
|
||||
| `cible-bilan-perime-relache-comme-avant` (bilan vieux de 2 h) | relache — le comportement qui a coute 1,49 kWh |
|
||||
| `cible-bilan-ne-baisse-pas-la-cible` (SOC 30, requis 25) | palier 35 maitre, reseau maintenu |
|
||||
| `cible-bilan-plafonnee-a-90` (SOC 92, requis 118,9) | plafonnee, relache |
|
||||
|
||||
Mutation, quatre directions (bilan ignore / `Math.max` en affectation directe /
|
||||
plafond 90 supprime / garde de fraicheur supprimee) : **chacune fait tomber
|
||||
exactement UN scenario, different a chaque fois**.
|
||||
|
||||
### ⚠️ LIMITE CONNUE, MESUREE ET FIGEE — la passe unique
|
||||
Scenario `cible-bilan-limite-passe-unique`, verifie par sonde : recovery deja
|
||||
latchee, SOC 30 repassant sous un requis de 37,1 % => **le reseau reste
|
||||
relache**, et la raison affiche meme « batterie a la cible » sept points sous
|
||||
la ligne. La passe unique de recovery (§26, anti-oscillateur) latche
|
||||
`nightRecoveryDone` pour toute la session : la cible dynamique n'ameliore donc
|
||||
que la PREMIERE passe.
|
||||
|
||||
Filet restant : l'hysteresis a SOC ≤ 20 %, mais elle peut tomber HORS heures
|
||||
creuses — c'est exactement le 1,49 kWh plein tarif du 03/09.
|
||||
|
||||
Ce comportement est epingle par un scenario pour qu'un changement futur soit
|
||||
delibere. **§26 avait deja designe le bon critere de re-engagement** : « un
|
||||
budget d'energie restant a couvrir — il appartient au bilan energetique, pas a
|
||||
une constante de plus ici ». Le bilan est desormais cable ; la suite naturelle
|
||||
est une **session reseau unique et dimensionnee** — ne pas relacher tant qu'on
|
||||
est sous la ligne ET dans la fenetre HC. C'est un chantier a part : il touche la
|
||||
machine a etats de la nuit (§18/§19/§26), qui a deja produit quatre
|
||||
oscillateurs, et merite ses propres scenarios.
|
||||
|
||||
### Etat du cablage du bilan
|
||||
| consommateur | statut |
|
||||
|---|---|
|
||||
| plancher de demarrage du soir | ✅ §38 |
|
||||
| cible du matin | ✅ §39 |
|
||||
| re-engagement du reseau la nuit | ❌ passe unique (ci-dessus) |
|
||||
| hysteresis `grid_soc_on`/`grid_soc_off` (20/30) | ❌ toujours des niveaux fixes (§11.8.A) |
|
||||
|
||||
---
|
||||
*Document mis a jour le : 03/09/2026 (~22:55) — cible du matin issue du bilan energetique, golden 75/75, deploye*
|
||||
|
||||
@@ -830,10 +830,42 @@ Portee : demarrage. Le plancher de maintien reste a 80 %, donc aucune charge en
|
||||
cours n'est coupee. Golden 66 → 70, quatre mutations faisant tomber chacune
|
||||
exactement un scenario different. Detail : HANDOFF §38.
|
||||
|
||||
⚠️ Le meme defaut subsiste sur l'autre bout de la nuit : `night_target_soc` est
|
||||
toujours deduit du TOTAL de la prevision du lendemain (paliers 35/55/85), aveugle
|
||||
a l'heure d'arrivee de l'energie — 35 % cote controleur contre 99,7 % cote bilan
|
||||
le 03/09.
|
||||
#### F. La cible du matin etait un palier, pas une energie (03/09/2026)
|
||||
|
||||
Symetrique du precedent, a l'autre bout de la nuit. La regle classe le lendemain
|
||||
en trois paliers a partir de son TOTAL (≥ 18 kWh → 35 %, ≥ 10 → 55 %, sinon
|
||||
85 %) et ignore donc **l'heure d'arrivee** de l'energie. Le 03/09, demain
|
||||
annoncait 33,9 kWh — « fort », donc 35 % — avec un matin creux et un croisement
|
||||
a 9 h.
|
||||
|
||||
Releve de la nuit 02-03/09, qui montre le probleme et sa solution dans le meme
|
||||
tableau :
|
||||
|
||||
| heure | requis (bilan) | SOC reel | cible fixe |
|
||||
|---|---:|---:|---:|
|
||||
| 00:30 | 62,4 | 53 | 35 |
|
||||
| 03:00 | **50,4** | **45** | 35 |
|
||||
| 06:00 | 37,1 | 22 | 35 |
|
||||
|
||||
Le `required_soc` decroit avec la nuit qui se consomme. La batterie est restee
|
||||
sous la ligne toute la nuit ; a 03:00 EDF a ete relache cinq points en dessous,
|
||||
la batterie est tombee a 20 % vers 06:30 et le reseau est revenu **au plein
|
||||
tarif** de 07:24 a 10:33 (1,49 kWh).
|
||||
|
||||
La cible vaut desormais `min(90, max(palier ou advisor, required_soc))`. Sens
|
||||
unique delibere, comme le plancher du soir : le bilan ne pousse jamais dans le
|
||||
sens « couvre moins bien la nuit ». Plafond 90 % parce qu'au-dela la batterie
|
||||
cesse d'etre un puits et evince la production du matin — et parce que le bilan
|
||||
publie sans ecretage des valeurs > 100 (§26). Golden 70 → 75, quatre mutations
|
||||
faisant tomber chacune un scenario different. Detail : HANDOFF §39.
|
||||
|
||||
⚠️ **Limite connue et figee par un scenario** : la passe unique de recovery
|
||||
(§26) latche le relachement pour toute la session, donc la cible dynamique
|
||||
n'ameliore que la PREMIERE passe. Si le SOC repasse sous la ligne ensuite, le
|
||||
reseau ne revient qu'via l'hysteresis a 20 %, possiblement hors heures creuses.
|
||||
Le bon critere de re-engagement — « un budget d'energie restant a couvrir » —
|
||||
etait deja designe par §26 ; le bilan est maintenant cable, mais la suite touche
|
||||
la machine a etats de la nuit et fera l'objet d'un chantier propre.
|
||||
|
||||
⚠️ Point structurel mis au jour par cet incident : le bilan energetique publie
|
||||
l'heure de croisement, l'energie a couvrir, le SOC requis, `grid_needed` et
|
||||
|
||||
@@ -361,6 +361,7 @@ const batteryMorningTargetPct =
|
||||
? nightPrev.batteryMorningTargetPct
|
||||
: params.evcsNightTargetWeakForecastPct;
|
||||
const advisorNightTargetApplied = !!nightPrev.advisorNightTargetApplied;
|
||||
const balanceMorningTargetApplied = !!nightPrev.balanceMorningTargetApplied;
|
||||
const maxBatteryDischargePoints =
|
||||
Number.isFinite(nightPrev.maxBatteryDischargePoints) ? nightPrev.maxBatteryDischargePoints : 0;
|
||||
const gridTakeoverTriggerPct =
|
||||
@@ -1080,6 +1081,7 @@ return [{
|
||||
batteryHardFloorPct,
|
||||
batteryMorningTargetPct,
|
||||
advisorNightTargetApplied,
|
||||
balanceMorningTargetApplied,
|
||||
maxBatteryDischargePoints,
|
||||
gridTakeoverTriggerPct,
|
||||
|
||||
|
||||
@@ -1319,7 +1319,7 @@ else {
|
||||
// =====================================================
|
||||
if (nightEvcs?.nightSessionActive) {
|
||||
reason.push(
|
||||
`Nuit EVCS: target=${round1(nightEvcs.batteryMorningTargetPct)}%${nightEvcs.advisorNightTargetApplied ? ' (ADVISOR)' : ''} | trigger réseau=${round1(nightEvcs.gridTakeoverTriggerPct)}%`
|
||||
`Nuit EVCS: target=${round1(nightEvcs.batteryMorningTargetPct)}%${nightEvcs.advisorNightTargetApplied ? ' (ADVISOR)' : ''}${nightEvcs.balanceMorningTargetApplied ? ' (BILAN)' : ''} | trigger réseau=${round1(nightEvcs.gridTakeoverTriggerPct)}%`
|
||||
);
|
||||
|
||||
if (Number.isFinite(nightEvcs.nightSessionStartSocPct)) {
|
||||
|
||||
@@ -285,7 +285,7 @@ const advisorNightTargetApplied =
|
||||
advisorTargetAgeMin !== null &&
|
||||
advisorTargetAgeMin <= ADVISOR_TARGET_MAX_AGE_MIN;
|
||||
|
||||
const batteryMorningTargetPct =
|
||||
const batteryMorningTargetBasePct =
|
||||
advisorNightTargetApplied
|
||||
? clamp(
|
||||
params.advisorNightTargetSocPct,
|
||||
@@ -294,6 +294,65 @@ const batteryMorningTargetPct =
|
||||
)
|
||||
: batteryMorningTargetRulePct;
|
||||
|
||||
// =====================================================
|
||||
// CIBLE DU MATIN : UNE ENERGIE A COUVRIR, PAS UN PALIER (03/09/2026)
|
||||
// =====================================================
|
||||
// La regle historique classe la journee du lendemain en trois paliers
|
||||
// (>= 18 kWh -> 35 %, >= 10 -> 55 %, sinon 85 %) a partir de son TOTAL. Elle
|
||||
// est donc aveugle a l'heure d'arrivee de l'energie : le 03/09, demain
|
||||
// annoncait 33,9 kWh — « fort », donc 35 % — mais avec un matin creux
|
||||
// (0,03 kWh a 7 h, 0,77 a 8 h, 1,81 a 9 h) et un croisement a 9 h.
|
||||
//
|
||||
// C'est le meme defaut que le plancher du soir (cf. le bloc BILAN de
|
||||
// BATTERY_CLOUD_LOCKS), a l'autre bout de la nuit : un palier fige contre une
|
||||
// energie mesurable. Le bilan publie la seconde, instant par instant.
|
||||
//
|
||||
// RELEVE DE LA NUIT 02-03/09, qui a motive ce cablage :
|
||||
//
|
||||
// heure requis SOC reel cible fixe
|
||||
// 00:30 62,4 53 35
|
||||
// 03:00 50,4 45 35 <- EDF relache ici, 5 points sous la ligne
|
||||
// 04:30 41,7 37 35
|
||||
// 06:00 37,1 22 35 <- hysteresis, puis reseau PLEIN TARIF
|
||||
// de 07:24 a 10:33 (1,49 kWh)
|
||||
//
|
||||
// La batterie est restee sous la ligne toute la nuit et le bilan le savait des
|
||||
// 00:30. Le `required_soc` decroit proprement avec la nuit qui se consomme
|
||||
// (6,1 -> 0 kWh a couvrir) : c'est bien une cible instantanee, pas une
|
||||
// constante deguisee.
|
||||
//
|
||||
// SENS UNIQUE, comme pour le plancher du soir : le bilan ne peut que RELEVER
|
||||
// la cible, jamais l'abaisser. La direction corrigee est celle de l'echec
|
||||
// observe (cible trop basse -> batterie a plat avant le croisement -> reseau
|
||||
// au plein tarif le matin). L'abaisser — la regle dit 85 % l'hiver quand le
|
||||
// bilan dira parfois moins — ouvrirait un risque neuf que rien n'a encore
|
||||
// valide. Le principe unificateur : le bilan ne pousse JAMAIS dans le sens
|
||||
// « couvre moins bien la nuit ».
|
||||
//
|
||||
// PLAFOND 90 % : au-dela, la batterie cesse d'etre un puits et la production
|
||||
// du matin se fait evincer (cf. mesures du 31/08). Charger au reseau au-dela
|
||||
// de 90 echangerait un kWh bon marche cette nuit contre plusieurs kWh censures
|
||||
// demain. C'est deja la borne du chemin advisor : aucune constante nouvelle.
|
||||
//
|
||||
// PAS D'OSCILLATEUR : `required_soc` decroit de facon monotone pendant la nuit
|
||||
// (l'energie restant a couvrir ne fait que diminuer), et la passe unique de
|
||||
// recovery (`nightRecoveryDonePrev`, 27/08) reste en place.
|
||||
//
|
||||
// REPLI identique au plancher du soir : fraicheur, statut, valeur finie —
|
||||
// sinon regle historique. Kill-switch existant : `evcs_balance_enabled` OFF
|
||||
// fige `balance_last_run` et la cible retombe seule sur les paliers.
|
||||
const BALANCE_TARGET_MAX_AGE_MIN = 30;
|
||||
const balanceTargetAgeMin = minutesSince(params.balanceLastRunMs, nowMs);
|
||||
const balanceMorningTargetApplied =
|
||||
params.balanceStatusOk &&
|
||||
Number.isFinite(params.balanceRequiredSocPct) &&
|
||||
balanceTargetAgeMin !== null &&
|
||||
balanceTargetAgeMin <= BALANCE_TARGET_MAX_AGE_MIN;
|
||||
|
||||
const batteryMorningTargetPct = balanceMorningTargetApplied
|
||||
? Math.min(90, Math.max(batteryMorningTargetBasePct, params.balanceRequiredSocPct))
|
||||
: batteryMorningTargetBasePct;
|
||||
|
||||
const maxBatteryDischargePoints =
|
||||
nightSessionActive && Number.isFinite(nightSessionStartSocPct)
|
||||
? Math.max(0, nightSessionStartSocPct - batteryMorningTargetPct)
|
||||
@@ -898,8 +957,13 @@ return [{
|
||||
|
||||
batteryHardFloorPct,
|
||||
batteryMorningTargetPct,
|
||||
batteryMorningTargetBasePct,
|
||||
balanceMorningTargetApplied,
|
||||
balanceTargetAgeMin:
|
||||
balanceTargetAgeMin === null ? null : Math.round(balanceTargetAgeMin * 10) / 10,
|
||||
batteryMorningTargetRulePct,
|
||||
advisorNightTargetApplied,
|
||||
balanceMorningTargetApplied,
|
||||
maxBatteryDischargePoints,
|
||||
gridTakeoverTriggerPct,
|
||||
|
||||
|
||||
@@ -1043,6 +1043,141 @@ export const scenarios = [
|
||||
},
|
||||
},
|
||||
|
||||
// ===== 03/09/2026 : la cible du matin est une energie, pas un palier =====
|
||||
// Releve de la nuit 02-03/09 a 03:00 : le bilan demandait 50,4 % pour tenir
|
||||
// jusqu'au croisement de 9 h, la regle des paliers disait 35 %, le SOC etait
|
||||
// a 45 %. EDF a ete relache 5 points sous la ligne, la batterie s'est videe
|
||||
// a 20 % vers 06:30, et le reseau est revenu de 07:24 a 10:33 AU PLEIN TARIF.
|
||||
{
|
||||
id: 'cible-bilan-tient-le-reseau',
|
||||
label: "Nuit HC 03:00 (relevé du 03/09), VW pleine, SOC 45 : le bilan demande 50,4 % → cible relevée → le réseau est MAINTENU au lieu d'être relâché",
|
||||
time: '2026-08-08T03:00:00+02:00',
|
||||
overrides: {
|
||||
...VEHICLE_NIGHT, allow_grid_hc_night: 'on',
|
||||
grid_state: 'on', victron_acin1_available: '1',
|
||||
battery_current_a: '2', night_takeover_prev: 'on',
|
||||
evcs_charging_switch: 'off',
|
||||
prev_surplus_state: 'night_session_done_idle',
|
||||
soc_percent: '45',
|
||||
balance_required_soc: '50.4', balance_energy_to_cover_kwh: '4.3',
|
||||
balance_status: 'ok', balance_last_run: '08/08 02:58',
|
||||
},
|
||||
expect: {
|
||||
profile: 'night_hc',
|
||||
state: 'night_session_done_idle',
|
||||
takeoverNeeded: true,
|
||||
takeoverHelperService: 'turn_on',
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
// CONTREFACTUEL : exactement la nuit du 03/09. Bilan indisponible => regle
|
||||
// des paliers (35 %) => SOC 45 >= 35 => relache. C'est ce qui s'est passe.
|
||||
id: 'cible-bilan-perime-relache-comme-avant',
|
||||
label: "Même relevé, bilan vieux de 2 h → repli sur le palier 35 % → EDF relâché (le comportement qui a coûté 1,49 kWh au plein tarif)",
|
||||
time: '2026-08-08T03:00:00+02:00',
|
||||
overrides: {
|
||||
...VEHICLE_NIGHT, allow_grid_hc_night: 'on',
|
||||
grid_state: 'on', victron_acin1_available: '1',
|
||||
battery_current_a: '2', night_takeover_prev: 'on',
|
||||
evcs_charging_switch: 'off',
|
||||
prev_surplus_state: 'night_session_done_idle',
|
||||
soc_percent: '45',
|
||||
balance_required_soc: '50.4', balance_energy_to_cover_kwh: '4.3',
|
||||
balance_status: 'ok', balance_last_run: '08/08 01:00',
|
||||
},
|
||||
expect: {
|
||||
profile: 'night_hc',
|
||||
state: 'night_recovery_done_idle',
|
||||
takeoverNeeded: false,
|
||||
takeoverHelperService: 'turn_off',
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
// SENS UNIQUE : le bilan ne doit jamais ABAISSER la cible.
|
||||
id: 'cible-bilan-ne-baisse-pas-la-cible',
|
||||
label: "Nuit HC, SOC 30, le bilan ne demande que 25 % → le palier 35 % reste maître → le réseau est maintenu",
|
||||
time: '2026-08-08T03:00:00+02:00',
|
||||
overrides: {
|
||||
...VEHICLE_NIGHT, allow_grid_hc_night: 'on',
|
||||
grid_state: 'on', victron_acin1_available: '1',
|
||||
battery_current_a: '2', night_takeover_prev: 'on',
|
||||
evcs_charging_switch: 'off',
|
||||
prev_surplus_state: 'night_session_done_idle',
|
||||
soc_percent: '30',
|
||||
balance_required_soc: '25', balance_energy_to_cover_kwh: '0.5',
|
||||
balance_status: 'ok', balance_last_run: '08/08 02:58',
|
||||
},
|
||||
expect: {
|
||||
profile: 'night_hc',
|
||||
state: 'night_session_done_idle',
|
||||
takeoverNeeded: true,
|
||||
takeoverHelperService: 'turn_on',
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
// PLAFOND 90 % : le bilan publie sans ecretage des valeurs > 100 (c'est
|
||||
// voulu, §26 : signal de dimensionnement). Sans plafond ici, la cible
|
||||
// deviendrait inatteignable et EDF resterait allume toute la nuit a
|
||||
// charger la batterie — en evincant au passage la production du matin.
|
||||
id: 'cible-bilan-plafonnee-a-90',
|
||||
label: "Nuit HC, SOC 92, le bilan demande 118,9 % (stockage insuffisant) → cible plafonnée à 90 % → recovery terminée, EDF relâché",
|
||||
time: '2026-08-08T03:00:00+02:00',
|
||||
overrides: {
|
||||
...VEHICLE_NIGHT, allow_grid_hc_night: 'on',
|
||||
grid_state: 'on', victron_acin1_available: '1',
|
||||
battery_current_a: '2', night_takeover_prev: 'on',
|
||||
evcs_charging_switch: 'off',
|
||||
prev_surplus_state: 'night_session_done_idle',
|
||||
soc_percent: '92',
|
||||
balance_required_soc: '118.9', balance_energy_to_cover_kwh: '14.54',
|
||||
balance_status: 'ok', balance_last_run: '08/08 02:58',
|
||||
},
|
||||
expect: {
|
||||
profile: 'night_hc',
|
||||
state: 'night_recovery_done_idle',
|
||||
takeoverNeeded: false,
|
||||
takeoverHelperService: 'turn_off',
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
// LIMITE CONNUE, FIGEE VOLONTAIREMENT (03/09/2026).
|
||||
// La passe unique de recovery (27/08, anti-oscillateur) latche
|
||||
// `nightRecoveryDone` : une fois la cible atteinte, le reseau est relache
|
||||
// DEFINITIVEMENT pour la session, meme si le SOC repasse ensuite sous la
|
||||
// ligne du bilan. La cible dynamique n'ameliore donc que la PREMIERE passe.
|
||||
// Ce scenario epingle ce comportement pour qu'un changement futur soit
|
||||
// deliberе et non accidentel. Filet restant : l'hysteresis a SOC <= 20 %,
|
||||
// mais elle peut tomber hors heures creuses (c'est ce qui a coute 1,49 kWh
|
||||
// au plein tarif le 03/09 entre 07:24 et 10:33).
|
||||
// §26 designait deja le bon critere de re-engagement : « un budget
|
||||
// d'energie restant a couvrir — il appartient au bilan energetique ».
|
||||
// Le bilan est desormais cable ; la suite est un chantier a part, car elle
|
||||
// touche la machine a etats de la nuit.
|
||||
id: 'cible-bilan-limite-passe-unique',
|
||||
label: "LIMITE FIGÉE : recovery déjà latchée, SOC 30 repasse sous le requis 37,1 % → le réseau reste relâché (passe unique, §26)",
|
||||
time: '2026-08-08T05:30:00+02:00',
|
||||
overrides: {
|
||||
...VEHICLE_NIGHT, allow_grid_hc_night: 'on',
|
||||
grid_state: 'off', victron_acin1_available: '0',
|
||||
battery_current_a: '-14', night_takeover_prev: 'off',
|
||||
evcs_charging_switch: 'off',
|
||||
prev_surplus_state: 'night_recovery_done_idle',
|
||||
soc_percent: '30',
|
||||
balance_required_soc: '37.1', balance_energy_to_cover_kwh: '2.3',
|
||||
balance_status: 'ok', balance_last_run: '08/08 05:28',
|
||||
},
|
||||
expect: {
|
||||
profile: 'night_hc',
|
||||
state: 'night_recovery_done_idle',
|
||||
takeoverNeeded: false,
|
||||
takeoverHelperService: 'turn_off',
|
||||
},
|
||||
},
|
||||
|
||||
// ===== 03/09/2026 : le plancher du soir vient de l'energie a couvrir =====
|
||||
// Tous ces scenarios ont un VRAI excedent (PV 2000 W, maison 1000 W) et des
|
||||
// chargeurs qui se retiennent : les gardes de §36 et §37 sont donc passantes,
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user