Prevision de nuit : « c'est juste » quand seul le profil habituel passe (incident 28/09 21:16)

Trois verdicts au lieu de deux ; « la batterie suffit » exige le requis PRUDENT.
Attribut soc_requis_maintenant_pct (l'ancien nom se lisait comme un SOC du matin).
Tests 73/73, mutation qui mord.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011uJ47NxgfpGnuuMr3f2n7Z
This commit is contained in:
Tallagrand Thierry
2026-09-28 21:28:03 +02:00
parent 5c43249899
commit 5721031e17
3 changed files with 75 additions and 8 deletions

View File

@@ -583,16 +583,34 @@ export function previsionNuit(st, maintenant = new Date()) {
const reseauKwh = nombre(st, 'input_number.evcs_balance_grid_energy_needed_kwh');
const reseauNecessaire = txt('input_boolean.evcs_balance_grid_needed') === 'on';
const retour = txt('input_text.evcs_balance_crossing_hour');
// ⚠️ SOC REQUIS MAINTENANT, pas un SOC projete du matin (incident 28/09 21:16 :
// l'agent a lu 57,5 comme « la batterie arrivera a 57-58 % au retour du
// soleil »). Le bilan ne projette AUCUN SOC du matin ; ce capteur non plus.
const socRequis = nombre(st, 'input_number.evcs_balance_required_soc');
const socPrudent = nombre(st, 'input_number.evcs_balance_required_soc_prudent');
const soc = nombre(st, 'sensor.victron_battery_soc');
const reseau = txt('sensor.evcs_reseau');
const session = txt('input_boolean.victron_evcs_night_grid_session_committed') === 'on';
const branche = txt('binary_sensor.victron_evcs_vehicle_connected');
const hcDebut = (txt('input_datetime.victron_evcs_hc_night_start') || '').slice(0, 5) || null;
const marge = soc !== null && socRequis !== null ? Math.round((soc - socRequis) * 10) / 10 : null;
// TROIS verdicts, pas deux (incident 28/09 21:16 : « la batterie suffit, sans
// EDF » avec 0,5 point de marge sur le profil HABITUEL, alors que le profil
// prudent demandait 68,5 % pour un SOC de 58 %). Le profil p50 est une
// mediane : a zero marge, c'est pile ou face. La decision reelle est reprise
// a l'ouverture des heures creuses, sur l'exigence recalculee a ce moment-la.
const verdict = session ? 'edf_engage'
: reseauNecessaire ? 'reseau_necessaire'
: socPrudent !== null && soc !== null && soc >= socPrudent ? 'batterie_suffit'
: 'juste';
const attributs = {
maison_kwh_a_couvrir: aCouvrir, heure_retour_solaire: retour,
reseau_necessaire: reseauNecessaire, reseau_necessaire_kwh: reseauNecessaire ? reseauKwh : 0,
soc_actuel_pct: soc, soc_requis_au_retour_solaire_pct: socRequis,
verdict,
soc_actuel_pct: soc, soc_requis_maintenant_pct: socRequis, soc_requis_prudent_maintenant_pct: socPrudent,
marge_points: marge, debut_heures_creuses: hcDebut,
contacteur_edf: reseau, session_reseau_nuit_engagee: session,
voiture: branche === 'on' ? 'branchee' : branche === 'off' ? 'aucune' : 'inconnue',
bilan_calcule_il_y_a_min: age,
@@ -610,12 +628,16 @@ export function previsionNuit(st, maintenant = new Date()) {
: attributs.voiture === 'branchee'
? 'Un vehicule est branche : sa charge s ajoute et sera decidee par le controleur.'
: 'Etat du vehicule inconnu.';
const edf = reseauNecessaire
? `Environ ${reseauKwh} kWh a prendre sur EDF avant le retour du solaire.`
: 'La batterie suffit, sans EDF, jusqu au retour du solaire.';
const hc = hcDebut ? `a ${hcDebut}` : 'a l ouverture des heures creuses';
const edf = {
edf_engage: `EDF est branche pour la nuit, en heures creuses${reseauNecessaire ? ` : environ ${reseauKwh} kWh a prendre sur EDF avant le retour du solaire` : ''} ; la batterie est tenue jusqu au matin.`,
reseau_necessaire: `Environ ${reseauKwh} kWh a prendre sur EDF en heures creuses avant le retour du solaire.`,
batterie_suffit: 'La batterie suffit jusqu au retour du solaire, meme si la maison consomme plus que d habitude : EDF ne devrait pas etre necessaire.',
juste: `C est juste : la batterie suffit seulement si la maison consomme comme d habitude${marge !== null ? ` (marge ${String(marge).replace('.', ',')} point${Math.abs(marge) >= 2 ? 's' : ''})` : ''}. ` +
`Le systeme refait le calcul ${hc} : si la soiree a consomme davantage, il prendra EDF en heures creuses.`,
}[verdict];
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}` +
`${session ? ' La session reseau de la nuit est engagee.' : ''}`;
`${edf} Batterie a ${soc !== null ? Math.round(soc) : '?'} %. ${voiture}`;
return { etat: reseauNecessaire ? reseauKwh : 0, attributs: { ...attributs, statut: 'frais', explication: texte, texte_rapport: texte } };
}