Elle empruntait le plafond de la borne — `maison + physicalCapA x V` — qui n a
aucune relation physique avec ce dont la batterie a besoin. Qu il tombe juste
etait un accident : le 17/09 a 13:51, voiture partie depuis cinq minutes,
consigne a 7032 W pour une maison a 933 W.
Elle additionne desormais des besoins NOMMES : la maison toujours, la voiture
seulement si un vehicule est branche, la batterie seulement dans une fenetre
d heures creuses — recharger la batterie sur le reseau n a de sens economique
que la. Hors fenetre le terme vaut zero, donc la division par un temps qui tend
vers zero disparait par construction et non par garde.
MAX ET NON ADDITION. La consigne est une AUTORISATION, pas une prediction : le
fichier le dit deja — « la consigne dit ce que le reseau a le DROIT de servir,
DVCC dit ce que la batterie a le droit de prendre ». Additionner deux
autorisations independantes n est pas plus honnete, seulement plus permissif.
Mesure : avec l addition, `consigne-session-engagee-couvre-la-maison` passe de
5595 a 6341 W — une autorisation en plus sur le chemin dominant (85 nuits sur
88 ont un vehicule) pour corriger un chemin emprunte zero fois en treize jours.
LE TERME BATTERIE EST BORNE PAR DVCC, PAS PAR LE BMS NI PAR LE TEMPS. Le BMS
declare 250 A, soit 12,2 kW : au-dessus de GRID_SETPOINT_MAX_W, il ne bornerait
rien. Et un plancher d horizon ne borne que le diviseur : en fin de fenetre
(14 min, manque 5,672 kWh) la division rend 17 kW, ecretes a 10 000, soit PIRE
que les 5437 empruntes qu on remplace. Avec DVCC le terme vaut 1538 W et la
consigne 2380 W. Corollaire : le plancher d horizon devient sans objet, il ne
reste qu une garde d une minute contre la division par zero.
Le manque vient de `evcs_balance_grid_energy_needed_kwh` et non de
`energy_to_cover_kwh` : la premiere est le MANQUE, nulle des que la batterie
couvre et convertie par la courbe mesuree par morceaux ; la seconde est
l energie que la batterie devra FOURNIR et ne tombe jamais a zero tant qu il
reste de la nuit — 11,96 kWh annonces le 17/09 a 20:00 avec un SOC de 91 %.
Le plancher nuage suit la voiture et PAS la batterie : il couvre l exposition
creee par le courant du vehicule ; une recharge batterie qui ralentit quand le
solaire s effondre ne coupe personne.
INVARIANT TENU PAR LA FORME : `maison + max(...)` ne peut jamais descendre sous
la maison, quel que soit DVCC. La regle du 01/09 et du 04/09 est donc garantie
par construction. Toute lecture manquante retombe sur la formule d avant.
Golden 102 -> 104. `nuit-sans-vehicule-session-engage` passe de 5437 a 2380 et
recoit le manque explicitement, sans quoi il heritait du zero de la fixture et
decrivait un etat impossible (SOC 20 pour un requis de 59,1 avec batterie
couverte). Deux scenarios ajoutes : la fin de fenetre bornee par DVCC — celui
qui protege contre la regression de 10 kW — et le contrefactuel a vehicule
branche qui epingle le choix du max.
Mutations : plafond DVCC retire -> 2 echecs dont la fin de fenetre ; max
remplace par une addition -> le contrefactuel seul ; bilan ignore -> les deux
scenarios pilotes par le bilan. Les autres suites sont intactes
(hysteresis 24, ACM 20, advisor, bilan 48).
⚠️ RIEN N EST POUSSE VERS n8n : la regle du depot impose la validation du
proprietaire avant tout PUT.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
Idee du proprietaire, apres la nuit du 14 au 15/09 : 8 kWh achetes au reseau, la
batterie encore a 69 % a 5 h du matin, et une prevision de 38,7 kWh le lendemain
dont 10,5 auraient ete ecretes faute de place. Payer du reseau la nuit pour
ecreter le solaire le lendemain, c est perdre deux fois.
Le mode `battery_assist_night` existait pour exactement ca, et etait MORT depuis
toujours : il exige `batteryCurrentA >= plancher de decharge` (0 A), impossible
la nuit puisque la maison tire sur la batterie. On ne cree donc pas un chemin,
on rend viable celui qui existe — en remplacant un test de COURANT impossible
par un test d ENERGIE.
Le plancher n est PAS une constante nouvelle : c est `required_soc_prudent`, que
le bilan publie deja en profil p80. La voiture descend la batterie jusqu au
niveau qui lui permet encore de tenir jusqu au croisement PV, et pas plus bas.
La bascule vers le reseau est automatique quand le surplus est epuise — la
soupape decrite par le proprietaire, sans aucune regle horaire.
⚠️ Verrou anti-oscillateur, et il n est pas decoratif. Le plancher descend
pendant la nuit et le SOC aussi : voiture en charge le SOC perd 7,1 pt/h contre
3,7 pour le plancher, mais voiture ARRETEE il n en perd que 2,6. Le surplus
reapparaitrait tout seul et la charge repartirait. Une seule passe par session
de nuit, comme la recovery batterie depuis le 27/08.
Les gardes de courant restent : commonSafety, l arret dur, et la garde souple
avec sa tolerance temporelle — c est elle qui arretera la charge quand la bande
de SOC deviendra trop basse pour le courant tire. Ce qu on retire est uniquement
le plancher de PROFIL, qui interdisait de demarrer des que la batterie n etait
pas a l equilibre.
Cinq scenarios, six mutations qui mordent chacune sur un jeu different. Deux
d entre elles ont trouve de vraies faiblesses : les attendus ne verifiaient que
le choix du mode et pas que la voiture charge, et la garde de fraicheur du bilan
n etait couverte par aucun scenario.
Rien n est deploye et le toggle est a off.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
Le hub reconnait les deux groupes — LED verte et trois bips, son accuse de
reception — mais le Cerbo n en enumere qu un : 4 modules et 400 Ah la ou le parc
en compte 9 et 650.
Le releve de reference apporte le fait qui manquait : a 20:14 les quatre US5000
debitent 24 A au total pendant que le Cerbo annonce 41 A au parc. Les 17 A
d ecart sont le pack 2, qui porte donc bien du courant sans etre enumere. Le
courant mesure au shunt n est pas un indicateur d enumeration — seuls
nombre_de_modules_en_ligne et capacite_installee le sont.
Quatre etapes par risque croissant, la premiere ne touchant a aucun cable : un
redemarrage du Cerbo, l inventaire ayant deja change une fois le 13/09 a 21:35,
evenement isole verifie comme n etant pas un redemarrage de Home Assistant.
Regle de securite tiree de l incident d aujourd hui : fermer EDF AVANT toute
manoeuvre. Couper la communication du BMS arrete la gestion batterie, donc l
onduleur, donc la maison — 72 secondes dans le noir a 16:24. EDF deja ferme, la
maison passe en direct et ne voit rien.
L etape 4 renvoie a la documentation constructeur et n avance aucune theorie de
cablage : sur du materiel batterie je ne raisonne pas de memoire.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
Le patch precedent n'avait releve que pv_boost : au-dessus de 80 % de SOC
c'est pv_mid qui commande, donc son plafond de 110 A restait le plus bas et
rien n'etait observable cet apres-midi. Table finale : 150 / 130 / 80 / 30,
toujours decroissante.
Applique a 13:31. Le courant est passe de 90 a 116 A dans la minute — mais
la charge de la maison a chute de 2,6 kW au meme moment, et le courant n'a
repris que 1,3 kW des 2,6 liberes tandis qu'un chargeur de plus se bridait.
Ce n'est donc PAS une preuve propre, et je ne la presente pas comme telle.
Ce que le releve montre vraiment : dans la tranche 80-90, le courant a
plafonne vers 116 A sans jamais approcher les 130, pendant que la tension
montait de 50,82 a 51,07 V vers la consigne. A ce niveau de SOC c'est la
TENSION qui contraint, pas le courant.
La ou le plafond mordait : a 12:36-12:42, SOC 78-80, le courant etait a
129 A pour une DVCC de 130 — colle dessus. C'est la tranche pv_boost, donc
c'est la charge du matin qui dira ce que le 150 A libere.
Cellules a 2 mV et aucune alarme sur toute la sequence. Golden ACM 20/20,
attendu de acm-jour-mid mis a jour dans le meme commit.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
Mesure du 13/09, 10:39 a 12:50 : la DVCC etait a 130 A et la batterie
prenait 114 a 127 A, soit 88 a 98 % du plafond, avec une tension plate a
50,6 V — a 0,5 V sous notre propre consigne. C'est le point decisif : il n'y
avait aucune phase d'absorption, le courant ne retombait pas de lui-meme,
il butait. Pendant ce temps six chargeurs sur sept se declaraient
`voltage_current_limited`, et sans injection cette ressource est perdue.
Le BMS, lui, declare autoriser 250 A et 53,2 V, ses 135 cellules tiennent
dans 2 mV et aucun module ne bloque la charge. Le 130 A venait de l'ANCIEN
parc, dont une cellule montait a 3 649 mV et faisait effondrer le courant de
tous. Ces modules sont sortis le 12/09.
- `pv_boost` 130 -> 150 A : un palier, pas une cible. 150 A reste a 60 % de
ce que le BMS declare ; on regarde ce que ca libere et l'ecart entre
cellules avant d'aller plus loin.
- `pv_mid` 51,2 -> 51,5 V : la colonne des tensions REDESCENDAIT entre 80 et
90 % avant de remonter, reste du 06/09 ou seul pv_topoff avait ete releve.
pv_topoff et pv_hold ne sont pas touches. L'effet du 150 A ne se verra que
sous 80 % de SOC, donc a la charge du matin.
Golden ACM : les trois scenarios qui epinglaient ces valeurs sont tombes,
attendus mis a jour dans le meme commit, 20/20. Verifie en reel : consigne
appliquee, aucune alarme, cellules toujours a 2 mV.
Corrige au passage : l'ACM tourne toutes les 5 MINUTES, pas 30 s comme
l'annoncaient le manuel et MEMORY.md.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
Quand il n y a rien a signaler il n y a pas de piste, et le repli sur le
constat faisait afficher la meme phrase deux fois de suite sur la carte —
et serait parti en double dans la colonne `piste` de la table
d observation, ou elle ne serait plus interrogeable pour rien.
« [95%] rien a creuser » garde la confiance visible et dit la verite.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
Six helpers que plus personne n ecrivait depuis la specialisation du 12/09
restaient affiches sur la carte du tableau EVCS Master comme des
recommandations courantes : strategie, charge du soir, divergence, cible SOC
matin figee a 55 %, plafond courant, et le toggle qui appliquait la cible.
C est exactement ce fantome qui a rendu le cablage dangereux — la garde de
fraicheur datait le run, pas la valeur.
Retires du paquet et de la carte, sauvegardes dans SAVE/. La carte est
reecrite pour ce que le conseiller fait desormais : gravite, ce qu il voit,
ce qui cloche, la piste et sa confiance.
Le conseiller relisait aussi SA PROPRE strategie precedente — figee depuis
le 12/09, et parsee sans jamais servir dans le prompt. Retiree de son
snapshot et de BUILD_PROMPT.
Apres rechargement des trois domaines : dix helpers restants, exactement
ceux que l observateur ecrit. Les compteurs ont survecu (8 cycles calmes,
0 signalement), ce qui valide la suppression des `initial:` du matin meme.
Gabarit du conseiller re-rendu contre Home Assistant : 48 champs, JSON
valide, aucun null. Pousse.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
Le premier cablage reel (§20, 09/08) faisait suivre a la cible SOC du matin
`input_number.evcs_advisor_night_target_soc`, derriere quatre gardes :
toggle, statut ok, fraicheur de 120 minutes, bornage [22, 90].
Depuis que le conseiller est devenu observateur le 12/09, il n emet plus de
cible et ce helper est fige a 55 %. Les quatre gardes continuaient pourtant
de passer toutes les quatre, parce que la garde de fraicheur date le RUN et
non la VALEUR : le conseiller tourne toujours, donc son horodatage est
frais. Activer le toggle aurait applique un chiffre perime sans qu aucune
garde ne s y oppose.
Retire : les quatre parametres d INPUT_PARSE, le bloc de WINDOWS_SOURCEV2,
le passe-plat de BATTERY_CLOUD_LOCKS, la trace (ADVISOR) de DECISION et les
quatre champs du gabarit de snapshot. Le cablage du BILAN (§39) est intact.
`parseAdvisorRunToMs` devient `parseRunStampToMs` : le bilan publie le meme
format et reste son seul appelant.
Golden 98 → 96. Les trois scenarios du cablage sont remplaces par un seul,
`advisor-cible-ignoree`, qui pinne l ABSENCE de cablage : toutes les
conditions de l ancienne regle reunies, et la cible doit rester celle des
regles de prevision. Mutation : cablage restaure → il tombe, avec
« target=22% (ADVISOR) » dans la raison ; retire → 96/96.
Gabarit re-rendu contre Home Assistant : 196 champs, JSON valide, aucun
null. Pousse en production, cycle suivant en succes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
Reprise de la campagne apres la specialisation en observateur. Le harnais
affichait encore `strategy` et `night_target_soc`, deux champs que
l observateur n emet plus : il mesurait des undefined. Reecrit pour noter
ce qui compte chez un observateur — la gravite tombe-t-elle dans la
fourchette attendue, et a-t-il NOMME la chose, par des mots-cles choisis
hors du vocabulaire du prompt.
Quatre defauts trouves, aucun n etant un defaut de raisonnement du modele :
- « Contacteur FERME » : pour un relais, ferme veut dire qui laisse passer.
Le modele l a lu comme coupe et a demande, reseau present, « pourquoi le
contacteur reste FERME alors que le bilan juge le reseau necessaire ».
- Le signe de l excedent : le prompt affichait « 14 W », il a ecrit
« negatif (-14 W) » — et sur un autre cas « negatif » puis « positif » au
passage suivant, sur le MEME prompt.
- « day_vehicle_full_idle » ne veut rien dire pour lui : il signalait une
ressource refusee sans voir que le vehicule est PLEIN.
- Un excedent calcule sous censure ne veut rien dire : sur le BOOST du
11/09 il concluait « pas de soleil, donc le reseau est normal » alors que
les 121 W de PV sont bas PARCE QUE la consigne de 8260 W les evince.
Plus une grandeur derivee de plus, `consigne - maison`, parce qu il voyait
la version flagrante du defaut (SOC 20, 0 A) et manquait la version
discrete (SOC 45, +2 A). Elle a d abord fait TOMBER le cas du BOOST, en
annoncant « il reste 7005 W pour recharger » comme une bonne nouvelle sur
une batterie a 96 % : corrigee en lui faisant dire l inverse quand il n y a
rien a recharger, la question ayant deja une reponse dans le bilan.
Trois defauts etaient les miens : deux fixtures decrivaient un etat que
l installation ne peut pas prendre — c est le conseiller qui l a signale —
et un attendu exigeait « haute » la ou l echelle de gravite du prompt ancre
elle-meme cet incident sur « moyenne ».
Incidents 39/40 au final, contre 23/35 au depart. Les deux cas de vrai
silence restent silencieux 5/5.
⚠️ Trouve en marge : cinq helpers du conseiller sont geles depuis la
specialisation, et le cablage de la cible SOC matin les lit encore — ses
quatre gardes passent toutes, la fraicheur datant le RUN et non la VALEUR.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
Apres specialisation, l observateur discriminait parfaitement (5/5 dans
les deux sens) mais notait l oscillation « moyenne » au lieu de
« haute » : j avais pose quatre niveaux sans jamais dire ce que chacun
signifie. Defaut de briefing, pas de detection.
L echelle est desormais ancree sur des cas mesures de cette installation
— la consigne reseau qui evince 5,6 kW de solaire pour « moyenne », le
contacteur qui bascule six fois en dix minutes pour « haute » — avec une
regle explicite : UNE OSCILLATION EST TOUJOURS DE GRAVITE HAUTE, parce
que c est la repetition qui fait le degat et que c est precisement ce
qu aucune regle locale ne peut voir.
Mesure apres ancrage : oscillation « haute » 3/3, systeme calme
« aucune » 3/3.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
SPECIALISATION. Campagne du 12/09 : lui demander d observer ET de
planifier degradait les deux — l ecart de cible entre passages est passe
de 0 a 35 points sur certains cas des l ajout de la mission
d observation. Il ne planifie plus : la planification est faite par le
bilan, qui est calcule, mesure et teste a 48/48. Sortie reduite a
constat / gravite / ce_qui_cloche / piste. Prompt 7609 -> 6250 caracteres.
Mesure apres specialisation, horloge epinglee : oscillation reelle
detectee 5/5, contrefactuel calme 5/5. La discrimination est parfaite.
⚠️ Mais la gravite est retombee de « haute » a « moyenne » : mon echelle
a quatre niveaux n est ancree sur aucun exemple. Defaut de briefing a
corriger, pas defaut de detection.
Le compteur mesure desormais le VOLUME de signalements : on ne peut pas
verifier automatiquement s il a raison, on peut mesurer s il crie au loup.
COUCHE D ENQUETE. Trouver le coupable ce matin a demande sept requetes
enchainees ; rien n y exigeait un humain, seulement d appeler des outils
et d enchainer d apres ce qu on vient de lire. Six sous-commandes en
LECTURE SEULE, exposees en ligne de commande pour qu OpenClaw — que le
proprietaire veut utiliser — ou tout autre pilote les appelle sans
reecriture : bascules, mesures, decisions, ecrivains, bilan, cherche.
`bascules` calcule l ecart entre transitions successives du meme objet :
c est la signature d une oscillation, et l appelant n a pas a la refaire.
L enquete de ce matin se rejoue en trois commandes, jusqu a
automations.yaml ligne 22.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
Idee du proprietaire, et elle est meilleure que la mienne : ce systeme
n a pas besoin qu on lui suggere une strategie de plus, il a besoin que
quelqu un VOIE que « je coupe EDF, non je remets, et hop je coupe » est
absurde. Cinq automates ecrivent sur la meme installation, chacun
localement correct, aucun ne voit les autres. Leurs pannes sont des
CONTRADICTIONS, et elles ne se lisent que dans la SUITE des evenements —
jamais dans un instantane.
Le 12/09 au matin le contacteur reseau a bascule toutes les 4 minutes
pendant dix minutes : une automatisation HA coupait a 35 % de SOC,
l hysteresis rallumait. Aucun automate ne l a vu ; un humain oui.
Sortie elargie : `constat`, `gravite` (aucune/faible/moyenne/haute) et
`ce_qui_cloche`, valides strictement, publies dans trois helpers et dans
le logbook. Le snapshot porte desormais l anciennete des cinq transitions
cles (contacteur, verrou, takeover, etat EVCS, mode ACM).
⚠️ VALIDATION SCINDEE. Essai sur l oscillation reelle : le modele a
produit un constat JUSTE et un `current_max_a` de 100, hors bornes. La
validation tout-ou-rien jetait le diagnostic avec le champ fautif —
c est-a-dire exactement ce qu on lui demande, perdu a cause de ce qu on
ne lui demande plus. Les champs d ACTION gardent leurs bornes mais sont
NEUTRALISES au lieu de faire echouer l observation ; `actionUtilisable`
est le seul drapeau qui autoriserait un jour un cablage, et les compteurs
ne comptent que lui.
Tests advisor : +6. Deux attendus mis a la nouvelle semantique dans le
meme commit (hors bornes -> observation gardee, action neutralisee).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
Diagnostic du proprietaire, et il est juste : le conseiller n est pas
utilisable parce qu on lui donne des consignes fausses et des informations
partielles.
CONSIGNES FAUSSES. Son briefing enoncait mot pour mot la regle des paliers
(« forecast fort >= 18 kWh => cible ~35 % »), celle que le bilan a demontree
fausse le 03/09. Il declarait 17,5 kWh de batterie (mesure : 6,8 sur quatre
modules) et 9 kWc de panneaux (16,1 en realite). Retires. La capacite est
desormais CALCULEE depuis la courbe mesuree et le parc declare.
INFORMATIONS PARTIELLES. Il ne recevait AUCUNE sortie du bilan. Il ignorait
donc l heure de croisement, l energie a couvrir et le SOC requis -- les
seules grandeurs sur lesquelles la question se decide. +23 champs au
snapshot : bilan complet, parc, limites BMS, consigne reseau, modes des
chargeurs solaires, vehicule selectionne.
Ajoute aussi ce que personne ne lui disait : sans vehicule branche il y a
quand meme quelque chose a decider (c est la maison qui traverse la nuit),
les chargeurs declarent eux-memes s ils se brident, la cuisson du soir se
decale de trois heures, l hiver la nuit est plus longue de deux heures en
temps solaire.
PREUVE. Rejeu de la nuit bloquee du 12/09 a 04:00, sans aucune aide :
avant auto_solar_plus, cible 35 %, « prevision forte => cible basse »
apres force_grid_now, cible 60 %, « bilan exige 3.13 kWh avant 09h »
Le bilan demandait 59,1 %. En production a la meme heure, il n avait rien vu
-- quatre fois de suite.
COMPTEUR. Il comparait la STRATEGIE, constante a auto_solar_plus : 517
accords contre 23, soit 95,7 % — un score qui mesurait une constante. Il
compare desormais la CIBLE, contre le BILAN, et ne compte rien quand le
bilan est indisponible plutot que de compter faux.
Tests advisor : 3 nouveaux sur le compteur (ecart 2 pts -> accord, 13 pts ->
divergence, bilan indisponible -> aucun comptage). Perimetre mode ombre
inchange et toujours verifie.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
Quatre US5000 arrivent aujourd'hui. Les bandes de politique batterie sont
en amperes ABSOLUS (souple -50 A / dur -100 A au-dessus de 90 % de SOC,
etc.) et decrivent le parc de 4 modules sur lequel elles sont en vigueur
-- l'arret dur du 11/09 a mordu au bon endroit, 87 A pour une limite de
70. Les garder telles quelles briderait un parc trois fois plus gros au
niveau de l'ancien.
Deux lectures, aucune table reecrite :
- ECHELLE : le parc DECLARE (`evcs_balance_modules_en_service`, en
equivalents US2000C -- un US5000 en vaut DEUX), le meme helper que la
capacite utile et que le bilan energetique. Une seule valeur a tenir a
jour, et les trois consommateurs restent forcement d'accord.
- PLAFOND : ce que le BMS declare accepter a l'instant
(`maximum_allowed_discharge_current` / `_charge_current`, nouvellement
lus dans le snapshot). On ne s'autorise jamais plus.
⚠️ On ne met PAS a l'echelle sur la limite BMS lue en direct : elle
s'effondre quand une cellule monte en tension (04/09 : plafond de charge
de 150 a 20 A en cinq secondes). Une regle de confort ne suit pas un
signal aussi nerveux ; elle se plafonne dessus, c'est tout.
Parc absent ou BMS illisible => echelle 1, plafond inactif, comportement
inchange. C'est pourquoi les 95 scenarios existants passent sans
modification.
Golden 95 -> 98. Mutation : echelle neutralisee -> seul
`parc-double-decharge-toleree` tombe ; plafond BMS ignore -> seul
`parc-double-plafond-bms` tombe.
Verifie en production : execution 05:28:30 en succes, le gabarit rend
bms_max_discharge_current_a=100, bms_max_charge_current_a=100,
modules_en_service=4.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
Nuit du 11-12/09, vehicule rendu la veille : le bilan a reclame entre
92 % et 59 % de SOC a CHAQUE calcul de la nuit, `reseau_necessaire` vrai
partout, et rien ne s'est passe. SOC fige a 20 % de 23:43 a l'aube,
consigne reseau a 700 W depuis 18:36 -- soit exactement la maison.
L'hysteresis avait bien ferme le contacteur (SOC <= 20), mais fermer le
contacteur ne suffit pas : il faut DEMANDER la puissance (lecon du
01/09). Personne ne la demandait, parce que la session reseau de nuit
exigeait un vehicule branche.
Or le besoin n'a rien a voir avec la voiture : c'est la MAISON qui doit
traverser la nuit, et le bilan sait exactement ce qu'il lui faut. La
fenetre HC suffit comme condition d'engagement. Le relachement reste la
fin de fenetre, donc monotone, donc toujours immune a l'oscillation
(§40) -- la mutation le verifie.
Cout evite : a 07:24 le SOC etait encore sous le seuil OFF de
l'hysteresis (30), donc le contacteur serait reste ferme et la maison
serait passee au PLEIN TARIF jusqu'au croisement PV de 9 h. C'est le
1,49 kWh deja consigne le 03/09.
Golden 91 -> 95. Mutation : exigence de vehicule retablie -> seul le
scenario d'incident tombe ; borne de fenetre retiree -> le scenario de
fin de fenetre du 03/09 tombe AUSSI, donc la monotonie est bien testee.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
Incident 11/09 18:00, voiture a 28 A : la descente avait amene la
consigne a 1281 W alors que le solaire portait tout (PV 6058 W, reseau
1163 W). Un nuage a fait chuter la PV de 4,6 kW en une minute ; le reseau
etant plafonne a 1281 W, toute la difference est tombee sur la batterie
-- 87 A pour une limite dure de 70 -> `battery_current_hard_stop`, charge
coupee, redemarrage a 6 A.
Sans injection la production peut s'effondrer de plusieurs kW en quelques
secondes, et une boucle a 30 s ne rattrape pas cela : le reseau doit etre
DEJA autorise a prendre le relais. Second plancher : la consigne ne
descend jamais au point ou la perte totale du solaire depasserait ce que
la batterie sait encaisser, budget pris sur la politique par bande de SOC
(§35) avec 20 % de marge sous la limite DURE -- c'est elle qui coupe.
Sur le releve de l'incident, le plancher vaut 4829 W : au moment du
nuage la batterie n'aurait pris que 28 A au lieu de 87.
Contrepartie assumee : a 28 A la descente est nettement moins profonde
qu'a 6 A. C'est proportionne, le courant de la voiture est ce qui cree
l'exposition -- et proteger le materiel prime sur les kilowattheures.
Golden 90 -> 91. Mutation : plancher retire -> 2 scenarios tombent ;
budget pris sur la limite souple au lieu de la dure -> 3 tombent.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
Premiere version du credit solaire, en production 12 minutes : la
consigne descendait bien a 2241 W et la PV remontait a 7074 W, puis tous
les chargeurs repassant `mppt_active`, la condition de descente devenait
fausse, le besoin revenait au plafond et la consigne etait REECRITE a
7100 W. La PV s'effondrait a 1785 W, les chargeurs se bridaient, on
redescendait. Oscillateur de periode ~5 min -- le sixieme du projet, et
celui-ci vient de moi.
Releve : 17:40:30 -> 2241 / 17:47:19 -> 7100 / 17:47:28 PV 1785 /
17:48:30 -> 7368 / 17:49:30 -> 2186 / 17:50:30 -> 3762.
Une fois descendue, la consigne est TENUE tant que le solaire produit.
Rien a memoriser : la valeur vit dans le GX, et le plancher maison la
fait remonter d'elle-meme si la maison grossit. La nuit les chargeurs
sont `off`, donc ne produisent pas : on retombe sur le comportement
historique ou la consigne monte au plafond pour que le reseau porte
maison et voiture (§31, §57).
Golden 89 -> 90. Mutation : remettre le besoin au plafond fait tomber le
seul scenario `consigne-credit-converge-tient` ; appliquer le maintien la
nuit fait tomber les TROIS scenarios de session reseau nocturne, dont
deux anterieurs a ce chantier.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
BOOST 28 A en plein soleil, 11/09 17:02 : consigne reseau calculee a
8242 W (maison 1802 + 28 A x 230), PV effondre a 121 W, reseau 7697 W,
batterie 0 A. L'ESS n'a qu'un moyen de prelever 8,2 kW quand le soleil
en donne 4 : brider les MPPT. La production etait refusee par notre
propre consigne.
Le commentaire qui justifiait une consigne genereuse ("elle ne coute
rien") datait de la nuit du 01/09, ou la PV valait zero. En plein jour
il est faux.
On ne peut pas soustraire la PV mesuree : elle vaut 121 W A CAUSE de
cette consigne. Le proprietaire l'a montre en la baissant a la main a
2280 W -- PV 4758 W en 50 secondes, batterie +9 A. On descend donc par
paliers et on laisse la physique repondre, sur deux signaux incensurables
et deja lus : les chargeurs declarent eux-memes s'ils se BRIDENT, et le
courant batterie dit si on est descendu trop bas.
`off` ne compte pas comme bride : la nuit les six le sont, et les
confondre ferait descendre la consigne au crepuscule -- un oscillateur
de plus. C'est ce que verifie le scenario de nuit.
Plancher : la consigne ne descend jamais sous la maison hors voiture,
garantie du 01/09 et du 04/09. On ne libere que la part voiture.
Golden 84 -> 89. Mutation en quatre directions (descente neutralisee /
`off` recompte comme bride / garde batterie retiree / plancher retire) :
chacune fait tomber un jeu DIFFERENT, aucune garde n'est couverte par
le test d'une autre.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
Nuit du 07 au 08/09 : 32 calculs du bilan sur 120 en statut degrade, tous entre
00 h et 03 h, avec « aucun croisement PV/conso sur l'horizon, 47,6 kWh a
couvrir ». Le controleur, qui exige statut=ok, retombait sur le palier de 35 % —
d'ou une cible du matin oscillant entre 35, 78,8 et 85 % au lieu de decroitre.
Cause immediate : plus aucune publication de prevision de 23:45 a 04:30. Le
noeud d'appel porte neverError, donc les executions restaient en success ; la
reponse etait « socket hang up », et le noeud d'ecriture vers Home Assistant
rendait 0 item la nuit contre 1 en journee — le .17 etait lui aussi injoignable,
si bien que le message d'echec ne pouvait meme pas etre publie.
Mais le defaut qu'on controle est ailleurs : les courbes sont publiees sans leur
date, et PARSE_FORECAST prend days[0] pour « aujourd'hui ». Vrai a l'instant de
la publication, faux des qu'on passe minuit sans rafraichir. A 00:45 le bilan a
donc lu comme journee en cours celle du 7, dont toutes les heures etaient
passees.
Une courbe est desormais utilisable si elle DECRIT le jour dont on a besoin, pas
si elle est recente : une prevision publiee a 23:45 pour le 8 reste exacte a
03:00, la nuit il n'y a rien a reactualiser. La date part dans
evcs_balance_forecast_day0, et RESOURCE_ESTIMATE distingue trois cas — a jour,
decalee d'un jour (la courbe du lendemain devient celle du jour, l'enveloppe
mesuree reprend la main pour demain), perimee. Helper absent : ancienne garde
d'age, comportement inchange.
Le rapport de nuit signale un trou de plus de deux heures dans les
publications. Il lit la base sur l'autre NAS, seul temoin qui survit quand le
.17 est injoignable. Verifie sur la nuit ecoulee : 285 minutes.
Tests 44 -> 48. Les quatre scenarios partagent la meme heure — 00:45, l'instant
du decrochage — et les memes courbes : seule la date change. Quatre mutations,
chacune sur un jeu different, chaque scenario ayant la sienne.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
Le 07/09 a 14:28:18 la borne a declare le statut 3 apres 2 min 42 s de charge
et 0,10 kWh livre. Le controleur l'a cru, a latche day_vehicle_full_idle, et la
JEEP est restee immobile deux heures en plein soleil alors qu'elle pouvait
charger : elle a repris a 16:30 et tenu.
La premiere idee etait de distinguer une vraie fin de charge d'une interruption
par la forme de la coupure. La mesure a la seconde l'a tuee : les deux courbes
sont superposables (VW 06/09, vraie fin : 1534 -> 550 -> 82 -> 11 -> 0 W ;
JEEP 07/09, faux positif : 1626 -> 741 -> 100 -> 13 -> 0 W). Aucun signal
electrique instantane ne separe les deux cas.
Seule la duree de session les distingue, et le systeme porte deja la grandeur
qui dit ce qu'est une charge etablie : min_run_minutes, 29 min en production.
Trois formes de "charged", une seule est refusee :
energie de session nulle -> vehicule plein a l'arrivee, on latche (P10)
energie > 0, session < min_run -> charge INTERROMPUE, on ne latche pas
energie > 0, session >= min_run -> charge menee a terme, on latche
Aucune constante nouvelle. Pas d'oscillateur : une session interrompue
redemarre a energie nulle, donc un second "charged" immediat retombe dans le
premier cas et latche.
Confirmation independante le meme jour : Uconnect a envoye a 14:29 un courriel
"RECHARGE ELECTRIQUE INTERROMPUE" invitant a controler la borne et le
connecteur. Le vehicule qualifie donc l'evenement d'interruption. Le releve de
la boite montre que c'est chronique depuis au moins decembre 2025 (12
interruptions et 6 echecs entre le 31/12 et le 08/03) : nos automates n'ont pas
cree le defaut, ils en ont augmente le cout.
Golden 80 -> 84, dont le releve reel et ses deux contrefactuels (duree et
energie). Trois mutations tombent chacune sur un jeu different ; celle qui rend
le cas "energie nulle" non credible fait echouer trois scenarios existants
(P10, Fix D, Fix E).
Corrige au passage le HANDOFF du 06/09 : last_session_energy ne decrit pas la
derniere session terminee, il suit la session en cours (verifie dans InfluxDB).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
Le plafond a 93 % n etait pas une protection : le BMS autorisait 53,2 V, nous
imposions 51,3, et la cellule la plus haute du pack recent etait 57 mV sous la
premiere alarme. Le garde-fou datait des cellules faibles du pack ancien, hors
service depuis hier — il protegeait un parc qui n est plus la, au prix de
0,68 kWh, soit 12 % de la reserve utile.
Le helper de tension et ses paliers ne sont lus par personne : les valeurs sont
une table codee en dur dans l Auto Charge Manager, qui entre au passage dans le
depot. Seul le profil de la tranche 90-95 % passe a 52,4 V, soit 3,493 V par
cellule, sous la tension nominale que Pylontech annonce. Verifie dans la
minute : parc de 51,12 a 52,33 V, courant de -5,3 a +16,1 A, aucune alarme.
Et le rapport de nuit part par courriel a 6 h 47. Il ne vit pas dans une
session Claude, qui s arrete avec l ecran, mais dans le service
d historisation, seul composant allume en permanence — il n y avait rien a
surveiller, tout est deja enregistre, il manquait une lecture. Le texte est
ecrit pour etre entendu : pas de tableau, des phrases courtes, des virgules
decimales. Canal : le webhook n8n qui existait deja, teste de bout en bout.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
Valeurs negatives au point de raccordement, contacteur ferme. La mesure separe
deux phenomenes que rien ne reliait.
Le premier est bien la plaque qui cycle : sur la fenetre de midi, 9 % des
echantillons negatifs, minimum -477 W, mediane -146. Le regulateur ne rattrape
pas un delestage brutal d un kilowatt avec une consigne de repos a 200 W. Elle
passe a 700 : la courbe monte de 500 W et le minimum devient +23 W. Le surcout
va dans le bon sens, cette consigne ne s appliquant que contacteur ferme sans
session reseau — c est-a-dire apres une coupure sur SOC bas ou une fermeture
par la regle de protection, deux cas ou l on veut justement que le reseau
contribue davantage.
Le second, -2819 W pendant deux minutes, n a rien a voir : le debranchement du
vehicule a supprime 2,2 kW d un coup alors que la batterie a 93 % n absorbait
rien et que le MPPT produisait 4 kW. Aucune consigne n absorbe cela. Ce qui l
evite est le correctif du matin sur la regle de protection : la demande sur le
parc valait 741 W, le contacteur n aurait pas ete ferme, et sans reseau il n y
a rien ou injecter.
Golden 80/80, trois attendus mis a jour avec la mesure en commentaire.
Et docker n est pas dans le PATH d une session SSH sur DSM : les commandes de
deploiement appellent desormais /usr/local/bin/docker.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
Deux fermetures ce dimanche midi. Mesurees a l instant de la decision,
contacteur encore ouvert donc production non censuree : maison 4025 et 4981 W,
mais parc reellement sollicite 1132 et 772 W pour un plafond de 5100. La
decharge batterie mesuree aux memes instants — 1345 et 1223 W — colle a
maison moins PV, pas a la maison brute. Le solaire couvrait la cuisson ; la
regle a ferme le contacteur pour rien, 0,50 kWh importes en plein soleil.
Elle n avait bien fonctionne hier 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, un bridage du MPPT la fait
surestimer, donc l erreur pousse a rester ferme et jamais a relacher tot.
Golden 20 -> 24, dont les deux releves de midi et le contrefactuel du nuage.
Le test de mutation a montre que la premiere serie ne couvrait que le seuil de
fermeture : il a fallu ecrire le cas du soleil revenu pour qu elle morde.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
La regle du 05/09 ferme quand la maison depasse 80 % du plafond de decharge du
parc — elle a mordu au bon instant hier soir, a -97,4 A pour 100 A autorises.
Mais elle relachait sur un seul echantillon sous 50 %, et la soiree offrait
quatorze occasions de le faire. Le troisieme pic est tombe deux minutes avant
l'ouverture reelle : decale de cinq minutes, elle refermait, et chaque
aller-retour du contacteur coute 50 a 150 Wh.
Les accalmies mesurees sont franchement bimodales — treize de 5 min au plus
pendant la cuisson, une de 201 min apres. Le relachement se mesure donc en
duree, et la duree vient du bilan energetique : 20 min tant que la batterie est
condamnee a toucher son plancher avant les heures creuses (l'energie reseau du
soir est due de toute facon, la tenir ne change que son heure), 6 min des
qu'elle passerait la nuit seule (chaque kWh du soir deplacerait alors un kWh
d'heures creuses vers des heures pleines). Premiere lecture du bilan par le
workflow d'hysteresis.
Le dwell se compte sur la maison, jamais sur le contacteur : l'horodatage est
ecrit qu'il soit ouvert ou ferme, sans quoi la decision detruirait sa propre
cause. Et parce que la tension batterie s'est tue 27 minutes hier soir en
pleine cuisson, le plafond retombe sur la tension nominale du parc, et a defaut
l'horodatage — un fait persiste — tient la protection jusqu'au bout du dwell.
Golden-hysteresis 11 -> 20. Six mutations, chacune tombant sur un jeu different.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
Quatre modules : le BMS annonce 100 A de decharge sous 51 V, soit
5,1 kW, quand la maison a deja pointe a 8 kW en cuisinant. Contacteur
ouvert, la batterie est seule et se fait tirer au-dela de sa limite.
Le declenchement porte sur la CHARGE MAISON, jamais sur le courant
batterie : fermer le contacteur fait chuter ce courant, donc s'en
servir comme critere de relachement ferait que la decision detruirait
sa propre cause. Fermeture a 80 % du plafond, relachement sous 50 %,
les deux seuils derives du plafond annonce par le BMS - ils suivront
donc le parc sans qu'on y touche.
Les tests ont revele un vrai defaut au passage : les trois coupures
immediates s'executent avant la cascade et auraient ouvert le
contacteur que la regle venait de fermer. Elles cedent desormais
devant la charge maison. Preuve par mutation : sans cette garde, un
scenario tombe.
Plafond illisible => regle inerte, comportement historique intact.
11/11.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
La courbe energie/SOC a ete mesuree sur sept modules. Retirer un
module divise la capacite sans changer la forme de la courbe : les
pentes sont donc mises a l'echelle du nombre reellement en service,
lu dans input_number.evcs_balance_modules_en_service. Le controleur
EVCS lit le meme helper pour sa capacite utile - les deux decrivent
forcement le meme parc.
Helper absent, illisible ou hors bornes => sept, la valeur de la
mesure. Les 44 scenarios du bilan et les 80 golden passent donc sans
qu'un seul attendu ait ete touche : la bascule ne change rien tant
que personne ne l'ecrit.
Deux scenarios couvrent la bascule elle-meme, l'un avec quatre
modules (SOC exige 30,5 -> 35,2 %), l'autre avec une valeur
aberrante qui doit retomber sur sept. Preuve par mutation : ignorer
l'echelle fait tomber le premier et lui seul.
Le genou a 33 % est conserve par PRUDENCE et non par mesure :
l'hypothese est qu'il vient des cellules faibles du pack retire, donc
qu'il disparait avec lui. Le garder revient a sous-estimer la
reserve, c'est-a-dire a se tromper du bon cote.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
La veille de nuit a rendu son verdict : UNE seule bascule sur 69 releves entre
01:26 et 07:07. La session reseau unique fait ce pour quoi elle a ete concue,
EDF ferme d un bout a l autre de la fenetre sans creneau ni oscillation.
Mais a 02:50, la voiture finie, le sourceMode est passe a bloque et la consigne
reseau est retombee de 5078 a 50 W. Contacteur ferme, reseau disponible, heures
creuses, et l ESS ne demandait que 50 W pendant que la maison tirait 770 W sur
la batterie. Trois heures et demie, SOC 44 vers 17 pour cent, 2,60 kWh pris a la
batterie quand le reseau etait la et bon marche. L Auto Charge Manager est reste
pret a recharger avec DVCC a 30 A, mais la consigne ne demandait jamais l
energie. C est le defaut du 01/09 revenu ailleurs : j avais etabli que fermer le
contacteur ne suffit pas, puis cree la veille une nouvelle raison de le garder
ferme sans la brancher sur la consigne.
gridSessionActive inclut desormais l engagement de session. Regle : tant que le
contacteur est ferme a notre demande, la consigne couvre la maison, peu importe
laquelle des deux raisons le tient.
Consigne de repos portee de 50 a 200 W a la demande du proprietaire, avec une
justification mesuree : sur 12 074 echantillons du point de raccordement, 17 %
sont negatifs, mediane -18 W. Ce n est pas de l injection — la batterie
debitait 744 W au meme moment et les 22,7 Wh cumules representent 0,9 % de ce
qu elle perdait — c est le regulateur qui chasse autour d une cible trop proche
de zero. A 200 W le point de fonctionnement reste positif sur l essentiel des
excursions, sans supprimer les pointes les plus fortes.
Consigne aussi que le 20 % n est pas le notre mais le plancher de l ESS, qui a
fini par faire de lui-meme a 06:20 ce que la session aurait du faire depuis
02:50, apres avoir vide la batterie de 27 points.
Golden 78 -> 80, deux mutations ciblees. Piege rencontre et documente : la
premiere redaction du contrefactuel portait deux fois la clef balance_status, et
en JavaScript la derniere gagne — il testait donc l inverse de son libelle. Un
contrefactuel doit reposer sur une difference physique, pas sur la surcharge d
une clef deja presente.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
576 paliers de SOC mesures sur 8 jours (tools/mesure-courbe-batterie.mjs,
ajoute) : pour chaque palier ou le SOC reste a une valeur puis descend d un
point, on integre la puissance batterie, en ecartant les paliers ou la batterie
a charge et ceux ou le reseau a apporte quoi que ce soit.
Resultat : plate a 0,169 kWh/point de 33 a 93 — six tranches independantes entre
0,163 et 0,171 — genou net a 32-33, puis 0,097 en dessous. Sous le genou un
point de SOC vaut 57 % de ce qu il vaut au-dessus, ce qui est coherent avec le
parc reel (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.
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, trop haut de 4 a 6 pour
un gros. Cela corrige au passage une affirmation inexacte de la section 40, ou
j avais ecrit que required_soc etait systematiquement trop bas d un facteur
1,75 : ce facteur comparait la vitesse de descente du SOC a celle de la ligne,
deux grandeurs differentes, et l ecart venait surtout de la sous-estimation de
la consommation par le profil p50. La correction est posee en tete de la
section 40.
Trois fonctions remplacent les cinq conversions lineaires de BALANCE.js ;
requiredSocAtStartPct reste non ecrete au-dela de 100, l extrapolation utilisant
la pente haute. INPUT_PARSE passe de 17,5 a 16,9 avec la consigne explicite
qu un calcul traversant le genou doit lire la courbe et non cette constante.
Tests du bilan 42/42 apres mise a jour deliberee de six attendus, chacun verifie
a la main contre la courbe. Un libelle corrige : le seuil fixe de 30 % tombait
juste ce matin-la par coincidence, pas par construction. Deux mutations — pente
basse ramenee a la pente haute, puis genou ramene au plancher — font tomber les
six memes scenarios. Golden 78, hysteresis 7 et advisor inchanges.
Les trois nombres sont des resultats de mesure, pas des reglages, et vivent dans
le code avec l outil qui les produit ; a rejouer apres l extension du parc.
Principale erreur restante du bilan, desormais devant la conversion : le profil
de consommation p50 sous-estimait de 33 % les heures 03-06 de la nuit du
02-03/09. A instruire separement.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
§26 avait pose l objectif et designe le critere. Avant d ecrire quoi que ce
soit, j ai mesure 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
environ 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, alors que BALANCE.js convertit avec
une constante unique de 15 kWh. required_soc y est donc systematiquement trop
bas — c est le facteur 1,75 mesure la nuit du 02-03/09, ou le SOC descendait
bien plus vite que la ligne.
Cette mesure a dicte la conception : le relachement de la session ne peut pas
etre un seuil de SOC, puisqu il porterait sur une grandeur fausse et que 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.
Retenu : engagement sur le bilan (batterie sous la cible), 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 nouveau
helper input_boolean.victron_evcs_night_grid_session_committed porte
l engagement, cree par input_boolean.reload sans redemarrage HA et ecrit
seulement sur changement reel ; sans cette persistance la garde redeviendrait
une bande, donc un oscillateur.
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 l absence d override et le helper
takeover reste ON : aucune modification du workflow d hysteresis.
Golden 75 -> 78. Le scenario epingle quelques heures plus tot comme limite
connue devient celui du correctif, attendu mis a jour dans le meme commit.
Quatre mutations ; la plus parlante retire la garde bilan et fait tomber les
trois scenarios anti-oscillateur du 27/08 — les tests de l ancien correctif
protegent le nouveau code.
Prerequis identifie et non traite : la conversion kWh vers points de SOC est une
constante la ou la realite est une courbe. Consequence, un sous-declenchement
possible en bas d echelle, jamais une oscillation. Prochain chantier du bilan.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
La regle classait le lendemain en trois paliers a partir de son TOTAL (>= 18 kWh
-> 35 %, >= 10 -> 55 %, sinon 85 %) et ignorait donc l heure d arrivee de
l energie. Le 03/09 demain annoncait 33,9 kWh — donc "fort", donc 35 % — avec un
matin creux (0,03 kWh a 7 h, 0,77 a 8 h) et un croisement a 9 h. Meme defaut que
le plancher du soir, a l autre bout de la nuit.
Releve de la nuit 02-03/09, requis contre reel : 00:30 62,4 / 53 ; 03:00
50,4 / 45 ; 04:30 41,7 / 37 ; 06:00 37,1 / 22 — cible fixe a 35 tout du long.
Le required_soc decroit proprement avec la nuit qui se consomme (6,1 -> 0 kWh a
couvrir), la batterie est restee sous la ligne toute la nuit, et le bilan le
savait des 00:30. A 03:00 EDF a ete relache cinq points sous la ligne ; le
reseau est revenu de 07:24 a 10:33 au plein tarif, 1,49 kWh.
La cible vaut desormais min(90, max(palier ou advisor, required_soc)). Sens
unique delibere : la direction corrigee est celle de l echec observe, et le
principe unificateur des deux cablages est que 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 superieures a 100 — sans ce plafond la cible serait
inatteignable et EDF resterait allume toute la nuit. C est deja la borne du
chemin advisor, aucune constante nouvelle.
Pas d oscillateur : required_soc decroit de facon monotone pendant la nuit et la
passe unique de recovery reste en place. Gardes et repli identiques au plancher
du soir, kill-switch existant.
Golden 70 -> 75. Quatre mutations font tomber chacune exactement un scenario
different. Un cinquieme scenario fige une LIMITE CONNUE, mesuree par sonde : la
passe unique de recovery latche le relachement pour toute la session, donc la
cible dynamique n ameliore que la premiere passe. §26 avait deja designe le bon
critere de re-engagement — un budget d energie restant a couvrir, qui appartient
au bilan ; la suite touche la machine a etats de la nuit et fera l objet d un
chantier propre.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
grep evcs_balance sur les deux workflows de decision renvoyait 0 depuis la mise
en service du bilan le 26/08 : il calculait l heure de croisement, l energie a
couvrir et le SOC requis, et personne ne l ecoutait. Le 03/09 a 19:44 les deux
nombres coexistaient dans le meme systeme — evening_soc_start_min a 85 %, un
niveau qui ne sait rien de la nuit, contre evcs_balance_required_soc a 99,7 %,
l energie a couvrir jusqu au croisement de 9 h. A SOC 94 le premier autorisait
la charge, le second disait que la batterie ne passerait pas la nuit seule.
Le plancher de demarrage du soir vaut desormais max(regle, bilan). Sens unique
delibere : le bilan peut durcir, jamais relacher. L assouplir — il dira souvent
moins de 85 % par forte prevision d ete — autoriserait des charges qui n ont pas
lieu aujourd hui, decision distincte a valider pour elle-meme. Le max rend au
passage la garde robuste sans borne ni ecretage : une valeur nulle, negative ou
aberrante ne peut pas relacher le plancher.
Portee demarrage : le plancher de maintien reste min(...), donc a 80 %, et
aucune charge en cours n est coupee. L abondance P6 continue de primer, etant
une preuve mesuree que la ressource depasse ce que le systeme absorbe.
Gardes : fraicheur inferieure a 30 min (six cycles du bilan), horodatage futur
rejete, statut ok, valeur finie. Sinon regle historique. Aucun nouveau toggle :
evcs_balance_enabled a OFF arrete les ecritures du bilan, balance_last_run se
fige, la fraicheur expire et le plancher retombe seul sur 85 % en une
demi-heure — un helper de plus aurait fait doublon.
Gabarit complet re-rendu contre HA : 195 champs, JSON valide, aucun null.
parseAdvisorRunToMs reutilise, l advisor et le bilan publiant le meme format.
Golden 66 -> 70. Quatre mutations — bilan ignore, Math.max remplace par une
affectation directe, garde de fraicheur supprimee, garde de statut supprimee —
font tomber chacune exactement un scenario, et un different a chaque fois.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
Le correctif precedent bloque l incident de 19:44, mais un excedent proche de
zero est ambigu : c est la signature de la censure ET celle de l equilibre de
fin de journee. Le releve du 03/09 contient les deux avec le meme excedent —
18:50 : +14 W, ressource refusee ; 19:41 : +1 W, plus rien a donner. Rejeu du
19:41 : batteryAssistSolarStartOk etait encore vrai. Trois minutes avant
l incident, le systeme aurait commis la meme faute.
Le plan annoncait de lire evcs_balance_pv_censored. Lecture de CENSORSHIP.js :
ce drapeau est un OU de motifs dont l un est exactement le proxy qu on voulait
remplacer (socPct >= 90 et batterie sans puits). Et il est reste ON jusqu au
calcul de 19:50, soit cinq minutes APRES le demarrage de la charge — ce qui l a
fait basculer n est pas la censure mais sun_elevation passant sous 10 degres.
Il n aurait pas bloque l incident.
Le signal juste, ce sont les chargeurs eux-memes : sept entites
sensor.*_mppt_operation_mode, jamais lues par aucun workflow. mppt_active = je
suis a mon point de puissance maximale, je donne tout ; voltage_current_limited
ou off = je me retiens faute de preneur. Le 03/09 elles ont bascule a 19:20,
soit 24 minutes avant pv_censored, sans aucun proxy et a la cadence de la
boucle. Contre-verification le 01/09 a 14:22 : les trackers restaient limites
PENDANT une charge de 3,4 kW sous 6,9 kW de PV, donc le signal ne s auto-annule
pas a midi.
Collecte sans aucun entity_id code en dur (selectattr sur mppt et
operation_mode), expression testee sur /api/template puis gabarit complet
re-rendu : 191 champs, JSON valide, aucun null. Lectures inexploitables
ecartees, et repli sur le comportement anterieur quand il n en reste aucune.
Garde de DEMARRAGE uniquement, structurellement : la lier au sourceMode ou au
maintien ferait que la charge, en donnant un preneur au MPPT, detruirait sa
propre condition d autorisation — le bistable de l abondance P6 corrige le
24/08.
Golden 64 -> 66. Mutation dans trois directions : garde neutralisee -> 1 echec
cible, provocation toujours refusee -> 3 echecs, lecture illisible traitee
comme "a fond" -> 1 echec sur le scenario de repli.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
Le 03/09 a 19:44, voiture branchee : PV 758 W, maison 1202 W, batterie deja
a -12 A, nuit qui tombe. Le controleur a lance 1,6 kW de charge parce que
pv_start_min_w (700 W) est une puissance PV absolue : "758 >= 700, donc il y
a du soleil". 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), la veille d une
nuit que le bilan energetique annoncait deja deficitaire.
Rejeu du releve dans la vraie chaine : rawSolarStartOk ET
batteryAssistSolarStartOk etaient tous deux vrais. Corriger le seul seuil PV
n aurait donc rien change ; les deux chemins sont traites ensemble.
La grandeur juste 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 separe les deux situations que la mesure PV seule confond : sous
censure la production se cale sur la maison, l excedent vaut ~0 et il y a de
la ressource refusee ; en deficit reel l excedent est negatif et la batterie
porte deja la maison. Zero est la frontiere physique entre les deux, verifiee
sur le releve du 03/09 (excedent positif sur toute la plage ou pv_censored
etait ON, negatif ensuite).
Aucune constante nouvelle, aucun champ de snapshot, aucun helper :
derived.houseNonEvcsW existait deja. Le chemin "soleil reel" reutilise
pv_start_min_w tel quel, applique a la bonne grandeur ; le chemin
"provocation" exige seulement excedent >= 0. Demarrage uniquement : les
conditions de maintien gardent leur plancher et leur tolerance temporelle.
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. apresmidi-provocation-p3 est corrige : il portait
PV 300 W, maison 600 W, batterie +2 A reseau ouvert, un trou de 300 W que rien
n alimente, et passait quand meme parce que le demarrage ne regardait jamais
le bilan. Mutation dans les deux sens : 2 echecs cibles a chaque fois,
excedent-censure-demarre restant vert (il tient par le chemin assistance).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
La table des bandes SOC declarait depuis toujours un courant souple tolere
pendant des minutes et un courant dur tolere quelques secondes. Les deux
tolerances etaient calculees, exportees dans le debug, et lues par aucune
decision : le controleur comparait un echantillon instantane a un plancher,
toutes les 30 s.
A SOC 94 la batterie est en float et son courant oscille entre +1,8 et -2,6 A
d'un echantillon a l'autre. Le test devenait un tirage a pile ou face et la
charge du vehicule s'arretait sur du bruit : deux fois le 01/09, quatre a six
fois par jour la semaine precedente. Chaque arret coutait environ 0,45 kWh,
la batterie etant pleine et le vehicule le seul preneur.
Le correctif est purement temporel : aucun seuil n'est deplace, aucune
constante ajoutee. La tolerance de la bande est branchee sur les trois
conditions de MAINTIEN, via un helper de persistance qui porte le debut du
depassement en cours. Le plancher de demarrage et le garde dur restent
instantanes : la tolerance est du confort, jamais du risque.
Golden 56 -> 61. Preuve par mutation dans les deux sens : tolerance supprimee
-> 2 echecs cibles, tolerance infinie -> 3 echecs cibles, l'arret dur restant
vert dans les deux cas.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
Fermer le contacteur ne suffit pas : au-dessus du SOC minimal, l ESS en
autoconsommation ne preleve que sa consigne et laisse la batterie porter
maison et voiture. Nuit du 01/09 : charge HC demarree a 01:25, arretee a
01:26 par le garde batterie, contacteur ferme et inerte jusqu a 02:00.
La consigne a 4200 W du proprietaire n etait pas decorative : c est elle
qui faisait fonctionner la prise de relais nocturne depuis le 07/08. La
retirer le 31/08 a supprime la substitution de journee et casse la nuit.
Le controleur ecrit desormais la consigne lui-meme, a partir du besoin
mesure, seulement pendant une session reseau deliberee, avec une bande
asymetrique : trop basse se corrige tout de suite, trop haute ne coute
rien. Deux ecritures en 25 minutes au lieu d une toutes les 30 s.
Golden 51 -> 56. Verifie en reel : batterie a 0 A, voiture a 3500 W.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
Le plafond majore (28 A en BOOST) n est legitime que tant que le reseau alimente
AC-IN : sinon les deux MultiPlus portent seuls la voiture plus la maison, le
mecanisme du W-105. Personne ne baissait avant l ouverture -- c est l hysteresis
qui ouvre, l EVCS l apprenait apres coup -- et quand il l apprenait, la reduction
attendait le cooldown de courant et descendait d un pas a la fois.
Correctif sans poignee de main ni helper nouveau : le plafond majore exige que
l EVCS DEMANDE lui-meme le reseau. Sa demande tombe au cycle ou la fenetre se
ferme (30 s), l hysteresis ne peut ouvrir qu ensuite (override disparu PUIS
min_on, cycle 1 min) : l EVCS baisse toujours avant, mecaniquement.
Second volet : un plafond n est pas une cible qu on approche. Reduction
immediate et directe au plafond, sans cooldown.
Le calcul du plafond a ete deplace apres sourceMode dans WINDOWS_SOURCEV2 ; rien
entre les deux ne le lisait, verifie avant de bouger.
Helper a 20 A par defaut : comportement inchange. Le correctif ne mord que sur
le BOOST 28 A, le cas dangereux.
Golden 48 -> 51, chaque cas apparie a son contrefactuel. Mutations des deux
volets separement : 1 puis 2 echecs cibles, restauration 51/51.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
A la fermeture du contacteur, PV, import et courant batterie ne decrivent aucun
regime permanent pendant ~150 s (mesure du 31/08). La boucle de 30 s y prenait
cinq decisions, et la moyenne PV 10 min en gardait la trace dix minutes de plus
-- le systeme lisait "plus de soleil", en concluait qu il avait besoin du
reseau, et confirmait sa propre premisse.
Aucun seuil nouveau : le systeme publiait deja l horodatage de la transition et
personne ne le lisait. Pendant la fenetre, on ne demarre pas et on ne laisse pas
une charge s arreter sur ces mesures ; les step-down restent libres.
Deux asymetries voulues : la fenetre ne s ouvre qu a l ARRIVEE du reseau (a sa
disparition les onduleurs reprennent tout, les gardes doivent agir plus vite),
et elle suspend le confort, jamais le risque.
Golden 42 -> 48, chaque cas apparie a son contrefactuel hors fenetre. Mutation :
gridSettling force a false -> 2 echecs cibles, restauration -> 48/48.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
Une coupure reseau n arrete pas l installation : le solaire et la batterie
continuent, seul le filet de secours disparait. La reserve a tenir est donc la
couverture prudente p80 que le bilan calcule deja — aucune constante nouvelle.
En deficit c est la fenetre traversee, en surplus la prochaine, car a 15 h la
reponse « rien a couvrir » est exacte et inutile.
Le seuil d activation est la vigilance orange, echelle officielle de
Meteo-France et non un nombre choisi ici. Le snapshot lit l alerte sans
connaitre la commune, donc le code marche des l installation de l integration
et publie « indisponible » en attendant.
Tests 38 -> 42. Le fixture du test de perimetre ombre ne contenait pas storm :
les nouvelles ecritures n etaient pas couvertes. Corrige, assertion explicite,
preuve par mutation.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
La bande de 2 points du Fix A engageait le takeover a SOC 33 et le relachait
a 35 : 0,34 kWh, soit une demi-heure de conso nocturne plate. Trois cycles EDF
la nuit du 26-27/08, six la nuit du 20-21/08, 2,5 kWh importes pour rien.
Une seule passe de recovery par session de nuit. Le plancher dur reste un
terme independant, l hysteresis garde sa bande 20/30, et le vrai critere de
re-engagement (un budget d energie) appartient au bilan, pas a une constante
de plus ici.
Golden 40 -> 42, preuve par mutation. Documente aussi deux acteurs non lus :
les charges programmees de l ESS (45 % la nuit, contre notre cible 35 %) et
le regime majoritairement hors reseau.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
Le drapeau « degrade » introduit la veille s'allumait de 20 h a 07 h toutes les
nuits. La qualite de forme d'une heure vient du taux de censure ; les heures
sans soleil portent un taux de 1 faute d'avoir quoi que ce soit a observer, pas
parce que la mesure serait douteuse. Comme les heures de deficit sont justement
les heures sans soleil, le drapeau se declenchait exactement quand le bilan
sert.
Une heure dont l'enveloppe demontree est nulle recoit desormais la qualite
'nuit'. Scenario epingle sur l'enveloppe et le taux de censure releves en
production, pas sur le fixture — dont la nuit valait 0 et qui ne reproduisait
donc pas le defaut. Preuve par mutation : avant 'minoree', apres 'nuit'.
Suite 37 -> 38. Documente la nuit du 25-26/08 : profil corrige verifie a
0,2 kWh/h pres, bilan qui predit le point bas a un point pres, et non-linearite
du SOC mesuree (huit points en dix-sept minutes pour 0,16 kWh).
`bucketHourly` garde la derniere valeur de chaque heure : le delta entre H-1
et H est l'energie depensee PENDANT H. `deltaSeries` le rangeait sous H-1.
Discret sur un compteur dense, catastrophique sur un compteur epars — et les
compteurs de cette installation le sont : `ac_in_1_to_ac_out` ne peuple que 57
heures sur 267, `evcs_total` 57 sur 264, parce qu'ils n'emettent que lorsqu'ils
avancent. Une heure vide vaut « zero energie », donc toute l'energie d'un
intervalle a trou a ete consommee pendant l'heure FINALE. Rangee sous l'heure
initiale, l'import reseau de la nuit suivante atterrissait sur la derniere
heure de la nuit precedente.
Mesure du 25/08 : consumption_p50[8] = 2,90 kWh/h pour 0,80 reellement — six
echantillons sur douze portaient un delta etale sur 17 heures. Le bilan
reclamait environ deux fois trop d'energie le matin (3,37 kWh annonces a 06 h
contre 1,35 mesures), et donc un SOC requis de 44,5 % la ou 31 % suffisait.
L'enveloppe de production etait decalee de la meme heure, ce qui a contribue a
surestimer la part matinale de la production dans le journal de chantier.
Ajoute aussi un statut `degrade` : le bilan publie ses chiffres quand aucun
croisement n'apparait sur l'horizon ou quand les heures de deficit reposent sur
une forme minoree, mais il ne les presente plus comme fiables. La nuit du 25/08,
avant la mise en service de la courbe horaire, il a publie un SOC requis de
100 % avec un statut `ok`.
Tests 36 -> 37, dont `compteur-epars-attribution-horaire` (rafale reseau de
1/2/3 kWh a 01/02/03 h : montants distincts pour qu'un decalage d'un cran soit
impossible a confondre). Mutation verifiee : l'ancienne attribution le fait
echouer.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
Premiere execution reelle sur la courbe horaire (25/08 02:40) : croisement a
09 h, 4,39 kWh a couvrir, SOC requis 51,3 % pour 42 % reels, reseau necessaire
1,39 kWh. La traversee nocturne suivante s'affichait "17 h -> ?" : avec un
horizon de 30 h, la fenetre commencant en fin d'apres-midi ne se refermait pas
au croisement du lendemain matin. Porte a 40 h, la courbe couvrant 48 h.
L'energie manquante de stockage s'affichait non arrondie dans le texte de la
raison (2.9000000000000017).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
RESOURCE_ESTIMATE consomme desormais la courbe horaire publiee par le workflow
de prevision : forme et magnitude d'un seul tenant, sur 6 jours, avec les trois
plans reels et sans censure. Plus de repartition au prorata, plus de
renormalisation — le noeud se simplifie.
L'enveloppe est retrogradee en repli, utilisee seulement si la courbe est
absente ou vieille de plus d'une heure, le champ `mode` disant laquelle a
servi. Elle garde un role de repere de vraisemblance mais n'ecrete PLUS la
prevision : etant minoree l'apres-midi, elle tronquerait a tort une prevision
correcte.
Piege corrige au passage : le nouveau champ `source` entrait en collision avec
l'objet `source` deja present dans la sortie et etait silencieusement ecrase.
Renomme en `mode`.
Suite portee a 35 scenarios (courbe fraiche lue telle quelle, courbe perimee
basculant en repli).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
Workflow "EVCS Solar Forecast V1" (07P8I349ugna9FH4), actif, cadence 15 min —
la frequence de rafraichissement de la prevision elle-meme, l'API precisant
qu'interroger plus souvent n'a aucun interet. 96 appels par jour pour un quota
de 300 par heure.
Rien n'est code en dur : la cle d'API, les plans et les coordonnees viennent
tous de Home Assistant. La cle vit dans un input_text en mode password, exclue
du recorder, et n'apparait ni dans le depot ni dans le JSON du workflow —
l'URL est assemblee a l'execution par BUILD_FORECAST_URL, qui refuse
explicitement de construire une URL incomplete plutot que de gaspiller le
quota sur un appel malforme.
BUILD_HA_CALLS_FORECAST ne publie rien en cas d'echec plutot que d'ecraser une
prevision valide par du vide.
Suite portee a 33 scenarios, dont le refus sur cle absente, sur plans mal
formes, sur kill-switch, et la preservation de la prevision precedente en cas
d'echec.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
5c — BALANCE ne repondait qu'a "combien jusqu'a ce que le solaire prenne le
relais". A 15 h la reponse est zero : exacte mais inutile, le deficit qui
approche etant celui de la nuit. Ajout de la prochaine traversee deficitaire
(heure de debut, energie, SOC a atteindre avant). Ce SOC n'est PAS ecrete a
100 % : au-dela, meme une batterie pleine ne passe pas, et le manque est
publie comme storage_shortfall_kwh — c'est le chiffre du dimensionnement.
5b — Workflow "EVCS Energy Profiles Daily V1" (N6UaB4ZozsbRPrFb), actif,
03:30 : lit /api/history/period sur 30 jours glissants et republie les quatre
CSV (conso p50 et p80, enveloppe de production, taux de censure).
CONSUMPTION_PROFILE devient DAILY_PROFILES et sait desormais decoder la
reponse brute de l'API en plus des series deja pretes.
Piege trouve : sans end_time, /api/history/period ne renvoie qu'UNE journee,
silencieusement. Mes premieres mesures "sur 3 jours" n'en couvraient qu'une.
Validation croisee : profils calcules depuis l'API REST (etats bruts, 11 j)
contre profils calcules depuis les statistiques long terme (28 j) — 0,20 kWh/h
d'ecart absolu moyen, par deux chemins de donnees independants.
BUILD_HA_CALLS_PROFILES refuse d'ecraser les profils en place si l'historique
ne couvre pas les 24 heures. Meme garantie de perimetre que le bilan.
Suite a 27 scenarios.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
Workflow n8n "EVCS Energy Balance V1" (id QoSfPeyGq35orF1K), actif, cycle de
5 min : snapshot HA -> CENSORSHIP et RESOURCE_ESTIMATE en parallele ->
PREPARE_BALANCE -> BALANCE -> BUILD_HA_CALLS -> appels de service HA.
MODE OMBRE garanti structurellement : BUILD_HA_CALLS n'ecrit que vers des
entites evcs_balance_* plus une trace logbook. La suite de tests echoue si une
ecriture sort de ce perimetre — verifie par mutation, l'injection d'un
turn_on sur switch.edf_general_ok_switch fait rougir la suite. Kill-switch
input_boolean.evcs_balance_enabled : a OFF, aucune ecriture du tout.
Package HA evcs_energy_balance.yaml : 18 helpers. Profils de consommation,
enveloppe de production et taux de censure amorces avec les valeurs calculees
sur 28 jours reels ; capacite utile posee a 15 kWh (7 modules actifs).
Outillage : gen-energy-balance-workflow.mjs, enregistrement dans
lib-node-map.mjs, suite cablee dans n8n-push.mjs (bloquante). Suite a 24
scenarios.
Premiere execution reelle : le bilan s'est declare indisponible faute
d'entrees, exactement comme prevu, au lieu d'inventer des valeurs. Le format
du snapshot (corps JSON dans `data`) et la lecture des profils CSV ont ete
corriges ensuite.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
Incident du 24/08 12:24-12:28 : bascule de profil vers midday_hc_or_solar
avec SOC 58 %. Plancher de demarrage = min(midday_soc_min 75, abondance P6
40) = 40 ; plancher de maintien = max(soc_stop_min 29, 75-15) = 60. Le
systeme avait donc le droit de DEMARRER ce qu'il n'avait pas le droit de
MAINTENIR : cycle limite a la periode de min_run (3 min) sur toute la bande
[40 %, 60 %], et ~2,6 kW de PV ecretes a chaque creux (PV 10,24 kW -> 7,64 kW
quand la borne s'arrete, ESS sans injection).
Deux volets indissociables dans BATTERY_CLOUD_LOCKS.js :
- effectiveSocHoldFloor = min(regle du profil, plancher de demarrage
effectif). Sans abondance, comportement inchange.
- l'abondance P6 se prouve au demarrage (batterie >= +20 A) mais se maintient
en charge (batterie >= 0) : sinon la charge du vehicule, qui detourne
precisement le surplus, detruit sa propre condition d'autorisation.
Golden 39 -> 40. Preuve par mutation sur midday-inversion-start-hold : code
d'avant -> stop / "Conditions de maintien perdues", apres -> step_up 19 A.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
Fix G provoquait un yoyo EDF de 2-4 min (coupure a SOC 21 en bypass min_on
contre rallumage a SOC 20 en bypass cooldown) : son garde `soc > gridSocOn`
ne protegeait que l'instant de l'engagement sur SOC bas, pas la phase de
remontee 20 -> 30. jsCode restaure byte-identique a la version pre-Fix-G.
Le fixture de test portait les fallbacks du code (22/35) au lieu des valeurs
de production lues via MCP (20/30), et le scenario de non-regression testait
SOC 18 %, le seul point que Fix G epargnait. Suite reecrite avec les
garde-fous manquants h-recovery-band-no-cut-21/-25. Mutation : Fix G
reapplique -> 4/7 echecs, retire -> 7/7.
Documentation du diagnostic des deux oscillateurs (yoyo EDF et oscillation
de la charge EVCS en plein soleil) dans MANUEL_COMPLET 11.8 et HANDOFF 25.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
Incident nuit 21-22/08 : la fenêtre HC nuit se ferme pendant que le véhicule
est encore en session active (pas encore flag "charge terminée"). L'EVCS
relâche correctement son override, mais émet un état transitoire générique
(stop_source_lost/idle_wait_source) qu'aucune règle de coupure immédiate du
workflow Grid Hysteresis (Fix C/E2) ne reconnaît. EDF restait alors maintenu
des heures par la boucle générique jusqu'au seuil statique gridSocOff,
plafonnant le MPPT Victron à ~100W et privant la maison de solaire.
Nouvelle règle générique (Compute Grid Hysteresis) basée sur evcsGridOverride
plutôt que sur une liste blanche de noms de surplus_state — couvre donc aussi
tout futur état non énuméré. Garde anti-glitch sur lecture HA invalide.
Nouvelle suite tests/golden-hysteresis/ (7 scénarios, première pour ce
workflow), câblée bloquante dans tools/n8n-push.mjs. Déployé et validé
(golden-hysteresis 7/7, golden EVCS 39/39 inchangé).
Écarte le diagnostic incomplet laissé par un autre agent dans HANDOFF.md
(edf_general_ok_off côté EVCS aurait créé un deuxième écrivain non coordonné
sur le même switch).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>