Retrait de Fix G + garde-fous anti-yoyo + diagnostic des deux oscillateurs

Fix G provoquait un yoyo EDF de 2-4 min (coupure a SOC 21 en bypass min_on
contre rallumage a SOC 20 en bypass cooldown) : son garde `soc > gridSocOn`
ne protegeait que l'instant de l'engagement sur SOC bas, pas la phase de
remontee 20 -> 30. jsCode restaure byte-identique a la version pre-Fix-G.

Le fixture de test portait les fallbacks du code (22/35) au lieu des valeurs
de production lues via MCP (20/30), et le scenario de non-regression testait
SOC 18 %, le seul point que Fix G epargnait. Suite reecrite avec les
garde-fous manquants h-recovery-band-no-cut-21/-25. Mutation : Fix G
reapplique -> 4/7 echecs, retire -> 7/7.

Documentation du diagnostic des deux oscillateurs (yoyo EDF et oscillation
de la charge EVCS en plein soleil) dans MANUEL_COMPLET 11.8 et HANDOFF 25.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
This commit is contained in:
Tallagrand Thierry
2026-08-24 12:20:12 +02:00
parent c9dd79c30f
commit 522f47e821
6 changed files with 321 additions and 124 deletions

View File

@@ -445,13 +445,7 @@ Y1 EDF ON + latch
│ (turn_off_vehicle_unplugged, bypass min_on — Fix C)
│ v4: es ∈ {night_recovery_done_idle, departure_done_idle} + SOC ≥ seuil OFF
│ → coupure immédiate (turn_off_recovery_done, bypass min_on — E2+P9)
│ v5: override EVCS disparu (evcsGridOverride → false) ET SOC > seuil ON
│ (PAS seuil OFF : ne touche pas au cas indépendant "SOC bas")
│ → coupure immédiate (turn_off_evcs_override_released, bypass
│ min_on — Fix G, 22/08/2026). Contrairement à v3/v4, ne dépend PAS
│ d'un nom exact de `surplus_state` — couvre tout état transitoire
│ (y compris ceux non encore nommés). Garde anti-glitch : ignoré si
│ la lecture `evcs_source_mode` est vide/unavailable/unknown.
│ (v5 "Fix G" a existé du 22 au 24/08/2026 puis a été RETIRÉ : voir §11.8)
└─▶ retour Y0 (cooldown 15 min)
```
@@ -488,8 +482,12 @@ retesté. Remises à zéro : débranchement, session fraîche (P11), ou force_*.
terminé) → `surplus_state` retombe sur un état générique transitoire
(`stop_source_lost`/`idle_wait_source`) qu'aucune règle v3/v4 ne reconnaît →
EDF maintenu des heures par la boucle générique jusqu'à `gridSocOff`, PV
plafonné ~100 W par le MPPT. → Fix G (v5 : coupure générique dès que
l'override EVCS disparaît, sans dépendre du nom d'état `surplus_state`).
plafonné ~100 W par le MPPT. → Fix G (v5), **retiré le 24/08** : mauvais
diagnostic, le sujet réel est le bilan énergétique (§11.8).
- **Nuit 23-24/08 (yoyo EDF de 2-4 min)** : Fix G coupait à SOC 21 % ce que la
branche « SOC bas » venait de rallumer à 20 % → hystérésis 20/30 réduite à
20/20,1, MPPT qui flappe à chaque bascule. → Fix G retiré, garde-fous
anti-yoyo ajoutés à `tests/golden-hysteresis/` (§11.8).
### 11.7 Conseiller IA — mode ombre et câblages réels
@@ -505,6 +503,71 @@ retesté. Remises à zéro : débranchement, session fraîche (P11), ou force_*.
---
### 11.8 Les deux oscillateurs identifiés le 24/08/2026
Deux boucles de rétroaction distinctes, de même nature : **une décision prise
sur un seuil que l'action elle-même vient détruire**, sans bande morte.
#### A. Yoyo EDF (workflow hystérésis) — Fix G retiré
Fix G coupait EDF dès que l'override EVCS disparaissait et que
`soc > grid_soc_on`. Or la branche « SOC bas » allume EDF à `grid_soc_on`
(20 %) et doit tenir jusqu'à `grid_soc_off` (30 %) : pendant TOUTE cette
remontée, `soc > grid_soc_on` est vrai. Fix G coupait donc à 21 % ce que la
branche basse rallumait à 20 %, les deux en bypass de leur amortisseur
(min_on 25 min d'un côté, cooldown 15 min de l'autre) → oscillateur libre de
2 à 4 minutes, MPPT qui flappe à chaque bascule. Retiré le 24/08.
**Le problème de fond n'est pas le seuil mais son absence de sens physique.**
Le 24/08, conso maison ≈ 0,75 kWh/h de 07:00 à 09:00 pour une production
solaire de 0,07 puis 0,63 kWh/h : rien ne peut relayer EDF avant ~09:00, où la
PV passe à 2,74 kWh/h et la batterie remonte seule de 21 à 31 %. Couper EDF à
06:43 à 21 % rend le yoyo **mécaniquement inévitable, quels que soient les
seuils**. Double peine : EDF ON bride le MPPT (ESS sans injection), donc la
seule ressource capable de sortir du yoyo est étouffée par le yoyo.
Constat structurel : le snapshot du workflow hystérésis lit 25 champs et
**aucune prévision solaire, aucune conso projetée, aucun helper advisor**. Il
décide sur un point de SOC instantané comparé à deux nombres fixes. `30 %`
n'est pas mal réglé, il est hors sujet : la bonne valeur dépend de l'heure, de
la saison et de la courbe du jour (plus haute en saison des pluies, plus basse
par forte prévision). Cible retenue : une **session réseau unique et
dimensionnée** (charger en une fois jusqu'au niveau qui permet de tenir
jusqu'au croisement PV/conso), arbitrée par le conseiller IA, les règles codées
restant un filet de sécurité borné.
#### B. Oscillation de la charge EVCS en plein soleil
Observée le 24/08 vers 11:58-12:00 avec PV 7,7-7,9 kW : la borne alterne
`Waiting for start` / 0 A et `Charging` / 7 A. **Ce n'est pas une limite
5 kVA** — aucun `binary_sensor.victron_ve_bus_overload` depuis le 20/08,
`ac_loads_max_safe_w` = 9000 W, AC-out L1 mesuré à 5335 W sans overload (le
parallèle maître/esclave tient bien au-delà de 5 kVA), et le plafond calculé
par `WINDOWS_SOURCEV2` ressort à ~20 A. Deux causes réelles :
1. **Bande morte nulle.** `battery_discharge_soft_a` = 0 A et
`battery_neutral_band_a` = 0 A (réglés à 0 le 17/07/2026). Comme
`profileBatteryDischargeFloorA = max(seuil du profil, réglage global)`, la
tolérance de −12 A prévue pour la bande SOC 40-60 % est **annulée** : la
moindre pointe de conso (ballon, lave-vaisselle) fait passer le courant
batterie sous 0 A et casse `solarHoldOk`. Avec `min_run_minutes` = 3, la
période du cycle est de 3 à 6 minutes.
2. **Condition de démarrage auto-destructrice (P6).** En `outside_window`
(11:00-12:24) le plancher de démarrage est `soc_start_min` = 80 % alors que
le SOC est à 49 %. Le seul chemin autorisant le départ est l'override
d'abondance P6, qui exige `pvPowerAvg10m ≥ 4000 W` **et**
`batteryCurrentA ≥ +20 A`. Or brancher la voiture détourne le surplus et
fait tomber le courant batterie sous +20 A : l'action détruit sa propre
condition d'autorisation. Système bistable → oscillateur.
Direction retenue (même logique qu'en A) : lire la conso au lieu de la
deviner, la filtrer numériquement (les pointes nocturnes sont improbables hors
charge EVCS), lisser le SOC pour les décisions de confort en gardant
l'instantané pour la sécurité, et exploiter les messages d'état réels du
Victron et de la borne plutôt que de s'auto-limiter à l'aveugle sur un proxy.
---
## 12. Configuration opencode.json
```json