Budget voiture de la nuit : ce que la batterie peut donner sans EDF, arret au compteur, choix sans EDF / complete
This commit is contained in:
39
HANDOFF.md
39
HANDOFF.md
@@ -1233,5 +1233,42 @@ affiner ; demarrage solaire de l'apres-midi toujours non couvert par le besoin d
|
|||||||
- **A OBSERVER en reel** (non testable sans ecriture) : voiture vraiment branchee + « c'est
|
- **A OBSERVER en reel** (non testable sans ecriture) : voiture vraiment branchee + « c'est
|
||||||
la JEEP » -> l'agent doit relayer « ✅ Noté : JEEP… ».
|
la JEEP » -> l'agent doit relayer « ✅ Noté : JEEP… ».
|
||||||
|
|
||||||
|
### 30/09 midi — Budget voiture de la nuit : ce que la batterie peut donner sans EDF
|
||||||
|
Constat du matin : la nuit du 29-30/09 a fini a 39 % a 9 h pour un plancher de 22 %, soit
|
||||||
|
~5 kWh inutilises. Avec les chiffres publies a 01:25 (SOC 57, prudent 44,7), la voiture
|
||||||
|
pouvait prendre ~3,7-4,2 kWh sur la batterie sans EDF ; j'avais annonce EDF la veille, de
|
||||||
|
tete, a tort (SOC et requis estimes au lieu d'etre lus). Proposition du proprietaire :
|
||||||
|
**definir combien la voiture peut prendre sans EDF, et brider la charge a cette valeur, ou
|
||||||
|
autoriser une charge complete avec EDF.** Decisions (30/09) : profil **prudent + 22 %** ;
|
||||||
|
**par defaut « sans EDF »** ; en « complete », **budget batterie d'abord puis EDF**.
|
||||||
|
- **Bilan** : `input_number.evcs_balance_night_vehicle_budget_kwh` = creux de la reserve
|
||||||
|
au-dessus du plancher, profil p80, entre l'ouverture de la HC de nuit (ou maintenant) et
|
||||||
|
la nuit SUIVANTE (regle « tenir jusqu'a la prochaine HC »), recharge ecretee a 100 %.
|
||||||
|
Attendus verifies par un calcul Python independant (4,21 / 0,61 / 0 kWh). Bilan 76/76,
|
||||||
|
mutation qui mord. Premier calcul reel 13:25 : **6,46 kWh** pour cette nuit (SOC 98).
|
||||||
|
- **Controleur** (WINDOWS_SOURCEV2) : budget FIGE au premier cycle de la session de nuit
|
||||||
|
avec l'index du compteur `sensor.evcs_hq2239dnt7p_total_energy` dans
|
||||||
|
`input_text.victron_evcs_night_budget` (« budget|index », efface en fin de session).
|
||||||
|
Arret quand le compteur a avance du budget : condition MONOTONE, pas d'oscillateur. Le
|
||||||
|
plancher de SOC prudent de P12 reste un second arret. `input_select.victron_evcs_night_charge_mode`
|
||||||
|
(sans_edf | complete), **remis a sans_edf chaque jour a 12:00** (automatisation
|
||||||
|
`evcs_charge_nuit_retour_sans_edf`). Sans EDF : P7 ne prend plus la voiture ; budget
|
||||||
|
atteint ou inexploitable -> voiture `blocked`, raison « Budget batterie nuit x/y kWh —
|
||||||
|
atteint, sans EDF : la voiture attend le soleil ». ⚠️ **Exception de securite** : si EDF
|
||||||
|
est engage de toute facon pour la BATTERIE (plancher dur, cible du matin, session du bilan,
|
||||||
|
verrou), « sans EDF » ne bloque pas — trouve par le golden `night-hard-floor` (EDF ne se
|
||||||
|
fermait plus a SOC 20 dans ma premiere version). Complete : comportement historique.
|
||||||
|
- Golden 123 -> **130** (7 scenarios `budget-*`) ; les scenarios de nuit historiques
|
||||||
|
portent `night_charge_mode: 'complete'` (le comportement qu'ils decrivent). Trois
|
||||||
|
mutations mordent (arret au budget, sans EDF pour P7, exception de securite).
|
||||||
|
- ⚠️ **Limite connue** : le debit sur batterie est borne par les gardes durs de courant par
|
||||||
|
bande de SOC (-30 A en 40-60 %, -15 A en 25-40 %, valeurs fixes) : a SOC moyen la voiture
|
||||||
|
ne tire qu'environ 1 kW, et un budget peut ne pas etre entierement delivre en 6 h.
|
||||||
|
- P9 (reseau avant depart) est OFF chez le proprietaire : non touche.
|
||||||
|
- **A faire** : annoncer le budget et le mode dans `sensor.evcs_prevision_nuit` (lu par
|
||||||
|
l'agent) ; commande vocale « charge complete cette nuit » (SPARK, ecriture du seul
|
||||||
|
`input_select.victron_evcs_night_charge_mode`) ; carte sur EVCS Master ; verifier la
|
||||||
|
premiere nuit reelle (budget fige, arret, raison).
|
||||||
|
|
||||||
---
|
---
|
||||||
*Document mis a jour le : 30/09/2026 (~08:45) — fiche de l'agent allegee (25 831 car.), concierge sans silence, calendrier JEEP mar/sam ; 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*
|
*Document mis a jour le : 30/09/2026 (~13:30) — budget voiture de la nuit sans EDF (bilan + controleur) ; fiche de l'agent allegee (25 831 car.), concierge sans silence, calendrier JEEP mar/sam ; 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*
|
||||||
|
|||||||
@@ -113,6 +113,14 @@ input_number:
|
|||||||
unit_of_measurement: "%"
|
unit_of_measurement: "%"
|
||||||
mode: box
|
mode: box
|
||||||
icon: mdi:clock-alert-outline
|
icon: mdi:clock-alert-outline
|
||||||
|
evcs_balance_night_vehicle_budget_kwh:
|
||||||
|
name: "Bilan — voiture : budget batterie de la nuit sans EDF"
|
||||||
|
min: 0
|
||||||
|
max: 50
|
||||||
|
step: 0.01
|
||||||
|
unit_of_measurement: "kWh"
|
||||||
|
mode: box
|
||||||
|
icon: mdi:car-electric
|
||||||
evcs_balance_night_hc_house_kwh:
|
evcs_balance_night_hc_house_kwh:
|
||||||
name: "Bilan — maison sur le réseau en HC de nuit (si session)"
|
name: "Bilan — maison sur le réseau en HC de nuit (si session)"
|
||||||
min: 0
|
min: 0
|
||||||
|
|||||||
@@ -32,6 +32,16 @@ input_select:
|
|||||||
- JEEP
|
- JEEP
|
||||||
- ZERO
|
- ZERO
|
||||||
icon: mdi:car-multiple
|
icon: mdi:car-multiple
|
||||||
|
# Budget voiture de la nuit (30/09/2026, decisions du proprietaire) :
|
||||||
|
# sans_edf = la voiture ne prend que ce que la batterie peut donner sans EDF
|
||||||
|
# (budget du bilan) ; complete = budget batterie puis EDF en HC pour le reste.
|
||||||
|
# Remis a sans_edf chaque jour a 12:00 (defaut si rien n'est dit le soir).
|
||||||
|
victron_evcs_night_charge_mode:
|
||||||
|
name: EVCS - Charge de la voiture cette nuit
|
||||||
|
options:
|
||||||
|
- sans_edf
|
||||||
|
- complete
|
||||||
|
icon: mdi:car-battery
|
||||||
|
|
||||||
input_datetime:
|
input_datetime:
|
||||||
victron_evcs_departure_time_jeep:
|
victron_evcs_departure_time_jeep:
|
||||||
@@ -162,6 +172,12 @@ input_number:
|
|||||||
icon: mdi:ev-station
|
icon: mdi:ev-station
|
||||||
|
|
||||||
input_text:
|
input_text:
|
||||||
|
# Budget fige par le controleur a l'ouverture de la session de nuit :
|
||||||
|
# « budget_kWh|index_compteur_borne », vide hors session. Ne pas ecrire.
|
||||||
|
victron_evcs_night_budget:
|
||||||
|
name: EVCS - Budget voiture de la nuit (fige)
|
||||||
|
max: 40
|
||||||
|
icon: mdi:battery-lock
|
||||||
# Jours ou la JEEP repart apres le dejeuner (lun mar mer jeu ven sam dim).
|
# Jours ou la JEEP repart apres le dejeuner (lun mar mer jeu ven sam dim).
|
||||||
victron_evcs_jeep_midday_departure_days:
|
victron_evcs_jeep_midday_departure_days:
|
||||||
name: EVCS - Jours de départ JEEP après midi
|
name: EVCS - Jours de départ JEEP après midi
|
||||||
@@ -177,6 +193,18 @@ input_text:
|
|||||||
icon: mdi:calendar-week
|
icon: mdi:calendar-week
|
||||||
|
|
||||||
automation:
|
automation:
|
||||||
|
- id: evcs_charge_nuit_retour_sans_edf
|
||||||
|
alias: "EVCS — charge de nuit : retour a « sans EDF » chaque midi"
|
||||||
|
mode: single
|
||||||
|
trigger:
|
||||||
|
- platform: time
|
||||||
|
at: "12:00:00"
|
||||||
|
action:
|
||||||
|
- service: input_select.select_option
|
||||||
|
target:
|
||||||
|
entity_id: input_select.victron_evcs_night_charge_mode
|
||||||
|
data:
|
||||||
|
option: sans_edf
|
||||||
- id: evcs_niveau_vehicule_reference
|
- id: evcs_niveau_vehicule_reference
|
||||||
alias: "EVCS — mémoriser le compteur de la borne à la saisie du niveau"
|
alias: "EVCS — mémoriser le compteur de la borne à la saisie du niveau"
|
||||||
mode: queued
|
mode: queued
|
||||||
|
|||||||
@@ -421,6 +421,48 @@ if (nightHcActive) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
// BUDGET VOITURE DE LA NUIT (30/09/2026, decisions du proprietaire)
|
||||||
|
//
|
||||||
|
// « Definir combien la voiture peut prendre sans utiliser EDF, et brider la
|
||||||
|
// charge a cette valeur ou autoriser une charge complete avec EDF. » Choix du
|
||||||
|
// 30/09 : profil PRUDENT (p80) et plancher du bilan (22 %) ; par defaut « sans
|
||||||
|
// EDF » ; en charge complete, le budget batterie d'abord, EDF pour le reste.
|
||||||
|
//
|
||||||
|
// Budget = la plus petite reserve au-dessus du plancher que la batterie
|
||||||
|
// connaitra entre l'ouverture de la fenetre HC de nuit (ou maintenant si elle
|
||||||
|
// est ouverte) et le debut de la fenetre de nuit SUIVANTE, sur le profil
|
||||||
|
// prudent. Retirer X kWh a l'ouverture abaisse toute la trajectoire de X :
|
||||||
|
// le budget est donc le creux de la trajectoire. L'horizon jusqu'a la nuit
|
||||||
|
// suivante applique « la batterie tient jusqu'a la prochaine HC » ; la
|
||||||
|
// batterie pleine ecrete la recharge (on ne stocke pas au-dela de 100 %).
|
||||||
|
// Le 30/09 01:25 : SOC 57, prudent 44,7 -> ~3,7 kWh.
|
||||||
|
// ---------------------------------------------------------------------
|
||||||
|
let nightVehicleBudgetKwh = null;
|
||||||
|
if (nightHcActive && Number.isFinite(socPct)) {
|
||||||
|
const maintenant = num(input.nowMs, Date.now());
|
||||||
|
const depuis = Math.max(nightHcStartMs, maintenant);
|
||||||
|
const jusqua = nightHcStartMs + 24 * 3600000;
|
||||||
|
const plein = energyBetweenSoc(socFloorPct, 100);
|
||||||
|
let reserve = socPct >= socFloorPct
|
||||||
|
? energyBetweenSoc(socFloorPct, socPct) : -energyBetweenSoc(socPct, socFloorPct);
|
||||||
|
let creux = maintenant >= depuis ? reserve : Infinity;
|
||||||
|
for (const sl of slotsP80) {
|
||||||
|
const debut = num(sl.startMs, NaN);
|
||||||
|
if (!Number.isFinite(debut)) continue;
|
||||||
|
const a = Math.max(debut, maintenant), b = Math.min(debut + 3600000, jusqua);
|
||||||
|
if (b <= a) continue;
|
||||||
|
// La tranche qui contient l'ouverture est coupee en deux : le creux ne se
|
||||||
|
// lit qu'a partir de l'ouverture.
|
||||||
|
const coupes = depuis > a && depuis < b ? [a, depuis, b] : [a, b];
|
||||||
|
for (let i = 0; i + 1 < coupes.length; i++) {
|
||||||
|
reserve = Math.min(plein, reserve + sl.netKwh * (coupes[i + 1] - coupes[i]) / 3600000);
|
||||||
|
if (coupes[i + 1] >= depuis) creux = Math.min(creux, reserve);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nightVehicleBudgetKwh = Number.isFinite(creux) ? Math.max(0, creux) : null;
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
// VEHICULE BRANCHE EN HC AVEC UN DEPART AVANT LA PROCHAINE HC (28/09/2026)
|
// VEHICULE BRANCHE EN HC AVEC UN DEPART AVANT LA PROCHAINE HC (28/09/2026)
|
||||||
//
|
//
|
||||||
@@ -702,6 +744,12 @@ return [{
|
|||||||
houseKwh: nightHcHouseKwh === null ? null : round2(nightHcHouseKwh),
|
houseKwh: nightHcHouseKwh === null ? null : round2(nightHcHouseKwh),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Ce que la voiture peut prendre sur la batterie cette nuit sans EDF (30/09).
|
||||||
|
nightVehicleBudget: {
|
||||||
|
active: nightVehicleBudgetKwh !== null,
|
||||||
|
kwh: nightVehicleBudgetKwh === null ? null : round2(nightVehicleBudgetKwh),
|
||||||
|
},
|
||||||
|
|
||||||
// Voiture branchee en HC, depart avant la prochaine HC (28/09).
|
// Voiture branchee en HC, depart avant la prochaine HC (28/09).
|
||||||
vehicleMidday: {
|
vehicleMidday: {
|
||||||
active: vehicleRuleActive,
|
active: vehicleRuleActive,
|
||||||
|
|||||||
@@ -95,6 +95,10 @@ setNumber('input_number.evcs_balance_vehicle_solar_kwh', vm.active ? vm.solarKwh
|
|||||||
// Maison sur le reseau pendant la fenetre HC de nuit si la session s'engage (29/09).
|
// Maison sur le reseau pendant la fenetre HC de nuit si la session s'engage (29/09).
|
||||||
const nh = balance.nightHcImport || {};
|
const nh = balance.nightHcImport || {};
|
||||||
setNumber('input_number.evcs_balance_night_hc_house_kwh', nh.active && nh.houseKwh !== null ? nh.houseKwh : 0);
|
setNumber('input_number.evcs_balance_night_hc_house_kwh', nh.active && nh.houseKwh !== null ? nh.houseKwh : 0);
|
||||||
|
// Budget voiture de la nuit sans EDF (30/09) : 0 si inconnu — le controleur
|
||||||
|
// ne donne alors rien de la batterie.
|
||||||
|
const nb = balance.nightVehicleBudget || {};
|
||||||
|
setNumber('input_number.evcs_balance_night_vehicle_budget_kwh', nb.active && nb.kwh !== null ? nb.kwh : 0);
|
||||||
setNumber('input_number.evcs_balance_energy_to_cover_kwh', c.energyToCoverKwh);
|
setNumber('input_number.evcs_balance_energy_to_cover_kwh', c.energyToCoverKwh);
|
||||||
setNumber('input_number.evcs_balance_grid_energy_needed_kwh', c.gridEnergyNeededKwh);
|
setNumber('input_number.evcs_balance_grid_energy_needed_kwh', c.gridEnergyNeededKwh);
|
||||||
setNumber('input_number.evcs_balance_vehicle_surplus_kwh', balance.vehicle.surplusAvailableKwh);
|
setNumber('input_number.evcs_balance_vehicle_surplus_kwh', balance.vehicle.surplusAvailableKwh);
|
||||||
|
|||||||
@@ -1127,6 +1127,13 @@ return [{
|
|||||||
// P12 — passe-plat du verrou anti-oscillateur vers la sortie.
|
// P12 — passe-plat du verrou anti-oscillateur vers la sortie.
|
||||||
nightBatterySurplusExhausted: !!nightPrev.nightBatterySurplusExhausted,
|
nightBatterySurplusExhausted: !!nightPrev.nightBatterySurplusExhausted,
|
||||||
nightBatterySurplusAvailable: !!nightPrev.nightBatterySurplusAvailable,
|
nightBatterySurplusAvailable: !!nightPrev.nightBatterySurplusAvailable,
|
||||||
|
// Budget voiture de la nuit (30/09) — passe-plat vers la sortie.
|
||||||
|
nightBudgetKwh: nightPrev.nightBudgetKwh ?? null,
|
||||||
|
nightBudgetDeliveredKwh: nightPrev.nightBudgetDeliveredKwh ?? null,
|
||||||
|
nightBudgetReached: !!nightPrev.nightBudgetReached,
|
||||||
|
nightBudgetToWrite: nightPrev.nightBudgetToWrite ?? null,
|
||||||
|
nightChargeMode: nightPrev.nightChargeMode || 'sans_edf',
|
||||||
|
nightCarWaitsNoGrid: !!nightPrev.nightCarWaitsNoGrid,
|
||||||
maxBatteryDischargePoints,
|
maxBatteryDischargePoints,
|
||||||
gridTakeoverTriggerPct,
|
gridTakeoverTriggerPct,
|
||||||
|
|
||||||
|
|||||||
@@ -300,6 +300,15 @@ if (manualPriorityOverrideActive && !evcsVehicleNotRequestingPowerState) {
|
|||||||
// =====================================================
|
// =====================================================
|
||||||
const reason = [...decision.reason];
|
const reason = [...decision.reason];
|
||||||
|
|
||||||
|
// Budget voiture de la nuit (30/09) : dire pourquoi la voiture s'arrete.
|
||||||
|
if (night.nightBudgetKwh !== null && night.nightBudgetKwh !== undefined) {
|
||||||
|
const f = (x) => String(Math.round(x * 100) / 100).replace('.', ',');
|
||||||
|
reason.push(`Budget batterie nuit ${f(night.nightBudgetDeliveredKwh ?? 0)}/${f(night.nightBudgetKwh)} kWh` +
|
||||||
|
(night.nightCarWaitsNoGrid ? ' — atteint, sans EDF : la voiture attend le soleil'
|
||||||
|
: night.nightBudgetReached ? ' — atteint, EDF finit la charge' : ''));
|
||||||
|
} else if (night.nightCarWaitsNoGrid) {
|
||||||
|
reason.push('Pas de budget batterie exploitable, sans EDF : la voiture attend le soleil');
|
||||||
|
}
|
||||||
reason.push(`Stratégie=${strategy.userStrategy}`);
|
reason.push(`Stratégie=${strategy.userStrategy}`);
|
||||||
reason.push(`Profil=${context.profile}`);
|
reason.push(`Profil=${context.profile}`);
|
||||||
reason.push(`Source=${context.sourceMode}`);
|
reason.push(`Source=${context.sourceMode}`);
|
||||||
@@ -1374,6 +1383,17 @@ return [{
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Budget voiture de la nuit (30/09) : fige a l'ouverture, efface en fin.
|
||||||
|
helper_night_budget: {
|
||||||
|
execute: night.nightBudgetToWrite !== null && night.nightBudgetToWrite !== undefined,
|
||||||
|
domain: 'input_text',
|
||||||
|
service: 'set_value',
|
||||||
|
data: {
|
||||||
|
entity_id: 'input_text.victron_evcs_night_budget',
|
||||||
|
value: night.nightBudgetToWrite ?? ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
helper_night_session_start_at: {
|
helper_night_session_start_at: {
|
||||||
execute: decision.setNightSessionStart || decision.clearNightSessionStart,
|
execute: decision.setNightSessionStart || decision.clearNightSessionStart,
|
||||||
domain: 'input_text',
|
domain: 'input_text',
|
||||||
|
|||||||
@@ -148,6 +148,10 @@
|
|||||||
"balance_required_soc_prudent": states("input_number.evcs_balance_required_soc_prudent"),
|
"balance_required_soc_prudent": states("input_number.evcs_balance_required_soc_prudent"),
|
||||||
"night_battery_charge_enabled": states("input_boolean.victron_evcs_night_battery_charge"),
|
"night_battery_charge_enabled": states("input_boolean.victron_evcs_night_battery_charge"),
|
||||||
"night_battery_done_prev": states("input_boolean.victron_evcs_night_battery_done"),
|
"night_battery_done_prev": states("input_boolean.victron_evcs_night_battery_done"),
|
||||||
|
"night_charge_mode": states("input_select.victron_evcs_night_charge_mode"),
|
||||||
|
"balance_night_vehicle_budget_kwh": states("input_number.evcs_balance_night_vehicle_budget_kwh"),
|
||||||
|
"night_budget_prev": states("input_text.victron_evcs_night_budget"),
|
||||||
|
"evcs_total_energy_kwh": states("sensor.evcs_hq2239dnt7p_total_energy"),
|
||||||
"balance_required_soc": states("input_number.evcs_balance_required_soc"),
|
"balance_required_soc": states("input_number.evcs_balance_required_soc"),
|
||||||
"balance_energy_to_cover_kwh": states("input_number.evcs_balance_energy_to_cover_kwh"),
|
"balance_energy_to_cover_kwh": states("input_number.evcs_balance_energy_to_cover_kwh"),
|
||||||
"balance_grid_energy_needed_kwh": states("input_number.evcs_balance_grid_energy_needed_kwh"),
|
"balance_grid_energy_needed_kwh": states("input_number.evcs_balance_grid_energy_needed_kwh"),
|
||||||
|
|||||||
@@ -504,6 +504,16 @@ const params = {
|
|||||||
balanceRequiredSocPrudentPct: num(input.balance_required_soc_prudent, NaN),
|
balanceRequiredSocPrudentPct: num(input.balance_required_soc_prudent, NaN),
|
||||||
nightBatteryChargeEnabled: low(input.night_battery_charge_enabled || 'off') === 'on',
|
nightBatteryChargeEnabled: low(input.night_battery_charge_enabled || 'off') === 'on',
|
||||||
nightBatteryDonePrev: low(input.night_battery_done_prev || 'off') === 'on',
|
nightBatteryDonePrev: low(input.night_battery_done_prev || 'off') === 'on',
|
||||||
|
// BUDGET VOITURE DE LA NUIT (30/09/2026, decisions du proprietaire) : ce
|
||||||
|
// que la voiture peut prendre sur la batterie sans EDF, calcule par le bilan
|
||||||
|
// (profil prudent, plancher 22 %, jusqu'a la nuit suivante), FIGE a
|
||||||
|
// l'ouverture de la session et mesure au compteur de la borne. Choix de la
|
||||||
|
// nuit : `sans_edf` (defaut : on s'arrete au budget) ou `complete` (budget
|
||||||
|
// batterie puis EDF en HC pour le reste). Toute autre valeur = sans_edf.
|
||||||
|
nightChargeMode: low(input.night_charge_mode || 'sans_edf') === 'complete' ? 'complete' : 'sans_edf',
|
||||||
|
balanceNightVehicleBudgetKwh: num(input.balance_night_vehicle_budget_kwh, NaN),
|
||||||
|
nightBudgetPrevRaw: cleanText(input.night_budget_prev),
|
||||||
|
evcsTotalEnergyKwh: num(input.evcs_total_energy_kwh, NaN),
|
||||||
balanceEnergyToCoverKwh: num(input.balance_energy_to_cover_kwh, NaN),
|
balanceEnergyToCoverKwh: num(input.balance_energy_to_cover_kwh, NaN),
|
||||||
// ⚠️ NE PAS CONFONDRE LES DEUX GRANDEURS DU BILAN.
|
// ⚠️ NE PAS CONFONDRE LES DEUX GRANDEURS DU BILAN.
|
||||||
// `balanceEnergyToCoverKwh` est l'energie que la batterie devra FOURNIR
|
// `balanceEnergyToCoverKwh` est l'energie que la batterie devra FOURNIR
|
||||||
|
|||||||
@@ -625,9 +625,44 @@ const nightBatterySurplusFloorPct = Math.max(
|
|||||||
// Sans verrou, la charge repartirait des qu'elle s'arrete : cinquieme
|
// Sans verrou, la charge repartirait des qu'elle s'arrete : cinquieme
|
||||||
// oscillateur du projet, par construction. UNE SEULE PASSE de surplus par
|
// oscillateur du projet, par construction. UNE SEULE PASSE de surplus par
|
||||||
// session de nuit, comme la recovery batterie depuis le 27/08.
|
// session de nuit, comme la recovery batterie depuis le 27/08.
|
||||||
|
// BUDGET VOITURE DE LA NUIT (30/09/2026, decisions du proprietaire).
|
||||||
|
// « Definir combien la voiture peut prendre sans utiliser EDF, et brider la
|
||||||
|
// charge a cette valeur ou autoriser une charge complete avec EDF. »
|
||||||
|
// Le bilan publie le budget ; il est FIGE au premier cycle de la session
|
||||||
|
// (avec l'index du compteur de la borne) dans input_text
|
||||||
|
// victron_evcs_night_budget = « budget|index », efface en fin de session.
|
||||||
|
// L'arret se juge sur le COMPTEUR, qui ne fait que monter : condition
|
||||||
|
// monotone, aucun oscillateur possible (meme logique que §40). Le plancher de
|
||||||
|
// SOC prudent reste un second arret, jamais retire.
|
||||||
|
const nightBudgetPrev = (() => {
|
||||||
|
const m = String(params.nightBudgetPrevRaw || '').match(/^\s*([\d.]+)\|([\d.]+)\s*$/);
|
||||||
|
return m ? { budgetKwh: Number(m[1]), refKwh: Number(m[2]) } : null;
|
||||||
|
})();
|
||||||
|
const nightBudgetCaptureOk =
|
||||||
|
nightSessionActive && !nightBudgetPrev &&
|
||||||
|
balanceMorningTargetApplied &&
|
||||||
|
Number.isFinite(params.balanceNightVehicleBudgetKwh) &&
|
||||||
|
Number.isFinite(params.evcsTotalEnergyKwh);
|
||||||
|
const nightBudget = !nightSessionActive
|
||||||
|
? null
|
||||||
|
: nightBudgetPrev || (nightBudgetCaptureOk
|
||||||
|
? { budgetKwh: Math.max(0, params.balanceNightVehicleBudgetKwh), refKwh: params.evcsTotalEnergyKwh }
|
||||||
|
: null);
|
||||||
|
const nightBudgetToWrite = nightSessionActive
|
||||||
|
? (nightBudgetCaptureOk ? `${Math.round(nightBudget.budgetKwh * 100) / 100}|${nightBudget.refKwh}` : null)
|
||||||
|
: (nightBudgetPrev ? '' : null);
|
||||||
|
const nightBudgetDeliveredKwh = nightBudget && Number.isFinite(params.evcsTotalEnergyKwh)
|
||||||
|
? Math.max(0, params.evcsTotalEnergyKwh - nightBudget.refKwh)
|
||||||
|
: null;
|
||||||
|
const nightBudgetReached =
|
||||||
|
!!nightBudget && nightBudgetDeliveredKwh !== null &&
|
||||||
|
nightBudgetDeliveredKwh >= nightBudget.budgetKwh - 0.05;
|
||||||
|
const nightChargeComplete = params.nightChargeMode === 'complete';
|
||||||
|
|
||||||
const nightBatterySurplusExhausted =
|
const nightBatterySurplusExhausted =
|
||||||
params.nightBatteryDonePrev ||
|
params.nightBatteryDonePrev ||
|
||||||
(nightSessionActive && parsed.soc <= nightBatterySurplusFloorPct);
|
(nightSessionActive && parsed.soc <= nightBatterySurplusFloorPct) ||
|
||||||
|
(nightSessionActive && nightBudgetReached);
|
||||||
|
|
||||||
const nightBatterySurplusAvailable =
|
const nightBatterySurplusAvailable =
|
||||||
nightSessionActive &&
|
nightSessionActive &&
|
||||||
@@ -644,15 +679,26 @@ const nightBatterySurplusAvailable =
|
|||||||
// decrite par le proprietaire — « quitte a fermer EDF entre 6h et 7h24 pour
|
// decrite par le proprietaire — « quitte a fermer EDF entre 6h et 7h24 pour
|
||||||
// completer » — et elle devient automatique : l'epuisement du surplus rend
|
// completer » — et elle devient automatique : l'epuisement du surplus rend
|
||||||
// `nightGridHcPreferred` vrai, donc P7 prend le relais.
|
// `nightGridHcPreferred` vrai, donc P7 prend le relais.
|
||||||
|
// « Sans EDF » (defaut) : la voiture ne prend JAMAIS le reseau la nuit ; une
|
||||||
|
// fois le budget batterie atteint (ou sans budget exploitable), elle attend le
|
||||||
|
// soleil. « Charge complete » : EDF en HC finit la charge, comme avant.
|
||||||
const nightGridHcPreferred =
|
const nightGridHcPreferred =
|
||||||
nightSessionActive &&
|
nightSessionActive &&
|
||||||
params.allowGridHcNight &&
|
params.allowGridHcNight &&
|
||||||
|
nightChargeComplete &&
|
||||||
|
!vehicleChargeCompleted &&
|
||||||
|
!nightBatterySurplusAvailable;
|
||||||
|
|
||||||
|
const nightCarWaitsNoGrid =
|
||||||
|
nightSessionActive &&
|
||||||
|
!nightChargeComplete &&
|
||||||
!vehicleChargeCompleted &&
|
!vehicleChargeCompleted &&
|
||||||
!nightBatterySurplusAvailable;
|
!nightBatterySurplusAvailable;
|
||||||
|
|
||||||
const batteryAssistAllowed =
|
const batteryAssistAllowed =
|
||||||
nightSessionActive &&
|
nightSessionActive &&
|
||||||
!nightGridHcPreferred &&
|
!nightGridHcPreferred &&
|
||||||
|
!nightCarWaitsNoGrid &&
|
||||||
parsed.soc > batteryHardFloorPct &&
|
parsed.soc > batteryHardFloorPct &&
|
||||||
parsed.soc > gridTakeoverTriggerPct &&
|
parsed.soc > gridTakeoverTriggerPct &&
|
||||||
!nightTakeoverLatched &&
|
!nightTakeoverLatched &&
|
||||||
@@ -794,6 +840,12 @@ const nightPreferredSourceMode =
|
|||||||
!nightSessionActive
|
!nightSessionActive
|
||||||
? 'blocked'
|
? 'blocked'
|
||||||
: vehicleChargeCompleted
|
: vehicleChargeCompleted
|
||||||
|
? 'blocked'
|
||||||
|
// « Sans EDF » ne bloque la voiture que si EDF n'est PAS deja engage pour
|
||||||
|
// la batterie (plancher dur, cible du matin, session du bilan, verrou) :
|
||||||
|
// proteger le materiel prime (regle du proprietaire, 05/09), et EDF deja
|
||||||
|
// ferme en HC, la voiture en profite au meme tarif.
|
||||||
|
: nightCarWaitsNoGrid && !nightGridTakeoverNeeded
|
||||||
? 'blocked'
|
? 'blocked'
|
||||||
: batteryAssistAllowed
|
: batteryAssistAllowed
|
||||||
? 'battery_assist_night'
|
? 'battery_assist_night'
|
||||||
@@ -1189,6 +1241,12 @@ return [{
|
|||||||
nightBatterySurplusFloorPct,
|
nightBatterySurplusFloorPct,
|
||||||
nightBatterySurplusAvailable,
|
nightBatterySurplusAvailable,
|
||||||
nightBatterySurplusExhausted,
|
nightBatterySurplusExhausted,
|
||||||
|
nightBudgetKwh: nightBudget ? nightBudget.budgetKwh : null,
|
||||||
|
nightBudgetDeliveredKwh,
|
||||||
|
nightBudgetReached,
|
||||||
|
nightBudgetToWrite,
|
||||||
|
nightChargeMode: params.nightChargeMode,
|
||||||
|
nightCarWaitsNoGrid,
|
||||||
nightGridSessionCommitted,
|
nightGridSessionCommitted,
|
||||||
middayVehicleGridNeeded,
|
middayVehicleGridNeeded,
|
||||||
nightGridSessionUncovered,
|
nightGridSessionUncovered,
|
||||||
|
|||||||
@@ -112,6 +112,9 @@ const SUMMARIZE = {
|
|||||||
// Maison sur le reseau pendant la fenetre HC de nuit (29/09).
|
// Maison sur le reseau pendant la fenetre HC de nuit (29/09).
|
||||||
nightHcActive: o.nightHcImport ? o.nightHcImport.active : false,
|
nightHcActive: o.nightHcImport ? o.nightHcImport.active : false,
|
||||||
nightHcHouseKwh: o.nightHcImport ? o.nightHcImport.houseKwh : null,
|
nightHcHouseKwh: o.nightHcImport ? o.nightHcImport.houseKwh : null,
|
||||||
|
// Budget voiture de la nuit sans EDF (30/09).
|
||||||
|
nightVehicleBudgetActive: o.nightVehicleBudget ? o.nightVehicleBudget.active : false,
|
||||||
|
nightVehicleBudgetKwh: o.nightVehicleBudget ? o.nightVehicleBudget.kwh : null,
|
||||||
// Voiture branchee en HC, depart avant la prochaine HC (28/09).
|
// Voiture branchee en HC, depart avant la prochaine HC (28/09).
|
||||||
vehicleActive: o.vehicleMidday ? o.vehicleMidday.active : false,
|
vehicleActive: o.vehicleMidday ? o.vehicleMidday.active : false,
|
||||||
vehicleNeedKwh: o.vehicleMidday ? o.vehicleMidday.needKwh : null,
|
vehicleNeedKwh: o.vehicleMidday ? o.vehicleMidday.needKwh : null,
|
||||||
|
|||||||
@@ -73,6 +73,16 @@ function jeep(snapshot, niveau, extra = {}) {
|
|||||||
vehicle_delivered_since_level_kwh: 0 }, extra);
|
vehicle_delivered_since_level_kwh: 0 }, extra);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const NUIT_HC_2809 = { night_hc_start_ms: Date.parse('2026-09-28T01:24:00+02:00'),
|
||||||
|
night_hc_end_ms: Date.parse('2026-09-28T07:24:00+02:00') };
|
||||||
|
// Lendemain ensoleille : production du 28/09 x 1,5 (~49 kWh), le reste inchange.
|
||||||
|
function soleil2809(snapshot) {
|
||||||
|
snapshot.horizon = snapshot.horizon.map(sl =>
|
||||||
|
new Date(sl.startMs).toLocaleDateString('sv-SE', { timeZone: 'Europe/Paris' }) === '2026-09-28'
|
||||||
|
? { ...sl, expectedKwh: FS_2809[sl.hour] * 1.5 } : sl);
|
||||||
|
return snapshot;
|
||||||
|
}
|
||||||
|
|
||||||
export const balanceScenarios = [
|
export const balanceScenarios = [
|
||||||
{
|
{
|
||||||
// Le parc a change deux fois en une semaine et rechangera cet hiver : le
|
// Le parc a change deux fois en une semaine et rechangera cet hiver : le
|
||||||
@@ -593,6 +603,38 @@ export const balanceScenarios = [
|
|||||||
night_hc_start_ms: Date.parse('2026-09-28T01:24:00+02:00'), night_hc_end_ms: Date.parse('2026-09-28T07:24:00+02:00') }),
|
night_hc_start_ms: Date.parse('2026-09-28T01:24:00+02:00'), night_hc_end_ms: Date.parse('2026-09-28T07:24:00+02:00') }),
|
||||||
expect: { usable: true, nightHcActive: true, nightHcHouseKwh: 2.68 },
|
expect: { usable: true, nightHcActive: true, nightHcHouseKwh: 2.68 },
|
||||||
},
|
},
|
||||||
|
// ======== BUDGET VOITURE DE LA NUIT SANS EDF (30/09/2026) ========
|
||||||
|
// Decisions du proprietaire : profil prudent (p80), plancher 22 %, jusqu'a la
|
||||||
|
// nuit suivante. Attendus calcules par un script Python independant (meme
|
||||||
|
// trajectoire, creux a 9 h). Lendemain ensoleille = production du 28/09 x 1,5.
|
||||||
|
{
|
||||||
|
node: 'BALANCE',
|
||||||
|
id: 'bilan-budget-voiture-nuit-soleil',
|
||||||
|
label: '01:25, SOC 57, lendemain ensoleille : la voiture peut prendre 4,21 kWh sur la batterie',
|
||||||
|
snapshot: soleil2809(Object.assign(snap2709('2026-09-28T01:25:00+02:00', 57, null), NUIT_HC_2809)),
|
||||||
|
expect: { usable: true, nightVehicleBudgetActive: true, nightVehicleBudgetKwh: 4.21 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: 'BALANCE',
|
||||||
|
id: 'bilan-budget-voiture-nuit-soc-bas',
|
||||||
|
label: '01:25, SOC 45 : il ne reste que 0,61 kWh au-dessus du creux de 9 h',
|
||||||
|
snapshot: soleil2809(Object.assign(snap2709('2026-09-28T01:25:00+02:00', 45, null), NUIT_HC_2809)),
|
||||||
|
expect: { usable: true, nightVehicleBudgetActive: true, nightVehicleBudgetKwh: 0.61 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: 'BALANCE',
|
||||||
|
id: 'bilan-budget-voiture-nuit-lendemain-sombre',
|
||||||
|
label: 'Lendemain sombre (27-28/09) : la batterie ne tiendrait pas la nuit suivante, budget nul',
|
||||||
|
snapshot: Object.assign(snap2709('2026-09-27T23:00:00+02:00', 52, null), NUIT_HC_2809),
|
||||||
|
expect: { usable: true, nightVehicleBudgetActive: true, nightVehicleBudgetKwh: 0 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: 'BALANCE',
|
||||||
|
id: 'bilan-budget-voiture-fenetre-inconnue',
|
||||||
|
label: 'Fenetre HC de nuit non transmise : pas de budget (le controleur ne donne rien)',
|
||||||
|
snapshot: snap2709('2026-09-28T01:25:00+02:00', 57, null),
|
||||||
|
expect: { usable: true, nightVehicleBudgetActive: false, nightVehicleBudgetKwh: null },
|
||||||
|
},
|
||||||
{
|
{
|
||||||
node: 'BALANCE',
|
node: 'BALANCE',
|
||||||
id: 'bilan-hc-nuit-fenetre-inconnue',
|
id: 'bilan-hc-nuit-fenetre-inconnue',
|
||||||
|
|||||||
@@ -122,6 +122,8 @@ function summarize(out) {
|
|||||||
sessionCommittedService: calls.helper_night_grid_session_committed?.execute
|
sessionCommittedService: calls.helper_night_grid_session_committed?.execute
|
||||||
? calls.helper_night_grid_session_committed.service
|
? calls.helper_night_grid_session_committed.service
|
||||||
: null,
|
: null,
|
||||||
|
// Budget voiture de la nuit (30/09) : valeur ecrite ce cycle, null sinon.
|
||||||
|
nightBudgetWrite: calls.helper_night_budget?.execute ? calls.helper_night_budget.data.value : null,
|
||||||
// Consigne de puissance reseau ecrite ce cycle (null = aucune ecriture).
|
// Consigne de puissance reseau ecrite ce cycle (null = aucune ecriture).
|
||||||
gridSetpointW: calls.grid_power_setpoint?.execute
|
gridSetpointW: calls.grid_power_setpoint?.execute
|
||||||
? calls.grid_power_setpoint.data.value
|
? calls.grid_power_setpoint.data.value
|
||||||
|
|||||||
@@ -19,7 +19,28 @@ const EVENING = '2026-08-08T18:00:00+02:00';
|
|||||||
// donc on exprime l'âge de la transition par rapport à cet instant simulé.
|
// donc on exprime l'âge de la transition par rapport à cet instant simulé.
|
||||||
const MORNING_TS = Date.parse(MORNING) / 1000;
|
const MORNING_TS = Date.parse(MORNING) / 1000;
|
||||||
|
|
||||||
|
// Budget voiture de la nuit (30/09) : releve du 30/09 01:25.
|
||||||
|
const BUDGET_NUIT_BASE = {
|
||||||
|
soc_percent: '57', allow_grid_hc_night: 'on',
|
||||||
|
night_battery_charge_enabled: 'on', night_battery_done_prev: 'off',
|
||||||
|
grid_state: 'off', victron_acin1_available: '0',
|
||||||
|
battery_current_a: '-16', evcs_charging_switch: 'off',
|
||||||
|
balance_status: 'ok', balance_last_run: '30/09 01:20',
|
||||||
|
balance_required_soc: '39.2', balance_required_soc_prudent: '44.7',
|
||||||
|
balance_energy_to_cover_kwh: '5.2', balance_night_vehicle_budget_kwh: '3.7',
|
||||||
|
};
|
||||||
|
const EN_CHARGE_BATTERIE = {
|
||||||
|
evcs_charging_switch: 'on', charge_permission_now: 'on', control_latch: 'on',
|
||||||
|
// P12 charge doucement : 6 A, batterie a -25 A (le garde dur de la bande
|
||||||
|
// 40-60 % est a -30 A).
|
||||||
|
evcs_current_a: '6', evcs_ac_power_w: '1400', battery_current_a: '-25',
|
||||||
|
prev_surplus_state: 'charging_hold_battery_assist_night',
|
||||||
|
};
|
||||||
const VEHICLE_NIGHT = {
|
const VEHICLE_NIGHT = {
|
||||||
|
// 30/09 : les scenarios de nuit historiques decrivent le mode « charge
|
||||||
|
// complete » (EDF finit la charge). Le mode par defaut « sans EDF » a ses
|
||||||
|
// propres scenarios (budget-*).
|
||||||
|
night_charge_mode: 'complete',
|
||||||
evcs_vehicle_connected: 'on',
|
evcs_vehicle_connected: 'on',
|
||||||
evcs_device_connected: 'on',
|
evcs_device_connected: 'on',
|
||||||
pv_power_w: '0',
|
pv_power_w: '0',
|
||||||
@@ -29,6 +50,7 @@ const VEHICLE_NIGHT = {
|
|||||||
vebus_ac_out_l1_power_w: '700',
|
vebus_ac_out_l1_power_w: '700',
|
||||||
battery_current_a: '-14',
|
battery_current_a: '-14',
|
||||||
};
|
};
|
||||||
|
const BUDGET_NUIT = { ...VEHICLE_NIGHT, ...BUDGET_NUIT_BASE };
|
||||||
|
|
||||||
export const scenarios = [
|
export const scenarios = [
|
||||||
|
|
||||||
@@ -406,7 +428,7 @@ export const scenarios = [
|
|||||||
overrides: {
|
overrides: {
|
||||||
evcs_vehicle_connected: 'on', evcs_device_connected: 'on',
|
evcs_vehicle_connected: 'on', evcs_device_connected: 'on',
|
||||||
night_session_active: 'on',
|
night_session_active: 'on',
|
||||||
allow_grid_hc_night: 'on',
|
allow_grid_hc_night: 'on', night_charge_mode: 'complete',
|
||||||
soc_percent: '55', pv_power_w: '0', pv_power_10m_avg_w: '0',
|
soc_percent: '55', pv_power_w: '0', pv_power_10m_avg_w: '0',
|
||||||
pv_trend_w: '0', battery_current_a: '0',
|
pv_trend_w: '0', battery_current_a: '0',
|
||||||
house_ac_power_w: '800', vebus_ac_out_l1_power_w: '800',
|
house_ac_power_w: '800', vebus_ac_out_l1_power_w: '800',
|
||||||
@@ -3051,6 +3073,73 @@ export const scenarios = [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// =====================================================
|
||||||
|
// BUDGET VOITURE DE LA NUIT (30/09/2026, decisions du proprietaire)
|
||||||
|
// =====================================================
|
||||||
|
// « Definir combien la voiture peut prendre sans utiliser EDF, et brider la
|
||||||
|
// charge a cette valeur ou autoriser une charge complete avec EDF. » Par
|
||||||
|
// defaut « sans EDF » ; « complete » = budget batterie puis EDF. Budget fige
|
||||||
|
// a l'ouverture avec l'index du compteur de la borne ; arret au compteur.
|
||||||
|
// Releve de reference : 30/09 01:25, SOC 57, requis 39,2, prudent 44,7.
|
||||||
|
{
|
||||||
|
id: 'budget-fige-a-l-ouverture',
|
||||||
|
label: 'Nuit HC, sans EDF, budget 3,7 kWh publie : fige avec l index 4000, la voiture part sur la batterie',
|
||||||
|
time: '2026-09-30T01:25:00+02:00',
|
||||||
|
overrides: { ...BUDGET_NUIT, balance_last_run: '30/09 01:20', night_charge_mode: 'sans_edf', night_budget_prev: '', evcs_total_energy_kwh: '4000' },
|
||||||
|
expect: { profile: 'night_hc', sourceMode: 'battery_assist_night',
|
||||||
|
state: 'start_battery_assist_night_min_current', desiredCharging: true,
|
||||||
|
nightBudgetWrite: '3.7|4000', takeoverNeeded: false, edfOnAction: false },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'budget-pas-atteint-la-charge-continue',
|
||||||
|
label: 'Budget 3,7, 2 kWh delivres, SOC 52 au-dessus du prudent : la voiture continue sur la batterie',
|
||||||
|
time: '2026-09-30T02:10:00+02:00',
|
||||||
|
overrides: { ...BUDGET_NUIT, balance_last_run: '30/09 02:05', ...EN_CHARGE_BATTERIE, soc_percent: '52', night_charge_mode: 'sans_edf',
|
||||||
|
night_budget_prev: '3.7|4000', evcs_total_energy_kwh: '4002' },
|
||||||
|
expect: { sourceMode: 'battery_assist_night', desiredCharging: true, nightBudgetWrite: null,
|
||||||
|
takeoverNeeded: false, edfOnAction: false },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'budget-atteint-sans-edf-la-voiture-attend',
|
||||||
|
label: 'Budget 3,7 atteint (3,75 delivres), SOC 50 encore au-dessus du prudent, sans EDF : arret, pas de reseau',
|
||||||
|
time: '2026-09-30T02:30:00+02:00',
|
||||||
|
overrides: { ...BUDGET_NUIT, balance_last_run: '30/09 02:25', ...EN_CHARGE_BATTERIE, soc_percent: '50', night_charge_mode: 'sans_edf',
|
||||||
|
night_budget_prev: '3.7|4000', evcs_total_energy_kwh: '4003.75' },
|
||||||
|
expect: { sourceMode: 'blocked', desiredCharging: false, takeoverNeeded: false, edfOnAction: false },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'budget-atteint-complete-edf-finit',
|
||||||
|
label: 'CONTREFACTUEL — meme nuit en charge complete : EDF prend le relais en HC',
|
||||||
|
time: '2026-09-30T02:30:00+02:00',
|
||||||
|
overrides: { ...BUDGET_NUIT, balance_last_run: '30/09 02:25', ...EN_CHARGE_BATTERIE, soc_percent: '50', night_charge_mode: 'complete',
|
||||||
|
night_budget_prev: '3.7|4000', evcs_total_energy_kwh: '4003.75' },
|
||||||
|
expect: { sourceMode: 'grid_hc_allowed', takeoverNeeded: true, edfOnAction: true },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'budget-sans-edf-plancher-dur-edf-protege',
|
||||||
|
label: 'Sans EDF mais SOC 20 sous le plancher dur : EDF se ferme quand meme pour la batterie',
|
||||||
|
time: '2026-09-30T04:00:00+02:00',
|
||||||
|
overrides: { ...BUDGET_NUIT, balance_last_run: '30/09 03:55', soc_percent: '20', night_charge_mode: 'sans_edf',
|
||||||
|
night_budget_prev: '3.7|4000', evcs_total_energy_kwh: '4003.75' },
|
||||||
|
expect: { sourceMode: 'grid_forced', edfOnAction: true },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'budget-bilan-perime-sans-edf-rien',
|
||||||
|
label: 'Sans EDF, bilan vieux de 3 h : aucun budget fige, la voiture attend, pas de reseau',
|
||||||
|
time: '2026-09-30T01:25:00+02:00',
|
||||||
|
overrides: { ...BUDGET_NUIT, night_charge_mode: 'sans_edf', balance_last_run: '29/09 22:20',
|
||||||
|
night_budget_prev: '', evcs_total_energy_kwh: '4000' },
|
||||||
|
expect: { sourceMode: 'blocked', desiredCharging: false, nightBudgetWrite: null,
|
||||||
|
takeoverNeeded: false, edfOnAction: false },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'budget-efface-en-fin-de-session',
|
||||||
|
label: 'Fin de fenetre HC (08:00) : le budget fige est efface',
|
||||||
|
time: '2026-09-30T08:00:00+02:00',
|
||||||
|
overrides: { ...BUDGET_NUIT, balance_last_run: '30/09 07:55', night_budget_prev: '3.7|4000', evcs_total_energy_kwh: '4003.75' },
|
||||||
|
expect: { nightBudgetWrite: '' },
|
||||||
|
},
|
||||||
|
|
||||||
// ===================================================================
|
// ===================================================================
|
||||||
// BOOST 28 A du 18/09/2026 — le verrou survivait a sa cause (HANDOFF)
|
// BOOST 28 A du 18/09/2026 — le verrou survivait a sa cause (HANDOFF)
|
||||||
// Releve reel : clic BOOST 13:08:50, contacteur ferme 13:09:53, garde
|
// Releve reel : clic BOOST 13:08:50, contacteur ferme 13:09:53, garde
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user