Le plancher du soir vient de l energie a couvrir, plus d un niveau fixe
grep evcs_balance sur les deux workflows de decision renvoyait 0 depuis la mise en service du bilan le 26/08 : il calculait l heure de croisement, l energie a couvrir et le SOC requis, et personne ne l ecoutait. Le 03/09 a 19:44 les deux nombres coexistaient dans le meme systeme — evening_soc_start_min a 85 %, un niveau qui ne sait rien de la nuit, contre evcs_balance_required_soc a 99,7 %, l energie a couvrir jusqu au croisement de 9 h. A SOC 94 le premier autorisait la charge, le second disait que la batterie ne passerait pas la nuit seule. Le plancher de demarrage du soir vaut desormais max(regle, bilan). Sens unique delibere : le bilan peut durcir, jamais relacher. L assouplir — il dira souvent moins de 85 % par forte prevision d ete — autoriserait des charges qui n ont pas lieu aujourd hui, decision distincte a valider pour elle-meme. Le max rend au passage la garde robuste sans borne ni ecretage : une valeur nulle, negative ou aberrante ne peut pas relacher le plancher. Portee demarrage : le plancher de maintien reste min(...), donc a 80 %, et aucune charge en cours n est coupee. L abondance P6 continue de primer, etant une preuve mesuree que la ressource depasse ce que le systeme absorbe. Gardes : fraicheur inferieure a 30 min (six cycles du bilan), horodatage futur rejete, statut ok, valeur finie. Sinon regle historique. Aucun nouveau toggle : evcs_balance_enabled a OFF arrete les ecritures du bilan, balance_last_run se fige, la fraicheur expire et le plancher retombe seul sur 85 % en une demi-heure — un helper de plus aurait fait doublon. Gabarit complet re-rendu contre HA : 195 champs, JSON valide, aucun null. parseAdvisorRunToMs reutilise, l advisor et le bilan publiant le meme format. Golden 66 -> 70. Quatre mutations — bilan ignore, Math.max remplace par une affectation directe, garde de fraicheur supprimee, garde de statut supprimee — font tomber chacune exactement un scenario, et un different a chaque fois. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KKzkkVTG6KXnGXFFC7X9XJ
This commit is contained in:
101
HANDOFF.md
101
HANDOFF.md
@@ -2720,3 +2720,104 @@ repli). Restauration → 66/66.
|
|||||||
|
|
||||||
---
|
---
|
||||||
*Document mis a jour le : 03/09/2026 (~21:45) — provocation solaire gagee sur le mode des chargeurs, golden 66/66, deploye*
|
*Document mis a jour le : 03/09/2026 (~21:45) — provocation solaire gagee sur le mode des chargeurs, golden 66/66, deploye*
|
||||||
|
|
||||||
|
## 38. Session du 03/09/2026 (suite) — Le plancher du soir cesse d'etre un niveau fixe
|
||||||
|
|
||||||
|
### Le constat, enfin traite
|
||||||
|
`grep evcs_balance` sur les deux workflows de decision renvoyait **0** depuis la
|
||||||
|
mise en service du bilan (26/08). Il calculait l'heure de croisement,
|
||||||
|
l'energie a couvrir et le SOC requis, et personne ne l'ecoutait.
|
||||||
|
|
||||||
|
Le 03/09 a 19:44, les deux nombres coexistaient dans le meme systeme :
|
||||||
|
|
||||||
|
| source | valeur | nature |
|
||||||
|
|---|---:|---|
|
||||||
|
| `evening_soc_start_min` | **85 %** | un NIVEAU, fixe, qui ne sait rien de la nuit |
|
||||||
|
| `evcs_balance_required_soc` | **99,7 %** | l'ENERGIE a couvrir jusqu'au croisement de 9 h |
|
||||||
|
|
||||||
|
SOC 94 : le premier autorisait la charge, le second disait que la batterie ne
|
||||||
|
passerait meme pas la nuit toute seule. La charge du soir a fait passer le
|
||||||
|
manque de 0,86 a 2,21 kWh.
|
||||||
|
|
||||||
|
### Le correctif (deploye 03/09 22:18, golden 70/70)
|
||||||
|
Dans `BATTERY_CLOUD_LOCKS.js`, le plancher de DEMARRAGE du profil
|
||||||
|
`evening_high_soc` devient :
|
||||||
|
|
||||||
|
```js
|
||||||
|
eveningSocStartFloorPct = Math.max(params.eveningSocStartMin, params.balanceRequiredSocPct)
|
||||||
|
```
|
||||||
|
|
||||||
|
**SENS UNIQUE, ET C'EST DELIBERE.** Le bilan ne peut que RENFORCER le plancher,
|
||||||
|
jamais l'abaisser. L'assouplir — il dira souvent moins de 85 % par forte
|
||||||
|
prevision d'ete — autoriserait des charges qui n'ont pas lieu aujourd'hui :
|
||||||
|
c'est une decision distincte, avec ses propres risques, qui doit etre validee
|
||||||
|
pour elle-meme et non glissee dans ce correctif. Corollaire agreable : le `max`
|
||||||
|
rend la garde robuste **sans borne ni ecretage** — une valeur nulle, negative ou
|
||||||
|
aberrante ne peut pas relacher le plancher.
|
||||||
|
|
||||||
|
**PORTEE : demarrage.** Le plancher de maintien reste
|
||||||
|
`min(profileSocHoldFloor, ...)`, donc inchange a 80 % : relever le plancher de
|
||||||
|
demarrage ne coupe aucune charge en cours. Troisieme fois de suite que la
|
||||||
|
distinction demarrage/maintien est ce qui rend un correctif sur.
|
||||||
|
|
||||||
|
**L'abondance P6 continue de primer** (PV moyen ≥ 4 kW ET batterie a ≥ +20 A) :
|
||||||
|
c'est une PREUVE MESUREE que la ressource depasse ce que le systeme absorbe,
|
||||||
|
donc le cas ou la voiture est effectivement gratuite.
|
||||||
|
|
||||||
|
### Gardes et repli
|
||||||
|
- fraicheur ≤ **30 min** (six cycles du bilan, qui tourne toutes les 5 min),
|
||||||
|
avec rejet d'un horodatage dans le futur de plus de 5 min ;
|
||||||
|
- `evcs_balance_status` exactement `ok` ;
|
||||||
|
- valeur numerique finie.
|
||||||
|
Sinon : regle historique inchangee.
|
||||||
|
|
||||||
|
**Aucun nouveau toggle : le kill-switch existe deja.**
|
||||||
|
`input_boolean.evcs_balance_enabled` a OFF arrete les ecritures du bilan
|
||||||
|
(`BUILD_HA_CALLS` : `if (!enabled) return []`), `balance_last_run` se fige, la
|
||||||
|
garde de fraicheur expire et le plancher retombe seul sur 85 % en une
|
||||||
|
demi-heure. Un helper de plus aurait fait doublon.
|
||||||
|
|
||||||
|
### Chaine technique
|
||||||
|
`HA_SNAPSHOT_TEMPLATE` : +`balance_required_soc`, +`balance_energy_to_cover_kwh`,
|
||||||
|
+`balance_status`, +`balance_last_run` (gabarit complet re-rendu : **195 champs,
|
||||||
|
JSON valide, aucun null**). `INPUT_PARSE` : `params.balance*`, en reutilisant
|
||||||
|
`parseAdvisorRunToMs` — l'advisor et le bilan publient le meme format
|
||||||
|
`DD/MM HH:mm`. `HA_SERVICE_CALLS_OUTPUT` : trace
|
||||||
|
`Plancher soir=X% (BILAN, Y kWh a couvrir)`, emise uniquement quand le bilan
|
||||||
|
durcit le plancher — sans elle, un blocage un soir de SOC 94 % est
|
||||||
|
incomprehensible a la lecture du logbook.
|
||||||
|
|
||||||
|
### Golden 66 → 70
|
||||||
|
Les quatre scenarios ont un VRAI excedent (PV 2000 W, maison 1000 W) et des
|
||||||
|
chargeurs qui se retiennent : les gardes de §36 et §37 sont passantes, le
|
||||||
|
plancher est le SEUL discriminant.
|
||||||
|
|
||||||
|
| scenario | SOC | bilan | attendu |
|
||||||
|
|---|---:|---|---|
|
||||||
|
| `bilan-plancher-soir-durci` | 94 | 99,7 %, frais | pas de charge |
|
||||||
|
| `bilan-plancher-soir-ne-relache-pas` | 70 | 60 %, frais | pas de charge (85 % reste maitre) |
|
||||||
|
| `bilan-perime-regle-historique` | 94 | 99,7 %, vieux de 2 h | charge |
|
||||||
|
| `bilan-statut-degrade-regle-historique` | 94 | 99,7 %, statut non ok | charge |
|
||||||
|
|
||||||
|
Mutation, quatre directions — bilan ignore / `Math.max` remplace par une
|
||||||
|
affectation directe / garde de fraicheur supprimee / garde de statut supprimee :
|
||||||
|
**chacune fait tomber exactement UN scenario, et un different a chaque fois.**
|
||||||
|
Chaque garde a donc son test dedie, aucun ne couvre pour un autre.
|
||||||
|
Restauration → 70/70.
|
||||||
|
|
||||||
|
### Observation
|
||||||
|
A 20:15 le bilan demandait 99,7 % (11,66 kWh a couvrir) ; a 22:15, **81,9 %**
|
||||||
|
(8,98 kWh). Le plancher suit la nuit qui s'ecoule — ce qu'un niveau fixe ne fait
|
||||||
|
pas, et c'est tout l'interet.
|
||||||
|
|
||||||
|
### Reste ouvert
|
||||||
|
- La **cible du matin** (`night_target_soc`) reste sur la regle des paliers
|
||||||
|
35/55/85, deduite du TOTAL de demain et aveugle a l'heure d'arrivee de
|
||||||
|
l'energie. Le 03/09 : 35 % cote controleur contre 99,7 % cote bilan. C'est le
|
||||||
|
meme defaut que celui corrige ici, sur l'autre bout de la nuit.
|
||||||
|
- Le workflow d'hysteresis ne lit toujours aucun helper du bilan : ses seuils
|
||||||
|
`grid_soc_on`/`grid_soc_off` (20/30) restent des niveaux fixes (§11.8.A).
|
||||||
|
- `houseSpikeDetected` reste structurellement faux (§35).
|
||||||
|
|
||||||
|
---
|
||||||
|
*Document mis a jour le : 03/09/2026 (~22:25) — plancher du soir issu du bilan energetique, golden 70/70, deploye*
|
||||||
|
|||||||
@@ -802,6 +802,39 @@ que la charge, en donnant un preneur au MPPT, detruirait sa propre autorisation
|
|||||||
— le bistable P6 du 24/08. Lectures indisponibles → repli sur le comportement
|
— le bistable P6 du 24/08. Lectures indisponibles → repli sur le comportement
|
||||||
anterieur. Golden 64 → 66. Detail : HANDOFF §37.
|
anterieur. Golden 64 → 66. Detail : HANDOFF §37.
|
||||||
|
|
||||||
|
#### E. Le plancher du soir etait un niveau, pas une energie (03/09/2026)
|
||||||
|
|
||||||
|
`evening_soc_start_min` = 85 % tente de dire « garde de quoi passer la nuit ».
|
||||||
|
C'est un NIVEAU, pris a un instant, qui ne sait rien de la nuit qui vient : ni
|
||||||
|
sa duree, ni la consommation a couvrir, ni l'heure ou le solaire prendra le
|
||||||
|
relais. Le bilan energetique calcule exactement cela depuis le 26/08 et le
|
||||||
|
publie dans `input_number.evcs_balance_required_soc` — et **aucun des deux
|
||||||
|
workflows de decision ne le lisait** (`grep evcs_balance` → 0).
|
||||||
|
|
||||||
|
Le 03/09 a 19:44, SOC 94 % : le plancher fixe autorisait la charge, le bilan
|
||||||
|
demandait 99,7 % pour tenir jusqu'au croisement de 9 h.
|
||||||
|
|
||||||
|
Le plancher de demarrage du soir vaut desormais
|
||||||
|
`max(evening_soc_start_min, evcs_balance_required_soc)`. **Sens unique
|
||||||
|
delibere** : le bilan peut durcir, jamais relacher — l'assouplir en ete
|
||||||
|
autoriserait des charges qui n'ont pas lieu aujourd'hui, decision distincte a
|
||||||
|
valider pour elle-meme. Le `max` rend d'ailleurs la garde robuste sans borne :
|
||||||
|
une valeur aberrante ne peut pas relacher le plancher.
|
||||||
|
|
||||||
|
Gardes : fraicheur ≤ 30 min (six cycles du bilan), statut `ok`, valeur finie ;
|
||||||
|
sinon regle historique. Pas de nouveau toggle — `evcs_balance_enabled` a OFF
|
||||||
|
fige `balance_last_run`, la fraicheur expire, et le plancher retombe seul sur
|
||||||
|
85 % en une demi-heure.
|
||||||
|
|
||||||
|
Portee : demarrage. Le plancher de maintien reste a 80 %, donc aucune charge en
|
||||||
|
cours n'est coupee. Golden 66 → 70, quatre mutations faisant tomber chacune
|
||||||
|
exactement un scenario different. Detail : HANDOFF §38.
|
||||||
|
|
||||||
|
⚠️ Le meme defaut subsiste sur l'autre bout de la nuit : `night_target_soc` est
|
||||||
|
toujours deduit du TOTAL de la prevision du lendemain (paliers 35/55/85), aveugle
|
||||||
|
a l'heure d'arrivee de l'energie — 35 % cote controleur contre 99,7 % cote bilan
|
||||||
|
le 03/09.
|
||||||
|
|
||||||
⚠️ Point structurel mis au jour par cet incident : le bilan energetique publie
|
⚠️ Point structurel mis au jour par cet incident : le bilan energetique publie
|
||||||
l'heure de croisement, l'energie a couvrir, le SOC requis, `grid_needed` et
|
l'heure de croisement, l'energie a couvrir, le SOC requis, `grid_needed` et
|
||||||
`pv_censored` — et **aucun des deux workflows de decision n'en lit une seule
|
`pv_censored` — et **aucun des deux workflows de decision n'en lit une seule
|
||||||
|
|||||||
@@ -393,10 +393,69 @@ const nightPreferredSourceMode = nightPrev.nightPreferredSourceMode || 'blocked'
|
|||||||
// =====================================================
|
// =====================================================
|
||||||
// PROFILE-BASED THRESHOLDS
|
// PROFILE-BASED THRESHOLDS
|
||||||
// =====================================================
|
// =====================================================
|
||||||
|
// =====================================================
|
||||||
|
// PLANCHER DU SOIR : UN NIVEAU FIXE, REMPLACE PAR L'ENERGIE A COUVRIR (03/09/2026)
|
||||||
|
// =====================================================
|
||||||
|
// `evening_soc_start_min` = 85 % est une tentative de dire « garde de quoi
|
||||||
|
// passer la nuit ». C'est un NIVEAU, pris a un instant, et il ne sait rien de
|
||||||
|
// la nuit qui vient : ni sa duree, ni la consommation a couvrir, ni l'heure a
|
||||||
|
// laquelle le solaire prendra le relais.
|
||||||
|
//
|
||||||
|
// Le bilan energetique calcule exactement cela et le publie —
|
||||||
|
// `evcs_balance_required_soc`, deduit de l'energie a couvrir jusqu'au
|
||||||
|
// croisement production/consommation. Personne ne le lisait : `grep
|
||||||
|
// evcs_balance` sur les deux workflows de decision renvoyait 0.
|
||||||
|
//
|
||||||
|
// Le 03/09 a 19:44, les deux nombres coexistaient dans le meme systeme :
|
||||||
|
// plancher du soir 85 % (SOC 94, donc charge autorisee) contre SOC requis
|
||||||
|
// 99,7 % pour tenir jusqu'au croisement de 9 h. La charge du soir a fait
|
||||||
|
// passer le manque de la nuit de 0,86 a 2,21 kWh.
|
||||||
|
//
|
||||||
|
// SENS UNIQUE, ET C'EST DELIBERE : le bilan ne peut que RENFORCER le plancher,
|
||||||
|
// jamais l'abaisser (Math.max). L'assouplir — le bilan dira souvent moins de
|
||||||
|
// 85 % par forte prevision d'ete — autoriserait des charges qui n'ont pas lieu
|
||||||
|
// aujourd'hui : c'est une decision distincte, avec ses propres risques, qui
|
||||||
|
// doit etre validee pour elle-meme et non glissee dans ce correctif.
|
||||||
|
// Corollaire : le max rend la garde robuste sans borne ni ecretage — une
|
||||||
|
// valeur nulle, negative ou aberrante ne peut pas relacher le plancher.
|
||||||
|
//
|
||||||
|
// PORTEE : plancher de DEMARRAGE. Le plancher de maintien reste
|
||||||
|
// min(profileSocHoldFloor, ...) donc inchange a 80 % : relever le plancher de
|
||||||
|
// demarrage ne coupe aucune charge en cours.
|
||||||
|
//
|
||||||
|
// L'abondance P6 continue de primer : PV moyen >= 4 kW ET batterie qui monte a
|
||||||
|
// >= +20 A est une PREUVE MESUREE que la ressource depasse ce que le systeme
|
||||||
|
// absorbe — le cas ou la voiture est effectivement gratuite.
|
||||||
|
//
|
||||||
|
// REPLI : lecture absente, statut non 'ok', ou bilan plus vieux que six de ses
|
||||||
|
// cycles => regle historique inchangee. Le kill-switch existe deja et n'a pas
|
||||||
|
// besoin d'etre double : `input_boolean.evcs_balance_enabled` a OFF arrete les
|
||||||
|
// ecritures du bilan, `balance_last_run` se fige, et le plancher retombe seul
|
||||||
|
// sur 85 % en une demi-heure.
|
||||||
|
const BALANCE_MAX_AGE_MIN = 30;
|
||||||
|
const balanceAgeMin =
|
||||||
|
params.balanceLastRunMs !== null && params.balanceLastRunMs !== undefined
|
||||||
|
? (nowMs - params.balanceLastRunMs) / 60000
|
||||||
|
: null;
|
||||||
|
const balanceFresh =
|
||||||
|
balanceAgeMin !== null &&
|
||||||
|
balanceAgeMin >= -5 &&
|
||||||
|
balanceAgeMin <= BALANCE_MAX_AGE_MIN;
|
||||||
|
const balanceEveningFloorUsable =
|
||||||
|
balanceFresh &&
|
||||||
|
params.balanceStatusOk &&
|
||||||
|
Number.isFinite(params.balanceRequiredSocPct);
|
||||||
|
|
||||||
|
const eveningSocStartFloorPct = balanceEveningFloorUsable
|
||||||
|
? Math.max(params.eveningSocStartMin, params.balanceRequiredSocPct)
|
||||||
|
: params.eveningSocStartMin;
|
||||||
|
const eveningFloorFromBalance =
|
||||||
|
balanceEveningFloorUsable && eveningSocStartFloorPct > params.eveningSocStartMin;
|
||||||
|
|
||||||
const profileSocStartFloor =
|
const profileSocStartFloor =
|
||||||
context.profile === 'morning_solar' ? params.morningSocMin :
|
context.profile === 'morning_solar' ? params.morningSocMin :
|
||||||
context.profile === 'midday_hc_or_solar' ? params.middaySocMin :
|
context.profile === 'midday_hc_or_solar' ? params.middaySocMin :
|
||||||
context.profile === 'evening_high_soc' ? params.eveningSocStartMin :
|
context.profile === 'evening_high_soc' ? eveningSocStartFloorPct :
|
||||||
params.socStartMin;
|
params.socStartMin;
|
||||||
|
|
||||||
// P6 ABONDANCE : PV moyen élevé + batterie en charge franche => le plancher SOC
|
// P6 ABONDANCE : PV moyen élevé + batterie en charge franche => le plancher SOC
|
||||||
@@ -1058,6 +1117,14 @@ return [{
|
|||||||
profileBatteryDischargeFloorA,
|
profileBatteryDischargeFloorA,
|
||||||
|
|
||||||
// Excedent solaire (03/09/2026) : la grandeur qui autorise un demarrage.
|
// Excedent solaire (03/09/2026) : la grandeur qui autorise un demarrage.
|
||||||
|
// Plancher du soir issu du bilan energetique (03/09/2026).
|
||||||
|
eveningSocStartFloorPct,
|
||||||
|
eveningFloorFromBalance,
|
||||||
|
balanceRequiredSocPct: params.balanceRequiredSocPct,
|
||||||
|
balanceEnergyToCoverKwh: params.balanceEnergyToCoverKwh,
|
||||||
|
balanceAgeMin: balanceAgeMin === null ? null : Math.round(balanceAgeMin * 10) / 10,
|
||||||
|
balanceEveningFloorUsable,
|
||||||
|
|
||||||
solarSurplusW,
|
solarSurplusW,
|
||||||
solarSurplusProvocationOk,
|
solarSurplusProvocationOk,
|
||||||
solarSurplusStartOk,
|
solarSurplusStartOk,
|
||||||
|
|||||||
@@ -394,6 +394,14 @@ if (batteryPolicy.batterySoftBreachNow) {
|
|||||||
`Batt souple ${round1(batteryPolicy.batterySoftBreachMinutes)}/${round1(batteryPolicy.batterySoftToleranceMinutes)}min`
|
`Batt souple ${round1(batteryPolicy.batterySoftBreachMinutes)}/${round1(batteryPolicy.batterySoftToleranceMinutes)}min`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// Idem : visible seulement quand le bilan energetique DURCIT le plancher du
|
||||||
|
// soir. Sans cette trace, un blocage de charge un soir de SOC 94 % est
|
||||||
|
// incomprehensible a la lecture du logbook.
|
||||||
|
if (safeguards.eveningFloorFromBalance) {
|
||||||
|
reason.push(
|
||||||
|
`Plancher soir=${round1(safeguards.eveningSocStartFloorPct)}% (BILAN, ${round1(safeguards.balanceEnergyToCoverKwh)}kWh a couvrir)`
|
||||||
|
);
|
||||||
|
}
|
||||||
reason.push(`Cap=${derived.physicalCapA}A`);
|
reason.push(`Cap=${derived.physicalCapA}A`);
|
||||||
reason.push(`Ref=${round1(derived.currentReferenceA)}A`);
|
reason.push(`Ref=${round1(derived.currentReferenceA)}A`);
|
||||||
reason.push(`Target=${round1(desiredCurrentA)}A`);
|
reason.push(`Target=${round1(desiredCurrentA)}A`);
|
||||||
|
|||||||
@@ -139,6 +139,11 @@
|
|||||||
"advisor_night_target_soc": states("input_number.evcs_advisor_night_target_soc"),
|
"advisor_night_target_soc": states("input_number.evcs_advisor_night_target_soc"),
|
||||||
"advisor_status": states("input_text.evcs_advisor_status"),
|
"advisor_status": states("input_text.evcs_advisor_status"),
|
||||||
"advisor_last_run": states("input_text.evcs_advisor_last_run"),
|
"advisor_last_run": states("input_text.evcs_advisor_last_run"),
|
||||||
|
|
||||||
|
"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_status": states("input_text.evcs_balance_status"),
|
||||||
|
"balance_last_run": states("input_text.evcs_balance_last_run"),
|
||||||
"allow_grid_hc_midday": states("input_boolean.victron_evcs_allow_grid_hc_midday"),
|
"allow_grid_hc_midday": states("input_boolean.victron_evcs_allow_grid_hc_midday"),
|
||||||
"probe_enabled": states("input_boolean.victron_evcs_probe_enabled"),
|
"probe_enabled": states("input_boolean.victron_evcs_probe_enabled"),
|
||||||
|
|
||||||
|
|||||||
@@ -439,6 +439,13 @@ const params = {
|
|||||||
advisorStatusOk: cleanText(input.advisor_status).toLowerCase() === 'ok',
|
advisorStatusOk: cleanText(input.advisor_status).toLowerCase() === 'ok',
|
||||||
advisorLastRunMs: parseAdvisorRunToMs(cleanText(input.advisor_last_run)),
|
advisorLastRunMs: parseAdvisorRunToMs(cleanText(input.advisor_last_run)),
|
||||||
|
|
||||||
|
// BILAN ENERGETIQUE (03/09/2026). Meme format d'horodatage que l'advisor
|
||||||
|
// ("DD/MM HH:mm"), d'ou la reutilisation du parseur.
|
||||||
|
balanceRequiredSocPct: num(input.balance_required_soc, NaN),
|
||||||
|
balanceEnergyToCoverKwh: num(input.balance_energy_to_cover_kwh, NaN),
|
||||||
|
balanceStatusOk: cleanText(input.balance_status).toLowerCase() === 'ok',
|
||||||
|
balanceLastRunMs: parseAdvisorRunToMs(cleanText(input.balance_last_run)),
|
||||||
|
|
||||||
// Duree de la fenetre d'etablissement. Valeur mesuree le 31/08/2026 : le
|
// Duree de la fenetre d'etablissement. Valeur mesuree le 31/08/2026 : le
|
||||||
// transitoire de fermeture dure ~150 s (import 1985 -> 25 W et 2600 -> 52 W,
|
// transitoire de fermeture dure ~150 s (import 1985 -> 25 W et 2600 -> 52 W,
|
||||||
// deux campagnes), on prend 180 s de marge. Reglable sans redeploiement via
|
// deux campagnes), on prend 180 s de marge. Reglable sans redeploiement via
|
||||||
|
|||||||
@@ -1043,6 +1043,108 @@ export const scenarios = [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// ===== 03/09/2026 : le plancher du soir vient de l'energie a couvrir =====
|
||||||
|
// Tous ces scenarios ont un VRAI excedent (PV 2000 W, maison 1000 W) et des
|
||||||
|
// chargeurs qui se retiennent : les gardes de §36 et §37 sont donc passantes,
|
||||||
|
// et le plancher est le SEUL discriminant.
|
||||||
|
{
|
||||||
|
id: 'bilan-plancher-soir-durci',
|
||||||
|
label: "Soir, SOC 94 et vrai excédent, mais le bilan demande 99,7 % pour tenir jusqu'au croisement → le plancher passe de 85 à 99,7 → pas de charge",
|
||||||
|
time: EVENING,
|
||||||
|
overrides: {
|
||||||
|
evcs_vehicle_connected: 'on', evcs_device_connected: 'on',
|
||||||
|
battery_current_a: '2',
|
||||||
|
pv_power_w: '2000', pv_power_10m_avg_w: '2000', pv_trend_w: '0',
|
||||||
|
house_ac_power_w: '1000', vebus_ac_out_l1_power_w: '1000',
|
||||||
|
evcs_ac_power_w: '0',
|
||||||
|
mppt_operation_modes: 'voltage_current_limited,voltage_current_limited,voltage_current_limited,voltage_current_limited,voltage_current_limited,voltage_current_limited,voltage_current_limited',
|
||||||
|
soc_percent: '94',
|
||||||
|
balance_required_soc: '99.7', balance_energy_to_cover_kwh: '11.66',
|
||||||
|
balance_status: 'ok', balance_last_run: '08/08 17:58',
|
||||||
|
},
|
||||||
|
expect: {
|
||||||
|
profile: 'evening_high_soc',
|
||||||
|
state: 'idle_wait_conditions',
|
||||||
|
decision: 'hold',
|
||||||
|
desiredCharging: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
// SENS UNIQUE : le bilan ne doit JAMAIS relacher le plancher historique.
|
||||||
|
// Sans ce scenario, remplacer Math.max par une affectation directe
|
||||||
|
// passerait inapercu et autoriserait des charges qui n'ont pas lieu
|
||||||
|
// aujourd'hui.
|
||||||
|
id: 'bilan-plancher-soir-ne-relache-pas',
|
||||||
|
label: "Soir, SOC 70, le bilan ne demande que 60 % → le plancher historique 85 % reste maître, pas de charge",
|
||||||
|
time: EVENING,
|
||||||
|
overrides: {
|
||||||
|
evcs_vehicle_connected: 'on', evcs_device_connected: 'on',
|
||||||
|
battery_current_a: '2',
|
||||||
|
pv_power_w: '2000', pv_power_10m_avg_w: '2000', pv_trend_w: '0',
|
||||||
|
house_ac_power_w: '1000', vebus_ac_out_l1_power_w: '1000',
|
||||||
|
evcs_ac_power_w: '0',
|
||||||
|
mppt_operation_modes: 'voltage_current_limited,voltage_current_limited,voltage_current_limited,voltage_current_limited,voltage_current_limited,voltage_current_limited,voltage_current_limited',
|
||||||
|
soc_percent: '70',
|
||||||
|
balance_required_soc: '60', balance_energy_to_cover_kwh: '4.2',
|
||||||
|
balance_status: 'ok', balance_last_run: '08/08 17:58',
|
||||||
|
},
|
||||||
|
expect: {
|
||||||
|
profile: 'evening_high_soc',
|
||||||
|
state: 'idle_wait_conditions',
|
||||||
|
decision: 'hold',
|
||||||
|
desiredCharging: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
id: 'bilan-perime-regle-historique',
|
||||||
|
label: "Soir, SOC 94, bilan exigeant (99,7 %) mais vieux de 2 h → repli sur la règle historique 85 % → la charge démarre",
|
||||||
|
time: EVENING,
|
||||||
|
overrides: {
|
||||||
|
evcs_vehicle_connected: 'on', evcs_device_connected: 'on',
|
||||||
|
battery_current_a: '2',
|
||||||
|
pv_power_w: '2000', pv_power_10m_avg_w: '2000', pv_trend_w: '0',
|
||||||
|
house_ac_power_w: '1000', vebus_ac_out_l1_power_w: '1000',
|
||||||
|
evcs_ac_power_w: '0',
|
||||||
|
mppt_operation_modes: 'voltage_current_limited,voltage_current_limited,voltage_current_limited,voltage_current_limited,voltage_current_limited,voltage_current_limited,voltage_current_limited',
|
||||||
|
soc_percent: '94',
|
||||||
|
balance_required_soc: '99.7', balance_energy_to_cover_kwh: '11.66',
|
||||||
|
balance_status: 'ok', balance_last_run: '08/08 16:00',
|
||||||
|
},
|
||||||
|
expect: {
|
||||||
|
profile: 'evening_high_soc',
|
||||||
|
state: 'start_min_current',
|
||||||
|
decision: 'start',
|
||||||
|
desiredCharging: true,
|
||||||
|
currentA: 6,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
id: 'bilan-statut-degrade-regle-historique',
|
||||||
|
label: "Soir, SOC 94, bilan frais mais statut non 'ok' → repli sur la règle historique → la charge démarre",
|
||||||
|
time: EVENING,
|
||||||
|
overrides: {
|
||||||
|
evcs_vehicle_connected: 'on', evcs_device_connected: 'on',
|
||||||
|
battery_current_a: '2',
|
||||||
|
pv_power_w: '2000', pv_power_10m_avg_w: '2000', pv_trend_w: '0',
|
||||||
|
house_ac_power_w: '1000', vebus_ac_out_l1_power_w: '1000',
|
||||||
|
evcs_ac_power_w: '0',
|
||||||
|
mppt_operation_modes: 'voltage_current_limited,voltage_current_limited,voltage_current_limited,voltage_current_limited,voltage_current_limited,voltage_current_limited,voltage_current_limited',
|
||||||
|
soc_percent: '94',
|
||||||
|
balance_required_soc: '99.7', balance_energy_to_cover_kwh: '11.66',
|
||||||
|
balance_status: 'donnees_insuffisantes', balance_last_run: '08/08 17:58',
|
||||||
|
},
|
||||||
|
expect: {
|
||||||
|
profile: 'evening_high_soc',
|
||||||
|
state: 'start_min_current',
|
||||||
|
decision: 'start',
|
||||||
|
desiredCharging: true,
|
||||||
|
currentA: 6,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
// ===== 01/09/2026 : le depassement souple de la batterie doit DURER =====
|
// ===== 01/09/2026 : le depassement souple de la batterie doit DURER =====
|
||||||
// Incident du 01/09 (14:26 et 14:56) : SOC 94, batterie en float, courant
|
// Incident du 01/09 (14:26 et 14:56) : SOC 94, batterie en float, courant
|
||||||
// oscillant entre +1,8 et -2,6 A d'un echantillon a l'autre. Le controleur
|
// oscillant entre +1,8 et -2,6 A d'un echantillon a l'autre. Le controleur
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user