Commit Graph

129 Commits

Author SHA1 Message Date
Tallagrand Thierry
7a5ab7a616 sensor.evcs_reseau : verdict de raccordement conscient du contacteur (un 0 fige n'est pas une panne quand EDF est ouvert)
Incident du 26/09 : l'agent vocal a annonce le capteur reseau bloque a 07:24,
alors que le contacteur s'etait ouvert a la fin des heures creuses. Le verdict
ne juge l'age de la mesure que contacteur ferme ; ouvert, c'est non_raccorde.
Tests diagnostics 37 -> 48, trois mutations qui mordent.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011xd7aRDEChdShwsECohnDN
2026-09-26 11:51:03 +02:00
Tallagrand Thierry
dd83727900 Repere des modules = pack x 10 + rang (11 = pack 1 module 1, 21 = pack 2 module 1)
Colonne cellule.pack deduite du nom du fichier de releve ; Grafana et
sensor.evcs_cellules l'affichent. Historique renseigne depuis le 24/09.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011uJ47NxgfpGnuuMr3f2n7Z
2026-09-26 01:05:54 +02:00
Tallagrand Thierry
7942577967 Pack 1 (US5000) sous surveillance cellule : repli bat, essais code-barres, boot tolerant
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011uJ47NxgfpGnuuMr3f2n7Z
2026-09-26 00:57:42 +02:00
Tallagrand Thierry
08a1cee1b1 Releve du pack 1 (US5000) sur yd-5CG6110DG0 : service, regle udev, suffixe de fichier
Le cable du pack 1 est a puce Prolific, sans pilote sur DSM : lu par un
portable a noyau recent. --suffixe pack1 separe les CSV des deux lecteurs ;
evcs_cellules regarde 15 min (deux lecteurs non synchronises) et publie
modules_lus (9 attendus).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011uJ47NxgfpGnuuMr3f2n7Z
2026-09-26 00:41:47 +02:00
Tallagrand Thierry
07ee35bdfd Grafana : le suiveur reconnu dans le panneau des modes (mesure prefixee sensor.)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011uJ47NxgfpGnuuMr3f2n7Z
2026-09-25 16:58:13 +02:00
Tallagrand Thierry
e4c6af555e Grafana Le solaire : les quatre entrees du RS 450/200
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011uJ47NxgfpGnuuMr3f2n7Z
2026-09-25 16:28:35 +02:00
Tallagrand Thierry
ac70dcf1e1 Grafana : production du jour par chargeur ; suiveur V1 ajoute a l'export InfluxDB
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011uJ47NxgfpGnuuMr3f2n7Z
2026-09-25 15:50:21 +02:00
Tallagrand Thierry
c75d2ffcb8 sensor.evcs_bilan_nuit : le bilan de nuit de l'agent vient du code du rapport du matin
Incident 25/09 11:49 : l'agent sans source avait invente 0,56 kWh / zero
reseau / 35 % pour une nuit a 7,9 kWh dont 2,2 reseau. donneesNuit() extrait
de rapport-nuit.mjs (texte identique sur 5 nuits), publie pour l'agent.
Tests 37/37.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011uJ47NxgfpGnuuMr3f2n7Z
2026-09-25 12:31:35 +02:00
Tallagrand Thierry
beed8028ca Capteur de charge : origine explicite par libelle (incident 25/09, batterie publiee en solaire)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011uJ47NxgfpGnuuMr3f2n7Z
2026-09-25 12:05:04 +02:00
Tallagrand Thierry
30193a1d27 Capteurs production du jour et relais de charge pour l'agent vocal (G1/G9, G6/G7)
sensor.evcs_production_jour_kwh (somme des 3 yield_today, remises a zero
decalees gerees) et sensor.evcs_charge_solaire (relais de la decision du
controleur, pas un second arbitre). Tests 26/26 + mutations.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011uJ47NxgfpGnuuMr3f2n7Z
2026-09-25 01:18:35 +02:00
Tallagrand Thierry
83c790d9b3 Retrait des helpers evcs_cell_* remplaces par sensor.evcs_cellules
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011uJ47NxgfpGnuuMr3f2n7Z
2026-09-25 01:07:55 +02:00
Tallagrand Thierry
b9142aac54 Diagnostics PV et cellule calcules cote service pour l'agent vocal (G5/G13b)
La fiche OpenClaw basculait G5 de 7/7 a 1/7 sur un ajout sans rapport :
les deux jugements sortent du modele. sensor.evcs_pv_diagnostic (import
teste avant bridage) et sensor.evcs_cellules (perime => aucune valeur
visible), publies meme quand le cycle echoue. Tests 15/15 + mutations.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011uJ47NxgfpGnuuMr3f2n7Z
2026-09-25 00:55:17 +02:00
Tallagrand Thierry
d64b634a66 Détail cellule exposé en 3 helpers HA pour l'agent vocal OpenClaw
Les trames BMS cellule de HA sont mortes depuis le 15/09 ; le relevé série est la
source vivante. Le service publie evcs_cell_spread_max_mv, evcs_cell_weakest_module
et evcs_cell_releve_age_min à chaque cycle (publierCellulesHelpers). L'âge donne à
l'agent la discipline anti-valeur-figée (comme le gel GX). Vérifié en réel :
21 mV, âge 1 min, K220803C30160323. Package evcs_cellules.yaml (hors dépôt, HA).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
2026-09-25 00:07:28 +02:00
Tallagrand Thierry
41381fcdb9 Rapport de nuit envoye a 07:30 (total complet) + HANDOFF §76
Envoi decale 06:47 -> 07:30 : apres la fermeture de la fenetre HC (07:24)
l'import de la nuit est termine, donc le total est complet. A 06:47 le rapport
ratait l'import 06:47->07:24 meme apres le fix d'extrapolation (ec5f43e).
Proposition du proprietaire. HANDOFF §76 consigne le bug (extrapolation de la
derniere puissance sur la fenetre future), le fix et ce decalage.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
2026-09-24 15:46:37 +02:00
Tallagrand Thierry
ec5f43ecff rapport-nuit : l'import etait extrapole sur les heures futures de la fenetre
Signale par la session SPARK via les compteurs d'energie Victron : le rapport du
24/09 annoncait 4,2 kWh importes contre ~1,6 mesure. Cause reelle (verifiee en
base) : le rapport tourne a 06:47 mais sa fenetre va jusqu'a 10:00 ; l'ancienne
methode (grille generate_series 1 min + derniere valeur connue + sum/60000)
reportait la derniere puissance connue sur les ~3 h futures -> import fantome.
Ce n'est PAS la cadence d'echantillonnage (donnees eparses, 130 pts/961 min) et
les compteurs d'energie ne sont pas dans la table mesure (seul grid_power_l1).

Fix : integration ponderee par l'intervalle reel entre points (cap 300 s, jamais
d'extrapolation apres le dernier echantillon) et fenetre plafonnee a now().
Applique aux 4 grandeurs integrees (importe/injecte/voiture/batterie_chargee).
Verifie : 1,60 kWh sur fenetre complete (= compteurs), 1,19 en simulation 06:47.
Tous les rapports depuis le 08/09 surestimaient ces kWh ; le reste (SOC,
fermetures, vehicule, injection) etait juste.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
2026-09-24 15:30:11 +02:00
Tallagrand Thierry
ca90ce1e28 Releve des cellules sur le Synology .17 + garde anti-blocage
Le releve tournait sur le PC portable (deploy/releve-cellules/lancer.sh) : ferme,
il ne releve plus, et le 20/09 son @reboot a refuse de relancer sur un faux
positif du garde anti-doublon -> 4 jours de trou dans la table cellule, Grafana
"No data". Le portable n'a pas vocation a rester allume.

Deplacement vers le Synology .17 (ARCHIVE3, DS920+), toujours allume :
- compose.yaml : conteneur node:20 en uid 1026:100 (le montage NFS peut ecraser
  root ; le dossier CSV est g+w pour users), device /dev/ttyUSB0 mappe, depot
  monte en /depot. Ecrit les CSV comme avant ; le service d'historisation du .22
  les ingere sans changement. restart:unless-stopped remplace la boucle lancer.sh.
- charger-pilotes.sh : DSM embarque usbserial.ko + ftdi_sio.ko mais ne les charge
  pas d'office. Script root (Planificateur DSM au boot) qui insmod les deux et
  ouvre les droits de /dev/ttyUSB0.
- README.md : deploiement, bascule depuis le portable, verification.

Garde anti-blocage dans pylontech-console.mjs (--suivi) : lireJusqua resout au
timeout au lieu de rejeter, donc un port fige renvoie du vide en boucle sans
jamais crasher -- exactement le hang du 20/09. Un controle du mtime du CSV force
process.exit(1) apres 3x le pas sans ecriture, pour que le superviseur (conteneur
ou lancer.sh) rouvre le port.

Menage : modified/*.bak-* (rollbacks locaux) ignores comme prepush-* ; ajout des
relevés de mesure batterie des sessions 16-20/09.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
2026-09-24 12:24:06 +02:00
Tallagrand Thierry
39a4444fec Plafond de charge pv_boost 180 -> 250 A (parc assaini, BMS autorise 250)
Le 180 A venait de nous (monte 130->150->180 le 13/09, §64), pas du BMS qui
autorise 250. Il bridait reellement : PV 10,6 kW, excedent ~187 A que la
batterie prendrait, plafonnee a 180. Parc sain (cellules pack 2 a 3-6 mV) : on
prend toute la marge, direct a 250 sur decision du proprietaire.
golden-acm 20/20 (2 attendus 180->250), mutation : retour 180 -> 2 echecs.
patch rejouable tools/patch-20260920b-boost-250a.mjs.
⚠️ Surveillance pack 2, surtout module rang 5 (K220803C30160323, le plus ancien).
Pack 1 (US5000) hors surveillance continue (2e cable en commande).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
2026-09-20 14:01:16 +02:00
Tallagrand Thierry
7b2e8e74d9 Rec 2 : top-off ACM 52,4 -> 52,8 V sur le parc assaini
Le 52,4 V avait ete pose le 06/09 pour menager la cellule 12 faible du pack
ANCIEN (§57). Ce pack est sorti. Cellules du pack 2 a 3-6 mV, la plus haute a
3356 mV, loin des 3550 mV ou le BMS reduit le courant. On releve le top-off
pour atteindre une charge plus pleine et RECALIBRER la jauge SOC Pylontech (qui
derive tant qu'on n'atteint jamais 100 %). 52,8 V = 3,52 V/cellule, sous les
53,2 V autorises par le BMS.

⚠️ Cellules du pack 1 (US5000) pas encore sous surveillance continue (2e cable
en commande). Proprietaire a autorise explicitement malgre le caveat.

patch rejouable tools/patch-20260920-topoff-52v8.mjs. golden-acm 20/20, attendu
acm-jour-topoff mis a jour (52,4->52,8), mutation : retour a 52,4 -> 1 echec.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
2026-09-20 13:47:16 +02:00
Tallagrand Thierry
dff6809560 Afficher anomalie= dans la ligne de resume du cycle d'historisation
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
2026-09-19 18:38:09 +02:00
Tallagrand Thierry
2d2ced54a1 Detection anomalie 'branchee mais ne charge pas' (je detecte, SPARK envoie)
Grief du proprietaire du 19/09 : JEEP branchee, du soleil, borne figee apres un
swap rapide -> rien qui charge, et il ne l'a su qu'en regardant. Le service
d'historisation detecte desormais l'episode et le SIGNALE dans un helper ;
la session OpenClaw lira ce helper et enverra l'alerte WhatsApp (son cote).

Critere, robuste par la censure sans injection : batterie pleine => MPPT bride
=> PV ~ conso => excedent ~ 0 => PAS d'alerte. Un excedent POSITIF qui persiste
(> 500 W) avec vehicule branche + borne < 300 W + etat controleur bloquant,
tenu > 10 min => il manque un preneur a de l'energie gratuite => signalement.
Un seul par episode (dedup sur son debut), helper efface a la resolution.

- helper input_text.evcs_alerte_charge (max 255, sans initial:), reload fait.
- detecterAnomalieCharge() + ecrireHelperTexte(), appele dans cycle().
- etat d'episode en processus (repart de null au redemarrage, se re-arme en 10
  min sur une anomalie reelle).
⚠️ SEUILS A CALIBRER sur l'historique avant d'etre figes. Le helper reste
INERTE tant que SPARK n'a pas cable l'envoi : deployer maintenant ne fait rien
partir.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
2026-09-19 18:35:38 +02:00
Tallagrand Thierry
5db8291bc7 La colonne adresse etait posee dans la mauvaise branche du releve
Le remplacement du commit precedent avait atterri sur l'en-tete de
--historique-distant au lieu de celui de --suivi : le nouveau fichier de suivi
sortait sans la colonne, et le rang restait NULL en base. Corrige, et retire de
la branche historique ou il n'avait rien a faire.

Trouve aussi en relancant : le releve est SUPERVISE par
deploy/releve-cellules/lancer.sh (@reboot, boucle de relance a 60 s, garde
anti-doublon). Ne jamais le relancer a la main — tuer le processus node suffit,
le superviseur repart seul avec le code a jour ; un lancement manuel cree un
doublon sur le port serie et entrelace les lectures.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
2026-09-18 12:31:51 +02:00
Tallagrand Thierry
8c35f8c2ca Le rang du module dans sa chaine accompagne desormais chaque releve de cellules
Le proprietaire demandait si le rang dans le pack etait accessible ou si seul
le code-barres l'etait. Il l'etait depuis le debut : l'outil de releve resout
adresse <-> code-barres au demarrage mais ne l'ecrivait pas. Desormais :
- pylontech-console.mjs --suivi ecrit une colonne 'adresse' (vide en mono-module,
  jamais devinee) ;
- historise-evcs.mjs l'ingere par son NOM dans cellule.rang, enregistre PAR
  RELEVE et non dans une table figee — un recablage du LVHUB renumerote, et
  l'historique de chaque ligne doit garder le rang vrai a son instant ;
- Grafana : colonne 'Rang' dans le tableau de sante, et la liste deroulante
  des modules affiche 'rang - code-barres' quand le rang est connu.
75/75 requetes valides.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
2026-09-18 12:12:12 +02:00
Tallagrand Thierry
463f1b1b06 Les cellules disent desormais si le module chargeait
Le proprietaire veut « dans Grafana le detail de chaque cellule pendant la
charge ». Le detail existait deja ; ce qui manquait etait le « pendant la
charge » — rien ne disait QUAND le module chargeait, et un ecart entre cellules
ne veut rien dire hors de son courant : le 05/09 la cellule meneuse etait a
3555 mV sous 50 A et a 3496 mV sous 30 A, meme module, meme tension de parc.

Le releve console porte le courant depuis le 17/09, mais l ingestion ecrivait
`null` : elle ne lisait que les quinze tensions. Elle repere maintenant la
colonne `courant_mA` PAR SON NOM — les US5000 et les US2000C n emettent pas les
memes colonnes, et une position ferait lire la mauvaise grandeur des qu on
deplace le cable d un pack a l autre. Absente des anciens fichiers, donc les
lignes deja versees gardent leur courant inconnu.

Deux panneaux au tableau « Les batteries ».

« Sante des modules — tous, d un coup d oeil » : le resume qu on lit en premier,
tous modules ensemble, la ou les autres panneaux demandent de choisir un module
d avance. Ecart maintenant, ecart maximum sur la periode, cellule la plus haute
et la plus basse, courant au moment du releve, date du dernier releve. Releve au
deploiement : cinq modules vivants, ecarts de 1 a 3 mV — le parc restant est
sain, les trois modules atteints sont sortis le 12/09.

« Le module chargeait-il ? » : le courant du MODULE, lu dans la table des
cellules et non dans celle du parc, ce qui permet de voir qu un module se
charge moins que ses voisins.

Verifie contre la base et pas seulement execute : 75/75 requetes valides ne
prouve que l execution, donc les deux nouvelles ont ete rejouees avec la vraie
fenetre et rendent bien les grandeurs voulues.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
2026-09-18 02:56:03 +02:00
Tallagrand Thierry
1541ccf7b4 La prevision entre dans « La journee » et sur le telephone
Suite du correctif de l onglet Home Assistant. « La journee » avait le meme
angle mort : cadre sur le jour civil, il s arretait a l heure en cours.

Fenetre portee a la journee ENTIERE (dashboard() gagne un parametre `jusqu`),
serie « Encore attendu » en gris translucide a la suite des barres mesurees,
et colonne « Reste attendu » dans le bandeau du haut, a cote de « Solaire
produit ».

Sur le telephone, aucun panneau ajoute — un panneau de plus y est un ecran de
plus a faire defiler. « Soleil restant » rejoint le bandeau Maintenant, a cote
de Excedent ; « Soleil demain » rejoint La nuit qui vient, puisque c est lui
qui decide jusqu ou la batterie peut descendre.

Trois pieges, tous dans la meme direction. La mesure ne doit pas suivre la
fenetre dans le futur : ENERGIE_SQL construisait son axe entre les deux macros
puis reportait la derniere valeur connue, ce qui aurait rempli les heures a
venir avec la puissance de l instant et gonfle l energie du jour — sa borne
haute est desormais least($__timeTo(), now()). FULL OUTER JOIN et non LEFT :
une periode a venir n a aucune ligne de mesure. Et borne haute stricte, sans
quoi une barre « 18/09 00 h » apparaissait dans La journee.

L heure EN COURS n a volontairement pas de barre de prevision : elle est deja
mesuree pour ses minutes ecoulees.

73/73 requetes valides — mais ce controle prouve l execution, pas la grandeur.
Les deux requetes de La journee ont donc ete rejouees a la main avec la vraie
fenetre : 24 lignes, mesures jusqu a 02 h, prevision de 03 h a 23 h, somme des
barres 36,95 kWh contre 37,0 annonces par le bandeau. C est ce recoupement qui
a fait apparaitre le troisieme piege.

Corrige au passage la note du 08/09 sur l acces a l API Grafana : les
apostrophes du .env sont SIMPLES et non doubles, verifie a l octet.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
2026-09-17 02:37:43 +02:00
Tallagrand Thierry
a6baad54dc Le chien de garde arretait la charge qu il devait proteger
Nuit du 16 au 17/09 : neuf arrets de la charge nuit de la VW, de 30 s a 3 min,
sans que le controleur EVCS ait bouge — sa table de decision ne porte que deux
lignes sur toute la periode. Le journal de bord de Home Assistant montre le
switch de charge passant a off SANS contexte de service, donc commande depuis
le GX, puis le controleur qui reessaie au cycle suivant.

Correlation un pour un avec les actions du chien de garde, trois secondes
avant chacune, et aucune coupure sans action. Son message porte la signature :
« CONTROLEUR MUET — derniere execution il y a NaNs ».

Cause : n8n inscrit une execution AVANT de la demarrer, avec status "new" et
startedAt null. Date.parse(null) vaut NaN, et le test !(ageSec <= 600) — forme
choisie pour echouer du cote sur — declare alors mort le controleur qui vient
precisement de demarrer un cycle. Le signal de vie retourne contre lui-meme.

La fenetre dure moins d une seconde : 3 sondages sur 968 y tombent, 0,3 %. Ce
qui a change le 16/09 n est pas le code mais la PHASE du chien de garde, qui
derive d environ vingt secondes par jour et est venue se poser exactement sur
les instants de declenchement du controleur (:00 et :30) — 34 evenements ce
jour-la contre 1 a 2 les jours precedents. Le defaut dormait depuis le 01/09.

Correction a la session precedente : la nuit du 15 au 16, presentee comme
irreprochable, portait deja trois coupures dont une de trois minutes. Ce que
j avais verifie — consigne a 6 A inchangee pendant 153 min — restait exact et
ne prouvait rien : la consigne ne bouge pas quand la borne s arrete, seule la
puissance tombe.

Second defaut, latent et plus grave : CFG.idleSetpointW valait 50 W quand le
controleur est passe a 700 W le 06/09, donc dangerousSetpoint etait vrai en
permanence et chaque fausse alerte ecrasait aussi la consigne reseau a 50 W.
Sans consequence cette nuit — EDF etait ouvert — mais pendant une nuit ou le
reseau porte la maison, c est le defaut du 04/09 reintroduit.

Trois correctifs : un horodatage manquant n est plus une panne (on prend le
plus recent startedAt exploitable, repli cote sur si aucun) ; valeur de repos
portee a 700 W avec le commentaire qui dit ou vit l autre exemplaire ; et une
panne doit DURER — deux lectures consecutives avant d agir, meme doctrine que
la tolerance batterie et le relachement du contacteur.

Verification par REJEU et non par absence de symptome : le redemarrage a remis
la phase a :07, donc une nuit calme ne prouverait rien. Un serveur local
rejouant la charge JSON exacte capturee a 02:07:01 donne, code d avant,
« MUET — il y a NaNs » et les deux ecritures ; code corrige, « controleur
vivant (execution il y a 36s) » et aucune ecriture. Le filet mord toujours sur
une panne soutenue : 1/2 puis alerte et StartStop = 0 au second cycle.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
2026-09-17 02:14:52 +02:00
Tallagrand Thierry
49a6ee88db La prevision affichee cesse d etre de l histoire
Le graphe « production prevue et realisee heure par heure » du troisieme
onglet du bilan energetique ne montrait que du passe : sa courbe « prevue »
etait la prevision publiee le matin de chaque jour ECOULE, et la fenetre
s arretait a l heure en cours. C est un instrument de mesure du biais, pas
une prevision.

Deux courbes desormais, et elles n ont ni la meme provenance ni le meme
usage. Pour un jour ecoule, ce qui avait ete annonce LE MATIN MEME reste la
seule reference honnete : une prevision revisee a 18 h connait deja la
journee, la comparer au reel ne mesure plus rien. Pour les heures a venir,
c est la DERNIERE publication qui fait foi — aujourd hui jusqu au soir,
demain en entier. Les deux se touchent sur l heure en cours au lieu de
laisser un trou, et la seconde est tracee en pointilles.

Au-dela de l heure en cours, « reel » et « bridage » valent NULL et non
zero : un zero dessinerait une chute de production qui n a pas eu lieu.

Defaut trouve en chemin : l ecart moyen comptait l heure EN COURS, mesuree
sur ses seules minutes ecoulees. A 14h05 son reel vaut cinq minutes de
production contre une prevision d heure pleine, soit -92 % qui n existent
pas. La colonne `clos` l exclut. Et la serie mesuree s arrete desormais a
la minute courante et non au debut de l heure, si bien que l heure en cours
est reellement tracee au lieu de valoir zero.

Le partage aujourd hui / demain se fait en SQL, dans le fuseau deja utilise
par le reste de la requete : le conteneur repond en UTC a `date`, il ne
doit pas servir d arbitre.

Fenetre de la carte portee a hier / aujourd hui / demain (graph_span 3d,
span end day offset +1d) : sans cela la prevision, qui est justement ce
qu on veut voir, tombe hors du cadre. Verifie dans le paquet installe :
`span.offset` exige bien un signe, et l offset decale les deux bornes.

Verification en production : 47 points de prevision publies, du 17/09 01 h
au 18/09 23 h, 33,3 kWh encore attendus aujourd hui et 34,5 annonces pour
demain.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
2026-09-17 01:54:10 +02:00
Tallagrand Thierry
3587f236da Le courant par module entre dans les CSV de releve
La colonne courant_mA etait vide depuis la mise en service : le mode --modules
interroge chaque adresse avec soh <n>, qui donne les quinze tensions mais AUCUN
courant. La source juste est pwr, qui rend courant, tension et SOC pour TOUS les
modules en un seul appel — une commande serie par cycle au lieu d'une par
module.

⚠️ LE TABLEAU pwr N'A PAS LES MEMES COLONNES SELON LA FAMILLE DE MODULES.
Mesure du 16/09 : les US5000 (firmware B69.26) intercalent Tlow.Id, Thigh.Id,
Vlow.Id et Vhigh.Id que les US2000C (B69.13) n'ont pas. Un parseur a index figes
lit donc n'importe quoi des qu'on change de pack — c'est la meme famille de
piege que le trou de 44 h. Les colonnes sont resolues PAR LEUR NOM dans
l'en-tete. Les trois utiles (Volt, Curr, Coulomb) precedent Time, dont la valeur
contient une espace, donc le decoupage positionnel reste valable.

Echec de pwr non bloquant : on ecrit la ligne sans courant plutot que de perdre
les tensions, qui sont l'essentiel du releve.

Verifie sur cinq modules, trois cycles : courant et SOC par module dans le
journal et dans le CSV. Pack 2 a 13:18 — 9,5 + 9,4 + 9,0 + 9,2 + 9,1 = 46,2 A,
SOC 82/79/83/81/87 %.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
2026-09-16 13:19:02 +02:00
Tallagrand Thierry
54b0dd14b8 Guichet d'ordres : Airtria demande, ce service decide et applique
Valide separement par le proprietaire le 16/09, comme la session OpenClaw et moi
l'avions demande : c'est la premiere fois qu'une reponse WhatsApp touche au
PILOTAGE et non a une etiquette consultative.

⚠️ LA LISTE BLANCHE EST DANS LE SERVICE, JAMAIS CHEZ L'AGENT — moindre
privilege : il demande, il ne decide pas de ce qui est demandable. Six ordres
admis : p12, p9, hc_nuit, strategie, vehicule, plafond_edf (borne 6-28).
Les options d'un input_select sont lues EN DIRECT sur l'entite, jamais codees en
dur : ZERO sera consomme sans modification quand la moto reviendra.

⚠️ HORS LISTE DEFINITIVEMENT : le contacteur EDF, les limites DVCC, la consigne
de puissance reseau, les planchers SOC de securite — exactement ceux qui peuvent
vider la batterie sous son plancher, la gaver sur le reseau, ou evincer le
solaire une journee entiere.

Garde supplementaire : un ordre de pilotage exige un canal HUMAIN. Une regle qui
deduit « il faudrait activer P12 » n'a rien a faire ici — c'est une decision,
pas une observation.

Interrupteur DISTINCT de celui du concierge (input_boolean.airtria_ordres_enabled,
a OFF), pour que couper le pilotage ne coupe pas l'etiquetage des vehicules.
Il gate l'ECRITURE, pas la lecture : a OFF le service journalise ce qu'il aurait
fait, ce qui permet d'eprouver la chaine avant qu'elle ne compte.

NEUF ESSAIS, tous verifies. Refuses : ordre edf, dvcc, consigne_reseau,
soc_stop_min (hors liste) · source regle-puissance (canal non humain) ·
plafond 45 A (hors bornes) · strategie « turbo » et vehicule « MEGANE » (absents
des options, listees en direct). Applique : plafond_edf 28 -> 20, journalise avec
l'etat anterieur ; rejeu du MEME confirmed_at -> ordre=0, rien ; nouveau
confirmed_at -> restauration a 28. P12 intact tout du long.

⚠️ DEFAUT TROUVE EN EPROUVANT CECI : le mode --once n'appelait pas
assurerConnexion(). Une base absente au demarrage lui donnait client = null,
donc un TypeError au lieu d'un message clair. Trouve sur un simple mauvais
numero de port. Corrige.

Carte « Agents & surveillance » completee : le guichet et son dernier ordre, a
cote du concierge et de l'etat du service.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
2026-09-16 09:20:37 +02:00
Tallagrand Thierry
0fe24ff950 Battement de coeur du service — et le test a trouve que le service MOURAIT dans la panne qu'il doit signaler
Valide par le proprietaire le 16/09. Le service publie desormais
sensor.evcs_historisation_heartbeat a chaque cycle : etat = horodatage ISO 8601
UTC, attributs statut (ok|degrade), base_joignable, cycles_en_echec,
dernier_echec. Forme figee avec la session OpenClaw pour que les deux battements
du systeme soient identiques.

POURQUOI UN CAPTEUR DEDIE. Mesure du 16/09 : Home Assistant ne materialise pas
une ecriture identique, et last_reported — le champ introduit en 2024 pour
marquer chaque remontee d'etat — est rigoureusement EGAL a last_changed. Aucun
champ de l'API ne distingue donc un ecrivain mort d'un ecrivain qui republie la
meme valeur. Sur une installation saine, trois entites sur cinq paraissaient
figees. La vivacite se lit donc sur ce capteur seul, dont l'etat est un
horodatage : il change forcement a chaque ecriture.

L'appel est HORS du try/catch du cycle, dans les deux branches. C'est tout le
correctif : base morte, le battement part quand meme en portant degrade et la
cause. Avant, un cycle en echec n'ecrivait que sur console.error, et l'incident
n'etait journalise qu'au RETOUR a la normale — dans PostgreSQL, donc jamais
quand c'est PostgreSQL qui est tombe.

⚠️ CE QUE LE TEST A TROUVE, ET QUI RENDAIT LE BATTEMENT INUTILE. Eprouve sur une
base JETABLE derriere un relais TCP coupable a volonte (pas sur la production :
deux instances sur la meme base double-compteraient l'energie des sessions, le
UPDATE energie_kwh = energie_kwh + ... n'est pas idempotent). Premier essai : le
service a CRASHE a la coupure. Le client pg emet un evenement 'error' sur le
socket ; sans ecouteur, c'est une exception non capturee qui ne passe PAS par le
try/catch du cycle — il n'attend qu'une promesse — et qui tue le processus. Le
service mourait donc exactement dans la panne que le battement existe pour
signaler.

Trois correctifs qui en decoulent : un ecouteur 'error' qui marque la connexion
morte au lieu de faire tomber le processus ; une reconnexion, un client pg
n'etant pas reutilisable apres erreur (sans elle le service resterait vivant mais
definitivement muet) ; et une connexion initiale non fatale, pour qu'une base
absente au demarrage ne tue pas le service — un service mort ne signale rien.

Sequence complete verifiee : base vivante -> ok ; coupure -> service VIVANT,
degrade, base_joignable false, cycles_en_echec 2, cause « connect ECONNREFUSED » ;
retour -> reconnexion automatique, ok, et l'episode journalise avec sa duree.

Le message de reprise disait « Home Assistant injoignable » quelle que soit la
cause ; il nomme desormais ce qui a reellement echoue.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
2026-09-16 08:58:18 +02:00
Tallagrand Thierry
d3ef261e78 La reponse du proprietaire pilote le selecteur, et deux ecrivains cessent de se battre
Corriger le selecteur a la main ne corrige rien : « demain si je dis JEEP il va
rester sur VW, donc la solution c'est de le piloter quand je reponds ».

Le selecteur n'est pas qu'une etiquette. Le CONTROLEUR n8n le lit pour en
deduire l'heure de depart (VW 08:50, JEEP 06:30), donc minutesUntilDeparture,
donc batteryRecoveryUrgent — qui coupe P12 et ferme EDF trente minutes avant le
depart suppose. Mesure de cette nuit : selecteur reste sur JEEP alors que la VW
etait branchee et confirmee par WhatsApp a 19:56 => EDF se serait ferme a 06:00
pour rien, la voiture etant pleine depuis 05:30 et la batterie a 51 %.

Deux correctifs, indissociables.

1. piloterSelecteurVehicule() : une reponse du proprietaire ecrit
   input_select.victron_evcs_vehicle. UNE SEULE FOIS par reponse — la fonction
   appelante est idempotente par confirmed_at — donc le dernier mot reste a
   l'humain quel que soit le canal. Seulement pour les labels qui SONT des
   options du selecteur : MEGANE, INVITE et ZERO n'y figurent pas, et l'heure de
   depart n'a aucun sens pour un vehicule de passage.

2. ecrireSession() n'ecrase plus une session confirmee. Cette ligne reecrivait
   le vehicule depuis le selecteur a CHAQUE CYCLE d'une session ouverte, pendant
   que appliquerEtiquettesEnAttente remettait l'etiquette juste apres : deux
   ecrivains sur la meme colonne toutes les 60 s, et une ligne de journal a
   chaque passe — une soixantaine le 15/09. Le drapeau vehicule_sur dit « un
   humain a confirme » : quand il est vrai, le selecteur n'a plus voix au
   chapitre.

Preuve du diagnostic, par l'experience : le dernier « Etiquette VW posee » est a
01:40:58, le selecteur passe a VW a 01:41:59, et plus une seule ligne ensuite.
La bagarre s'arrete a la seconde ou les deux ecrivains s'accordent.

Preuve du correctif 2, en lecture seule sur les lignes reelles : sur les deux
sessions VW, l'expression d'avant ecrirait JEEP, la nouvelle garde VW ; sur les
sessions JEEP les deux concordent. Et sur un cas synthetique non confirme, la
nouvelle expression suit bien le selecteur — la garde est ciblee.

DEFAUT TROUVE EN RELISANT LA SORTIE DU PREMIER ESSAI A BLANC : sans garde, un
--dry-run aurait pilote le selecteur pour de vrai. Seule l'egalite fortuite
actuel === label avait evite l'ecriture. Garde posee, puis eprouvee en mettant
le selecteur sur JEEP : la sortie annonce « [blanc] piloterait JEEP -> VW » et
le selecteur est reste JEEP.

MANUEL : capacite des vehicules. La VW annonce 10 kWh de plaque pour 42 km ;
la reference MESUREE au compteur de la borne est 7,70 kWh pour une charge menee
a son terme (15/09 01:25-03:41). C'est ce chiffre qui dimensionne une nuit, pas
la plaque. La JEEP n'est pas mesuree de la meme facon : ne pas lui appliquer
les 7,70 kWh.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
2026-09-16 01:47:14 +02:00
Tallagrand Thierry
b6010b9342 Prevision contre reel : la serie que Home Assistant ne peut pas produire
Le proprietaire veut comparer prevision et production heure par heure sur une
semaine, dans son tableau de bilan. Les courbes de prevision vivent dans des
input_text ECRASES a chaque publication : HA n en garde aucun historique. La
base, elle, a treize jours de previsions horaires et la production mesuree.

Le service pousse donc la serie dans un capteur cree par l API HA, dont les
attributs portent les tableaux — un input_text plafonne a 255 caracteres ne
tiendrait pas 168 points.

⚠️ Premiere ecriture de ce service vers Home Assistant, qui a toujours ete
lecteur. Perimetre minuscule et delibere : un capteur, son propre espace de
noms, aucun actionneur.

⚠️ Et la troisieme serie n est pas decorative. Une heure BRIDEE n est pas
comparable : production sous la prevision peut vouloir dire mauvaise prevision
OU batterie pleine. Les mesures le montrent — le 13/09 a 15 h, prevu 5,32 et
realise 1,82 avec 100 % de bridage, l ecart n est pas meteorologique ; le 15/09
a 13 h, prevu 3,92 et realise 7,12 sans aucun bridage, la prevision SOUS-estime
de 82 %. Sans la bande, la courbe ferait accuser la meteo a tort.

L etat du capteur porte l ecart moyen sur les seules heures comparables — non
bridees — qui est le seul chiffre qui juge vraiment la prevision.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
2026-09-15 18:12:53 +02:00
Tallagrand Thierry
b5ac62ba1e Le proprietaire est un canal de confirmation, pas seulement WhatsApp
Il vient de me dire directement quel vehicule est branche. C est une
confirmation humaine au meme titre qu une reponse WhatsApp, mais le code ne
reconnaissait que ce canal-la et aurait marque sa parole « non confirmee ».

Les canaux humains sont desormais enumeres explicitement — whatsapp et
proprietaire — plutot que teste contre une seule valeur. Enumeres, et non
inverses : un canal inconnu ne doit pas valoir confirmation par defaut.
`regle-puissance` n y est pas et n y sera jamais, c est une deduction.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
2026-09-14 21:41:40 +02:00
Tallagrand Thierry
b4b3eece84 Une migration unique qui se rejoue n est pas unique
Le bloc qui inverse la semantique de vehicule_sur n etait pas garde : a chaque
redemarrage il remettait les lignes anterieures a faux puis les six arbitrees a
vrai. Le resultat restait juste — l operation est idempotente en sortie — mais
elle ecrivait une ligne de journal trompeuse a chaque fois. Quatre en une
journee, qui seraient apparues en annotation sur tous les tableaux Grafana comme
autant de faux evenements.

Garde sur la trace elle-meme : si la ligne de journal existe, c est fait.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
2026-09-14 21:16:59 +02:00
Tallagrand Thierry
d31878c66a Le concierge etiquette le branchement, plus la session
Il demandait « quel vehicule ? » a l ouverture d une session de charge. Trop
tard, et ca s est vu ce soir : a 19:55 la voiture est branchee, le selecteur
perime depuis six jours, et aucune question ne peut partir parce qu aucune
session n existe — la borne ne tire rien, il fait nuit. La premiere session de
la nuit serait nee etiquetee VW sans que personne ne soit consulte.

On etiquette desormais le BRANCHEMENT. C est d ailleurs l invariant du projet —
un cable, un vehicule — et ca rend la question possible des l instant ou on sait
qu il y a une voiture.

Deux temps. Le lecteur accepte une clef `branchement` en plus des `sessions`, et
memorise l etiquette dans une table dediee ; une passe differee, a chaque cycle,
la pose sur les sessions du branchement AU FUR ET A MESURE qu elles s ouvrent,
sans nouvelle question. Bornee par le debranchement suivant, avec les deux
secondes de tolerance du 09/09 — une session s ouvre jusqu a 62 ms avant que sa
transition de branchement soit journalisee.

L ancien contrat reste accepte : une etiquette portant des sessions fonctionne
comme avant.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
2026-09-14 21:14:38 +02:00
Tallagrand Thierry
0d597e7efc Protocole pour comprendre pourquoi le Cerbo ne voit qu un pack sur deux
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
2026-09-14 20:16:13 +02:00
Tallagrand Thierry
60165e139b Calibration des regles d anomalie : trois tiennent, une ne tient pas
L oscillation rapide se calibre sans ambiguite : sur le contacteur reseau, le
plus grand ecart pathologique vaut 193 s et le plus petit ecart normal 857 s,
facteur 4,4 sans aucune valeur entre les deux. Quatre bascules en dix minutes
isole exactement la salve du 12/09 et reste muet sur dix entites pendant dix
jours.

Piege trouve en calibrant : les plus petits ecarts normaux de plusieurs entites
valent 242 a 320 s, c est-a-dire la cadence des workflows. Ce ne sont pas des
oscillations mais deux executions consecutives qui changent d avis — toute
regle a deux bascules en cinq minutes se declenche sur le fonctionnement normal.

En revanche la regle des sessions reseau repetees NE SE CALIBRE PAS : les ecarts
entre fermetures forment un continuum de 4 minutes a 24 heures, sans
discontinuite. Or c est la pathologie la plus couteuse des deux. Je ne pose pas
de seuil dessus : elle demande une formulation metier et plus d historique, et
la bacler serait refaire l erreur que ce projet a payee six fois.

La regle de la mesure figee, elle, se valide sur un incident reel : le 05/09 la
tension et le courant batterie se sont tus 27 minutes pendant que le SOC, issu
du meme flux, publiait toutes les deux minutes. Le discriminant est relatif, pas
absolu — un silence long est normal pour une grandeur intermittente.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
2026-09-14 03:22:18 +02:00
Tallagrand Thierry
b9d79ed22a L auteur des transitions etait lisible depuis le debut, on cherchait le mauvais champ
auteurDeLaTransition filtrait sur x.context_name. Ce champ n existe pas dans le
journal de bord de Home Assistant : la fonction rendait null a tous les coups et
les 416 transitions journalisees portaient un auteur vide. Personne ne s en
etait apercu parce qu un auteur absent ressemble a un auteur inconnaissable.

Le contexte etait la, sous d autres noms, avec trois signatures distinctes
relevees sur des transitions dont je connaissais l auteur : une ligne voisine
script/automation qui se nomme ; un service exterieur dont la rafale se CLOT par
une ligne de narration portant le nom du workflow ET sa raison ; ou une simple
derivation depuis un autre capteur — qui n est pas un auteur et ne doit pas etre
annoncee comme tel.

On balaie vers l AVANT pour trouver la narration : un workflow ecrit ses helpers
puis se journalise, donc vers l arriere on ramasserait celle du precedent.
Verifie sur la seconde ou l Auto Charge Manager et le Water Heater Advisor
ecrivent ensemble — chaque helper revient a son propre workflow, 3 sur 3.

Benefice non cherche : le declencheur porte desormais la raison que le workflow
a lui-meme publiee. C est ce que « expliquer les decisions » reclamait, et
c etait deja dans le journal.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
2026-09-14 03:03:56 +02:00
Tallagrand Thierry
9ccbcc0619 Une clef de session ecrite deux fois n est pas deux sessions
Airtria envoie la clef telle que PostgreSQL l affiche — 2026-09-12
11:55:54.493+02 — et la base me la rend en ISO. Meme instant, caracteres
differents : mon Set les comptait deux fois, et le journal annoncait « 2
sessions, dont 1 ajoutee par le branchement » la ou le branchement n en
contient qu une.

L UPDATE resistait, les deux formes se transtypant en timestamptz. Ce qui ne
resistait pas, c est le tableau sessions du detail, qui portait le doublon —
et c est precisement lui que le controle de contradiction interroge sur les
etiquettes suivantes.

Trouve par le journal du service en essai a blanc, trois minutes avant la
bascule du kill-switch. Mon harnais de verification ne pouvait pas le voir :
il comptait les lignes SQL, pas les elements du Set.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
2026-09-14 02:21:05 +02:00
Tallagrand Thierry
d8ef69b584 vehicule_sur cesse de mentir : le drapeau dit desormais qu un humain a confirme
Les trois pieces soudees, parce qu aucune ne tient seule. Le defaut de la
colonne passe a faux ; plus rien dans le chemin d ecriture ordinaire ne peut le
mettre a vrai ; le libelle Grafana « selecteur change » devient « a confirmer »,
et le compteur « Etiquette douteuse » devient « A confirmer ».

L ancienne semantique — « le selecteur n a pas bouge pendant la session » — ne
prouvait rien : le selecteur est reste sur VW du 07/09 au 13/09 et les onze
sessions fausses portaient toutes true. La mesure d hier a acheve de la
disqualifier : sur douze branchements, le selecteur n a ete regle au bon moment
qu une seule fois.

Rattrapage des lignes anterieures a faux, sauf les six que le proprietaire a
arbitrees lui-meme le 13/09 — une vraie confirmation humaine, seulement donnee
de vive voix, qu il serait absurde de jeter. Une ligne de journal l explique.

Rien n est deploye : le service tourne encore l ancien code.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
2026-09-14 02:16:58 +02:00
Tallagrand Thierry
7b5cddcc60 Le lecteur d etiquette du concierge, en essai a blanc — et 62 ms qui cassaient tout
Le kill-switch gate l ecriture, pas la lecture : tant qu il est a OFF, le
lecteur resout le branchement, applique ses refus et journalise ce qu il aurait
ecrit. L essai grandeur nature d Airtria eprouve donc aussi ma moitie, pas
seulement la leur.

Et il a servi immediatement. La resolution du branchement rendait deux sessions
sur trois : une session s ouvre AVANT que sa transition de branchement soit
journalisee, les deux etant ecrites dans le meme cycle — 62 ms d ecart le
09/09 — donc la session qui OUVRE un branchement etait exclue de son propre
groupe. Tolerance de deux secondes sur la borne basse ; les trois remontent.

Le meme controle, passe sur tout l historique, signale deux branchements
anterieurs a etiquettes contradictoires. Rien n est repare : un groupe mixte
peut aussi etre un echange de vehicule que le capteur a manque, et c est au
proprietaire de trancher.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
2026-09-13 21:43:50 +02:00
Tallagrand Thierry
43bda3df01 L energie du compteur cesse de porter treize decimales de bruit
`energie_compteur_kwh` vaut la difference de deux releves du compteur
cumulatif de la borne, proches de 3 800 kWh : en double precision la
soustraction rend « 0.8000000000001819 » pour une mesure dont la resolution
est de 0,1 kWh. Arrondi a l ecriture, au millieme, plutot que de laisser
chaque lecteur s en charger.

Signale par la session OpenClaw en calibrant son module de detection sur la
table. Cosmetique pour la logique, mais ce projet a deja paye le prix de la
fausse precision affichee comme une mesure.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
2026-09-13 17:45:50 +02:00
Tallagrand Thierry
d41eed977e Le triplet du mercredi etait la JEEP, les trois
Correction de ma propre correction. J'avais mis 09/09 15:55 en JEEP et
laisse les deux sessions suivantes en VW — physiquement impossible, il n'y
a qu'un point de charge et le journal `evenement` montre aucun
debranchement entre mercredi 15:55 et jeudi 09:05.

L'explication du proprietaire est exactement ce qu'aucune regle ne
produira : sa femme a branche la JEEP l'apres-midi, et le soir son fils
n'a PAS debranche pour mettre la VW a la place — il a roule a l'essence le
jeudi. Trois sessions, un seul cable, un seul vehicule, et une decision
humaine que ni l'heure, ni la puissance, ni l'historique ne laissent
deviner.

La reparation passe de quatre a six lignes. Etiquettes finales sur la
semaine : 5 VW, 6 JEEP, 1 MEGANE.

Lecon inscrite dans le commentaire : la frontiere d'un branchement est un
FAIT lu dans `evenement`, jamais un ecart de temps — les creux entre la
session du soir et celle des heures creuses font 5 h 20 et ne se
distinguent pas d'une nuit entiere.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
2026-09-13 17:32:25 +02:00
Tallagrand Thierry
095d86d146 Onze sessions etiquetees VW a tort, et l une n est meme pas du foyer
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
2026-09-13 17:11:10 +02:00
Tallagrand Thierry
283ef42203 pv_mid passe aussi a 130 A
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
2026-09-13 13:41:19 +02:00
Tallagrand Thierry
df8a0e03c2 Le parc butait sur NOTRE plafond, pas sur le sien
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
2026-09-13 13:22:30 +02:00
Tallagrand Thierry
bfa8a5ffd8 Les fantomes du conseiller sont retires
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
2026-09-13 12:39:39 +02:00
Tallagrand Thierry
4a9ad0bc65 Le conseiller ne lisait pas mal : on lui parlait mal
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
2026-09-13 11:59:24 +02:00
Tallagrand Thierry
2345b87d04 Les observations du conseiller cessent de s evaporer
Ses helpers sont ecrases toutes les quinze minutes : un signalement grave
emis a 3 h du matin avait disparu au reveil, et rien dans la memoire du
projet n en gardait trace. C est precisement ce que le proprietaire
demandait quand il a dit vouloir un outil pour garder une trace des
evolutions — voir un comportement idiot du systeme ne sert a rien si
personne ne peut le relire le lendemain.

Une table `observation`, alimentee par le service d historisation, clef sur
l horodatage du marqueur du conseiller : rejouer un cycle n invente rien et
un conseiller a l arret n ecrit pas la meme ligne toutes les minutes. La
confiance est extraite de `_reason` (« [NN%] la piste ») pour rester
interrogeable sans decouper une chaine en SQL.

`node tools/enquete.mjs observations [heures] [gravite]` ne montre par
defaut que ce qui a ete signale, et compte a part les cycles calmes : un
observateur qui fonctionne est silencieux la plupart du temps, et noyer les
signalements sous des centaines de « rien a dire » les rendrait invisibles.

Essai a blanc : observation=1, le service ecrirait bien sa ligne.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
2026-09-13 11:30:18 +02:00
Tallagrand Thierry
9448676cbd Chaque transition dit desormais QUI l a provoquee
Le 12/09, le contacteur reseau a bascule six fois en dix minutes. Trouver
le coupable a demande sept requetes enchainees — executions n8n des deux
workflows, liste des ecrivains, puis automations.yaml — parce que la
table des evenements disait QUE ca avait bascule, jamais PAR QUI.

Home Assistant le savait pourtant. Son logbook resout le contexte d un
changement d etat et nomme l auteur. Sur la coupure de 06:29:44 :
  auteur      : automation.victron_grid_off_si_soc_35
  declencheur : triggered by numeric state of sensor.victron_battery_soc

Un appel par transition REELLE — quelques-uns par jour, pas par cycle.
Echec de lecture => pas d auteur, la ligne est ecrite quand meme : on ne
devine jamais.

⚠️ L auteur est colle au RESUME, pas seulement au detail jsonb. C est le
resume que Grafana affiche en annotation sur TOUS les tableaux et dans
les panneaux « journal des evenements », et que le rapport de nuit
reprend. Le mettre la le rend visible partout sans toucher a un seul
tableau.

 remonte l auteur et son declencheur : l enquete de ce
matin tient desormais en UNE commande, et l observateur pourra nommer le
coupable au lieu de dire « un des trois ».

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
2026-09-12 09:12:35 +02:00
Tallagrand Thierry
1945fdfe5c Le conseiller devient observateur, et une couche d enquete voit le jour
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
2026-09-12 08:36:31 +02:00