La session unique tenait le contacteur, pas l energie
La veille de nuit a rendu son verdict : UNE seule bascule sur 69 releves entre 01:26 et 07:07. La session reseau unique fait ce pour quoi elle a ete concue, EDF ferme d un bout a l autre de la fenetre sans creneau ni oscillation. Mais a 02:50, la voiture finie, le sourceMode est passe a bloque et la consigne reseau est retombee de 5078 a 50 W. Contacteur ferme, reseau disponible, heures creuses, et l ESS ne demandait que 50 W pendant que la maison tirait 770 W sur la batterie. Trois heures et demie, SOC 44 vers 17 pour cent, 2,60 kWh pris a la batterie quand le reseau etait la et bon marche. L Auto Charge Manager est reste pret a recharger avec DVCC a 30 A, mais la consigne ne demandait jamais l energie. C est le defaut du 01/09 revenu ailleurs : j avais etabli que fermer le contacteur ne suffit pas, puis cree la veille une nouvelle raison de le garder ferme sans la brancher sur la consigne. gridSessionActive inclut desormais l engagement de session. Regle : tant que le contacteur est ferme a notre demande, la consigne couvre la maison, peu importe laquelle des deux raisons le tient. Consigne de repos portee de 50 a 200 W a la demande du proprietaire, avec une justification mesuree : sur 12 074 echantillons du point de raccordement, 17 % sont negatifs, mediane -18 W. Ce n est pas de l injection — la batterie debitait 744 W au meme moment et les 22,7 Wh cumules representent 0,9 % de ce qu elle perdait — c est le regulateur qui chasse autour d une cible trop proche de zero. A 200 W le point de fonctionnement reste positif sur l essentiel des excursions, sans supprimer les pointes les plus fortes. Consigne aussi que le 20 % n est pas le notre mais le plancher de l ESS, qui a fini par faire de lui-meme a 06:20 ce que la session aurait du faire depuis 02:50, apres avoir vide la batterie de 27 points. Golden 78 -> 80, deux mutations ciblees. Piege rencontre et documente : la premiere redaction du contrefactuel portait deux fois la clef balance_status, et en JavaScript la derniere gagne — il testait donc l inverse de son libelle. Un contrefactuel doit reposer sur une difference physique, pas sur la surcharge d une clef deja presente. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
This commit is contained in:
96
HANDOFF.md
96
HANDOFF.md
@@ -3274,3 +3274,99 @@ les regles comme celui-ci.
|
||||
|
||||
---
|
||||
*Document mis a jour le : 04/09/2026 (~01:05) — state_class pose sur 10 capteurs, 299 entites en statistiques long terme*
|
||||
|
||||
## 43. Nuit du 03-04/09 — La session unique tenait le contacteur, pas l'energie
|
||||
|
||||
### Ce qui a marche
|
||||
Veille de nuit, 69 releves de 01:26 a 07:07 : **UNE seule bascule**, celle de
|
||||
01:24. La session reseau unique (§40) a fait exactement ce pour quoi elle a ete
|
||||
concue — EDF ferme d'un bout a l'autre de la fenetre HC, aucun creneau, aucune
|
||||
oscillation. Engagement au premier cycle : `night_grid_session_committed` a
|
||||
01:24:00, contacteur a 01:24:03.
|
||||
|
||||
### Ce qui n'a pas marche
|
||||
| phase | reseau | batterie |
|
||||
|---|---:|---:|
|
||||
| 01:24 → 02:45 (voiture en charge) | **+5,66 kWh** | se recharge |
|
||||
| 02:45 → 06:15 (voiture finie) | **+0,07 kWh** | **−2,60 kWh** |
|
||||
|
||||
A 02:50, la voiture finie : `source_mode` passe a `Bloqué`, et la consigne
|
||||
reseau retombe de **5078 W a 50 W**. Contacteur ferme, reseau disponible, heures
|
||||
creuses — et l'ESS ne demandait que 50 W pendant que la maison tirait 770 W
|
||||
**sur la batterie**. Trois heures et demie. SOC **44 % → 17 %**.
|
||||
|
||||
L'Auto Charge Manager est reste en `evcs_takeover_recover`, DVCC a 30 A, tout du
|
||||
long : pret a recharger, mais la consigne ne demandait jamais l'energie.
|
||||
|
||||
**C'est le defaut du 01/09 (§31) revenu ailleurs.** J'y avais etabli que fermer
|
||||
le contacteur ne suffit pas, que la consigne doit demander la puissance — et
|
||||
conditionne la consigne au `sourceMode`. La veille (§40) j'ai cree une NOUVELLE
|
||||
raison de garder le contacteur ferme, l'engagement de session, sans la brancher
|
||||
sur la consigne.
|
||||
|
||||
### « Injection » a batterie vide : il n'y en a pas eu
|
||||
Question du proprietaire devant des valeurs negatives au point de raccordement.
|
||||
Mesure sur 02:40-06:10, **12 074 echantillons** :
|
||||
|
||||
| | |
|
||||
|---|---:|
|
||||
| echantillons negatifs | 2 083 (17,3 %) |
|
||||
| **mediane des negatifs** | **−18 W** |
|
||||
| minimum | −356 W |
|
||||
| **plus long episode continu** | **35 s** |
|
||||
| **energie totale** | **22,7 Wh** |
|
||||
|
||||
Ce n'est pas de l'injection mais le **regulateur qui chasse autour d'une cible
|
||||
trop proche de zero**. L'energie ne vient pas d'un excedent : la batterie
|
||||
debitait 744 W au meme moment. Les 22,7 Wh representent **0,9 %** des 2,60 kWh
|
||||
qu'elle perdait. Un compteur de facturation, integre a l'heure, ne verrait rien.
|
||||
|
||||
### « Pourquoi 20 % » : c'est le plancher de l'ESS, pas le notre
|
||||
`number.gx_device_ess_min_soc_limit` = **20 %**, `active_soc_limit` = 20 %.
|
||||
Sequence lisible dans `ess_batterylife_state` :
|
||||
```
|
||||
06:20 recharge_no_battery_life l'ESS touche son plancher, tire 2483 W
|
||||
06:40 batterie a +30,8 A
|
||||
07:11 self_consumption_soc_below_min il tient la batterie au plancher et
|
||||
sert la maison sur le reseau (802 W)
|
||||
```
|
||||
Notre `grid_soc_on` vaut aussi 20, mais l'hysteresis n'y est pour rien : EDF
|
||||
etait deja ferme. **L'ESS a fini par faire de lui-meme, a 06:20, ce que la
|
||||
session aurait du faire depuis 02:50 — apres avoir vide la batterie de 27
|
||||
points.**
|
||||
|
||||
### Correctifs (deployes 04/09 07:20, golden 80/80)
|
||||
1. **`HA_SERVICE_CALLS_OUTPUT`** — `gridSessionActive` inclut desormais
|
||||
`night.nightGridSessionCommitted`. Regle : **tant que le contacteur est
|
||||
ferme A NOTRE DEMANDE, la consigne doit couvrir la maison**, peu importe
|
||||
laquelle des deux raisons le tient.
|
||||
2. **`INPUT_PARSE`** — consigne de repos **50 → 200 W** (demande du
|
||||
proprietaire, justification physique ci-dessus : a 50 W le point de
|
||||
fonctionnement passe sous zero 17 % du temps).
|
||||
⚠️ Reduit le nombre d'excursions negatives, ne les annule pas : une pointe
|
||||
a −356 W passerait encore sous zero.
|
||||
|
||||
### Golden 78 → 80
|
||||
`consigne-session-engagee-couvre-la-maison` (le releve de la nuit : session
|
||||
engagee, voiture finie, maison 770 W → consigne 5595 W et non 200) et son
|
||||
contrefactuel `consigne-sans-engagement-retombe-au-repos` (SOC 70 au-dessus de
|
||||
la ligne, donc aucune session, donc repos). Deux attendus existants passent de
|
||||
50 a 200.
|
||||
|
||||
Mutation : engagement retire de la condition → 1 echec cible ; repos ramene a
|
||||
50 → 3 echecs. Restauration → 80/80.
|
||||
|
||||
⚠️ **Piege rencontre en ecrivant le contrefactuel** : sa premiere redaction
|
||||
portait DEUX fois la clef `balance_status` dans le meme objet. En JavaScript la
|
||||
derniere gagne, donc il testait l'inverse de son libelle — et il l'a signale en
|
||||
renvoyant 5595 au lieu de 200. **Ne jamais construire un contrefactuel en
|
||||
surchargeant une clef deja presente** : le faire porter par une difference
|
||||
PHYSIQUE (ici le SOC au-dessus de la ligne).
|
||||
|
||||
### A surveiller la nuit prochaine
|
||||
1. Voiture finie → la consigne doit RESTER haute, pas retomber a 200 ;
|
||||
2. SOC quasi plat entre la fin de charge et 07:24, au lieu de −27 points ;
|
||||
3. `ess_batterylife_state` ne doit jamais atteindre `recharge_no_battery_life`.
|
||||
|
||||
---
|
||||
*Document mis a jour le : 04/09/2026 (~07:25) — session unique validee (1 bascule), consigne branchee sur l'engagement, repos a 200 W, golden 80/80*
|
||||
|
||||
@@ -334,9 +334,30 @@ reason.push(`PV10=${Math.round(parsed.pvPowerAvg10mW)}W`);
|
||||
// son plafond, la consigne est deja genereuse, et l'exces ne peut pas partir
|
||||
// dans la batterie (DVCC tenue a 2 A par l'Auto Charge Manager pendant un
|
||||
// takeover). Hors session, retour a la valeur de repos.
|
||||
// ⚠️ LA SESSION ENGAGEE COMPTE AUSSI (04/09/2026).
|
||||
// Nuit du 03-04/09 : la session reseau unique a tenu le contacteur toute la
|
||||
// nuit — une seule bascule, comme voulu. Mais a 02:50, la voiture finie, le
|
||||
// sourceMode est passe a 'blocked' et la consigne est retombee de 5078 W a
|
||||
// 50 W. Contacteur ferme, reseau disponible, heures creuses, et l'ESS ne
|
||||
// demandait que 50 W pendant que la maison tirait 770 W SUR LA BATTERIE.
|
||||
// Trois heures et demie, SOC 44 % -> 17 %, 2,60 kWh pris a la batterie quand
|
||||
// le reseau etait la et bon marche.
|
||||
//
|
||||
// C'est le defaut du 01/09 revenu ailleurs : fermer le contacteur ne suffit
|
||||
// pas, la consigne doit demander la puissance. J'avais conditionne la consigne
|
||||
// au sourceMode, puis cree la veille une NOUVELLE raison de garder le
|
||||
// contacteur ferme — l'engagement de session — sans la brancher ici. La
|
||||
// session tenait le contacteur, pas l'energie.
|
||||
//
|
||||
// Regle : tant que le contacteur est ferme A NOTRE DEMANDE, la consigne doit
|
||||
// couvrir la maison. Peu importe laquelle des deux raisons le tient.
|
||||
const gridSessionActive =
|
||||
parsed.acInAvailable &&
|
||||
(context.sourceMode === 'grid_forced' || context.sourceMode === 'grid_hc_allowed');
|
||||
(
|
||||
context.sourceMode === 'grid_forced' ||
|
||||
context.sourceMode === 'grid_hc_allowed' ||
|
||||
night.nightGridSessionCommitted === true
|
||||
);
|
||||
|
||||
const gridSetpointNeedW = gridSessionActive
|
||||
? clamp(
|
||||
|
||||
@@ -461,7 +461,16 @@ const params = {
|
||||
|
||||
// Consigne réseau au repos. 50 W est le défaut Victron (légèrement positif
|
||||
// pour ne jamais injecter), pas une valeur choisie ici.
|
||||
gridSetpointIdleW: clamp(num(input.grid_setpoint_idle_w, 50), 0, 500),
|
||||
// CONSIGNE DE REPOS : 200 W et non plus 50 (04/09/2026).
|
||||
// 50 W etait le defaut Victron. Mesure sur la nuit du 03-04/09, 12 074
|
||||
// echantillons du point de raccordement : 17 % sont NEGATIFS, mediane -18 W,
|
||||
// excursions jusqu'a -356 W, episodes de 35 s au plus. Ce n'est pas de
|
||||
// l'injection — la batterie se dechargeait a 744 W au meme moment — c'est le
|
||||
// regulateur qui chasse autour d'une cible trop proche de zero. A 200 W le
|
||||
// point de fonctionnement reste positif sur l'essentiel des excursions.
|
||||
// ⚠️ Ne supprime pas les pointes les plus fortes : une excursion de -356 W
|
||||
// passerait encore sous zero. Reduit leur nombre, ne les annule pas.
|
||||
gridSetpointIdleW: clamp(num(input.grid_setpoint_idle_w, 200), 0, 500),
|
||||
|
||||
probeEnabled: low(input.probe_enabled || 'off') === 'on',
|
||||
probeMinutes: Math.max(1, num(input.probe_minutes, 3)),
|
||||
|
||||
@@ -1143,6 +1143,71 @@ export const scenarios = [
|
||||
},
|
||||
},
|
||||
|
||||
// ===== 04/09/2026 : LA SESSION TENAIT LE CONTACTEUR, PAS L'ENERGIE =====
|
||||
// Releve de la nuit du 03-04/09. La session unique a fonctionne — une seule
|
||||
// bascule du contacteur, EDF ferme jusqu'a 07:24. Mais a 02:50, la voiture
|
||||
// finie, le sourceMode est passe a 'blocked' et la consigne reseau est
|
||||
// retombee de 5078 W a 50 W. Contacteur ferme, heures creuses, et la maison
|
||||
// a tire 770 W SUR LA BATTERIE pendant trois heures et demie :
|
||||
// SOC 44 % -> 17 %, 2,60 kWh pris a la batterie quand le reseau etait la.
|
||||
{
|
||||
id: 'consigne-session-engagee-couvre-la-maison',
|
||||
label: "Nuit 03:30, session engagée mais voiture finie (source bloquée) → la consigne DOIT couvrir la maison au lieu de retomber au repos",
|
||||
time: '2026-08-08T03:30:00+02:00',
|
||||
overrides: {
|
||||
...VEHICLE_NIGHT, allow_grid_hc_night: 'on',
|
||||
grid_state: 'on', victron_acin1_available: '1',
|
||||
battery_current_a: '-16', night_takeover_prev: 'on',
|
||||
evcs_charging_switch: 'off', evcs_ac_power_w: '0',
|
||||
house_ac_power_w: '770', vebus_ac_out_l1_power_w: '770',
|
||||
prev_surplus_state: 'night_session_done_idle',
|
||||
night_grid_session_committed_prev: 'on',
|
||||
soc_percent: '40',
|
||||
balance_required_soc: '57.2', balance_energy_to_cover_kwh: '7.58',
|
||||
balance_status: 'ok', balance_last_run: '08/08 03:28',
|
||||
},
|
||||
expect: {
|
||||
profile: 'night_hc',
|
||||
takeoverNeeded: true,
|
||||
// 770 W de maison + le plafond de courant en marge. Ce qui compte n'est
|
||||
// pas la valeur exacte mais qu'on ne retombe PAS au repos.
|
||||
gridSetpointW: 5595,
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
// CONTREFACTUEL. La difference est PHYSIQUE et non un drapeau force : le
|
||||
// SOC est au-dessus de la ligne du bilan, donc la nuit est couverte, donc
|
||||
// aucune session ne s'engage — et la consigne doit bien retomber au repos.
|
||||
// Sans ce scenario, le correctif pourrait fuir hors session.
|
||||
//
|
||||
// ⚠️ Premiere redaction fausse : elle portait DEUX fois `balance_status`
|
||||
// dans le meme objet. En JavaScript la derniere gagne, donc le scenario
|
||||
// testait l'inverse de ce que son libelle annoncait — et il l'a signale en
|
||||
// renvoyant 5595. Ne jamais construire un contrefactuel en surchargeant une
|
||||
// clef deja presente.
|
||||
id: 'consigne-sans-engagement-retombe-au-repos',
|
||||
label: "Même relevé mais SOC 70 au-dessus de la ligne : aucune session engagée → la consigne retombe à la valeur de repos",
|
||||
time: '2026-08-08T03:30:00+02:00',
|
||||
overrides: {
|
||||
...VEHICLE_NIGHT, allow_grid_hc_night: 'on',
|
||||
grid_state: 'on', victron_acin1_available: '1',
|
||||
battery_current_a: '-16', night_takeover_prev: 'off',
|
||||
evcs_charging_switch: 'off', evcs_ac_power_w: '0',
|
||||
house_ac_power_w: '770', vebus_ac_out_l1_power_w: '770',
|
||||
prev_surplus_state: 'night_recovery_done_idle',
|
||||
night_grid_session_committed_prev: 'off',
|
||||
soc_percent: '70',
|
||||
balance_required_soc: '57.2', balance_energy_to_cover_kwh: '7.58',
|
||||
balance_status: 'ok', balance_last_run: '08/08 03:28',
|
||||
},
|
||||
expect: {
|
||||
profile: 'night_hc',
|
||||
takeoverNeeded: false,
|
||||
gridSetpointW: 200,
|
||||
},
|
||||
},
|
||||
|
||||
// ===== 03/09/2026 : SESSION RESEAU UNIQUE DE LA NUIT =====
|
||||
// Engagement sur le bilan, relachement a la FIN DE LA FENETRE — jamais sur
|
||||
// un seuil de SOC. Deux raisons, toutes deux mesurees le 03/09 : un seuil de
|
||||
@@ -1929,7 +1994,7 @@ export const scenarios = [
|
||||
grid_setpoint_w: '4000',
|
||||
},
|
||||
expect: {
|
||||
gridSetpointW: 50,
|
||||
gridSetpointW: 200,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -1976,7 +2041,7 @@ export const scenarios = [
|
||||
grid_setpoint_w: '4000',
|
||||
},
|
||||
expect: {
|
||||
gridSetpointW: 50,
|
||||
gridSetpointW: 200,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user