From c2f9e83a39203c28951b599b06ac77fe1c5ee188 Mon Sep 17 00:00:00 2001 From: Tallagrand Thierry Date: Tue, 29 Sep 2026 10:53:39 +0200 Subject: [PATCH] Prevision de nuit : mode jour (plus de fausse reponse sur la nuit ecoulee) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Le jour, sans rien a couvrir avant le retour du solaire, le texte parlait de la nuit ecoulee (« 0 kWh jusqu au retour du solaire vers 10 h, la batterie suffit »). Etat `jour` : la prevision se fait le soir, avec un repere provisoire (prochaine traversee prudente) et l'achat si EDF s'engage. Diagnostics 87/87. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_011uJ47NxgfpGnuuMr3f2n7Z --- HANDOFF.md | 15 +++++++++++++-- tests/diagnostics-agent/run.mjs | 25 +++++++++++++++++++++++++ tools/diagnostics-agent.mjs | 25 +++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 2 deletions(-) diff --git a/HANDOFF.md b/HANDOFF.md index ae025c9..31ff24d 100644 --- a/HANDOFF.md +++ b/HANDOFF.md @@ -1158,8 +1158,19 @@ affiner ; demarrage solaire de l'apres-midi toujours non couvert par le besoin d « EDF sera branche de 01:24 a 07:24 : environ 4,6 kWh achetes en heures creuses (maison 4,5, batterie 0,14), car la maison passe la nuit sur le reseau ». Bilan 72/72, diagnostics 85/85, mutations qui mordent (une premiere ne mordait pas : scenario a - 03:00 pile, horizon sans tranche anterieure -> deplace a 03:30). Fiche de l'agent a - mettre a jour par SPARK. + 03:00 pile, horizon sans tranche anterieure -> deplace a 03:30). Fiche mise a jour par SPARK + (l'agent recopie `prevision-nuit.js`, qui imprime `texte_rapport` : aucun attribut lu). +- **Mode jour** (remarque de SPARK, banc 10:49 : « combien d'EDF la nuit prochaine ? » -> + « la maison doit couvrir 0 kWh jusqu'au retour du solaire vers 10 h, la batterie + suffit », qui parlait de la nuit ECOULEE). Quand plus rien n'est a couvrir avant le + retour du solaire et sans session : etat/verdict `jour`, « il est trop tot pour la + prevision de la nuit : elle se calcule le soir … repere provisoire, profil prudent : + pour passer de 18 h a 09 h sans EDF (17,87 kWh), il faudrait la batterie a 82 % a + 18 h ; si EDF s'engage a 01:24, la maison y achetera environ 4,2 kWh ». Attributs + `prochaine_traversee*`. Diagnostics 87/87, mutation qui mord. En reel a 10:53. +- SPARK : les transcripts SQLite (`openclaw-agent.sqlite`, droits 600) remontent au + 18/07, AUCUNE rotation ; un evenement contient le jeton HA (l'agent a lu `.ha-token`). + Signale au proprietaire par SPARK, base non modifiee. --- *Document mis a jour le : 29/09/2026 (~10:50) — nuit du 28-29 verifiee, achat EDF annonce = maison en HC + manque batterie ; regle HC active, vehicule branche a midi (JEEP/VW/ZERO), prevision de nuit a trois verdicts, nuits superposees et bilan recale sur la soiree* diff --git a/tests/diagnostics-agent/run.mjs b/tests/diagnostics-agent/run.mjs index 665c3b1..207b66f 100644 --- a/tests/diagnostics-agent/run.mjs +++ b/tests/diagnostics-agent/run.mjs @@ -397,6 +397,31 @@ for (const [nom, r, test] of imp) { 'input_boolean.victron_evcs_night_grid_session_committed': 'off', 'input_number.evcs_balance_night_hc_house_kwh': '4.46', })) m.set(k, { state: v }); return previsionNuit(m, t); })(), (r) => r.etat === 0 && r.attributs.verdict === 'juste' && /la maison y achetera alors environ 4,5 kWh/.test(r.attributs.explication)], + // Releve REEL du 29/09 10:45 (banc SPARK) : « la maison doit couvrir 0 kWh + // jusqu au retour du solaire vers 10 h … la batterie suffit » en reponse a + // « combien d EDF la nuit prochaine ? ». + ['29/09 10:45 : le jour, pas de fausse prevision de nuit, un repere provisoire', (() => { + const m = base(); for (const [k, v] of Object.entries({ + 'input_number.evcs_balance_energy_to_cover_kwh': '0', 'input_boolean.evcs_balance_grid_needed': 'off', + 'input_number.evcs_balance_grid_energy_needed_kwh': '0', 'input_text.evcs_balance_crossing_hour': '10 h', + 'input_number.evcs_balance_required_soc': '22', 'input_number.evcs_balance_required_soc_prudent': '22', + 'sensor.victron_battery_soc': '46', 'input_boolean.victron_evcs_night_grid_session_committed': 'off', + 'sensor.evcs_reseau': 'non_raccorde', 'input_number.evcs_balance_night_hc_house_kwh': '4.16', + 'input_datetime.victron_evcs_hc_night_start': '01:24:00', 'input_datetime.victron_evcs_hc_night_stop': '07:24:00', + 'input_text.evcs_balance_next_deficit_window': '18 h → 09 h', + 'input_number.evcs_balance_next_deficit_required_soc': '81.6', 'input_number.evcs_balance_next_deficit_kwh': '17.87', + })) m.set(k, { state: v }); return previsionNuit(m, t); })(), + (r) => r.etat === 'jour' && r.attributs.verdict === 'jour' + && /trop tot pour la prevision de la nuit/.test(r.attributs.texte_rapport) + && /de 18 h a 09 h sans EDF \(environ 17,87 kWh\), il faudrait la batterie a 82 % a 18 h/.test(r.attributs.texte_rapport) + && /Si EDF s engage a 01:24, la maison y achetera environ 4,2 kWh jusqu a 07:24/.test(r.attributs.texte_rapport) + && !/batterie suffit/.test(r.attributs.texte_rapport) && !/couvrir environ 0 kWh/.test(r.attributs.texte_rapport)], + ['le jour, fenetre de deficit inconnue -> pas de repere invente', (() => { + const m = base(); for (const [k, v] of Object.entries({ + 'input_number.evcs_balance_energy_to_cover_kwh': '0', 'input_boolean.evcs_balance_grid_needed': 'off', + 'input_boolean.victron_evcs_night_grid_session_committed': 'off', 'input_text.evcs_balance_next_deficit_window': 'déficit en cours', + })) m.set(k, { state: v }); return previsionNuit(m, t); })(), + (r) => r.etat === 'jour' && !/Repere provisoire/.test(r.attributs.texte_rapport)], ['plus jamais d attribut reseau_necessaire_kwh (lu comme un achat le 28/09)', previsionNuit(base(), t), (r) => !('reseau_necessaire_kwh' in r.attributs) && 'import_prevu_kwh' in r.attributs], ['jamais d attribut qui ressemble a un SOC du matin (incident 21:16)', previsionNuit(base(), t), diff --git a/tools/diagnostics-agent.mjs b/tools/diagnostics-agent.mjs index 694c814..f48fdc9 100644 --- a/tools/diagnostics-agent.mjs +++ b/tools/diagnostics-agent.mjs @@ -658,6 +658,31 @@ export function previsionNuit(st, maintenant = new Date()) { `Le systeme refait le calcul ${hc} : si la soiree a consomme davantage, il prendra EDF en heures creuses` + `${maisonHcKwh !== null ? `, et la maison y achetera alors environ ${kwh(Math.round(maisonHcKwh * 10) / 10)} kWh` : ''}.`, }[verdict]; + // LE JOUR (29/09, remarque de SPARK) : plus rien a couvrir avant le retour + // du solaire = le solaire couvre deja la maison. Le texte « la maison doit + // couvrir 0 kWh jusqu au retour du solaire vers 10 h » parlait alors de la + // nuit ECOULEE, et une question « et cette nuit ? » posee a midi recevait + // une reponse fausse. La vraie prevision se fait le soir, sur la soiree + // reelle (facteur de nuit) et la decision de 01:24. Le jour, on le dit, avec + // un repere provisoire : la prochaine traversee du bilan (profil PRUDENT). + if (aCouvrir <= 0 && !session) { + const fen = txt('input_text.evcs_balance_next_deficit_window'); + const m = fen ? fen.match(/^(\d{2}) h → (\d{2}) h/) : null; + const ndSoc = nombre(st, 'input_number.evcs_balance_next_deficit_required_soc'); + const ndKwh = nombre(st, 'input_number.evcs_balance_next_deficit_kwh'); + const repere = m && ndSoc !== null && ndKwh !== null + ? ` Repere provisoire, profil prudent : pour passer de ${m[1]} h a ${m[2]} h sans EDF (environ ${kwh(ndKwh)} kWh), ` + + `il faudrait la batterie a ${kwh(Math.round(ndSoc))} % a ${m[1]} h.` + : ''; + const achatSi = maisonHcKwh !== null + ? ` Si EDF s engage ${hc}, la maison y achetera environ ${kwh(Math.round(maisonHcKwh * 10) / 10)} kWh ${jusqua}.` : ''; + const texteJour = `Il est trop tot pour la prevision de la nuit : elle se calcule le soir, sur la consommation reelle ` + + `de la soiree, et la decision d EDF se prend ${hc}.${repere}${achatSi} Batterie a ${soc !== null ? Math.round(soc) : '?'} % maintenant.`; + return { etat: 'jour', attributs: { ...attributs, verdict: 'jour', statut: 'jour', + prochaine_traversee: m ? `${m[1]} h -> ${m[2]} h` : null, + prochaine_traversee_soc_requis_pct: m ? ndSoc : null, prochaine_traversee_kwh: m ? ndKwh : null, + explication: texteJour, texte_rapport: texteJour } }; + } const texte = `La maison doit couvrir environ ${aCouvrir} kWh jusqu au retour du solaire vers ${retour}. ` + `${edf} Batterie a ${soc !== null ? Math.round(soc) : '?'} %. ${voiture}`; const etat = verdict === 'edf_engage' || verdict === 'reseau_necessaire' ? (importPrevu ?? manqueKwh) : 0;