199 lines
14 KiB
Markdown
199 lines
14 KiB
Markdown
# HANDOFF.md — EVCS / Grid Hysteresis — État au 09/07/2026
|
||
|
||
## 1. Contexte Projet
|
||
|
||
- **Installation** : Victron ESS **sans injection réseau**. Batterie 17,5 kWh utile.
|
||
- **Workflows n8n actifs** :
|
||
- `HA Snapshot EVCS Surplus Controller V2.6` (id `ATswvGfG4KJUls0K`) — pilote la borne EVCS (30 s)
|
||
- `Victron - Battery / Grid Hysteresis Fix V1` (id `7iIlu7LLTW7TZA8o`) — pilote le switch EDF (1 min)
|
||
- **Accès** :
|
||
- HA : `http://10.10.10.17:8123` — jeton dans `jeton_EVCS.txt` (⚠️ en clair, à révoquer si dépôt partagé)
|
||
- n8n : `https://n8n.airtria.pro` — clé API dans `~/.config/opencode/opencode.json` (mcp.n8n-mcp)
|
||
- **MCP opencode** (option 1 déployée) : 5 serveurs distants dans `~/.config/opencode/opencode.json`
|
||
(`ha-get-state`, `ha-set-helper`, `grid-set-state`, `victron-set-charge-limits`, `pv-get-forecast`)
|
||
→ endpoints SSE `https://n8n.airtria.pro/mcp/<path>/sse`.
|
||
Les 4 outils paramétrés utilisent `$fromAI(...)` (corrigé le 09/07).
|
||
⚠️ **Endpoints MCP n8n sans authentification** — à sécuriser (Bearer sur les nodes MCP Server Trigger).
|
||
- **Fichiers de référence locaux** :
|
||
- `WINDOWS/WINDOW_SOURCEV2.js`, `BATTERY/BATTERY_CLOUD_LOCKS.js`, `HYSTERESIS/COMPUTE.js` — copies de lecture (le code qui fait foi est dans n8n)
|
||
- `modified/GRID_HYSTERESIS_backup_20260709-*.json` — rollback avant P1
|
||
- `modified/EVCS_V2.6_backup_20260709-*.json` — rollbacks avant P2 puis P3 (2 fichiers)
|
||
|
||
## 2. Architecture Data-Flow
|
||
|
||
```
|
||
EVCS V2.6 (30s) :
|
||
HA Snapshot (template) → INPUT_PARSE → WINDOWS_SOURCEV2
|
||
→ BATTERY_CLOUD_LOCKS → DECISION_ENGINEV2 → HA_SERVICE_CALLS_OUTPUT
|
||
→ Build Actions → Execute HA Service
|
||
|
||
Grid Hysteresis (1min) :
|
||
HA Snapshot → Compute Grid Hysteresis → Build Actions → Execute HA Service
|
||
```
|
||
|
||
Communication inter-workflows via helpers HA :
|
||
`input_text.victron_evcs_source_mode` (labels FR), `input_boolean.victron_evcs_night_grid_takeover_needed`,
|
||
`input_text.victron_evcs_surplus_state`, `input_select.victron_evcs_strategy`.
|
||
|
||
## 3. Patchs déployés le 09/07/2026 (session opencode)
|
||
|
||
### P1 — Grid Hysteresis (déployé, vérifié)
|
||
1. **Entité fantôme corrigée** : le snapshot lisait `input_select.victron_evcs_user_strategy`
|
||
(inexistante → toujours `unknown`). Corrigé en `input_select.victron_evcs_strategy`.
|
||
Conséquence avant fix : les overrides `force_grid_now`/`force_charge_now` et la coupure
|
||
« voiture pleine » ne fonctionnaient JAMAIS dans l'hystérésis.
|
||
2. **Switch EDF `unavailable`** : nouvel état `switch_unavailable` = aucun ordre, aucun timestamp,
|
||
réévaluation complète au retour du switch. Avant : spam `turn_on` chaque minute + rallumage
|
||
aveugle à la reconnexion (incident du 08-09/07 : disjoncteur physique coupé par l'utilisateur,
|
||
EDF rallumé à 00:41 au retour, batterie chargée sur réseau à SOC 48 %).
|
||
3. **`last_on_at`** : réécrit uniquement sur vraie transition (latch OFF→ON), plus à chaque retry.
|
||
Avant : `hold_on_min_runtime` pouvait durer éternellement.
|
||
4. **Bug latent corrigé** : le bloc `turn_off_force_grid_vehicle_full` (V2.5) était écrasé par la
|
||
chaîne principale (code mort). Flag `forcedCut` ajouté.
|
||
|
||
### P2 — EVCS V2.6 : continuité takeover nuit / anti-créneaux (déployé, vérifié en réel)
|
||
- Le snapshot relit `night_takeover_prev` (= helper takeover du cycle précédent).
|
||
- `nightTakeoverLatched` dans `WINDOWS_SOURCEV2` **et** `BATTERY_CLOUD_LOCKS` :
|
||
une fois le réseau HC engagé en session nuit, on y reste jusqu'à fin de session
|
||
(fenêtre/débranchement) ou SOC ≥ 90 (`NIGHT_TAKEOVER_RELEASE_SOC_PCT`).
|
||
- Supprime le cycle « château fort » : batterie→jeep→seuil 20 %→EDF ON→30 %→EDF OFF→batterie...
|
||
- Vérifié en production dans la nuit du 09/07 : takeover engagé à SOC 35 %, EDF resté ON,
|
||
Jeep en charge continue (`hold_min_run`).
|
||
|
||
### P3 — EVCS V2.6 : provocation PV batteries pleines (déployé, dry-run complet)
|
||
- Problème (ancien sujet de ce HANDOFF) : sans injection, batteries pleines ⇒ MPPT bridé à la
|
||
conso maison ⇒ aucun seuil PV observable ; en plus `forecastBufferKwh` (10,5 kWh véhicule
|
||
soustraits) toujours ≤ 0 l'après-midi, et `cloudDebt` en deadlock (batterie pleine = courant
|
||
nul = dette jamais remboursée). Sonde afternoon inopérante (`probe_enabled = off` + seuil PV 1000 W).
|
||
- Fix : `pvProvocationEligible = SOC ≥ 90 && batterie non déchargée` → `solar_potential`
|
||
(intégré à `isHighBatteryForPotential`, donc actif sur les 4 profils jour). Gardes aval intactes.
|
||
- **Attention réglage** : `soc_start_min` (HA) = 94 ⇒ plancher de démarrage hors fenêtre.
|
||
Le déclenchement pratique est donc SOC ≥ 94 %. Baisser ce helper à 90 pour aligner.
|
||
|
||
### P4 — Maintien SOC adapté au forecast pendant le takeover nuit (déployé 09/07 après-midi)
|
||
- **Découverte clé** : `Victron - Auto Charge Manager V1.2` (id `cTeeHy4ePiVeELLh`) est le
|
||
propriétaire des limites DVCC (`MaxChargeCurrent`/`MaxChargeVoltage` via MQTT,
|
||
feedback : `sensor.victron_max_charge_current_setting`). Son mode « nuit idle » laissait
|
||
30 A de charge batterie dès que EDF était ON → batterie rechargée à fond pendant un takeover.
|
||
- **ACM patché** : nouvelle branche prioritaire `evcs_takeover_hold` / `evcs_takeover_recover` :
|
||
si `night_grid_takeover_needed` ON + EDF ON → SOC < cible-1 : recharge 30 A ; sinon **maintien
|
||
2 A / 50.1 V** (maison + VE sur HC, batterie en pause). Cible lue depuis
|
||
`input_number.victron_evcs_night_target_soc` (écrite par le workflow EVCS : forecast fort→35 %,
|
||
moyen→55 %, faible→85 % — donc été ~35, hiver ~85 comme demandé).
|
||
- **EVCS patché** : avant minuit (20h→8h), la cible matin utilise
|
||
`max(today_remaining, tomorrow_kwh)` (sinon today_remaining≈0 à 23h → cible 85 % à tort en été).
|
||
Ajout `tomorrow_kwh` au snapshot + `parsed.tomorrowKwh`.
|
||
- Dry-runs : 8 scénarios ACM + 2 scénarios cible EVCS validés (voir session 09/07).
|
||
|
||
### Autres réalisations du 09/07 (après-midi)
|
||
- **Borne fantôme résolue** : firmware EVCS 2.05 → **2.08** (session repartie de zéro,
|
||
détection véhicule correcte). Les 19 kWh affichés étaient un cumul de session non réinitialisé.
|
||
- **Dashboard « EDF Urgence »** créé via API HA (sidebar) : scripts `script.edf_urgence_off`
|
||
(hystérésis OFF + latch OFF + stratégie stop + switch OFF — rien ne rallume),
|
||
`script.edf_force_on`, `script.edf_rendre_la_main` + cartes d'état et « pourquoi ».
|
||
- **Incident Synology** : NAS éteint dans la nuit (cause à chercher dans les logs DSM) →
|
||
n8n + HA morts → EDF resté ON toute la nuit, batterie chargée à 96 % sur réseau.
|
||
⚠️ SPOF structurel : tout le contrôle vit sur le Synology.
|
||
|
||
### P5 — Plafond courant EVCS configurable quand EDF est ON (déployé 09/07 soir)
|
||
- Le plafond 20 A venait de `cfg.evcsDedicatedMaxW` (4900−300 W / 230 V) codé en dur dans INPUT_PARSE.
|
||
- Nouveau helper **`input_number.evcs_plafond_courant_edf_on`** (6–32 A, défaut 20) : quand
|
||
**AC-IN est physiquement présent** (`acin1_available`, pas juste le switch), le plafond = helper ;
|
||
hors réseau, retour au plafond câblé ~20 A. Dry-run 5 scénarios OK (dont disjoncteur coupé).
|
||
- Subtilité : `victron_evcs_current_max_auto_a` (22) plafonne EN PLUS les modes auto ;
|
||
en force_grid/force_charge seul le nouveau helper compte.
|
||
- **Boutons dashboards** (EVCS Master = fichier YAML `/mnt/ARCH3/docker/HA/dashboards/evcs_master.yaml`
|
||
édité via NFS ; EDF Urgence = API) : carte « Plafonds courant EVCS » + boutons
|
||
**⚡ BOOST EDF 28A** (`script.evcs_boost_edf` : plafonds 28/28 + force_grid_now + consigne 28)
|
||
et **Retour normal** (`script.evcs_boost_off` : 20/22 + auto_solar_plus).
|
||
- Sémantique clarifiée : « Courant demandé » = « Consigne envoyée » = `number.victron_evcs_set_current_command`
|
||
(réécrit toutes les 30 s par le workflow) ; « Consigne lue » = readback borne. En force_charge_now,
|
||
PV ≥ 700 W ⇒ source « Solaire » ⇒ gardes nuages/batterie freinent : pour une grosse charge, force_grid_now.
|
||
|
||
### Maintenance du 09/07 soir (analyse des messages d'erreurs)
|
||
- **W-105 borne** (surcharge) : survenu en charge 20 A sur onduleur seul (disjoncteur EDF coupé).
|
||
Déjà couvert : gardes vebus_overload + P5 (plafond retombe à 20 A si AC-IN absent).
|
||
- **`saveDataErrorExecution: all`** activé sur les 8 workflows critiques (diagnostic des
|
||
prochaines erreurs avec données des nodes ; Water Heater V2.3 avait erré 4× le 09/07 20:20-20:35,
|
||
cause inconnue faute de données, rétabli seul).
|
||
- **Garage Thermal** : la prise `switch.clim_hygro_socket_1` est débranchée volontairement par
|
||
moments → l'appel au switch est maintenant conditionné à sa disponibilité (`execute: switchAvailable`).
|
||
Plus de warnings « missing entity » toutes les 10 min. Backup `modified/GARAGE_backup_*`.
|
||
- **Templates MQTT durcis** (33 occurrences, `configuration.yaml` + `packages/victron_vebus_mqtt.yaml`) :
|
||
garde `value_json is defined` → plus d'erreurs `value_json is undefined` aux reconnexions MQTT.
|
||
Backups `SAVE_CONFIG/*.bak.20260709-234800`, `check_config` valid, `mqtt.reload` fait.
|
||
⚠️ Après un `mqtt.reload`, les sensors restent `unknown` jusqu'à republication Venus :
|
||
publier `R/c0619ab34ac5/keepalive` (payload vide) force la republication complète.
|
||
|
||
## 4. Root Cause de l'incident « EDF ON à 48 % sans charge Jeep » (nuit 08→09/07)
|
||
|
||
Chaîne complète reconstituée via l'historique HA :
|
||
1. Borne fantôme au matin du 08/07 (« véhicule en charge » sans véhicule) + `force_grid_now`
|
||
de la veille ⇒ EDF maintenu ON (la coupure voiture-pleine était du code mort, cf. P1.1/P1.4).
|
||
2. L'utilisateur coupe le **disjoncteur physique** ⇒ switch `unavailable` pendant ~5 h.
|
||
3. Le workflow reste coincé en `hold_on_min_runtime` (P1.3) en spammant `turn_on` (P1.2).
|
||
4. 00:40:54 : le switch revient ⇒ 00:41:03 EDF ON sans cause actuelle ⇒ Multiplus charge la
|
||
batterie sur réseau (2980 W) ⇒ coupé à 01:06 (min_on 25 min, SOC ≥ 30).
|
||
Tous les maillons sont corrigés par P1.
|
||
|
||
## 5. Sémantique utile (pour ne pas re-chercher)
|
||
|
||
- **Latch** (`input_boolean.victron_grid_hysteresis_latch`) : « c'est l'automate qui a allumé EDF
|
||
et il défend cet état ». Reprise en main manuelle : stratégie `stop` + hystérésis OFF + latch OFF.
|
||
- **Fenêtres EVCS (helpers HA, corrigées/vérifiées le 09/07)** : `night_hc` **01:24→07:24** (HC réelles),
|
||
`morning_solar` 07:30→11:00, `midday_hc_or_solar` **12:24→14:24** (HC réelles),
|
||
`evening_high_soc` 17:00→20:30, sinon `outside_window`.
|
||
L'Auto Charge Manager utilisait des fenêtres codées en dur légèrement fausses
|
||
(01:30-07:15 / 12:25-14:25) — alignées sur 01:24-07:24 / 12:24-14:24 le 09/07.
|
||
- **Seuils hystérésis réseau (HA, valeurs réelles)** : ON ≤ 20 %, OFF ≥ 30 %, min_on 25 min.
|
||
- **Cibles nuit** : hard floor 22 % ; cible matin selon forecast : ≥18 kWh→35 %, ≥10→55 %, sinon 85 %.
|
||
`nightSessionActive = fenêtre nuit && véhicule branché` (⚠️ pas besoin de charge active).
|
||
- **Statut borne 6** = branchée en attente de démarrage (« Inconnu (6) » sur le dashboard).
|
||
- **Labels FR** dans `source_mode` : `Réseau forcé`, `Réseau HC autorisé`, `Assistance batterie nuit`,
|
||
`Bloqué`, `Solaire`, `Potentiel solaire` — l'hystérésis matche ces labels.
|
||
|
||
## 6. Méthode de travail validée (à réutiliser)
|
||
|
||
1. Backup : `GET /api/v1/workflows/<id>` → `modified/*_backup_<stamp>.json`.
|
||
2. Patch des `jsCode` par remplacement exact (script node), `node --check` sur chaque node.
|
||
3. **Dry-run local de la chaîne complète** : snapshot réel via `POST /api/template` HA,
|
||
exécution séquentielle des 5 nodes avec shim `$input`, horloge simulable en surchargeant
|
||
`global.Date` (voir session du 09/07).
|
||
4. `PUT /api/v1/workflows/<id>` (⚠️ filtrer `settings` : seuls
|
||
`executionOrder/timezone/save*/executionTimeout/errorWorkflow` sont acceptés).
|
||
5. Vérification live : helpers HA 40-70 s après.
|
||
|
||
## 7. Backlog / Point du 10/07 au réveil
|
||
|
||
1. **Vérifier la nuit de test P2+P4** (fenêtre HC 01:24→07:24, forecast fort → cible 35 %) :
|
||
- takeover engagé quand SOC ≤ 35 → EDF ON **continu** (pas de créneaux) ;
|
||
- `input_text.victron_charge_mode` = `evcs_takeover_recover` puis **`evcs_takeover_hold`** ;
|
||
- `sensor.victron_max_charge_current_setting` = **2** pendant le hold (batterie tenue ~35 %) ;
|
||
- 07:24 : fin de fenêtre → EDF coupé (`turn_off_recovered`), ACM repasse en profil jour.
|
||
Historique utile : `switch.edf_general_ok_switch`, `sensor.victron_battery_soc`,
|
||
`input_text.victron_charge_mode` entre 01:00 et 08:00.
|
||
2. **Cause de l'extinction du Synology** (DSM → Centre des journaux) + réflexion SPOF :
|
||
le fail-safe physique actuel est « EDF ON + charge batterie » quand le NAS meurt.
|
||
3. Baisser `input_number.victron_evcs_soc_start_min` 94 → 90 (aligner avec P3) si souhaité.
|
||
4. **Sécuriser** : auth Bearer sur les 5 MCP Server Triggers n8n + révoquer/déplacer le jeton HA.
|
||
5. **À investiguer** : « conditions de démarrage nuit batterie non réunies » quand la batterie
|
||
suffit pour la nuit (conditions de départ `battery_assist_night`).
|
||
6. Optionnel : brancher un keepalive/republish Venus automatique après `mqtt.reload`
|
||
(cf. note maintenance §3).
|
||
|
||
## 8. Historique des sessions
|
||
|
||
- **12/06/2026** : analyse blocage outside_window, déploiement afternoon_probe (V2.6),
|
||
fix clignotement EDF (`edf_general_ok_on` conditionné au sourceMode).
|
||
- **09/07/2026 (nuit)** : incident EDF nocturne analysé (root cause complète), MCP option 1 en place,
|
||
P1 (hystérésis robuste + entité stratégie), P2 (anti-créneaux nuit), P3 (provocation PV).
|
||
- **09/07/2026 (journée/soir)** : incident Synology (NAS éteint → EDF ON toute la nuit, batterie 96 %),
|
||
firmware borne 2.08 (fantôme résolu), dashboard EDF Urgence + boost 28 A, P4 (maintien SOC
|
||
au forecast pendant takeover, via Auto Charge Manager), P5 (plafond EDF ON configurable),
|
||
fenêtres HC corrigées (01:24-07:24 / 12:24-14:24), maintenance erreurs (save error executions,
|
||
prise garage conditionnelle, 33 templates MQTT durcis).
|
||
|
||
---
|
||
*Document mis à jour le : 09/07/2026 (~23:55) — session opencode avec accès HA (REST+WS+NFS) + n8n (API+MCP)*
|
||
*État live à la clôture : SOC 65 % ↘, Jeep branchée, fenêtre HC à 01:24, nuit de validation P2+P4 en cours*
|