Files
EVCS/HANDOFF.md

14 KiB
Raw Blame History

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