// Scenarios golden pour le node "Compute Charge Targets" // (workflow "Victron - Auto Charge Manager V1.2", id cTeeHy4ePiVeELLh). // // Ce workflow decide ce que la BATTERIE a le droit de prendre : les limites // DVCC en courant et en tension. Il gouverne donc le haut de la reserve — c'est // lui qui plafonnait le parc a 93 % de SOC jusqu'au 06/09 — et il n'avait aucun // test : il n'etait meme pas suivi dans le depot. // // Le fixture est un snapshot REEL, capture le 06/09/2026 en rendant le gabarit // du node "HA Snapshot via Template" contre Home Assistant. Ne pas le remplacer // par des valeurs inventees : c'est la lecon du 24/08, ou le fixture de // l'hysteresis portait les valeurs de REPLI du code (22/35) au lieu des seuils // de production (20/30), ce qui masquait un bug de bande. // // ⚠️ ORDRE DES BRANCHES, a garder en tete en lisant les attendus : // 1. automatisation desactivee // 2. secours SOC < 20 hors fenetres HC // 3. takeover EVCS nuit (recover / hold) // 4. hiver + HC nuit // 5. ete + HC nuit // 6. HC midi (rattrapage, seulement si SOC < 85 ET forecast < 8 ET PV < 1500) // 7. fenetre jour (boost / mid / topoff / hold selon le SOC) // 8. hors fenetre // puis l'override se superpose a tout. const ETE = '2026-07-15'; const HIVER = '2026-01-15'; const h = (jour, hhmm) => `${jour}T${hhmm}:00+02:00`; const hHiver = (hhmm) => `${HIVER}T${hhmm}:00+01:00`; // Le parc a quatre modules du 06/09 : le BMS autorise 53,2 V, et nos profils // restent tous en dessous. const parcNeuf = { soc_percent: '60', battery_voltage_v: '51.0', battery_current_a: '20' }; export const scenarios = [ // ---------------------------------------------------------------- gardes { id: 'acm-automatisation-desactivee', label: "Toggle d'automatisation OFF : les reglages en place sont conserves tels quels", time: h(ETE, '11:00'), overrides: { ...parcNeuf, auto_enabled: 'off', current_max_charge_current_a: '77', current_max_charge_voltage_v: '50.9' }, expect: { mode: 'automation_disabled', profil: 'manual_keep_current', courantA: 77, tensionV: 50.9, publieCourant: false, publieTension: false }, }, { id: 'acm-secours-soc-critique', label: 'SOC 18 % hors fenetres HC : secours a 60 A / 50,4 V et alerte critique', time: h(ETE, '10:00'), overrides: { ...parcNeuf, soc_percent: '18' }, expect: { mode: 'emergency_rescue', profil: 'emergency_rescue', courantA: 60, tensionV: 50.4, alerte: true }, }, // ------------------------------------------------------- takeover de nuit { id: 'acm-takeover-recharge-vers-la-cible', label: 'Takeover EVCS, EDF ferme, SOC 30 sous la cible 50 : recharge a 30 A', time: h(ETE, '02:30'), overrides: { ...parcNeuf, soc_percent: '30', night_takeover: 'on', edf_switch: 'on', night_target_soc: '50' }, expect: { mode: 'evcs_takeover_recover', profil: 'night_slow', courantA: 30, tensionV: 50.1 }, }, { id: 'acm-takeover-maintien-a-la-cible', label: 'RELEVE 06/09 05:06 : cible atteinte, la batterie est tenue a 2 A pendant que le reseau porte la maison', time: h(ETE, '05:06'), overrides: { ...parcNeuf, soc_percent: '55', night_takeover: 'on', edf_switch: 'on', night_target_soc: '49.4' }, expect: { mode: 'evcs_takeover_hold', profil: 'takeover_hold', courantA: 2, tensionV: 50.1 }, }, { id: 'acm-takeover-cible-plafonnee-a-95', label: 'GARDE : une cible aberrante de 120 % est ramenee a 95, donc SOC 96 tient deja', time: h(ETE, '03:00'), overrides: { ...parcNeuf, soc_percent: '96', night_takeover: 'on', edf_switch: 'on', night_target_soc: '120' }, expect: { mode: 'evcs_takeover_hold', courantA: 2 }, }, { id: 'acm-takeover-sans-edf-ne-mord-pas', label: "CONTREFACTUEL : takeover demande mais contacteur OUVERT — on ne bride pas la batterie sur du reseau absent", time: h(ETE, '03:00'), overrides: { ...parcNeuf, soc_percent: '30', night_takeover: 'on', edf_switch: 'off', night_target_soc: '50' }, expect: { mode: 'summer_night_idle' }, }, // ------------------------------------------------------------ nuit HC { id: 'acm-hiver-nuit-forecast-sombre', label: 'Hiver, HC nuit, demain sombre (5 kWh) : on remonte vers 80 %', time: hHiver('03:00'), overrides: { ...parcNeuf, soc_percent: '50', today_remaining_kwh: '0', tomorrow_kwh: '5' }, expect: { mode: 'winter_night_charge_window', profil: 'night_slow', courantA: 30 }, }, { id: 'acm-hiver-nuit-forecast-ensoleille', label: 'PAIRE : meme nuit d hiver mais demain ensoleille (30 kWh), cible 40 % deja depassee', time: hHiver('03:00'), overrides: { ...parcNeuf, soc_percent: '50', today_remaining_kwh: '0', tomorrow_kwh: '30' }, expect: { mode: 'winter_night_idle' }, }, { id: 'acm-ete-nuit-secours', label: 'Ete, HC nuit, SOC 20 sous le seuil de 22 : secours', time: h(ETE, '03:00'), overrides: { ...parcNeuf, soc_percent: '20' }, expect: { mode: 'summer_night_rescue_window', profil: 'night_slow' }, }, { id: 'acm-ete-nuit-repos', label: 'PAIRE : meme nuit d ete a SOC 50, aucun besoin reseau', time: h(ETE, '03:00'), overrides: { ...parcNeuf, soc_percent: '50' }, expect: { mode: 'summer_night_idle' }, }, // ------------------------------------------------------------ midi HC { id: 'acm-midi-rattrapage', label: 'HC midi, SOC 60, journee sombre (5 kWh) et PV a 800 W : rattrapage reseau a 30 A', time: h(ETE, '13:00'), overrides: { ...parcNeuf, soc_percent: '60', today_remaining_kwh: '5', pv_power_w: '800' }, expect: { mode: 'midday_catchup_window', profil: 'midday_grid_catchup', courantA: 30, tensionV: 50.8 }, }, { id: 'acm-midi-pas-de-rattrapage-si-le-soleil-revient', label: 'CONTREFACTUEL : meme midi mais PV a 2000 W — le rattrapage ne mord plus, on repasse en profil jour', time: h(ETE, '13:00'), overrides: { ...parcNeuf, soc_percent: '60', today_remaining_kwh: '5', pv_power_w: '2000' }, expect: { mode: 'day_pv_boost', profil: 'pv_boost' }, }, // ------------------------------------------------------------ jour { // 13/09/2026 — 130 -> 150 A. Mesure de 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 (donc aucune absorption : le courant ne // retombait pas de lui-meme, il butait). Le BMS declare 250 A et 53,2 V, // les 135 cellules tiennent dans 2 mV, aucun module ne bloque la charge. // Le 130 A venait de l'ANCIEN parc, sorti le 12/09. 150 A est un palier, // pas une cible : on regarde ce qu'il libere avant d'aller plus loin. id: 'acm-jour-boost', label: 'Jour, SOC 60 sous 80 : capture PV maximale, 150 A a 51,5 V (releve du 13/09 : la batterie butait sur 130)', time: h(ETE, '11:00'), overrides: { ...parcNeuf, soc_percent: '60', pv_power_w: '4000' }, expect: { mode: 'day_pv_boost', profil: 'pv_boost', courantA: 150, tensionV: 51.5 }, }, { id: 'acm-jour-mid', label: 'Jour, SOC 85 entre 80 et 90 : 110 A a 51,5 V (la colonne des tensions redescendait entre 80 et 90)', time: h(ETE, '11:00'), overrides: { ...parcNeuf, soc_percent: '85', pv_power_w: '4000', battery_voltage_v: '50.5' }, expect: { mode: 'day_pv_mid', profil: 'pv_mid', courantA: 110, tensionV: 51.5 }, }, { id: 'acm-jour-topoff-52v4', label: "LE CORRECTIF DU 06/09 : SOC 93 dans la tranche 90-95, la tension monte a 52,4 V et le parc reprend de la charge", time: h(ETE, '15:00'), overrides: { ...parcNeuf, soc_percent: '93', pv_power_w: '4000', battery_voltage_v: '51.1' }, expect: { mode: 'day_pv_topoff', profil: 'pv_topoff', courantA: 80, tensionV: 52.4 }, }, { id: 'acm-jour-hold-au-dessus-de-95', label: "GARDE : au-dessus de 95 % on redescend a 50,6 V — on atteint le haut, on n'y sejourne pas", time: h(ETE, '15:00'), overrides: { ...parcNeuf, soc_percent: '96', pv_power_w: '4000' }, expect: { mode: 'day_pv_hold', profil: 'pv_hold', courantA: 30, tensionV: 50.6 }, }, { id: 'acm-hors-fenetre', label: 'Hors fenetre utile (21 h en ete) : profil de maintien', time: h(ETE, '21:00'), overrides: { ...parcNeuf, soc_percent: '70' }, expect: { mode: 'off_window_idle', profil: 'pv_hold', courantA: 30, tensionV: 50.6 }, }, // ------------------------------------------------------------ override { id: 'acm-override-manuel-actif', label: 'Override manuel valide : les valeurs saisies prennent la main sur le profil calcule', time: h(ETE, '11:00'), overrides: { ...parcNeuf, soc_percent: '60', override_enabled: 'on', override_profile: 'manual', override_current_a: '12', override_voltage_v: '50.0', override_until: '2026-07-15 23:00:00' }, expect: { overrideActif: true, profil: 'override_manual', courantA: 12, tensionV: 50 }, }, { id: 'acm-override-expire-sans-effet', label: "CONTREFACTUEL : meme override mais l'echeance est passee — le profil calcule reprend", time: h(ETE, '11:00'), overrides: { ...parcNeuf, soc_percent: '60', override_enabled: 'on', override_profile: 'manual', override_current_a: '12', override_voltage_v: '50.0', override_until: '2026-07-15 09:00:00' }, expect: { overrideActif: false, mode: 'day_pv_boost', courantA: 150 }, }, // ------------------------------------------------------------ publication { id: 'acm-pas-de-publication-si-identique', label: "GARDE : cible egale a ce qui est deja regle — on n'ecrit ni le courant ni la tension", time: h(ETE, '21:00'), overrides: { ...parcNeuf, soc_percent: '70', current_max_charge_current_a: '30', current_max_charge_voltage_v: '50.6' }, expect: { publieCourant: false, publieTension: false }, }, ];