Le selecteur de vehicule est reste sur VW du 07/09 20:49 au 13/09 : onze sessions consecutives ont herite de cette etiquette, toutes marquees « sur » — le drapeau `vehicule_sur` ne passe a faux que si le selecteur bouge PENDANT une session, donc un selecteur perime reste fiable a ses propres yeux. Quatre lignes corrigees, apres arbitrage du proprietaire : mer 09/09 15:55 6,61 kWh -> JEEP ven 11/09 16:54 7,45 kWh -> MEGANE sam 12/09 11:42 0,09 kWh -> JEEP sam 12/09 11:55 5,94 kWh -> JEEP La session du 11/09 n'est ni la VW ni la JEEP : 6 360 W a 28 A quand les deux vehicules du foyer plafonnent vers 3 680 W. C'est une Megane de service. Ce cas n'etait documente nulle part, et il corrige la doctrine « vehicules indiscernables » : elle ne vaut que pour la VW et la JEEP l'une par rapport a l'autre, un vehicule invite se lit dans `p_max_w`. Les sept autres lignes etaient justes — par chance, la VW etant celle qui charge le plus souvent. L'arbitrage a repose sur un contexte qu'aucun capteur ne produit : sa femme (JEEP) en conges, son fils (VW) en stage sans retour le midi. C'est l'argument central pour l'agent conversationnel — il dit lui-meme qu'il lui est plus facile de donner cela par WhatsApp que de venir sur un PC. Reparation idempotente, fenetre d'une minute, verifiee en lecture avant ecriture : chaque predicat vise exactement une ligne, energies concordantes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
1315 lines
68 KiB
Markdown
1315 lines
68 KiB
Markdown
# Manuel Utilisateur - Système EVCS Solaire
|
||
|
||
> Document généré le 17/07/2026 — dernière mise à jour le 22/08/2026
|
||
> (fixes anti-rebond A→G, câblage advisor cible SOC, P9 départ, véhicules VW/JEEP)
|
||
> Projet: n8n / Home Assistant / EVCS Solaire sans injection réseau
|
||
|
||
---
|
||
|
||
## 0. Installation physique (matériel réel)
|
||
|
||
> Relevé le 24/08/2026 depuis la console VRM (Paramètres → Appareils) et
|
||
> complété par le propriétaire. **À tenir à jour** : cette section existe pour
|
||
> qu'il n'ait jamais à redécrire son installation.
|
||
|
||
### Onduleurs
|
||
**2 × MultiPlus-II 48/5000/70-50**, *two units configured in parallel*
|
||
(instance VRM 276, id produit 2623, micrologiciel 2623556).
|
||
Numéros de série : `HQ2244WY9T6` (Phase 1 Maître) · `HQ23467ZN6F` (Phase 1
|
||
Unité parallèle 1). Puissance nominale du couple : **9000 W**
|
||
(`sensor.victron_ve_bus_nominal_inverter_power`).
|
||
⚠️ Le VE.Bus en parallèle n'expose **qu'une seule instance D-Bus** couvrant les
|
||
deux unités : `vebus/276/…` est déjà la grandeur système, pas celle d'un
|
||
onduleur isolé. Les unités individuelles n'apparaissent que sous
|
||
`vebus/276/Devices/N/…`.
|
||
|
||
### Champ photovoltaïque — 52 panneaux **RECOM/SILLIA 310 Wc**, quatre plans
|
||
|
||
Puissance de plaque : 310 Wc par panneau (valeur théorique à 25 °C).
|
||
**Total 16 120 Wc** pour 52 panneaux.
|
||
|
||
| Groupe | Chargeur solaire | Instance | Panneaux | Orientation | Inclinaison |
|
||
|---|---|---|---|---|---|
|
||
| **Sud-est** | SmartSolar **MPPT 250/70 rev2** (`AIRTRIA MPPT1`, s/n HQ2235HKX24) | 279 | **10** (2 strings de 5) | sud-est | **40°** |
|
||
| **Sud** | SmartSolar **MPPT RS 450/200** (s/n HQ2449YR9PT) | 280 | **30** (3 strings de 10) | plein sud | **35°** |
|
||
| **Ouest** | ″ (second tracker du même RS 450/200) | 280 | **9** (1 string de 9) | plein ouest | **45°** |
|
||
| **Suiveur** | SmartSolar **MPPT 150/35** (`V1`, s/n HQ2238U24HP) | 277 | **3** | suiveur de course | mobile |
|
||
|
||
Le groupe de 3 panneaux est sur un **tracker** : il démarre plein est puis suit
|
||
la course du soleil. En fin d'après-midi, **la moitié passe à l'ombre du
|
||
support des 30 panneaux sud**. Aucun modèle à plan fixe ne le représente
|
||
exactement ; l'approximation retenue pour la prévision est un plan est-sud-est
|
||
peu incliné (voir ci-dessous).
|
||
|
||
`V2` (instance 288) et `V3` (instance 278) apparaissent dans VRM avec
|
||
« dernière vue il y a un an » : appareils obsolètes, à ignorer.
|
||
|
||
**Conséquence majeure pour tout calcul de production** : avec du sud-est, du
|
||
sud, de l'ouest et un suiveur, la courbe journalière ne peut PAS être
|
||
représentée par un modèle solaire à plan unique. Une tentative d'ajustement
|
||
mono-plan (24/08) converge sur « plein est, 20° » et prédit 2,0 % de la journée
|
||
à 18 h contre 5,8 % réellement mesurés. La forme doit venir de la mesure, ou
|
||
d'un modèle à plusieurs plans. Voir `docs/CHANTIER_BILAN_ENERGETIQUE.md`.
|
||
|
||
⚠️ **Forecast.Solar est mal configuré** (constaté le 24/08, configuration lue
|
||
dans `.storage/core.config_entries`) : **un seul plan**, azimut 180 (plein sud),
|
||
inclinaison 25°, 15 000 Wc, et un `inverter_size` de 8 000 W alors que
|
||
l'installation a déjà produit **10 770 W** mesurés — le plafond tronque donc
|
||
toute prévision. Résultat : la prévision attend une journée orientée
|
||
l'après-midi (15,1 % de l'énergie entre 7 h et 11 h) là où l'installation
|
||
produit le matin. ⚠️ Le chiffre de « 39,3 % mesurés » cité dans les premières
|
||
versions de cette section est **abandonné** : il reposait sur une enveloppe qui
|
||
surpondère structurellement le matin, et sur une attribution horaire décalée
|
||
d'une heure (corrigée le 25/08, voir `docs/CHANTIER_BILAN_ENERGETIQUE.md`). Le
|
||
défaut de configuration était réel, son ampleur a été surestimée.
|
||
|
||
**Correction à appliquer** (interface HA, voir §0bis) : quatre plans.
|
||
|
||
| Plan | Azimut (0 = nord, 90 = est, 180 = sud, 270 = ouest) | Inclinaison | Puissance |
|
||
|---|---|---|---|
|
||
| Sud-est | 135 | 40° | 3 100 W |
|
||
| Sud | 180 | 35° | 9 300 W |
|
||
| Suiveur (approximation) | 120 | 30° | 930 W |
|
||
| Ouest | 270 | 45° | 2 790 W |
|
||
|
||
et `inverter_size` porté de 8 000 à **16 000 W**.
|
||
|
||
### Batterie
|
||
**8 × Pylontech US2000C** (`AIRTRIA 8 US2000C`, Battery Monitor, instance VRM
|
||
512, fabricant PYLON, interface CAN-bus), organisés en **deux packs de 4 reliés
|
||
par un hub**. Le premier pack a deux ans de plus que le second et a vécu avant
|
||
la climatisation du garage.
|
||
**État au 24/08/2026 : un module en panne et isolé → 7 modules actifs**, un
|
||
huitième commence à faiblir. Mélanger des packs d'âges différents est
|
||
déconseillé (contrainte de budget, pas un choix technique).
|
||
⚠️ `batteryUsableCapacityKwh: 17.5` est codé en dur dans `INPUT_PARSE.js` et
|
||
utilisé trois fois dans `WINDOWS_SOURCEV2.js` : avec 7 modules, cette valeur
|
||
surestime la réserve réelle de 15 à 20 %. Aucun capteur de capacité ou de santé
|
||
batterie n'est publié côté HA — à corriger.
|
||
|
||
**Accès diagnostic au BMS** (05/09/2026). Le câble console Pylontech est branché
|
||
sur une machine **Windows en 10.10.10.93**, qui fait tourner **BatteryView**.
|
||
Cette machine ne répond qu'en SMB (445) : RDP, SSH et WinRM sont fermés, et
|
||
BatteryView est de toute façon une application graphique qui garde le port COM
|
||
pour elle seule — il n'y a rien à interroger à distance. Les exports (history,
|
||
events, captures) se déposent dans
|
||
`\\10.10.10.22\projects\EVCS\EVCS\docs\mesures\batteries\`, dossier que je
|
||
lis directement.
|
||
|
||
⚠️ **`help` n'existe pas dans BatteryView** : c'est une commande de la console
|
||
série du BMS, un mode distinct sur le même port. Pour y accéder il faut FERMER
|
||
BatteryView (le port COM est exclusif) puis ouvrir un terminal série
|
||
(PuTTY → Serial → COMx, 115200 8N1, sans contrôle de flux ; replier sur 1200
|
||
bauds si rien ne s'affiche). Commandes utiles une fois au prompt : `help`,
|
||
`info`, `pwr` (vue par module), `bat <n>` (**tensions cellule par cellule** du
|
||
module n), `log`, `stat`.
|
||
|
||
### Borne de recharge
|
||
**EV Charging Station 32A** (s/n HQ2239DNT7P, micrologiciel v2.08, instance VRM
|
||
40), position « EV charger on output ».
|
||
Deux véhicules alternent : **VW** (hybride, départ ~08:50) et **JEEP**
|
||
(départ ~06:30) — cf. §11.5.
|
||
|
||
### Routine de charge des deux vehicules (donnee par le proprietaire, 05/09/2026)
|
||
|
||
| vehicule | conducteur | quand il charge |
|
||
|---|---|---|
|
||
| **JEEP** | sa femme, qui rentre dejeuner | **le midi en semaine**, typiquement 13 h - 15 h |
|
||
| **VW** | son fils, parti vers 9 h, rentre vers 19 h | **le soir et la nuit** |
|
||
|
||
Exemples donnes : lundi midi la JEEP · mardi midi la JEEP puis la VW la nuit ·
|
||
mercredi midi la JEEP.
|
||
|
||
**LE WEEK-END, LA ROUTINE S'INVERSE.** Sa femme travaille le samedi matin et le
|
||
dimanche matin, retour a midi : la **JEEP** charge donc le midi ET la nuit du
|
||
samedi au dimanche. La **VW** ne bouge pas du week-end — sauf sortie plongee —
|
||
et se charge **en journee**, pendant que la JEEP est au travail.
|
||
|
||
⚠️ **Aucune regle horaire ne permet donc d'identifier le vehicule.** Une
|
||
heuristique « midi = JEEP, nuit = VW » serait fausse un week-end sur deux. Ne
|
||
pas en ecrire une.
|
||
|
||
⚠️ **Les deux vehicules sont ELECTRIQUEMENT INDISCERNABLES.** Mesure le 05/09
|
||
sur deux sessions a consigne identique de 20 A : la VW accepte 3 680 W et la
|
||
JEEP 3 655 W — **vingt-cinq watts d'ecart, 0,1 A**. Tous deux embarquent un
|
||
chargeur de 3,7 kW et saturent au meme endroit. Ni la puissance de plateau ni
|
||
le taux d'acceptation de la consigne ne les separent. Inutile de rechercher une
|
||
signature electrique : elle n'existe pas.
|
||
|
||
Le seul etiquetage fiable est donc `input_select.victron_evcs_vehicle`, qui est
|
||
un **reglage manuel** — donc faillible : il peut etre oublie, et un redemarrage
|
||
de Home Assistant peut l'annuler (constate le 04/09 a 19:44, cf. HANDOFF §47).
|
||
L'heure de **debranchement** confirme a posteriori, les deux vehicules partant
|
||
a des heures differentes (JEEP ~06:30, VW ~08:50).
|
||
|
||
### Vehicules INVITES : ils se reconnaissent, eux
|
||
|
||
Un troisieme cas existe depuis toujours et n'etait documente nulle part : des
|
||
vehicules qui ne sont pas ceux du foyer.
|
||
- une **Megane electrique de service**, que le proprietaire utilise pour ses
|
||
deplacements professionnels (Rennes, 11/09/2026) ;
|
||
- les voitures d'**amis de passage**, a qui il propose de recharger.
|
||
|
||
⚠️ **Contrairement a la VW et a la JEEP, ceux-la se distinguent
|
||
electriquement.** Les deux vehicules du foyer plafonnent vers 3 680 W (~16 A
|
||
embarques) ; la Megane a pris **6 360 W a 28 A** le 11/09. La colonne
|
||
`session_charge.p_max_w` suffit donc a dire « ce n'est aucun des deux » :
|
||
|
||
| p_max_w | lecture |
|
||
|---|---|
|
||
| ~1 700 W | VW ou JEEP a courant reduit (6-9 A) |
|
||
| 3 600 a 3 800 W | VW ou JEEP a pleine consigne — **indiscernables entre elles** |
|
||
| > 4 000 W | vehicule INVITE, ni VW ni JEEP |
|
||
|
||
La doctrine « les vehicules sont indiscernables » ne vaut donc QUE pour la VW
|
||
et la JEEP l'une par rapport a l'autre. Toute question posee au proprietaire
|
||
sur l'identite d'un vehicule doit offrir une reponse « aucune des deux », sans
|
||
quoi elle le force a repondre faux.
|
||
|
||
### Le CONTEXTE qui decide, et qu'aucun capteur ne produit
|
||
|
||
Releve du 13/09/2026, donne par le proprietaire pour trancher deux sessions
|
||
ambigues : **sa femme (JEEP) etait en conges cette semaine et la suivante**, et
|
||
**son fils (VW) en stage toute la semaine sans retour le midi**. Ces deux faits
|
||
inversent la routine habituelle — la JEEP charge l'apres-midi au lieu du midi,
|
||
la VW ne charge pas en journee.
|
||
|
||
⚠️ Aucune regle horaire, aucune signature electrique, aucun historique ne
|
||
permet de deviner cela. C'est l'argument central en faveur d'un agent
|
||
conversationnel : le proprietaire dit qu'il lui est **plus facile de donner ces
|
||
informations par WhatsApp que de venir sur un PC**. Le trou a combler n'est pas
|
||
la mesure, c'est le contexte humain.
|
||
|
||
### Un TROISIEME vehicule a venir : la moto
|
||
|
||
Le proprietaire possede une **moto electrique Zero Motorcycles SR/F**. Elle
|
||
n'est pas chargee actuellement — il s'est ecrase le majeur de la main droite
|
||
avec une betonneuse et enfiler un gant est difficile — et il pense reconduire
|
||
**fin septembre 2026**.
|
||
|
||
A faire a ce moment-la, et rien avant :
|
||
1. ajouter `ZERO` aux options de `input_select.victron_evcs_vehicle`
|
||
(paquet `victron_evcs_vehicles.yaml`, puis rechargement des entrees) ;
|
||
2. creer son heure de depart si elle differe
|
||
(`input_datetime.victron_evcs_departure_time_zero`) et l'ajouter au choix
|
||
de `departureTimeMin` dans `INPUT_PARSE.js`, a cote de VW et JEEP ;
|
||
3. la table `session_charge` n'a rien a changer : elle enregistre la valeur du
|
||
selecteur, quelle qu'elle soit.
|
||
|
||
⚠️ Une moto a une batterie bien plus petite qu'une voiture (une SR/F est de
|
||
l'ordre de 14 a 17 kWh) et un chargeur embarque plus faible. **C'est donc
|
||
peut-etre le premier vehicule du foyer qui soit electriquement distinguable
|
||
des deux autres** — a verifier le moment venu, en comparant son plateau de
|
||
puissance a consigne elevee aux 3 655 / 3 680 W de la JEEP et de la VW.
|
||
|
||
NB : un ancien `input_select.victron_evcs_target_vehicle` (None/Jeep/Zero)
|
||
existe encore, cree par l'interface et cable nulle part. Ne pas le confondre
|
||
avec le selecteur en service, ni le reutiliser.
|
||
|
||
### Consommation de la maison — pilotee par les repas, pas par une courbe lisse
|
||
> Donne par le proprietaire le 03/09/2026. **A ne pas redecouvrir.**
|
||
|
||
Quatre personnes. Les gros appels de puissance sont ponctuels, brefs, et cales
|
||
sur les repas — pas etales :
|
||
|
||
| moment | charge | remarque |
|
||
|---|---|---|
|
||
| **05:45** | bouilloire | premier gros appel de la journee |
|
||
| **08:00** | grille-pain | second pic du matin |
|
||
| **20:00 a 23:00** | cuisson du soir | **l'heure varie de trois heures** selon les jours |
|
||
|
||
Les repas ne sont pas les memes d'un jour a l'autre, et l'heure du diner se
|
||
decale entre 20 h et 23 h. Consequences directes pour le bilan energetique :
|
||
|
||
1. **Un profil horaire moyen ne represente rien.** Un pic de bouilloire a 05:45
|
||
et un four a 21:30 disparaissent dans une mediane horaire alors qu'ils
|
||
dominent la decharge de la nuit. C'est la cause la plus probable de la
|
||
sous-estimation mesuree du profil p50 (2,1 kWh annonces pour 03:00-06:00 la
|
||
nuit du 02-03/09, contre 2,79 kWh reellement consommes).
|
||
2. **Le decalage de trois heures du diner interdit de caler le profil sur
|
||
l'heure d'horloge.** Deux jours consecutifs peuvent placer le meme pic a
|
||
20 h et a 23 h : moyenner les deux produit un profil que ni l'un ni l'autre
|
||
ne ressemble.
|
||
3. **Une decharge courte mais forte n'a pas le meme effet qu'une decharge lente
|
||
de meme energie.** Le proprietaire souligne que le comportement du stockage
|
||
et l'autonomie en dependent, et que ce n'est pas lineaire. La courbe
|
||
energie/SOC mesuree (§11.8.H) est etablie en decharge domestique ordinaire ;
|
||
elle ne dit rien du rendement sous fort courant.
|
||
|
||
### Strategie hivernale du proprietaire (contournement manuel a reprendre)
|
||
> Donne le 03/09/2026.
|
||
|
||
L'hiver, la production est « souvent minable toute la journee ». Le
|
||
proprietaire procede donc en **deux charges reseau par jour** :
|
||
|
||
1. **heures creuses de la nuit** (01:24-07:24) : recharge de la batterie a
|
||
**85 %**, de quoi faire la jonction avec la production PV du matin ;
|
||
2. **recharge de midi** : nouvelle charge batterie pour tenir jusqu'a la
|
||
fenetre HC de 01:24 suivante.
|
||
|
||
⚠️ C'est un **contournement manuel**, de la meme famille que les charges
|
||
programmees de l'ESS desactivees le 27/08 et que la consigne reseau a 4200 W
|
||
corrigee le 31/08. Le besoin qu'il couvre est reel et entier. Il ne doit pas
|
||
etre retire avant que le bilan energetique ne sache le produire seul —
|
||
c'est-a-dire viser une cible du matin elevee ET planifier une seconde session
|
||
reseau de midi quand la journee ne permet pas de tenir. Le cablage du 03/09
|
||
(§11.8.F et G) ne couvre que la session de nuit.
|
||
|
||
### Batterie — blocage de charge a 94 %, et le pack a rebrancher
|
||
> Donne le 03/09/2026.
|
||
|
||
Un des packs **bloque la charge a 94 %** : c'est la limite haute reelle du parc
|
||
aujourd'hui, et elle explique que la courbe mesuree (§11.8.H) s'arrete a 93.
|
||
En rebranchant le pack supplementaire actuellement isole, le blocage
|
||
**pourrait descendre a 85 %** — valeur que le proprietaire juge **possiblement
|
||
fausse**, donc a mesurer plutot qu'a supposer.
|
||
|
||
Consequence a ne pas oublier : `battery_full_soc` = 90, et le plafond de 90 %
|
||
utilise par la cible du matin (§11.8.F) supposent une batterie qui monte
|
||
au-dessus. Si le blocage reel est a 85, ces bornes deviennent inatteignables et
|
||
toute logique du type « charger jusqu'a 90 » tourne dans le vide. **A verifier
|
||
avant l'extension du parc prevue cet hiver.**
|
||
|
||
### Régime d'exploitation — majoritairement HORS RÉSEAU
|
||
Précision donnée par le propriétaire le 27/08/2026, à ne pas redécouvrir :
|
||
l'installation fonctionne **la plupart du temps AC-IN ouvert**
|
||
(`switch.edf_general_ok_switch` fermé seulement lors des sessions réseau
|
||
décidées par les workflows). Conséquence assumée : **l'alarme perte-réseau du
|
||
MultiPlus (`switch.airtria_mpii_v1_grid_lost_alarm_setting`) est désactivée
|
||
volontairement** — avec cette topologie elle se déclencherait en permanence. Ne
|
||
pas proposer de la réactiver.
|
||
|
||
Pour détecter une **vraie coupure subie** (orage), le signal correct n'est donc
|
||
pas l'alarme mais la contradiction commande/mesure : contacteur EDF commandé
|
||
fermé alors que `sensor.victron_ac_in1_available` reste à 0 ou que
|
||
`sensor.airtria_mpii_v1_input_voltage_l1` reste nulle. Entièrement local.
|
||
|
||
Les coupures d'orage sont **fréquentes** sur ce site, et emportent souvent la
|
||
connexion Internet avec elles — d'où l'exigence d'outils consultables hors
|
||
ligne (la console VRM est hébergée dans le cloud Victron).
|
||
|
||
### Charges programmées de l'ESS (propriétaire concurrent — 27/08/2026)
|
||
Le GX porte ses propres fenêtres de charge réseau, **trois actives tous les
|
||
jours**, qu'aucun workflow ne lit : 01:35 → 45 %, 07:30 → 45 %, 12:24 → 55 %
|
||
(plus deux désactivées). Elles entraient en concurrence directe avec la cible du
|
||
matin calculée par l'EVCS (35 % en été). Entités
|
||
`switch.gx_device_ess_batterylife_schedule_charge_N_enabled` et associées.
|
||
|
||
**Désactivées le 27/08/2026** (les cinq), sur décision du propriétaire : c'était
|
||
un contournement manuel de sa part — d'abord quand le système ne tenait plus un
|
||
seuil de 20 %, puis l'hiver pour garantir un minimum de charge en heures creuses
|
||
et éviter de rallumer EDF en heures pleines. Le contrôleur EVCS est désormais
|
||
seul propriétaire de la décision réseau. ⚠️ Le besoin hivernal reste entier et
|
||
doit être repris par le bilan énergétique (cf. règle saisonnière : l'hiver la
|
||
cible du matin monte vers 80 %, car 10 h locales = 9 h TU contre 9 h locales =
|
||
7 h TU l'été, soit ~2 h de nuit en plus à couvrir).
|
||
|
||
### Réseau
|
||
Victron **ESS sans injection** : la production est bridée en permanence à ce que
|
||
le système peut absorber (consommation + charge batterie). Voir
|
||
`docs/CHANTIER_BILAN_ENERGETIQUE.md` pour les conséquences sur toute mesure de
|
||
production.
|
||
|
||
---
|
||
|
||
## 1. Architecture Globale
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────────────┐
|
||
│ DGX Spark (10.10.10.8) │
|
||
│ ┌─────────────────┐ ┌─────────────────┐ │
|
||
│ │ Qwen3.6-35B │ │ Qwen3-VL │ │
|
||
│ │ (texte, code) │ │ (vision) │ │
|
||
│ └────────┬────────┘ └────────┬────────┘ │
|
||
└───────────┼──────────────────────┼──────────────────────────────┘
|
||
│ │
|
||
▼ ▼
|
||
┌───────────────────────────────────────────────────────────────────┐
|
||
│ opencode (minimax-m2.5) │
|
||
│ ┌─────────────────────────────────────────────────────────────┐ │
|
||
│ │ Skills: n8n-code-javascript, n8n-expression-syntax, │ │
|
||
│ │ n8n-mcp-tools-expert, n8n-node-configuration, │ │
|
||
│ │ n8n-validation-expert │ │
|
||
│ └─────────────────────────────────────────────────────────────┘ │
|
||
└───────────┬──────────────────────┬───────────────────────────────┘
|
||
│ │
|
||
▼ ▼
|
||
┌──────────────────────┐ ┌──────────────────────────────────────┐
|
||
│ n8n (cloud) │ │ Home Assistant (10.10.10.17:8123) │
|
||
│ https://n8n.airtria.pro │ ┌──────────────────────────────────┐ │
|
||
│ ┌────────────────┐ │ │ │ Dashboards YAML (17 fichiers) │ │
|
||
│ │ 40 workflows │ │ │ │ - evcs_master.yaml │ │
|
||
│ │ 13 actifs │ │ │ │ - evcs_mobile.yaml │ │
|
||
│ └────────┬───────┘ │ │ │ - victron_master.yaml │ │
|
||
│ │ │ │ │ - etc. │ │
|
||
│ ▼ │ │ └──────────────────────────────────┘ │
|
||
│ ┌────────────────┐ │ └──────────────────────────────────────┘
|
||
│ │ MCP Servers │ │
|
||
│ │ (6 outils) │ │
|
||
│ └────────┬───────┘ │
|
||
└───────────┼─────────┘
|
||
│
|
||
▼
|
||
┌───────────────────────────────────────────────────────────────────┐
|
||
│ Équipements physiques │
|
||
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
|
||
│ │ EVCS HQ229 │ │ Victron ESS │ │ MultiPlus │ │
|
||
│ │ (borne VE) │ │ (batterie) │ │ (onduleur) │ │
|
||
│ └─────────────┘ └─────────────┘ └─────────────┘ │
|
||
└───────────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 2. Workflows n8n Actifs
|
||
|
||
### 2.1 Gestion Énergie (EVCS + Grid)
|
||
|
||
| ID | Nom | Fréquence | Fonction |
|
||
|---|---|---|---|
|
||
| `ATswvGfG4KJUls0K` | HA Snapshot EVCS Surplus Controller V2.6 | 30s | Pilotage borne EVCS, décision charge solaire/réseau |
|
||
| `7iIlu7LLTW7TZA8o` | Victron - Battery / Grid Hysteresis Fix V1 | 1 min | Hystérésis réseau EDF (ON ≤20%, OFF ≥30%) |
|
||
| `cTeeHy4ePiVeELLh` | Victron - Auto Charge Manager V1.2 | **5 min** | Limites DVCC batterie (MaxChargeCurrent/Voltage) |
|
||
|
||
### 2.2 Gestion Charges
|
||
|
||
| ID | Nom | Fréquence | Fonction |
|
||
|---|---|---|---|
|
||
| `2NhrfxuGm4pTUNs9` | SDB Climate & Surplus Manager V2.2 | 1 min | Pilotage chauffage SDB selon surplus |
|
||
| `FtPVF7byhtu4o6Oh` | Victron - Garage Thermal Surplus Manager V2.2 | 1 min | Gestion garage thermique |
|
||
| `A11aOb50cGtpJmvn` | Water Heater Advisor V2.3 | 10 min | Advisor ballon ECS |
|
||
| `yX2j8m04e3pxaoQq` | Water Heater Advisor ECS 6 Nodes + Build + Execute | 10 min | Pilotage ballon ECS |
|
||
| `YjiNCpEoVhPT8JMw` | Victron - Flexible Load Advisor V1 | 5 min | Charge flexible |
|
||
|
||
### 2.3 Advisor / Monitoring
|
||
|
||
| ID | Nom | Fréquence | Fonction |
|
||
|---|---|---|---|
|
||
| `U0nRmdS9Pa0qzpWm` | Victron - PV Surplus Advisor V1 | 15 min | Advisor surplus PV |
|
||
|
||
### 2.4 MCP (Machine Communication Protocol)
|
||
|
||
| ID | Nom | Fonction |
|
||
|---|---|---|
|
||
| `76hHlVYIgt1lEHyR` | MCP - ha.get_state | Lecture états HA |
|
||
| `eeDmEICJ3ArjwpCt` | MCP - ha.set_helper | Écriture helpers HA |
|
||
| `uGZAOJjKegRuRNyb` | MCP - grid-set-state | Pilotage ON/OFF réseau EDF |
|
||
| `a92quWH4pokpIqdn` | MCP - victron-set-charge-limits | Limites courant/tension batterie |
|
||
| `RVTMdsvR4i8wSc18` | MCP - pv.get_forecast | Prévisions Forecast.Solar |
|
||
|
||
---
|
||
|
||
## 3. Skills opencode
|
||
|
||
| Skill | Chemin | Fonction |
|
||
|---|---|---|
|
||
| n8n-code-javascript | `.opencode/skills/n8n-code-javascript/SKILL.md` | Analyse/patch code JS dans nodes n8n |
|
||
| n8n-expression-syntax | `.opencode/skills/n8n-expression-syntax/SKILL.md` | Validation syntaxe {{ }} |
|
||
| n8n-mcp-tools-expert | `.opencode/skills/n8n-mcp-tools-expert/SKILL.md` | Utilisation outils MCP |
|
||
| n8n-node-configuration | `.opencode/skills/n8n-node-configuration/SKILL.md` | Configuration nœuds n8n |
|
||
| n8n-validation-expert | `.opencode/skills/n8n-validation-expert/SKILL.md` | Interprétation erreurs validation |
|
||
|
||
---
|
||
|
||
## 4. MCP - Outils disponibles
|
||
|
||
### 4.1 Lecture
|
||
|
||
- **ha-get-state** : Lire un état Home Assistant
|
||
- Input: `entity_id` (ex: `sensor.victron_battery_soc`)
|
||
- Output: état + attributs
|
||
|
||
- **pv-get-forecast** : Prévisions solaires
|
||
- Input: aucun
|
||
- Output: `today_remaining_kwh`, `tomorrow_kwh`, `tomorrow_peak_time`
|
||
|
||
### 4.2 Écriture
|
||
|
||
- **ha-set-helper** : Écrire un helper HA
|
||
- Input: `entity_id`, `value`
|
||
|
||
- **grid-set-state** : Piloter le réseau EDF
|
||
- Input: `state` ('on' ou 'off')
|
||
|
||
- **victron-set-charge-limits** : Limites de charge
|
||
- Input: `max_charge_current_a`, `max_charge_voltage_v`
|
||
|
||
### 4.3 Workflows n8n
|
||
|
||
- **n8n-mcp** : CRUD workflows
|
||
- List workflows, get workflow, update workflow, activate/deactivate
|
||
|
||
---
|
||
|
||
## 5. Dashboards Home Assistant
|
||
|
||
### 5.1 Principaux
|
||
|
||
| Fichier | Titre | Description |
|
||
|---|---|---|
|
||
| `evcs_master.yaml` | EVCS Master | Dashboard principal borne VE |
|
||
| `evcs_mobile.yaml` | EVCS Mobile | Version mobile |
|
||
| `victron_master.yaml` | Victron Master | Dashboard principal système Victron |
|
||
| `victron_mobile.yaml` | Victron Mobile | Version mobile |
|
||
|
||
### 5.2 Debug
|
||
|
||
| Fichier | Titre | Description |
|
||
|---|---|---|
|
||
| `big_victron_debug.yaml` | Victron Debug (complet) | Debug étendu |
|
||
| `victron_debug.yaml` | Victron Debug | Debug standard |
|
||
| `EVCS_SOLAR.yaml` | EVCS Solar | Vue solaire EVCS |
|
||
|
||
### 5.3 Pilotage
|
||
|
||
| Fichier | Titre | Description |
|
||
|---|---|---|
|
||
| `ECS_PILOTAGE.yaml` | ECS Pilotage | Pilotage ECS |
|
||
| `ECS_PILOTAGE_PREMIUM.yaml` | ECS Pilotage Premium | Pilotage ECS avancé |
|
||
| `GARAGE_PREMIUM_PILOTAGE.yaml` | Garage Premium Pilotage | Pilotage garage |
|
||
| `SDB_PREMIUM_PILOTAGE.yaml` | SDB Premium Pilotage | Pilotage SDB |
|
||
|
||
### 5.4 Debug Premium
|
||
|
||
| Fichier | Titre | Description |
|
||
|---|---|---|
|
||
| `ECS_DEBUG_REGLAGES.yaml` | ECS Debug Réglages | Debug ECS |
|
||
| `ECS_DEBUG_REGLAGES_PREMIUM.yaml` | ECS Debug Réglages Premium | Debug ECS avancé |
|
||
| `GARAGE_DEBUG_PREMIUM.yaml` | Garage Debug Premium | Debug garage |
|
||
| `SDB_DEBUG_PREMIUM.yaml` | SDB Debug Premium | Debug SDB |
|
||
|
||
---
|
||
|
||
## 6. Helpers Home Assistant (principaux)
|
||
|
||
### 6.1 Configuration EVCS
|
||
|
||
| Entity ID | Type | Description |
|
||
|---|---|---|
|
||
| `input_select.victron_evcs_strategy` | select | Stratégie (auto_solar_plus, force_grid_now, etc.) |
|
||
| `input_select.victron_evcs_vehicle` | select | **Véhicule branché : VW ou JEEP** (09/08/2026, à sélectionner au branchement) |
|
||
| `input_number.victron_evcs_required_energy_kwh` | number | Énergie demandée (kWh) |
|
||
| `input_boolean.victron_evcs_departure_priority_enabled` | boolean | Priorité départ |
|
||
| `input_datetime.victron_evcs_departure_time` | datetime | Heure de départ **VW** (~08:50) |
|
||
| `input_datetime.victron_evcs_departure_time_jeep` | datetime | Heure de départ **JEEP** (~06:30) |
|
||
| `input_boolean.victron_evcs_allow_grid_departure_urgent` | boolean | **P9 : réseau avant départ hors HC** (fenêtre 120 min) |
|
||
| `input_boolean.victron_evcs_allow_grid_hc_night` | boolean | Réseau HC nuit (P7) |
|
||
| `input_boolean.victron_evcs_allow_grid_hc_midday` | boolean | Réseau HC midi |
|
||
| `input_boolean.victron_evcs_surplus_auto_enabled` | boolean | Contrôleur surplus actif |
|
||
|
||
Package : `/mnt/ARCH3/docker/HA/packages/victron_evcs_vehicles.yaml` (sélecteur,
|
||
départ JEEP, toggle P9). NB : `input_select.victron_evcs_target_vehicle`
|
||
(None/Jeep/Zero) est un ancien helper UI non câblé — ne pas l'utiliser.
|
||
|
||
### 6.1bis Conseiller IA (advisor)
|
||
|
||
| Entity ID | Type | Description |
|
||
|---|---|---|
|
||
| `input_boolean.evcs_advisor_enabled` | boolean | Kill-switch : l'advisor tourne (15 min) et écrit ses recommandations |
|
||
| `input_boolean.evcs_advisor_apply_night_target` | boolean | **CÂBLAGE RÉEL** : la cible SOC matin suit l'advisor (bornes 22-90, statut ok, fraîcheur ≤ 120 min) |
|
||
| `input_number.evcs_advisor_night_target_soc` | number | Cible SOC matin recommandée |
|
||
| `input_text.evcs_advisor_strategy` / `_reason` / `_status` / `_divergence` / `_last_run` / `_model` | text | Détail des recommandations (cartes + historique) |
|
||
| `input_number.evcs_advisor_agree_count` / `_diverge_count` | number | Compteurs accord/divergence vs réel |
|
||
|
||
Package : `/mnt/ARCH3/docker/HA/packages/evcs_advisor_shadow.yaml`.
|
||
|
||
### 6.2 État système
|
||
|
||
| Entity ID | Type | Description |
|
||
|---|---|---|
|
||
| `input_text.victron_evcs_operating_mode` | text | Profil actif |
|
||
| `input_text.victron_evcs_surplus_state` | text | État interne |
|
||
| `input_text.victron_evcs_surplus_current_decision` | text | Décision logique |
|
||
| `input_text.victron_evcs_source_mode` | text | Source autorisée (Solaire/Réseau) |
|
||
| `input_text.victron_evcs_surplus_reason` | text | Raison courte |
|
||
| `input_text.victron_evcs_last_block_reason` | text | Dernier blocage |
|
||
|
||
### 6.3 Paramètres seuils
|
||
|
||
| Entity ID | Type | Description | Valeur actuelle |
|
||
|---|---|---|---|
|
||
| `input_number.victron_evcs_soc_start_min` | number | Seuil SOC démarrage | 80% |
|
||
| `input_number.victron_evcs_soc_stop_min` | number | Seuil SOC arrêt | 70% |
|
||
| `input_number.victron_evcs_midday_soc_min` | number | Seuil SOC midi | 75% |
|
||
| `input_number.victron_evcs_night_target_soc` | number | Cible SOC nuit | 70% |
|
||
| `input_number.evcs_plafond_courant_edf_on` | number | Plafond EDF ON | 20A |
|
||
| `input_number.victron_evcs_current_max_auto_a` | number | Plafond modes auto | 22A |
|
||
|
||
### 6.4 Hystérésis réseau
|
||
|
||
| Entity ID | Type | Description |
|
||
|---|---|---|
|
||
| `input_boolean.victron_grid_hysteresis_latch` | boolean | Latch hystérésis |
|
||
| `input_boolean.victron_evcs_night_session_active` | boolean | Session nuit active |
|
||
| `input_boolean.victron_evcs_night_grid_takeover_needed` | boolean | Takeover réseau nuit |
|
||
|
||
---
|
||
|
||
## 7. Capteurs clés (lecture seule)
|
||
|
||
| Entity ID | Description |
|
||
|---|---|
|
||
| `sensor.victron_battery_soc` | SOC batterie (%) |
|
||
| `sensor.victron_battery_current` | Courant batterie (A) |
|
||
| `sensor.victron_pv_power_system` | Puissance PV totale (W) |
|
||
| `sensor.victron_consumption_power_l1` | Consommation maison (W) |
|
||
| `sensor.victron_grid_power_l1` | Puissance réseau (W) |
|
||
| `sensor.victron_evcs_current` | Courant EVCS réel (A) |
|
||
| `sensor.victron_evcs_set_current` | Consigne lue borne (A) |
|
||
| `sensor.victron_evcs_ac_power` | Puissance EVCS (W) |
|
||
| `sensor.victron_evcs_charging_time` | Durée de charge |
|
||
| `sensor.victron_evcs_statut_fr` | Statut FR borne |
|
||
| `sensor.victron_evcs_mode_fr` | Mode FR borne |
|
||
| `switch.edf_general_ok_switch` | Interrupteur réseau EDF |
|
||
| `binary_sensor.victron_evcs_vehicle_connected` | Véhicule connecté |
|
||
| `binary_sensor.victron_evcs_device_connected` | Borne détectée |
|
||
|
||
---
|
||
|
||
## 8. Scripts HA
|
||
|
||
| Script | Fonction |
|
||
|---|---|
|
||
| `script.evcs_boost_edf` | BOOST EDF 28A (plafonds 28A + force_grid_now) |
|
||
| `script.evcs_boost_off` | Retour normal (plafonds 20/22 + auto_solar_plus) |
|
||
| `script.edf_urgence_off` | EDF Urgence OFF (hystérésis OFF + latch OFF + stratégie stop) |
|
||
| `script.edf_force_on` | EDF forcé ON |
|
||
| `script.edf_rendre_la_main` | Rendre la main au système auto |
|
||
|
||
---
|
||
|
||
## 9. Stratégies de charge
|
||
|
||
| Stratégie | Description | SourceMode | Conditions |
|
||
|---|---|---|---|---|
|
||
| `auto_solar_plus` | Solaire uniquement + assistance batterie haute | solar_only / solar_potential | SOC ≥ 90% + dette nuageuse faible |
|
||
| `auto_solar` | Solaire classique | solar_only | - |
|
||
| `force_grid_now` | Préservation batterie (remonter à seuil) | grid_forced / grid_hc_allowed | Si SOC < 22% → remonter à 35% été / 50% mi-saison / 75% hiver |
|
||
| `force_charge_now` | Charge immédiate (solution de secours manuelle) | solar_only si possible, grid_forced si SOC < 35% | À la discrétion du conducteur qui doit prendre sa voiture |
|
||
| `stop` | Arrêt complet | - | - |
|
||
|
||
---
|
||
|
||
## 10. Profils temporels
|
||
|
||
| Profil | Horaire | Description |
|
||
|---|---|---|
|
||
| `morning_solar` | 07:30 - 11:00 | Fenêtre solaire matin |
|
||
| `midday_hc_or_solar` | 12:24 - 14:24 | HC midi ou solaire |
|
||
| `evening_high_soc` | 17:00 - 20:30 | Soir haute priorité SOC |
|
||
| `night_hc` | 01:24 - 07:24 | Heures creuses nuit |
|
||
| `outside_window` | Autres | Hors fenêtres → Mode probe (sonde) pour relancer le PV si besoin |
|
||
|
||
---
|
||
|
||
## 11. Logique de décision (DECISION_ENGINEV2)
|
||
|
||
### 11.1 Garde-fous (Safety)
|
||
|
||
- **commonSafetyStartOk** : Vérifications sécurité au démarrage
|
||
- **commonSafetyHoldOk** : Vérifications sécurité au maintien
|
||
- **mustStopHard** : Arrêt d'urgence (batterie basse, surcharge)
|
||
|
||
### 11.2 Conditions de démarrage
|
||
|
||
| Condition | Seuil | Description |
|
||
|---|---|---|
|
||
| `solarStartOk` | SOC ≥ profil + PV ≥ 1000W | Démarrage solaire |
|
||
| `gridStartOk` | SOC ≤ 35% + réseau dispo | Démarrage réseau |
|
||
| `batteryAssistSolarStartOk` | SOC ≥ 90% + dette nuageuse faible | Assistance batterie solaire |
|
||
| `probeStartOk` | Mode probe actif | Sonde PV |
|
||
|
||
### 11.3 Step-up / Step-down
|
||
|
||
- **Step-up** : Augmente le courant si PV suffisant ou batterie en charge
|
||
- **Step-down** : Diminue si batterie décharge trop ou dette nuageuse
|
||
|
||
### 11.4 Cloud Debt (Dette Nuageuse) & Probe
|
||
|
||
#### Problème
|
||
Quand les batteries sont pleines (SOC > 90%) et que la maison consomme peu (< 1200W), le MPPT de l'onduleur Victron se bride à la consommation maison uniquement. Le PV visible reste bas tant que l'EVCS ne démarre pas.
|
||
|
||
#### Dette Nuageuse
|
||
- **Définition** : La batterie se décharge pour alimenter la maison + VE sans production PV suffisante
|
||
- **Seuil max** : 1.5 kWh
|
||
- **Durée max** : 30 min
|
||
- Cette dette doit être "remboursée" par du surplus PV ultérieur
|
||
|
||
#### Mode Probe (Sonde)
|
||
- **Principe** : Lancer la borne à 10A pour "provoquer" une production PV qui va s'adapter en quelques secondes
|
||
- **Courant probe** : 10A (augmenté de 6A à 10A)
|
||
- **Durée probe** : 3 minutes
|
||
- **Retry** : 45 minutes si échec
|
||
- **Activation** : En dehors des fenêtres définies (`outside_window`) ou lors de passages nuageux
|
||
|
||
#### Bypass outside_window
|
||
En mode `auto_solar_plus` ou `force_charge_now`, le profil `outside_window` ne bloque plus la charge solaire locale si :
|
||
- SOC batterie ≥ 90%
|
||
- Forecast solaire fort
|
||
- Maison consommation faible
|
||
|
||
### 11.5 Logique Heure de départ (Night EVCS + P9)
|
||
|
||
#### Objectif
|
||
S'assurer que le véhicule est chargé avant l'heure de départ prévue.
|
||
|
||
#### Deux véhicules (09/08/2026)
|
||
Le sélecteur `input_select.victron_evcs_vehicle` choisit l'heure de départ
|
||
effective — **à positionner au branchement** (la borne ne détecte pas qui est
|
||
branché) :
|
||
|
||
| Véhicule | Heure départ (helper) | Particularité |
|
||
|---|---|---|
|
||
| **VW** (défaut) | `victron_evcs_departure_time` (~08:50) | Ne publie pas franchement "charged" → fin de charge via VDF |
|
||
| **JEEP** | `victron_evcs_departure_time_jeep` (~06:30) | "Charged" franc (statut 3) ; départ DANS la fenêtre HC → logique nuit |
|
||
|
||
#### Comportement
|
||
|
||
| Scénario | Action |
|
||
|---|---|
|
||
| Départ pendant la fenêtre HC (JEEP 06:30) | Logique nuit : P7 + recovery urgent avant départ |
|
||
| Départ après la fenêtre HC (VW 08:50) + charge finie | Rien (veille collante) |
|
||
| Départ ≤ 120 min, hors HC, charge NON finie, **toggle P9 ON** | `grid_hc_allowed` → EDF ON → charge jusqu'à fin (VDF/statut) → `departure_done_idle` collant → EDF coupé immédiatement |
|
||
| Toggle P9 OFF | Comportement historique (attente solaire) |
|
||
|
||
P9 ne s'impose jamais sur `solar_only` (solaire réel prioritaire) ni sur
|
||
`stop` / `force_*`. Pendant P9 le helper takeover est tenu ON (ACM maintient
|
||
la batterie, l'hystérésis maintient EDF).
|
||
|
||
#### Paramètres
|
||
- **batteryHardFloorPct** : Plancher dur batterie (ex: 22%)
|
||
- **batteryMorningTargetPct** : Objectif SOC matin
|
||
- Règles forecast (fort/moyen/faible) — valeurs helpers ;
|
||
- **OU la recommandation de l'advisor** si le toggle
|
||
`evcs_advisor_apply_night_target` est ON (bornes [max(22, hard floor), 90],
|
||
statut `ok`, fraîcheur ≤ 120 min ; trace `(ADVISOR)` dans la raison) —
|
||
câblage réel du 09/08/2026, HANDOFF §20.
|
||
- **gridTakeoverTriggerPct** : Seuil de basculement réseau
|
||
- **batteryRecoveryUrgent** : Si temps restant < temps de charge nécessaire
|
||
(utilise l'heure de départ du véhicule sélectionné)
|
||
- **P9_DEPARTURE_LEAD_MIN** : 120 min (constante WINDOWS_SOURCEV2)
|
||
|
||
### 11.6 Cycle nuit HC complet — GRAFCET (P7 + P8 + fixes 08-09/08/2026)
|
||
|
||
Deux automates coordonnés via les helpers HA (`night_grid_takeover_needed`,
|
||
`victron_evcs_surplus_state`) :
|
||
- **G1** = contrôleur EVCS V2.6 (boucle 30 s)
|
||
- **G2** = hystérésis EDF (« Victron - Battery / Grid Hysteresis Fix V1 », 1 min)
|
||
|
||
```
|
||
G1 — SESSION NUIT EVCS
|
||
──────────────────────
|
||
X0 JOUR / attente (profils solaires)
|
||
│ t1: fenêtre HC (01:24) ET véhicule branché
|
||
X1 SESSION NUIT ACTIVE — capture startSOC/startAt (une seule fois, Fix B)
|
||
│ t2: toggle "Réseau HC nuit" ON → nightGridHcPreferred (P7)
|
||
X2 TAKEOVER: helper ON → G2 force EDF ON ; ACM tient la batterie (~2 A)
|
||
│ t3: EDF ON confirmé (gridAvailable)
|
||
X3 CHARGE VE: start 6 A → step-up (plafond 20 A / boost 28 A)
|
||
│ t4: fin de charge = VDF no-demand OU statut EVCS brut 3 "charged"
|
||
│ + puissance ≤ 300 W (Fix D+E)
|
||
X4 CHARGE TERMINÉE (collant): vehicleChargeCompleted, sourceMode='blocked'
|
||
│ ⚑ Fix F : cet état est réécrit à CHAQUE cycle AU-DESSUS des gardes
|
||
│ (hard stop batterie, source-lost...) → il survit aux micro-charges
|
||
│ du véhicule et ne peut plus être écrasé.
|
||
│
|
||
├─ t5a: SOC < cible matin (cible = règles forecast OU advisor si câblé)
|
||
│ X5a RECOVERY BATTERIE: takeover ON (EDF ON), ACM recharge → cible
|
||
│ │ t6: SOC ≥ cible
|
||
│ ▼
|
||
└─ t5b: SOC ≥ cible matin
|
||
X5b RECOVERY DONE (collant, Fix A): état 'night_recovery_done_idle'
|
||
│ takeover OFF définitif → G2 coupe EDF IMMÉDIATEMENT (cut E2)
|
||
│ ré-engagement UNIQUEMENT si SOC ≤ cible − 2 (bande anti-rebond)
|
||
│ t7: débranchement OU fin de fenêtre (07:24)
|
||
X6 CLÔTURE: clear session → retour X0 (profil jour)
|
||
|
||
G1bis — P9 : DÉPART IMMINENT HORS HC (09/08/2026)
|
||
─────────────────────────────────────────────────
|
||
Z0 JOUR, hors fenêtre HC
|
||
│ w1: toggle P9 ON ET véhicule branché ET départ (véhicule sélectionné)
|
||
│ dans ≤ 120 min ET charge non terminée
|
||
Z1 RÉSEAU PRÉ-DÉPART: sourceMode='grid_hc_allowed' (bypass garde SOC 35),
|
||
│ takeover helper ON (ACM + hystérésis), EDF ON, charge du véhicule.
|
||
│ NB: solar_only réel reste prioritaire ; stop/force* restent maîtres.
|
||
│ w2: fin de charge (VDF vehicle_full_or_paused OU statut 3)
|
||
Z2 'departure_done_idle' (COLLANT, réécrit chaque cycle comme Fix F)
|
||
│ takeover OFF → G2 coupe EDF immédiatement (cut E2 étendu)
|
||
│ w3: heure de départ passée OU débranchement
|
||
Z0 retour au jour normal
|
||
|
||
G2 — HYSTÉRÉSIS EDF (seuils ON ≤ 20 % | OFF ≥ 30 % | min_on 25 | cooldown 15)
|
||
──────────────────────────────────────────────────────────────────────────────
|
||
Y0 EDF OFF (observe_only)
|
||
│ u1: override EVCS (takeover/force_grid/grid_forced/grid_hc_allowed)
|
||
│ sans no-demand sémantique
|
||
│ u2: SOC ≤ seuil ON (bypass cooldown)
|
||
Y1 EDF ON + latch
|
||
│ v1: override disparu ET min_on écoulé ET SOC ≥ seuil OFF → turn_off_recovered
|
||
│ v2: force_grid + voiture pleine → coupure immédiate
|
||
│ v3: véhicule débranché + SOC ≥ seuil OFF → coupure immédiate
|
||
│ (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 "Fix G" a existé du 22 au 24/08/2026 puis a été RETIRÉ : voir §11.8)
|
||
└─▶ retour Y0 (cooldown 15 min)
|
||
```
|
||
|
||
États surplus « fin de charge » (aucun ne doit matcher les patterns no-demand
|
||
de G2 — full_or_paused / not_requesting_power / charge_complete / no_demand) :
|
||
- `night_session_done_idle` : charge finie, recovery batterie possible (EDF
|
||
maintenu si SOC < cible)
|
||
- `night_recovery_done_idle` : charge finie ET batterie à la cible → EDF
|
||
relâché définitivement (anti-rebond)
|
||
- `departure_done_idle` : charge finie pendant la fenêtre départ P9 (jour)
|
||
→ EDF relâché définitivement
|
||
- `day_vehicle_full_idle` (P10) : véhicule plein en journée → plus AUCUNE
|
||
tentative (même solaire) jusqu'au débranchement ; héritages bidirectionnels
|
||
jour↔nuit ; échappatoires force_charge_now / force_grid_now
|
||
|
||
**Reset du collant "plein" (P11, 12/08/2026)** : au CHANGEMENT DE VÉHICULE,
|
||
`sensor.victron_evcs_charging_time` repart de 0 → `sessionFresh` (≤ 90 s)
|
||
neutralise TOUS les collants (night/departure/day) → le nouveau véhicule est
|
||
retesté. Remises à zéro : débranchement, session fraîche (P11), ou force_*.
|
||
|
||
#### Incidents de référence
|
||
- **Nuit 07-08/08 (JEEP)** : SOC bloqué pile à la cible = point dégénéré →
|
||
rebond EDF ~10 min + flapping ACM ; EDF maintenu 25 min après débranchement.
|
||
→ Fix A (collant + bande 2 pts), B (snapshot startSOC/At), C (coupure au
|
||
débranchement), D (statut charged).
|
||
- **Nuit 08-09/08 (JEEP)** : statut 3 pendant la session armée → branches
|
||
source-lost zombies, état collant jamais écrit, statut retombe à l'ouverture
|
||
du relais → re-P7 ~30 min. → Fix E (latch en session active) + E2 (coupure
|
||
immédiate recovery done).
|
||
- **Matin 09/08 (VW pleine rebranchée)** : micro-charges du véhicule sur
|
||
batterie → hard stop ÉCRASAIT l'état collant → re-P7. → Fix F (mémoire
|
||
prioritaire sur les gardes, réécrite chaque cycle).
|
||
- **Nuit 21-22/08** : fenêtre HC fermée mi-session (véhicule pas encore flag
|
||
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), **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
|
||
|
||
- Workflow `EVCS Advisor Shadow V1` (15 min) : snapshot HA compact → LLM local
|
||
(qwen3-vl / qwen3.6-35b sur la Spark, fallback cloud) → validation stricte →
|
||
helpers `evcs_advisor_*` + logbook. N'écrit RIEN d'autre (testé).
|
||
- **Câblage réel n°1 (09/08/2026)** : cible SOC matin
|
||
(`evcs_advisor_apply_night_target`, cf. §11.5). Garde-fous : statut ok,
|
||
fraîcheur ≤ 120 min, bornes, fallback règles, rollback toggle.
|
||
- Suivi : carte « Conseiller IA (ombre) » (accords/divergences), historique
|
||
des entités `evcs_advisor_*`, logbook « EVCS Advisor », executions n8n.
|
||
- Prochains candidats (après observation) : stratégie, plafond courant.
|
||
|
||
---
|
||
|
||
### 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 entre 12:25 et 12:28 : la borne charge à 18 A / 3502 W avec
|
||
PV 10,24 kW et batterie à **+127 A**, puis s'arrête (0 A, `Waiting for start`)
|
||
— et la PV retombe à 7638 W, soit **~2,6 kW écrêtés** faute de preneur (ESS
|
||
sans injection, batterie déjà à son courant de charge maximal).
|
||
|
||
**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), plafond
|
||
calculé par `WINDOWS_SOURCEV2` ~20 A. **Ce n'est pas non plus une bande morte
|
||
batterie trop étroite** : le courant était à +127 A au moment de l'arrêt, très
|
||
loin de tout seuil de décharge.
|
||
|
||
**Cause réelle : inversion du plancher de démarrage et du plancher de maintien.**
|
||
À 12:24:00 le profil bascule `outside_window` → `midday_hc_or_solar`. Dans ce
|
||
profil, avec SOC 58 % :
|
||
|
||
| | Calcul | Valeur |
|
||
|---|---|---|
|
||
| Plancher de **démarrage** | `min(midday_soc_min 75, abondance P6 40)` | **40 %** |
|
||
| Plancher de **maintien** | `max(soc_stop_min 29, midday_soc_min 75 − 15)` | **60 %** |
|
||
|
||
`40 ≤ 58 < 60` : le système a le droit de **démarrer** ce qu'il n'a pas le
|
||
droit de **maintenir**. Cycle limite garanti à la période de `min_run_minutes`
|
||
(3 min) sur toute la bande [40 %, 60 %], traversée chaque jour vers midi.
|
||
L'origine est P6, qui abaissait le plancher de démarrage en cas d'abondance
|
||
sans toucher au plancher de maintien.
|
||
|
||
**Correctif déployé le 24/08 12:45** (`BATTERY_CLOUD_LOCKS.js`), deux volets :
|
||
|
||
1. **Invariant maintien ≤ démarrage** :
|
||
`effectiveSocHoldFloor = min(règle du profil, plancher de démarrage effectif)`.
|
||
Sans abondance, rien ne change (60 reste 60).
|
||
2. **L'abondance se prouve au démarrage, se maintient en charge.**
|
||
`solarAbundanceStart` exige toujours `pvAvg ≥ 4000 W` **et**
|
||
`batteryCurrentA ≥ +20 A` (preuve avant d'agir) ; `solarAbundanceHold`
|
||
n'exige que `pvAvg ≥ 4000 W` **et** `batteryCurrentA ≥ 0` (la batterie n'est
|
||
pas devenue fournisseuse). Sans cette distinction, la charge du véhicule —
|
||
qui détourne précisément le surplus — fait tomber le courant batterie sous
|
||
+20 A et **détruit sa propre condition d'autorisation** : système bistable.
|
||
|
||
Scénario golden `midday-inversion-start-hold` (relevé VRM du 24/08 12:25).
|
||
Preuve par mutation : sur le code d'avant → `stop` / « Conditions de maintien
|
||
perdues » ; après → `charging_step_up_battery` à 19 A. Golden 39 → 40.
|
||
|
||
Direction de fond (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.
|
||
|
||
#### C. Arrêt de la charge sur le bruit de la mesure batterie (01/09/2026)
|
||
|
||
Troisième membre de la même famille, découvert le 01/09 : la règle de maintien
|
||
comparait le **courant batterie instantané** à un plancher de 0 A, toutes les
|
||
30 s. À SOC 94 % la batterie est en float et son courant oscille entre +1,8 et
|
||
−2,6 A d'un échantillon à l'autre — le test devenait un tirage à pile ou face.
|
||
Deux arrêts ce jour-là (14:26 et 14:56), 1 à 6 par jour la semaine précédente.
|
||
|
||
Chaque arrêt coûtait ~0,45 kWh : batterie pleine, le véhicule était le **seul
|
||
preneur**, donc la PV s'effondrait de 6,6 à 2,5 kW en 30 s et la reprise mettait
|
||
21 min à remonter de 6 A à 20 A.
|
||
|
||
La table de politique batterie par bande de SOC (`INPUT_PARSE`) déclarait
|
||
pourtant déjà, pour chaque bande, un courant **souple** toléré pendant des
|
||
**minutes** (12 min au-dessus de 90 %) et un courant **dur** toléré quelques
|
||
**secondes**. Les deux tolérances étaient calculées, exportées dans le debug, et
|
||
lues par **aucune décision** : toute la dimension temporelle de la politique
|
||
était morte.
|
||
|
||
Correctif : brancher la tolérance souple sur les trois conditions de maintien,
|
||
via un helper de persistance
|
||
`input_text.victron_evcs_battery_soft_breach_at` qui porte le début du
|
||
dépassement en cours. **Aucun seuil déplacé, aucune constante ajoutée.** Le
|
||
plancher de démarrage et le garde dur restent instantanés — la tolérance est du
|
||
confort, jamais du risque. Le filtre discrimine parce que le bruit change de
|
||
signe en quelques secondes (compteur remis à zéro) alors qu'une vraie décharge
|
||
reste négative à chaque échantillon.
|
||
|
||
Golden 56 → 61, dont le contrefactuel `batt-decharge-soutenue-coupe` qui prouve
|
||
que la garde mord toujours après sa tolérance. Détail : HANDOFF §35.
|
||
|
||
#### D. Demarrage decide sur la production et non sur l'excedent (03/09/2026)
|
||
|
||
Quatrieme membre de la meme famille, et le plus couteux. `pv_start_min_w`
|
||
(700 W) est une **puissance PV absolue**. Le 03/09 a 19:44, voiture branchee :
|
||
PV 758 W, maison 1202 W, batterie deja a −12,2 A, nuit qui tombe. Le controleur
|
||
a lu « 758 ≥ 700, donc il y a du soleil » et a lance 1,6 kW de charge.
|
||
L'excedent valait **−444 W**.
|
||
|
||
En 33 minutes la voiture a pris 0,897 kWh et la batterie en a rendu 1,479 kWh
|
||
(SOC 94 → 85). Dans l'arithmetique du bilan energetique lui-meme, le manque de
|
||
la nuit est passe de 0,86 a 2,21 kWh — pour livrer 0,9 kWh que la voiture
|
||
reprenait de toute facon en heures creuses a 01:24.
|
||
|
||
**La grandeur juste n'est pas la production, c'est ce qui reste une fois la
|
||
maison servie.** Sans injection et reseau absent, `PV − maison(hors EVCS)` vaut
|
||
la puissance batterie au signe pres, et c'est ce qui separe les deux situations
|
||
que la mesure PV seule confond :
|
||
|
||
| | production | excedent | batterie | la voiture doit… |
|
||
|---|---|---:|---|---|
|
||
| **Censure** (batterie pleine, MPPT bride) | se cale sur la maison | **~0** | immobile | …demarrer : ressource refusee |
|
||
| **Deficit** (soir, nuages) | basse | **< 0** | decharge | …ne pas demarrer : ce serait la vider |
|
||
|
||
Zero n'est donc pas un seuil de plus : c'est la frontiere physique entre les
|
||
deux. Verifie sur le releve du 03/09 — excedent positif (+14 a +212 W) sur
|
||
toute la plage ou `pv_censored` etait ON (17:00-19:41), negatif ensuite.
|
||
|
||
Correctif : deux tests sur cette grandeur, aucune constante nouvelle. Le chemin
|
||
« soleil reel » reutilise `pv_start_min_w` tel quel ; le chemin « provocation »
|
||
(assistance batterie, `solar_potential`) exige seulement excedent ≥ 0.
|
||
**Demarrage uniquement** — les conditions de maintien gardent leur plancher et
|
||
leur tolerance temporelle (§C), sous peine de recreer l'oscillateur.
|
||
|
||
Golden 61 → 64, autour d'une paire de releves reels pris a 54 minutes d'ecart
|
||
dont les lectures PV ne different que de **11 W** (769 puis 758) : le premier
|
||
demarre, le second non — ce qui les separe est la maison. Detail : HANDOFF §36.
|
||
|
||
**Complement du 03/09 au soir — un excedent nul est ambigu.** L'excedent proche
|
||
de zero est la signature de la censure ET celle de l'equilibre de fin de
|
||
journee : 18:50 (+14 W, ressource refusee) et 19:41 (+1 W, plus rien a donner)
|
||
sont indiscernables par la puissance. Ce sont les **chargeurs eux-memes** qui
|
||
tranchent : `sensor.*_mppt_operation_mode` vaut `mppt_active` quand le tracker
|
||
donne tout, `voltage_current_limited` ou `off` quand il se retient. Sept
|
||
entites, que ne lisait aucun workflow. Le 03/09 elles ont bascule a 19:20 —
|
||
**24 minutes avant** le drapeau `pv_censored` du bilan (qui tourne toutes les
|
||
5 min et dont l'un des motifs est justement le proxy SOC ≥ 90 qu'on cherchait a
|
||
remplacer). La provocation `solar_potential` et l'assistance batterie exigent
|
||
desormais qu'au moins un chargeur se retienne.
|
||
|
||
⚠️ Garde de DEMARRAGE uniquement, structurellement : la lier au maintien ferait
|
||
que la charge, en donnant un preneur au MPPT, detruirait sa propre autorisation
|
||
— le bistable P6 du 24/08. Lectures indisponibles → repli sur le comportement
|
||
anterieur. Golden 64 → 66. Detail : HANDOFF §37.
|
||
|
||
#### D-bis. Le relachement du contacteur se mesurait sur un instant (06/09/2026)
|
||
|
||
La regle du 05/09 ferme le contacteur EDF quand la maison demande plus de 80 %
|
||
de ce que le parc sait delivrer — elle a mordu au bon moment le 05/09 au soir,
|
||
a **-97,4 A pour un plafond BMS de 100 A**. Mais elle relachait des que la
|
||
charge repassait sous 50 %, sur un SEUL echantillon. Duree des accalmies sous
|
||
2 550 W, pas d'une minute :
|
||
|
||
| periode | accalmies | la plus longue |
|
||
|---|---:|---:|
|
||
| pendant la cuisson, 20:33 -> 21:37 | **13** | **5 min** |
|
||
| apres la cuisson, 21:40 -> 01:00 | 1 | **201 min** |
|
||
|
||
Treize occasions de rendre le reseau au milieu du service, et chaque
|
||
aller-retour du contacteur coute 50 a 150 Wh de transitoire. Le troisieme pic
|
||
de la soiree (4 236 W a 21:01:55) est tombe **deux minutes avant l'ouverture
|
||
reelle** : decale de cinq minutes, la regle refermait.
|
||
|
||
Correctif : le relachement se mesure en DUREE — la maison doit rester sous le
|
||
seuil bas pendant N minutes, meme mecanisme que la tolerance temporelle de la
|
||
politique batterie (§C). Les deux valeurs se lisent sur la distribution
|
||
ci-dessus, franchement bimodale : **20 min** (milieu du fosse) et **6 min**
|
||
(juste au-dessus de la plus longue accalmie de cuisson).
|
||
|
||
**Et N vient du bilan energetique** — premiere lecture du bilan par le workflow
|
||
d'hysteresis, qui n'en lisait aucun champ. Tant que la batterie est de toute
|
||
facon condamnee a toucher son plancher avant l'ouverture des heures creuses, le
|
||
partage batterie/reseau de la soiree est fige : tenir le contacteur plus
|
||
longtemps ne change que l'HEURE d'achat, pas le montant. Des qu'elle passerait
|
||
la nuit seule, chaque kWh du soir deplace un kWh d'heures creuses vers des
|
||
heures pleines, et il faut relacher vite.
|
||
|
||
⚠️ Le dwell se compte sur la MAISON, jamais sur le contacteur ni sur le courant
|
||
batterie : l'horodatage `input_datetime.victron_grid_charge_high_last_at` est
|
||
ecrit que le contacteur soit ouvert ou ferme. Fermer le contacteur fait chuter
|
||
le courant batterie ; s'en servir comme critere ferait que la decision
|
||
detruirait sa propre cause.
|
||
|
||
⚠️ Mode de defaillance observe, pas suppose : le 05/09 de 21:22 a 21:49, la
|
||
tension et le courant batterie n'ont RIEN publie pendant 27 minutes. La tension
|
||
alimentant le plafond de decharge, la protection se serait eteinte pile a
|
||
l'heure du diner. Deux replis : tension nominale 51 V quand le plafond en
|
||
amperes reste lisible (48,85-51,5 V mesures sur la soiree, donc 5 % d'erreur au
|
||
pire), et a defaut l'horodatage de charge haute — un fait persiste — tient la
|
||
protection jusqu'a la fin du dwell.
|
||
|
||
Golden-hysteresis 11 -> 20, six mutations tombant chacune sur un jeu different.
|
||
Detail : HANDOFF §57.
|
||
|
||
#### D-ter. La protection comptait la maison brute, pas la demande sur le parc (06/09/2026)
|
||
|
||
La regle de fermeture comparait `sensor.victron_consumption_power_l1` au
|
||
plafond de decharge du BMS. Or le parc n'est sollicite que de ce que le solaire
|
||
ne couvre pas. Dimanche 06/09, deux fermetures, mesurees a l'instant de la
|
||
decision (contacteur encore ouvert, donc production non censuree) :
|
||
|
||
| fermeture | maison | PV | parc sollicite | decharge batterie |
|
||
|---|---:|---:|---:|---:|
|
||
| 12:07, cuisson | 4 025 W | ~2 890 W | **1 132 W** | 1 345 W |
|
||
| 13:34, cuisson + JEEP | 4 981 W | ~4 210 W | **772 W** | 1 223 W |
|
||
|
||
Plafond du parc : 5 100 W. Il etait a 22 % et 15 % de sa limite — deux
|
||
fermetures pour rien, 0,50 kWh importes en plein soleil. La regle n'avait bien
|
||
fonctionne la veille au soir que parce qu'il n'y avait plus de PV.
|
||
|
||
Les deux seuils portent desormais sur `max(0, maison - PV)`. Contacteur ouvert,
|
||
cette grandeur EST la decharge batterie ; ferme, elle est le contrefactuel
|
||
« ce que le parc devrait fournir si on ouvrait », qu'un eventuel bridage du MPPT
|
||
fait SURESTIMER — erreur unilaterale, qui pousse a rester ferme. Golden 20 -> 24.
|
||
Detail : HANDOFF §57.
|
||
|
||
⚠️ Question ouverte que cet episode souleve : `houseAcPowerW` inclut l'EVCS,
|
||
donc la voiture est comptee comme une charge incompressible alors qu'elle est la
|
||
seule charge entierement compressible du foyer. Le jour ou la demande sur le
|
||
parc depassera vraiment le plafond avec la voiture dedans, il faudrait brider la
|
||
voiture avant de fermer le contacteur — ce qu'aucun des deux workflows ne sait
|
||
faire : le controleur EVCS ignore le plafond de decharge du BMS, et
|
||
l'hysteresis ne commande pas la borne.
|
||
|
||
#### E. Le plancher du soir etait un niveau, pas une energie (03/09/2026)
|
||
|
||
`evening_soc_start_min` = 85 % tente de dire « garde de quoi passer la nuit ».
|
||
C'est un NIVEAU, pris a un instant, qui ne sait rien de la nuit qui vient : ni
|
||
sa duree, ni la consommation a couvrir, ni l'heure ou le solaire prendra le
|
||
relais. Le bilan energetique calcule exactement cela depuis le 26/08 et le
|
||
publie dans `input_number.evcs_balance_required_soc` — et **aucun des deux
|
||
workflows de decision ne le lisait** (`grep evcs_balance` → 0).
|
||
|
||
Le 03/09 a 19:44, SOC 94 % : le plancher fixe autorisait la charge, le bilan
|
||
demandait 99,7 % pour tenir jusqu'au croisement de 9 h.
|
||
|
||
Le plancher de demarrage du soir vaut desormais
|
||
`max(evening_soc_start_min, evcs_balance_required_soc)`. **Sens unique
|
||
delibere** : le bilan peut durcir, jamais relacher — l'assouplir en ete
|
||
autoriserait des charges qui n'ont pas lieu aujourd'hui, decision distincte a
|
||
valider pour elle-meme. Le `max` rend d'ailleurs la garde robuste sans borne :
|
||
une valeur aberrante ne peut pas relacher le plancher.
|
||
|
||
Gardes : fraicheur ≤ 30 min (six cycles du bilan), statut `ok`, valeur finie ;
|
||
sinon regle historique. Pas de nouveau toggle — `evcs_balance_enabled` a OFF
|
||
fige `balance_last_run`, la fraicheur expire, et le plancher retombe seul sur
|
||
85 % en une demi-heure.
|
||
|
||
Portee : demarrage. Le plancher de maintien reste a 80 %, donc aucune charge en
|
||
cours n'est coupee. Golden 66 → 70, quatre mutations faisant tomber chacune
|
||
exactement un scenario different. Detail : HANDOFF §38.
|
||
|
||
#### F. La cible du matin etait un palier, pas une energie (03/09/2026)
|
||
|
||
Symetrique du precedent, a l'autre bout de la nuit. La regle classe le lendemain
|
||
en trois paliers a partir de son TOTAL (≥ 18 kWh → 35 %, ≥ 10 → 55 %, sinon
|
||
85 %) et ignore donc **l'heure d'arrivee** de l'energie. Le 03/09, demain
|
||
annoncait 33,9 kWh — « fort », donc 35 % — avec un matin creux et un croisement
|
||
a 9 h.
|
||
|
||
Releve de la nuit 02-03/09, qui montre le probleme et sa solution dans le meme
|
||
tableau :
|
||
|
||
| heure | requis (bilan) | SOC reel | cible fixe |
|
||
|---|---:|---:|---:|
|
||
| 00:30 | 62,4 | 53 | 35 |
|
||
| 03:00 | **50,4** | **45** | 35 |
|
||
| 06:00 | 37,1 | 22 | 35 |
|
||
|
||
Le `required_soc` decroit avec la nuit qui se consomme. La batterie est restee
|
||
sous la ligne toute la nuit ; a 03:00 EDF a ete relache cinq points en dessous,
|
||
la batterie est tombee a 20 % vers 06:30 et le reseau est revenu **au plein
|
||
tarif** de 07:24 a 10:33 (1,49 kWh).
|
||
|
||
La cible vaut desormais `min(90, max(palier ou advisor, required_soc))`. Sens
|
||
unique delibere, comme le plancher du soir : le bilan ne pousse jamais dans le
|
||
sens « couvre moins bien la nuit ». Plafond 90 % parce qu'au-dela la batterie
|
||
cesse d'etre un puits et evince la production du matin — et parce que le bilan
|
||
publie sans ecretage des valeurs > 100 (§26). Golden 70 → 75, quatre mutations
|
||
faisant tomber chacune un scenario different. Detail : HANDOFF §39.
|
||
|
||
⚠️ **Limite connue et figee par un scenario** : la passe unique de recovery
|
||
(§26) latche le relachement pour toute la session, donc la cible dynamique
|
||
n'ameliore que la PREMIERE passe. Si le SOC repasse sous la ligne ensuite, le
|
||
reseau ne revient qu'via l'hysteresis a 20 %, possiblement hors heures creuses.
|
||
Le bon critere de re-engagement — « un budget d'energie restant a couvrir » —
|
||
etait deja designe par §26 ; le bilan est maintenant cable, mais la suite touche
|
||
la machine a etats de la nuit et fera l'objet d'un chantier propre.
|
||
|
||
#### G. Session reseau unique de la nuit (03/09/2026)
|
||
|
||
Le chantier annonce ci-dessus, fait le soir meme — mais pas comme prevu.
|
||
|
||
**Mesure prealable, qui a change la conception.** Les kWh reellement sortis de
|
||
la batterie par point de SOC, sur cinq fenetres et trois nuits : 0,164 a
|
||
0,171 kWh/point au-dessus de 42 % (soit ~17 kWh), mais **0,121 entre 45 et 22 %
|
||
et 0,082 entre 33 et 20 %**. En bas d'echelle, un point de SOC vaut moitie
|
||
moins. Or le bilan convertit avec une constante unique de 15 kWh :
|
||
`required_soc` y est donc systematiquement trop bas — d'ou la batterie qui,
|
||
la nuit du 02-03/09, descendait 1,75 fois plus vite que la ligne.
|
||
|
||
**Consequence : le relachement ne peut pas etre un seuil de SOC.** Il porterait
|
||
sur une grandeur fausse, et tout seuil que le SOC repasse ensuite rouvre
|
||
l'oscillateur du 27/08. Les deux variantes evidentes — relacher sur
|
||
`required_soc`, ou sur `required_soc_prudent` avec la bande p50/p80 — ont ete
|
||
ecartees pour cette raison.
|
||
|
||
**Conception retenue : engagement sur le bilan, relachement a la FIN DE LA
|
||
FENETRE.** L'oscillation devient structurellement impossible, la condition de
|
||
sortie etant monotone : une fenetre ne se ferme qu'une fois. Un helper
|
||
`input_boolean.victron_evcs_night_grid_session_committed` porte l'engagement —
|
||
sans cette persistance, la garde serait reevaluee a chaque cycle et redeviendrait
|
||
une bande.
|
||
|
||
Effet : l'ACM recharge jusqu'a la cible puis tient la batterie a 2 A, la maison
|
||
finit la nuit sur le reseau **en heures creuses** au lieu de vider la reserve, et
|
||
la batterie arrive a l'aube pres de sa cible, avec de la place pour le solaire.
|
||
La coupure immediate E2 de l'hysteresis exige `!evcsGridOverride` et le helper
|
||
takeover reste ON : aucune modification du workflow d'hysteresis n'a ete
|
||
necessaire.
|
||
|
||
Golden 75 → 78. La mutation la plus parlante : retirer la garde bilan fait
|
||
tomber les trois scenarios anti-oscillateur du 27/08 — les tests de l'ancien
|
||
correctif protegent le nouveau code. Detail : HANDOFF §40.
|
||
|
||
⚠️ **Prerequis identifie, non traite** : `evcs_balance_usable_capacity_kwh` = 15
|
||
est une constante la ou la realite est une courbe, et `INPUT_PARSE` code 17,5 en
|
||
dur de son cote. Consequence : `required_soc` sous-estime le besoin en bas
|
||
d'echelle, donc la session peut manquer des nuits ou elle aurait du s'engager
|
||
(sous-declenchement — jamais d'oscillation, la conception y est immune), et la
|
||
reserve d'orage est optimiste dans la meme bande. §28 avait deja signale
|
||
l'effondrement de la jauge ; les mesures du 03/09 lui donnent sa courbe. C'est
|
||
le prochain chantier du bilan energetique.
|
||
|
||
#### H. La conversion energie ↔ SOC devient une courbe mesuree (03/09/2026)
|
||
|
||
Le prerequis ci-dessus, traite le soir meme. `tools/mesure-courbe-batterie.mjs`
|
||
(rejouable) integre la puissance batterie sur chaque palier de SOC qui descend
|
||
d'un point, en ecartant les paliers avec charge ou apport reseau : **576 paliers
|
||
sur 8 jours**.
|
||
|
||
| tranche | paliers | kWh/point |
|
||
|---|---:|---:|
|
||
| 21-31 | 88 | **0,097** |
|
||
| 35-94 | 462 | **0,169** (six tranches, 0,163 a 0,171) |
|
||
|
||
Plate a 0,169 de 33 a 93, **genou net a 32-33**, puis 0,097 : sous le genou un
|
||
point de SOC vaut 57 % de ce qu'il vaut au-dessus. Coherent avec le parc reel
|
||
(§0 : un module en panne sur huit, un autre qui faiblit).
|
||
|
||
**Energie utile totale de 100 a 22 % : 12,39 kWh mesures**, contre 11,70 vus par
|
||
le bilan (15 kWh a plat) et 13,65 par `INPUT_PARSE` (17,5). Les deux constantes
|
||
etaient fausses, dans des sens opposes — chiffre a retenir pour le
|
||
dimensionnement du parc prevu cet hiver.
|
||
|
||
Comme 15 kWh se situe ENTRE les deux pentes, **l'erreur changeait de signe** :
|
||
SOC requis trop bas de 3 a 4 points pour un petit deficit (fin de nuit, la
|
||
direction dangereuse), trop haut de 4 a 6 points pour un gros (debut de nuit).
|
||
|
||
Correctif : trois fonctions (`energyBetweenSoc`, `socForEnergy`,
|
||
`socAfterEnergy`) remplacent les cinq conversions lineaires de `BALANCE.js`, et
|
||
`INPUT_PARSE` passe de 17,5 a 16,9. Tests du bilan 42/42 apres mise a jour
|
||
deliberee de six attendus, chacun verifie a la main ; deux mutations font tomber
|
||
les six memes scenarios. Detail : HANDOFF §41.
|
||
|
||
⚠️ Ces trois nombres sont des **resultats de mesure, pas des reglages** :
|
||
`node tools/mesure-courbe-batterie.mjs 8` est a rejouer apres toute evolution du
|
||
parc.
|
||
|
||
⚠️ **Principale erreur restante du bilan** : le profil de consommation p50
|
||
sous-estimait de ~33 % les heures 03-06 la nuit du 02-03/09 (2,1 kWh annonces,
|
||
2,79 mesures). Devant la conversion, desormais. A instruire separement.
|
||
|
||
⚠️ Point structurel mis au jour par cet incident : le bilan energetique publie
|
||
l'heure de croisement, l'energie a couvrir, le SOC requis, `grid_needed` et
|
||
`pv_censored` — et **aucun des deux workflows de decision n'en lit une seule
|
||
valeur**. La cible du matin en est l'illustration : 35 % cote controleur
|
||
(regle sur le total de demain) contre 99,7 % cote bilan (qui regarde quand
|
||
l'energie arrive). Memes donnees, facteur 3.
|
||
|
||
---
|
||
|
||
---
|
||
|
||
## 12. Configuration opencode.json
|
||
|
||
```json
|
||
{
|
||
"provider": {
|
||
"openrama": {
|
||
"models": {
|
||
"minimax-m2.5": { "name": "minimax-m2.5" }
|
||
}
|
||
},
|
||
"qwen-dgx-vl": {
|
||
"models": {
|
||
"qwen3-vl": { "attachment": true, "modalities": {"input": ["text","image"]} },
|
||
"qwen3.6-35b": { "options": { "temperature": 0.15, "reasoningEffort": "none" } }
|
||
}
|
||
}
|
||
},
|
||
"mcp": {
|
||
"n8n-mcp": { "type": "local", "command": ["npx", "-y", "n8n-mcp-server"] },
|
||
"ha-get-state": { "type": "remote", "url": "https://n8n.airtria.pro/mcp/..." },
|
||
"ha-set-helper": { "type": "remote", "url": "https://n8n.airtria.pro/mcp/..." },
|
||
"grid-set-state": { "type": "remote", "url": "https://n8n.airtria.pro/mcp/grid-set-state/sse" },
|
||
"victron-set-charge-limits": { "type": "remote", "url": "https://n8n.airtria.pro/mcp/..." },
|
||
"pv-get-forecast": { "type": "remote", "url": "https://n8n.airtria.pro/mcp/..." }
|
||
},
|
||
"permission": {
|
||
"bash": { "curl *": "deny", "wget *": "deny", "*": "ask" }
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 13. Méthode de travail
|
||
|
||
### 13.1 Source de vérité et déploiement (R2, 07/08/2026)
|
||
|
||
Le code des nodes du workflow EVCS V2.6 vit dans **`src/nodes/*.js`**
|
||
(+ `HA_SNAPSHOT_TEMPLATE.json.tpl`). Le JSON `workflows/*.json` est un
|
||
artefact reconstruit au push.
|
||
|
||
```
|
||
éditer src/nodes/<NODE>.js
|
||
node tools/n8n-push.mjs workflows/evcs-surplus-controller-v2.6.json
|
||
→ build src→JSON → node --check → GOLDEN 33 scénarios (bloquant)
|
||
→ backup serveur → PUT
|
||
git commit && git push
|
||
```
|
||
|
||
- **JAMAIS** d'édition du JSON ou de l'UI n8n (écrasée au prochain push).
|
||
- Tests : `node tests/golden/run.mjs` (33 scénarios figés, exécute le JSON
|
||
**buildé** → toujours `node tools/n8n-build.mjs` avant un run manuel).
|
||
- Évolution voulue du comportement → mettre à jour
|
||
`tests/golden/scenarios.mjs` dans le même commit.
|
||
- Workflow hystérésis (`7iIlu7LLTW7TZA8o`) : fichier local
|
||
`workflows/victron-grid-hysteresis-v1.json`, patches rejouables dans
|
||
`tools/patch-*.mjs`, push via `n8n-push.mjs` (backup auto).
|
||
|
||
### 13.2 Lecture d'un workflow n8n (hors EVCS V2.6)
|
||
|
||
1. Utiliser `n8n-mcp_get_workflow` avec l'ID
|
||
2. Le fichier est écrit dans `~/.local/share/opencode/tool-output/tool_*`
|
||
3. **Attention** : Le fichier commence par "Retrieved workflow: <nom>" AVANT le JSON
|
||
4. Extraction par nœud :
|
||
```bash
|
||
grep -n '"name": "NOM_DU_NOEUD"' <fichier>
|
||
sed -n 'DEBUT,FINp' <fichier>
|
||
```
|
||
|
||
### 13.3 Modification
|
||
|
||
1. **TOUJOURS** backup avant modification
|
||
2. Une seule modification à la fois
|
||
3. Vérifier avec dry-run
|
||
4. Valider en production
|
||
|
||
### 13.4 Interdiction
|
||
|
||
- **JAMAIS** de curl/wget direct vers HA/n8n/Victron
|
||
- **JAMAIS** d'IP/URL/token inventés
|
||
- Utiliser les MCP uniquement
|
||
|
||
---
|
||
|
||
## 14. À compléter par l'utilisateur
|
||
|
||
- [ ] Tableau détaillé des fonctionnalités (entrées/sorties/conditions)
|
||
- [ ] Documentation EDF Urgence (créé par FABLE)
|
||
- [x] Liste des incidents récurrents → §11.6 (incidents de référence) + HANDOFF §17-21
|
||
- [ ] Procédures de dépannage
|
||
- [ ] Glossaire des termes techniques
|
||
|
||
---
|
||
|
||
*Document généré le 17/07/2026 — mis à jour le 22/08/2026 (HANDOFF §17-24 : fixes A→G, advisor, P9, véhicules)* |