# 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//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. ### P6 — Override « abondance » du plancher SOC de démarrage (déployé 12/07 midi) - **Symptôme** : 12/07 midi, PV 8,9 kW, batterie en charge +125 A, Jeep branchée → EVCS bloqué `idle_wait_conditions`. Cause unique (dry-run) : plancher SOC fenêtre midi (`input_number.victron_evcs_midday_soc_min` = 75) > SOC 66. - **Fix (`BATTERY_CLOUD_LOCKS`)** : si `pvPowerAvg10m ≥ 4000 W` **et** `batteryCurrentA ≥ +20 A` (abondance physique : la batterie monte même avec l'EVCS), plancher de démarrage abaissé à **40 %** (`effectiveSocStartFloor`). Jours nuageux : planchers d'origine intacts. Debug exporté : `solarAbundance`, `effectiveSocStartFloor` (safeguards). - Vérifié en réel : déploiement 12:43 → `start_min_current` immédiat → charge 12 A. - **Observation borne** : après des heures branchée en statut 6, la Jeep a mis ~2,5 min à s'engager ; le workflow renvoie `turn_on` toutes les 30 s (retry intégré suffisant). - Planchers de référence : matin 35, midi 75, soir ?, hors fenêtre 94 (`soc_start_min`). ### 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/` → `modified/*_backup_.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/` (⚠️ 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). - **12/07/2026** : P6 (override abondance du plancher SOC midi — PV fort + batterie en charge ⇒ démarrage dès SOC 40) ; validation en réel à 12:43, charge Jeep engagée. - **17/07/2026 (après-midi)** : **Session de débogage majeure** — résolution d'un enchaînement de bugs bloquants empêchant la charge solaire de la Jeep : **Bug 1 — Typo critique dans DECISION_ENGINEV2** : - Ligne ~333 : `noDemandnightSessionNeedsClearScoreOff` (variable inexistante) au lieu de `noDemandScoreOff` - Conséquence : `evcsVehicleNoDemandSemantic` restait `false` même quand la voiture était pleine - Le filtre "véhicule plein/pause" ne fonctionnait jamais → blocage du système **Bug 2 — Artefacts de corruption dans WINDOWS_SOURCEV2** : - 3 occurrences de `tool_f6d3316d2001k4aAfEjbKGNUX2` (résidu de copier-coller ou debug) - Provoquaient des erreurs `is not defined` à l'exécution - Workflow en ERROR continu depuis 14:49 **Bug 3 — Session nuit jamais clearée** : - `input_boolean.victron_evcs_night_session_active` restait `on` depuis 23:24 la veille - Même après la fenêtre HC (01:24-07:24), le profil restait `night_hc` → `battery_assist_night` - En plein jour avec grand soleil, le système pensait être en "assistance batterie nuit" - Clearé manuellement à 14:45 **Bug 4 — EDF rebranché automatiquement en journée** : - Condition `edf_general_ok_on` déclenchée dès `sourceMode` = `grid_forced` ou `grid_hc_allowed` - Même en plein jour avec du soleil, EDF se rebranchait si le workflow passait en ces modes - Correction : ajout de `context.profile === 'night_hc'` pour ne rebrancher que la nuit **Configuration ajustée** : - `battery_discharge_soft_a` : 0A (au lieu de -8A) — permet le démarrage sans décharge batterie - `battery_neutral_band_a` : 0A (au lieu de -2A) — tolérance nulle - `soc_start_min` : 80% (au lieu de 94%) — seuil de démarrage plus réaliste - `night_target_soc` : 70% (au lieu de 85%) — laisse plus de marge pour le PV **Mode sonde activé** : - `probe_enabled` : ON — permet le démarrage à 6A pour "provoquer" la production PV - Particulièrement utile en autoconsommation sans injection où le PV ne produit que si chargé **Résultat** : - Workflow réparé et fonctionnel - Jeep en charge à 17A avec le soleil (16:58) - EDF OFF (ne se rebranche que la nuit) - Système 100% auto en `auto_solar_plus` - DeliveryRatio à 99.9% — charge stable et efficace **À noter** : Le courant de sonde (`probeCurrentA`) est codé en dur dans le workflow n8n (nœud SETUP/PARAMS), pas dans un helper HA. Pour le changer de 6A à 10A, modifier directement dans l'interface n8n. Mais le workflow augmente automatiquement le courant (17A atteints), donc ce n'est pas critique. ## ⚙️ CONFIG LOCALE — Qwen3.6-35B sur DGX Spark (≠ gros modèle cloud) > ⚠️ Cette config est CALIBRÉE pour le modèle LOCAL Qwen3.6-35B-A3B (3B actifs, > contexte limité). NE PAS appliquer telle quelle à un gros modèle cloud > (FABLE/Claude), qui n'a besoin ni du bornage strict ni du découpage par nœud. ### Infra (validée le 16/07/2026) - DGX Spark = 10.10.10.8, endpoint vLLM unique sur port 8000. - UN SEUL modèle à la fois (contrainte NVRAM 1 Spark) → swap via scripts : - `use-code` : docker compose down (VL) + sparkrun run qwen3.6-35b sur :8000 - `use-vl` : sparkrun stop --all + docker compose up (Qwen3-VL, vision) - Recette : @official/qwen3.6-35b-a3b-fp8-mtp-vllm --tp 1 --port 8000 --gpu-mem 0.8 --served-model-name qwen3.6-35b (MTP + flashinfer + tool-parser qwen3_coder déjà inclus dans la recette). - Qwen3-VL (docker /opt/vllm) réservé à l'analyse de captures d'écran. ### opencode.json (poste Ubuntu, PAS la Spark) - baseURL: http://10.10.10.8:8000/v1, apiKey "EMPTY". - Modèle "qwen3.6-35b" : options { temperature: 0.15, reasoningEffort: "none" }, cost tout à 0 (sinon compteur fantôme FABLE), limit context 65536. - permission.bash : "curl *": "deny", "wget *": "deny" (bloque hallucinations HTTP). - Les 6 MCP (n8n-mcp, ha-get-state, ha-set-helper, grid-set-state, victron-set-charge-limits, pv-get-forecast) : NE JAMAIS toucher ce bloc. ### RÈGLES DE TRAVAIL spécifiques au local (dans AGENTS.md) - Contexte trop petit pour un workflow entier (~357K = ~102K tokens > 65K). => JAMAIS charger le workflow complet. UN nœud / UNE tâche à la fois. - n8n-mcp_get_workflow renvoie le workflow entier => opencode l'écrit dans ~/.local/share/opencode/tool-output/tool_* (tronqué). Le fichier commence par "Retrieved workflow: " AVANT le JSON => json.load ÉCHOUE. Extraction validée : grep -n '"name":"NOEUD"' puis sed -n 'X,Yp'. (ripgrep/rg N'EST PAS installé sur la Spark, utiliser grep.) - reasoningEffort none coupe le thinking (le tag /no_think en tête de chat NE marche pas : opencode l'intercepte comme slash-command). - Skill n8n installée dans .opencode/skills/ — surveiller les compactions. ### PÉRIMÈTRE (le plus important) - LOCAL Qwen3.6 = tâches CIBLÉES : lire 1 nœud, repérer une faille logique, patch simple, dry-run. Rapide, gratuit, fiable SI bien borné. - CLOUD (FABLE/gros modèle) = refontes multi-nœuds, analyse d'un workflow ENTIER, orchestration MCP longue. Ne pas forcer le local dessus (il boucle). ## 🧩 SKILLS n8n — validées le 16/07/2026 (Qwen3.6 local, PAS gros modèle) > ⚠️ Config calibrée pour Qwen3.6-35B-A3B local (contexte 65K). Les skills > aident au tool-calling n8n. Sur gros modèle cloud, elles sont facultatives. ### Installation - Dépôt : github.com/viliamvolosv/n8n-opencode-skill - Emplacement OBLIGATOIRE : .opencode/skills//SKILL.md (dossier "skills" PLURIEL ; le repo clone dans un sous-dossier "skill" SINGULIER → il FAUT remonter : mv n8n-opencode-skill/skill/* .) - opencode doit être lancé DEPUIS le projet : cd /mnt/projects/EVCS/EVCS && opencode (sinon .opencode/skills/ n'est pas découvert → skills invisibles). - Chargement PROGRESSIF : au repos les 8 skills ne coûtent que ~12K tokens (18%). Le SKILL.md complet (~16K) ne se charge QUE si la skill est invoquée. ### Skills ACTIVES (5, validées par test réel sur DECISION_ENGINEV2) - n8n-mcp-tools-expert → récup config nœud via MCP (fiabilise les 6 MCP) - n8n-code-javascript → analyse/patch du jsCode (vars in/out, utilitaires) - n8n-expression-syntax → vérif syntaxe {{ }} - n8n-validation-expert → refs de nœuds, cohérence types, conditions - n8n-node-configuration → conformité params/mode/position ### Skills DÉSACTIVÉES (déplacées dans .opencode/skills-off/) - customize-opencode (méta, hors sujet EVCS) - n8n-code-python (on fait du JS) - n8n-workflow-patterns (exige le workflow ENTIER → risque contexte) → réactivables en les remettant dans skills/ , ou à réserver au cloud. ### Résultat du test de validation (5 skills, DECISION_ENGINEV2) - Les 5 skills invoquées et nommées correctement, analyse d'ingénieur juste (16 vars, 7 derived, 22 conditions, pipeline complet reconstitué). - UNE SEULE compaction (pic 88% au parsing du workflow 357K, reprise propre). - 2 AttributeError Python transitoires (structure connexions n8n) → auto-corrigés. - Coût : $0.00. ### RÈGLE contexte associée (dans AGENTS.md) - Analyse pipeline multi-nœuds : grep -n "name"/"jsCode" + sed sur la plage, JAMAIS le workflow JSON entier en mémoire Python. Traite 1 nœud, résume, libère. - Le fichier tool-output commence par "Retrieved workflow: " AVANT le JSON → parade validée : json.loads(text[text.index('{'):]). ### PÉRIMÈTRE (rappel) - Local Qwen3.6 + skills = analyse ciblée 1 nœud, validation, patch simple. ✅ - Cloud (FABLE/gros modèle) = refonte multi-nœuds massive, workflow entier. ## 9. Session du 18/07/2026 (matin) ### Corrections documentation (MANUEL_COMPLET.md) - **outside_window** : décrit comme "Mode probe (sonde) pour relancer le PV si besoin" (pas bloquant) - **Cloud Debt & Probe** : nouvelle section 11.4 complète avec explication dette nuageuse, mode probe 10A, bypass en auto_solar_plus / force_charge_now - **Stratégies** : clarifié `force_grid_now` = préservation batterie (SOC<22% → recover 35%/50%/75%) vs `force_charge_now` = secours manuel - **Heure de départ** : nouvelle section 11.5 "Logique Heure de départ (Night EVCS)" ### Modification workflow - **probeCurrentA** : augmenté de 6A à 10A dans le nœud INPUT_PARSE (fallback) - Rationale : 6A trop faible pour "provoquer" la production PV, 10A plus efficace ### Versionnage Git - Export du workflow dans `workflows/evcs-surplus-controller-v2.6.json` - Commit & push effectués ## 10. Session du 04/08/2026 (matin) — Fix grid HC 1h30 + libération takeover ### Problèmes诊断qués 1. **Charge HC ne démarre pas à 1h30** : Le grid ne se mettait pas en route à l'ouverture de la fenêtre HC 2. **Grid ne rend pas la main après charge** : EDF restait ON après la fin de charge (SOC 71% < 90%) ### Root Causes identifiées 1. **`gridAllowedBySoc`** (BATTERY_CLOUD_LOCKS) : autorise le grid seulement si `soc <= 35%` ou `forceGridRequested`. En profile `night_hc` avec SOC > 35%, le grid était bloqué. 2. **`nightTakeoverLatched`** (WINDOWS_SOURCEV2) : reste latché tant que `soc < 90%` (hardcodé). Pas de condition "véhicule chargé" → le takeover ne se libérait jamais. ### Corrections appliquées #### Fix 1: `gridAllowedBySoc` — Autoriser le grid en profile night_hc **Node:** `BATTERY_CLOUD_LOCKS` ```javascript // AVANT: const gridAllowedBySoc = parsed.soc <= 35 || strategy.forceGridRequested; // APRÈS: const gridAllowedBySoc = strategy.forceGridRequested || context.profile === 'night_hc' || parsed.soc <= 35; ``` #### Fix 2: `nightTakeoverLatched` — Libérer si charge terminée **Node:** `WINDOWS_SOURCEV2` ```javascript // AVANT: const nightTakeoverLatched = nightSessionActive && nightTakeoverPrev && parsed.soc < NIGHT_TAKEOVER_RELEASE_SOC_PCT; // APRÈS: const vehicleChargeCompleted = !parsed.evcsChargingSwitchOn && parsed.soc >= 50; const nightTakeoverLatched = nightSessionActive && nightTakeoverPrev && ( parsed.soc < NIGHT_TAKEOVER_RELEASE_SOC_PCT || vehicleChargeCompleted ); ``` ### Méthode de déploiement - **MCP n8n-mcp_update_workflow** : Erreur 1003 (request/body must NOT have additional properties) — bug du MCP - **Bypass** : Script `tools/n8n-rest-update-test.mjs` créé, utilise REST API n8n directement avec token - PUT réussi avec body minimal : `{name, nodes, connections, settings, staticData}` - Settings doit être minimal : `{"executionOrder":"v1","callerPolicy":"workflowsFromSameOwner"}` ### Backup - `backup-workflow-ATswvGfG4KJUls0K-1785849621547.json` ### Vérification - Les 2 patches sont dans le workflow en production - À surveiller : prochaine nuit HC (01:24-07:24) pour valider le comportement --- *Document mis à jour le : 04/08/2026 (~10:00) — Fix gridAllowedBySoc + nightTakeoverLatched via REST API* *État live à la clôture : Workflow patché, à tester en conditions réelles*