Budget de nuit borne au plancher prudent ; sans EDF : voiture bloquee meme quand EDF se ferme pour la batterie (session batterie seule)
This commit is contained in:
37
HANDOFF.md
37
HANDOFF.md
@@ -1628,5 +1628,40 @@ reseau + decharge - charge) : elle inclut la borne et les pertes de l'onduleur.
|
|||||||
a lieu un jour : verifier le selecteur vehicule (§47) et que les deux integrales batterie
|
a lieu un jour : verifier le selecteur vehicule (§47) et que les deux integrales batterie
|
||||||
repartent de leur derniere valeur (elles restaurent leur etat).
|
repartent de leur derniere valeur (elles restaurent leur etat).
|
||||||
|
|
||||||
|
### 04/10 matin — Nuit du budget : la JEEP chargee a 100 % sur EDF, deux defauts de ma conception
|
||||||
|
**Ce qui s'est passe** (mode sans_edf) : budget fige a 01:25 = **1,41 kWh** (SOC 47) ; JEEP sur
|
||||||
|
batterie, **arret au budget a 02:31** (1,40 kWh) — l'arret au compteur MARCHE. Puis a 02:57 SOC
|
||||||
|
39 sous la cible du matin 39,5 : reprise reseau de nuit, EDF ferme (02:58, session unique
|
||||||
|
jusqu'a 07:24) ; l'exception du 30/09 (« EDF deja engage pour la batterie -> la voiture en
|
||||||
|
profite ») a relance la JEEP sur le reseau : **4,7 kWh jusqu'au plein (04:02)**. Import depuis
|
||||||
|
02:58 : 5,6 kWh (HC). JEEP debranchee 05:57, pleine (54 % + 1,4 + 4,7 kWh).
|
||||||
|
**Cause 1** : le budget (creux de la trajectoire p80 au-dessus de 22 %) ne respectait pas le
|
||||||
|
critere qui ferme EDF : a 01:20, requis 42,5 (p50) / 43,6 (prudent) pour SOC 47 -> marge
|
||||||
|
~1,0 kWh, budget 1,41. La voiture a mange toute la marge ; une maison conforme au profil a
|
||||||
|
suffi a toucher la cible. Deux calculs du bilan jamais confrontes.
|
||||||
|
**Cause 2** : l'exception de securite du 30/09 etait trop large — elle devait garantir que
|
||||||
|
« sans EDF » n'empeche jamais EDF de proteger la BATTERIE, elle laissait aussi la VOITURE
|
||||||
|
charger sur le reseau.
|
||||||
|
**Correctifs (accord du proprietaire, deployes 06:08)** :
|
||||||
|
1. `BALANCE.js` : budget = min(creux, energie au-dessus du SOC requis PRUDENT) — le plancher
|
||||||
|
meme de P12. Bilan 76/76 : soleil 4,21 -> **3,75** et SOC bas 0,61 -> **0,15** kWh, verifies
|
||||||
|
a la main ((57 - 44,5) x 0,30 et (45 - 44,5) x 0,30), mutation qui mord.
|
||||||
|
2. Option A : en sans_edf la voiture reste `blocked` meme quand EDF se ferme pour la batterie.
|
||||||
|
Piege rencontre : la fermeture d'EDF (`edf_general_ok_on`) et la consigne (`gridSessionActive`)
|
||||||
|
suivaient la source de la VOITURE — bloquer la voiture coupait aussi la batterie (golden
|
||||||
|
`budget-sans-edf-plancher-dur-edf-protege` et `depart-matin-…-sous-la-cible` tombes). Nouveau
|
||||||
|
drapeau `nightBatteryGridOnly` (session de nuit && voiture en attente sans EDF && takeover) :
|
||||||
|
EDF + session reseau pour la batterie seule (WINDOWS, passe par BATTERY_CLOUD_LOCKS,
|
||||||
|
HA_SERVICE_CALLS_OUTPUT ; raison « sans EDF : EDF ferme pour la batterie seule, la voiture
|
||||||
|
attend le soleil »). Golden **136/136** (+1 : la nuit du 03-04/10 rejouee), attendus des deux
|
||||||
|
scenarios passes a `blocked` + EDF ferme, deux mutations qui mordent (3 scenarios chacune).
|
||||||
|
golden-acm 20/20, hysteresis 24/24. Executions n8n en succes apres deploiement.
|
||||||
|
**Tableau Energie, defaut de mon import** : l'import des statistiques AVANT la premiere heure
|
||||||
|
compilee ne suffit pas — HA est reparti de zero a 01:00 (sauts -1 615 / -335 / -481 / -465 kWh
|
||||||
|
sur la journee du 04/10). Corrige par `recorder/adjust_sum_statistics` a partir de 23:00Z
|
||||||
|
(+1 614,90 / +335,00 / +481,29 / +466,00, decharge 01:00-02:00 = 1,50 kWh reels d'apres la
|
||||||
|
base) ; heures continues verifiees. ⚠️ Lecon : apres un import sur une entite neuve,
|
||||||
|
verifier la premiere heure compilee et corriger par ajustement.
|
||||||
|
|
||||||
---
|
---
|
||||||
*Document mis a jour le : 04/10/2026 (~01:40) — tableau Energie complete (Sud/Ouest, batterie par integration, borne ; aucun redemarrage HA) ; kilometrage des vehicules (km/kWh, capacite, releves de reference, agent cable 15/15) ; a verifier le 04/10 au matin : nuit du budget JEEP ; concierge : vehicule non confirme demande, heure de saisie ; Grafana vehicules en tableau ; Grafana vehicules : ZERO et Invite ajoutes, session 16:46 reetiquetee ZERO ; prevision SOC 10 h ~35 % ; concierge fiable : niveau note par le script, une ligne, dedoublonnage, simulation par drapeau ; agent : message incompris = question, bourse sur demande explicite (banc final 6/6) ; a verifier : nuit du samedi 03 au dimanche 04/10 (budget < besoin JEEP), cron orange-cloture lundi 05/10 apres 17:40, comparaison VRM / Forecast.Solar lundi 05/10*
|
*Document mis a jour le : 04/10/2026 (~06:15) — nuit du budget : budget borne au plancher prudent, sans EDF = voiture bloquee meme EDF ferme (batterie seule) ; Energie : sauts corriges ; tableau Energie complete (Sud/Ouest, batterie par integration, borne ; aucun redemarrage HA) ; kilometrage des vehicules (km/kWh, capacite, releves de reference, agent cable 15/15) ; a verifier le 04/10 au matin : nuit du budget JEEP ; concierge : vehicule non confirme demande, heure de saisie ; Grafana vehicules en tableau ; Grafana vehicules : ZERO et Invite ajoutes, session 16:46 reetiquetee ZERO ; prevision SOC 10 h ~35 % ; concierge fiable : niveau note par le script, une ligne, dedoublonnage, simulation par drapeau ; agent : message incompris = question, bourse sur demande explicite (banc final 6/6) ; a verifier : nuit du samedi 03 au dimanche 04/10 (budget < besoin JEEP), cron orange-cloture lundi 05/10 apres 17:40, comparaison VRM / Forecast.Solar lundi 05/10*
|
||||||
|
|||||||
@@ -460,7 +460,17 @@ if (nightHcActive && Number.isFinite(socPct)) {
|
|||||||
if (coupes[i + 1] >= depuis) creux = Math.min(creux, reserve);
|
if (coupes[i + 1] >= depuis) creux = Math.min(creux, reserve);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nightVehicleBudgetKwh = Number.isFinite(creux) ? Math.max(0, creux) : null;
|
// BORNE PAR LE PLANCHER PRUDENT (04/10/2026). Nuit du 03-04/10 : SOC 47,
|
||||||
|
// prudent 43,6 -> ~1,0 kWh de marge, mais le creux a donne 1,41 kWh. La
|
||||||
|
// voiture a pris toute la marge, la batterie a touche la cible du matin a
|
||||||
|
// 02:57 et la reprise reseau a ferme EDF. Le budget ne peut donc jamais
|
||||||
|
// depasser l'energie au-dessus du SOC requis PRUDENT, celui-la meme que la
|
||||||
|
// voiture n'a pas le droit de franchir en assistance batterie (P12) : les
|
||||||
|
// deux criteres sont desormais les memes par construction.
|
||||||
|
const margePrudente = Number.isFinite(prudent.requiredSocPct)
|
||||||
|
? (socPct > prudent.requiredSocPct ? energyBetweenSoc(prudent.requiredSocPct, socPct) : 0)
|
||||||
|
: 0;
|
||||||
|
nightVehicleBudgetKwh = Number.isFinite(creux) ? Math.max(0, Math.min(creux, margePrudente)) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
|
|||||||
@@ -1134,6 +1134,7 @@ return [{
|
|||||||
nightBudgetToWrite: nightPrev.nightBudgetToWrite ?? null,
|
nightBudgetToWrite: nightPrev.nightBudgetToWrite ?? null,
|
||||||
nightChargeMode: nightPrev.nightChargeMode || 'sans_edf',
|
nightChargeMode: nightPrev.nightChargeMode || 'sans_edf',
|
||||||
nightCarWaitsNoGrid: !!nightPrev.nightCarWaitsNoGrid,
|
nightCarWaitsNoGrid: !!nightPrev.nightCarWaitsNoGrid,
|
||||||
|
nightBatteryGridOnly: !!nightPrev.nightBatteryGridOnly,
|
||||||
maxBatteryDischargePoints,
|
maxBatteryDischargePoints,
|
||||||
gridTakeoverTriggerPct,
|
gridTakeoverTriggerPct,
|
||||||
|
|
||||||
|
|||||||
@@ -304,7 +304,8 @@ const reason = [...decision.reason];
|
|||||||
if (night.nightBudgetKwh !== null && night.nightBudgetKwh !== undefined) {
|
if (night.nightBudgetKwh !== null && night.nightBudgetKwh !== undefined) {
|
||||||
const f = (x) => String(Math.round(x * 100) / 100).replace('.', ',');
|
const f = (x) => String(Math.round(x * 100) / 100).replace('.', ',');
|
||||||
reason.push(`Budget batterie nuit ${f(night.nightBudgetDeliveredKwh ?? 0)}/${f(night.nightBudgetKwh)} kWh` +
|
reason.push(`Budget batterie nuit ${f(night.nightBudgetDeliveredKwh ?? 0)}/${f(night.nightBudgetKwh)} kWh` +
|
||||||
(night.nightCarWaitsNoGrid ? ' — atteint, sans EDF : la voiture attend le soleil'
|
(night.nightBatteryGridOnly ? ' — sans EDF : EDF ferme pour la batterie seule, la voiture attend le soleil'
|
||||||
|
: night.nightCarWaitsNoGrid ? ' — atteint, sans EDF : la voiture attend le soleil'
|
||||||
: night.nightBudgetReached ? ' — atteint, EDF finit la charge' : ''));
|
: night.nightBudgetReached ? ' — atteint, EDF finit la charge' : ''));
|
||||||
} else if (night.nightCarWaitsNoGrid) {
|
} else if (night.nightCarWaitsNoGrid) {
|
||||||
reason.push('Pas de budget batterie exploitable, sans EDF : la voiture attend le soleil');
|
reason.push('Pas de budget batterie exploitable, sans EDF : la voiture attend le soleil');
|
||||||
@@ -365,7 +366,9 @@ const gridSessionActive =
|
|||||||
(
|
(
|
||||||
context.sourceMode === 'grid_forced' ||
|
context.sourceMode === 'grid_forced' ||
|
||||||
context.sourceMode === 'grid_hc_allowed' ||
|
context.sourceMode === 'grid_hc_allowed' ||
|
||||||
night.nightGridSessionCommitted === true
|
night.nightGridSessionCommitted === true ||
|
||||||
|
// Batterie seule sur le reseau, voiture bloquee « sans EDF » (04/10).
|
||||||
|
night.nightBatteryGridOnly === true
|
||||||
);
|
);
|
||||||
|
|
||||||
// =====================================================
|
// =====================================================
|
||||||
@@ -1471,7 +1474,8 @@ return [{
|
|||||||
// =================================================
|
// =================================================
|
||||||
edf_general_ok_on: {
|
edf_general_ok_on: {
|
||||||
execute:
|
execute:
|
||||||
['grid_forced', 'grid_hc_allowed'].includes(context.sourceMode) &&
|
(['grid_forced', 'grid_hc_allowed'].includes(context.sourceMode) ||
|
||||||
|
night.nightBatteryGridOnly === true) &&
|
||||||
!parsed.gridAvailable,
|
!parsed.gridAvailable,
|
||||||
domain: 'switch',
|
domain: 'switch',
|
||||||
service: 'turn_on',
|
service: 'turn_on',
|
||||||
|
|||||||
@@ -859,11 +859,14 @@ const nightPreferredSourceMode =
|
|||||||
? 'blocked'
|
? 'blocked'
|
||||||
: vehicleChargeCompleted
|
: vehicleChargeCompleted
|
||||||
? 'blocked'
|
? 'blocked'
|
||||||
// « Sans EDF » ne bloque la voiture que si EDF n'est PAS deja engage pour
|
// « Sans EDF » : la voiture ne prend JAMAIS le reseau la nuit, MEME quand
|
||||||
// la batterie (plancher dur, cible du matin, session du bilan, verrou) :
|
// EDF se ferme pour la batterie (plancher dur, cible du matin, session du
|
||||||
// proteger le materiel prime (regle du proprietaire, 05/09), et EDF deja
|
// bilan, verrou). Decision du proprietaire le 04/10 (option A) : la nuit du
|
||||||
// ferme en HC, la voiture en profite au meme tarif.
|
// 03-04/10, EDF ferme a 02:57 pour la batterie, l'ancienne exception a
|
||||||
: nightCarWaitsNoGrid && !nightGridTakeoverNeeded
|
// laisse la JEEP prendre 4,7 kWh au reseau jusqu'au plein. La protection
|
||||||
|
// du materiel reste entiere : EDF se ferme quand meme (takeover), seule la
|
||||||
|
// voiture attend le soleil.
|
||||||
|
: nightCarWaitsNoGrid
|
||||||
? 'blocked'
|
? 'blocked'
|
||||||
: batteryAssistAllowed
|
: batteryAssistAllowed
|
||||||
? 'battery_assist_night'
|
? 'battery_assist_night'
|
||||||
@@ -875,6 +878,16 @@ const nightPreferredSourceMode =
|
|||||||
? 'grid_forced'
|
? 'grid_forced'
|
||||||
: 'grid_hc_allowed';
|
: 'grid_hc_allowed';
|
||||||
|
|
||||||
|
// « Sans EDF » ET EDF necessaire pour la BATTERIE (04/10/2026, option A du
|
||||||
|
// proprietaire) : la voiture reste bloquee, mais la batterie a sa session
|
||||||
|
// reseau. Sans ce drapeau, la fermeture d'EDF et la consigne de recharge, qui
|
||||||
|
// suivent la source de la VOITURE, seraient perdues avec elle (golden
|
||||||
|
// budget-sans-edf-plancher-dur-edf-protege, depart-matin-…-sous-la-cible).
|
||||||
|
const nightBatteryGridOnly =
|
||||||
|
nightSessionActive &&
|
||||||
|
nightCarWaitsNoGrid &&
|
||||||
|
nightGridTakeoverNeeded;
|
||||||
|
|
||||||
const batteryRecoveryAllowedNow =
|
const batteryRecoveryAllowedNow =
|
||||||
nightSessionActive &&
|
nightSessionActive &&
|
||||||
nightGridTakeoverNeeded &&
|
nightGridTakeoverNeeded &&
|
||||||
@@ -1265,6 +1278,7 @@ return [{
|
|||||||
nightBudgetToWrite,
|
nightBudgetToWrite,
|
||||||
nightChargeMode: params.nightChargeMode,
|
nightChargeMode: params.nightChargeMode,
|
||||||
nightCarWaitsNoGrid,
|
nightCarWaitsNoGrid,
|
||||||
|
nightBatteryGridOnly,
|
||||||
nightGridSessionCommitted,
|
nightGridSessionCommitted,
|
||||||
middayVehicleGridNeeded,
|
middayVehicleGridNeeded,
|
||||||
nightGridSessionUncovered,
|
nightGridSessionUncovered,
|
||||||
|
|||||||
@@ -610,16 +610,16 @@ export const balanceScenarios = [
|
|||||||
{
|
{
|
||||||
node: 'BALANCE',
|
node: 'BALANCE',
|
||||||
id: 'bilan-budget-voiture-nuit-soleil',
|
id: 'bilan-budget-voiture-nuit-soleil',
|
||||||
label: '01:25, SOC 57, lendemain ensoleille : la voiture peut prendre 4,21 kWh sur la batterie',
|
label: '01:25, SOC 57, lendemain ensoleille : budget borne par le plancher prudent 44,5 % -> (57 - 44,5) x 0,30 = 3,75 kWh (creux seul : 4,21, avant le 04/10)',
|
||||||
snapshot: soleil2809(Object.assign(snap2709('2026-09-28T01:25:00+02:00', 57, null), NUIT_HC_2809)),
|
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 },
|
expect: { usable: true, nightVehicleBudgetActive: true, nightVehicleBudgetKwh: 3.75, prudentRequiredSocPct: 44.5 },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
node: 'BALANCE',
|
node: 'BALANCE',
|
||||||
id: 'bilan-budget-voiture-nuit-soc-bas',
|
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',
|
label: '01:25, SOC 45 : borne par le plancher prudent -> (45 - 44,5) x 0,30 = 0,15 kWh (creux seul : 0,61, avant le 04/10)',
|
||||||
snapshot: soleil2809(Object.assign(snap2709('2026-09-28T01:25:00+02:00', 45, null), NUIT_HC_2809)),
|
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 },
|
expect: { usable: true, nightVehicleBudgetActive: true, nightVehicleBudgetKwh: 0.15, prudentRequiredSocPct: 44.5 },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
node: 'BALANCE',
|
node: 'BALANCE',
|
||||||
|
|||||||
@@ -3122,7 +3122,18 @@ export const scenarios = [
|
|||||||
time: '2026-09-30T04:00:00+02:00',
|
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',
|
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' },
|
night_budget_prev: '3.7|4000', evcs_total_energy_kwh: '4003.75' },
|
||||||
expect: { sourceMode: 'grid_forced', edfOnAction: true },
|
// 04/10 (option A du proprietaire) : EDF se ferme pour la BATTERIE, la
|
||||||
|
// voiture reste bloquee « sans EDF » (avant : grid_forced, voiture sur EDF).
|
||||||
|
expect: { sourceMode: 'blocked', desiredCharging: false, edfOnAction: true, takeoverNeeded: true },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'budget-sans-edf-reprise-reseau-voiture-bloquee',
|
||||||
|
label: 'Nuit du 03-04/10 rejouee : budget 1,41 atteint, SOC 39 sous la cible 39,5 a 02:57 : EDF ferme pour la batterie, la JEEP ne prend PAS le reseau',
|
||||||
|
time: '2026-10-04T02:57:00+02:00',
|
||||||
|
overrides: { ...BUDGET_NUIT, balance_last_run: '04/10 02:55', soc_percent: '39',
|
||||||
|
balance_required_soc: '39.5', balance_required_soc_prudent: '40.4',
|
||||||
|
night_charge_mode: 'sans_edf', night_budget_prev: '1.41|4038.8', evcs_total_energy_kwh: '4040.2' },
|
||||||
|
expect: { sourceMode: 'blocked', desiredCharging: false, edfOnAction: true, takeoverNeeded: true },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'budget-bilan-perime-sans-edf-rien',
|
id: 'budget-bilan-perime-sans-edf-rien',
|
||||||
@@ -3170,7 +3181,8 @@ export const scenarios = [
|
|||||||
balance_required_soc: '28.6', balance_required_soc_prudent: '29.7',
|
balance_required_soc: '28.6', balance_required_soc_prudent: '29.7',
|
||||||
evcs_vehicle: 'JEEP', departure_time_jeep: '06:30:00', departure_day_ok: 'on',
|
evcs_vehicle: 'JEEP', departure_time_jeep: '06:30:00', departure_day_ok: 'on',
|
||||||
night_charge_mode: 'sans_edf', night_budget_prev: '5.93|4010', evcs_total_energy_kwh: '4015' },
|
night_charge_mode: 'sans_edf', night_budget_prev: '5.93|4010', evcs_total_energy_kwh: '4015' },
|
||||||
expect: { sourceMode: 'grid_forced', edfOnAction: true },
|
// « sans EDF » : l'urgence ferme EDF pour la batterie, la voiture reste bloquee (04/10).
|
||||||
|
expect: { sourceMode: 'blocked', desiredCharging: false, edfOnAction: true },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'depart-matin-pas-un-jour-de-depart',
|
id: 'depart-matin-pas-un-jour-de-depart',
|
||||||
|
|||||||
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