Boost sur batterie : force_charge_now donne d'abord le budget batterie (au-dessus du requis prudent), puis EDF ; script, fin automatique, bouton

This commit is contained in:
Tallagrand Thierry
2026-10-15 12:58:48 +02:00
parent 52c1703b6e
commit c47313a887
13 changed files with 235 additions and 16 deletions

View File

@@ -2443,5 +2443,13 @@ batterie a 32 A et JEEP (branchee 13:01, 52 %) qui ne demarre pas. SOC 47 % a 12
- Golden 149 -> **153** (fixture REELLE `tests/golden/fixtures/jeep-1410-1257.json` : sans niveau = latch historique ; 51 % = pas cru ; collant leve ; temoin 97 % = plein), mutation « regle coupee » -> 2 echecs. Verifie en reel : 13:13:00 `start_min_current`, borne « Charge en cours », 6 A / 1,08 kW. - Golden 149 -> **153** (fixture REELLE `tests/golden/fixtures/jeep-1410-1257.json` : sans niveau = latch historique ; 51 % = pas cru ; collant leve ; temoin 97 % = plein), mutation « regle coupee » -> 2 echecs. Verifie en reel : 13:13:00 `start_min_current`, borne « Charge en cours », 6 A / 1,08 kW.
- ⚠️ Si la voiture refuse vraiment la charge (limite reglee dans la voiture), le controleur retentera au lieu de se mettre en veille : a surveiller. VW sans saisie de niveau : non couverte. - ⚠️ Si la voiture refuse vraiment la charge (limite reglee dans la voiture), le controleur retentera au lieu de se mettre en veille : a surveiller. VW sans saisie de niveau : non couverte.
### 14/10 soir — Boost EDF d'une Volvo invitee, et ce qu'il a coute
- Volvo XC90 T8 (HYBRIDE rechargeable, ~70 km electriques, batterie ~18 kWh au compteur, chargeur embarque **3,7 kW** ; le proprietaire l'a d'abord crue electrique : « 30 km » sans icone = l'ESSENCE). Branchee 20:03 a 0 %, boost EDF 20:09 -> 22:01 : **6,45 kWh** (25 km). Etiquetee INVITE par le concierge (22:56).
- Achats EDF en HP 20:09-22:01 : **11,47 kWh** = voiture 6,35 + **batterie maison 2,81** (+30 A a SOC 86 %) + maison ~2,3. Nuit sans EDF ensuite (89 -> 60 % a 09:00).
- **A (deploye 15/10 12:51, `52c1703`)** : la part voiture de la consigne reseau suivait le plafond de borne (28 A = 6,4 kW) alors que la voiture plafonnait a 3,7 kW : les 2,7 kW de trop rechargeaient la batterie en HP. Voiture plafonnee (puissance < consigne - 2 A) -> part = puissance reelle (+ le pas de marge existant). Rejeu 20:40 : 7 304 -> **4 795 W** ; temoin voiture qui suit : 6 458 W inchange.
- **B (deploye 15/10 12:58)** : `force_charge_now` = **boost sur batterie** : budget = (SOC - requis prudent du bilan) x capacite, FIGE au demarrage avec l'index du compteur (`input_text.victron_evcs_boost_budget`), batterie d'abord (chemin `battery_assist_night`, libelle « Boost batterie »), EDF (`grid_forced`, `gridAllowedBySoc`) quand le budget est atteint ; bilan absent/perime -> budget 0 -> EDF. Paquet `evcs_boost_batterie.yaml` (helper, `script.evcs_boost_batterie`, automatisation de fin : debranchement 1 min ou `evcs_force_grid_max_minutes` -> BOOST OFF), bouton sur EVCS Master (Pilotage). Golden **159/159** (fixture reelle `volvo-1410-2040.json`), mutations : budget ignore -> 1, EDF refuse -> 2 ; `force-charge-nuit` change VOLONTAIREMENT (sans bilan : EDF au lieu de la batterie a l'aveugle). diagnostics 95/95 (« Boost batterie » -> en_charge_batterie).
- ⚠️ Rejeu du 14/10 20:40 : requis prudent **82,2 %** pour SOC 87 -> budget **1,44 kWh** seulement ; ma premiere analyse (« ~9 kWh, la batterie etait la bonne source ») utilisait le requis du matin (56 %) : fausse. Le gain reel du soir aurait ete ~1,4 kWh + les 2,8 kWh de batterie (corriges par A).
- ⚠️ Les gardes de courant par bande de SOC restent en place sur le chemin batterie : debit possiblement bride.
--- ---
*Document mis a jour le : 14/10/2026 (~00:10) — disjoncteur EDF 100A (identifiants repris), revue (EDF absent, voiture payee par la batterie, interventions, kWh sur la puissance), piles (hysteresis + acquittement), frontal web .17 en cours ; 13/10/2026 (~06:30) — nuit du 12-13/10 : disjoncteur EDF qui n'executait pas la fermeture (alerte edf_ne_ferme_pas, envoyee a toute heure), charge HC manuelle reparee et utilisee a 40 % ; 13/10 : certificats HTTPS du .50 renouveles (via le .17) + alerte d'expiration ; 12/10 : VW payee par la batterie (temps mini + tolerance nuage bornes par le bilan), niveaux estimes par l'autonomie ; 10/10/2026 (~16:00) — conseiller relecteur de la journee (revue calculee + pistes) ; nuit : voiture qui profite d'EDF ferme pour la batterie, nuit qui prepare le soir les jours annonces faibles ; 08/10/2026 (~00:15) — jour faible : charge maximale en HC de midi (bilan 100 %, ACM plafond + solaire) ; 07/10/2026 (~22:45) — reprise de 16 h verifiee, EDF en HP a 18:03, bilan : reprise du soir et prevision recalee sur la matinee ; bilan HC de midi, reprise du soir apres coupure en pleine chauffe, mesure ECS sur 10 min ; recharge reseau HC : courant calcule (12 kVA) et consigne non tenue ; HC de midi : AUTO ne chauffe pas (BOOST), alerte v2, Jeep (contact, relecture, zone), recharge batterie bridee a 30 A par l'ACM ; jour faible = EDF les deux fenetres HC pour le chauffe-eau, alerte BOOST, Victron Mobile refait ; 1re decision jour faible en reel, mesure ECS reparee, douches 06:00/20:00, Grafana chauffe-eau, tableaux ECS ; chauffe-eau en HC de nuit les jours faibles (decision du bilan, workflow ECS sous controle du depot, VRM, V2.3 desactive) ; garde batterie reseau : voiture bridee a 6 A au lieu d'un arret ; garde-fou concierge 2 h ; allers-retours brefs de la borne retrouves dans l'historique HA (echange VW -> JEEP de 20 s), production 14,5 kWh contre 22 prevus, defaut garde batterie en mode reseau a trancher ; voiture a midi : la batterie n'est plus comptee comme du solaire (EDF automatique les jours de depart si le surplus ne couvre pas) ; nuit 05->06 : JEEP chargee sur EDF en complete (6,32 kWh), budget 0 du a la prevision, Windy/ECMWF contre VRM, a comparer ce soir ; concierge aligne sur la preuve fin de trajet ; a verifier : nuit 05->06 et mardi faible, comparaison VRM/Forecast.Solar ; JEEP identifiee aussi par sa fin de trajet, prevision de la nuit 05->06 ; identification JEEP reussie en reel, correction humaine qui prime (refus supprime), session du 04/10 coupee ; EVCS Master en quatre onglets ; Jeep lue par Uconnect et identifiee seule, capacite JEEP 10 kWh, concierge variante (a) ; releve par photo (SPARK), hass-uconnect en attente ; ecart semaine/week-end mesure (pas de profil week-end la nuit) ; 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* *Document mis a jour le : 14/10/2026 (~00:10) — disjoncteur EDF 100A (identifiants repris), revue (EDF absent, voiture payee par la batterie, interventions, kWh sur la puissance), piles (hysteresis + acquittement), frontal web .17 en cours ; 13/10/2026 (~06:30) — nuit du 12-13/10 : disjoncteur EDF qui n'executait pas la fermeture (alerte edf_ne_ferme_pas, envoyee a toute heure), charge HC manuelle reparee et utilisee a 40 % ; 13/10 : certificats HTTPS du .50 renouveles (via le .17) + alerte d'expiration ; 12/10 : VW payee par la batterie (temps mini + tolerance nuage bornes par le bilan), niveaux estimes par l'autonomie ; 10/10/2026 (~16:00) — conseiller relecteur de la journee (revue calculee + pistes) ; nuit : voiture qui profite d'EDF ferme pour la batterie, nuit qui prepare le soir les jours annonces faibles ; 08/10/2026 (~00:15) — jour faible : charge maximale en HC de midi (bilan 100 %, ACM plafond + solaire) ; 07/10/2026 (~22:45) — reprise de 16 h verifiee, EDF en HP a 18:03, bilan : reprise du soir et prevision recalee sur la matinee ; bilan HC de midi, reprise du soir apres coupure en pleine chauffe, mesure ECS sur 10 min ; recharge reseau HC : courant calcule (12 kVA) et consigne non tenue ; HC de midi : AUTO ne chauffe pas (BOOST), alerte v2, Jeep (contact, relecture, zone), recharge batterie bridee a 30 A par l'ACM ; jour faible = EDF les deux fenetres HC pour le chauffe-eau, alerte BOOST, Victron Mobile refait ; 1re decision jour faible en reel, mesure ECS reparee, douches 06:00/20:00, Grafana chauffe-eau, tableaux ECS ; chauffe-eau en HC de nuit les jours faibles (decision du bilan, workflow ECS sous controle du depot, VRM, V2.3 desactive) ; garde batterie reseau : voiture bridee a 6 A au lieu d'un arret ; garde-fou concierge 2 h ; allers-retours brefs de la borne retrouves dans l'historique HA (echange VW -> JEEP de 20 s), production 14,5 kWh contre 22 prevus, defaut garde batterie en mode reseau a trancher ; voiture a midi : la batterie n'est plus comptee comme du solaire (EDF automatique les jours de depart si le surplus ne couvre pas) ; nuit 05->06 : JEEP chargee sur EDF en complete (6,32 kWh), budget 0 du a la prevision, Windy/ECMWF contre VRM, a comparer ce soir ; concierge aligne sur la preuve fin de trajet ; a verifier : nuit 05->06 et mardi faible, comparaison VRM/Forecast.Solar ; JEEP identifiee aussi par sa fin de trajet, prevision de la nuit 05->06 ; identification JEEP reussie en reel, correction humaine qui prime (refus supprime), session du 04/10 coupee ; EVCS Master en quatre onglets ; Jeep lue par Uconnect et identifiee seule, capacite JEEP 10 kWh, concierge variante (a) ; releve par photo (SPARK), hass-uconnect en attente ; ecart semaine/week-end mesure (pas de profil week-end la nuit) ; 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*

View File

@@ -267,6 +267,11 @@ embarques) ; la Megane a pris **6 360 W a 28 A** le 11/09. La colonne
| 3 600 a 3 800 W | VW ou JEEP a pleine consigne — **indiscernables entre elles** | | 3 600 a 3 800 W | VW ou JEEP a pleine consigne — **indiscernables entre elles** |
| > 4 000 W | vehicule INVITE, ni VW ni JEEP | | > 4 000 W | vehicule INVITE, ni VW ni JEEP |
Volvo **XC90 T8** d'un invite (14/10/2026) : HYBRIDE rechargeable (~70 km
electriques, ~18 kWh au compteur pour une charge complete), chargeur embarque
**3,7 kW** - elle plafonne comme la VW et la JEEP, donc PAS discernable a la
puissance. Au tableau de bord, « 30 km » sans icone = autonomie ESSENCE.
La doctrine « les vehicules sont indiscernables » ne vaut donc QUE pour la VW La doctrine « les vehicules sont indiscernables » ne vaut donc QUE pour la VW
et la JEEP l'une par rapport a l'autre. Toute question posee au proprietaire et la JEEP l'une par rapport a l'autre. Toute question posee au proprietaire
sur l'identite d'un vehicule doit offrir une reponse « aucune des deux », sans sur l'identite d'un vehicule doit offrir une reponse « aucune des deux », sans

View File

@@ -0,0 +1,74 @@
# =====================================================================
# BOOST SUR BATTERIE (15/10/2026, decision du proprietaire)
# Le 14/10 au soir, le boost EDF de la Volvo d'un invite a achete 11,5 kWh en
# heures pleines. « EVCS BOOST BATTERIE » passe en force_charge_now : le
# controleur donne d'abord a la voiture l'energie de la batterie AU-DESSUS du
# SOC requis prudent du bilan (budget fige au demarrage dans
# input_text.victron_evcs_boost_budget = « budget|index du compteur »), puis
# EDF prend le relais. Bilan absent ou perime : EDF tout de suite.
# Fin : debranchement (1 min) ou duree maximale du reseau force
# (input_number.evcs_force_grid_max_minutes) -> EVCS BOOST OFF.
# Retour arriere : supprimer ce fichier, recharger scripts / automatisations /
# input_text (aucun redemarrage).
# =====================================================================
input_text:
victron_evcs_boost_budget:
name: EVCS - Budget batterie du boost (fige)
max: 40
icon: mdi:battery-lock
script:
evcs_boost_batterie:
alias: EVCS BOOST BATTERIE (batterie d'abord, puis EDF)
icon: mdi:battery-charging-high
mode: restart
sequence:
- action: input_number.set_value
target:
entity_id: input_number.evcs_plafond_courant_edf_on
data:
value: 28
- action: input_number.set_value
target:
entity_id: input_number.victron_evcs_current_max_auto_a
data:
value: 28
- action: input_select.select_option
target:
entity_id: input_select.victron_evcs_strategy
data:
option: force_charge_now
automation:
- id: evcs_boost_batterie_fin
alias: "EVCS — fin du boost batterie"
description: >
Le boost (force_charge_now) s'arrete au debranchement ou apres la duree
maximale du reseau force ; EVCS BOOST OFF remet plafonds et strategie.
mode: single
trigger:
- platform: state
entity_id: binary_sensor.victron_evcs_vehicle_connected
to: "off"
for: "00:01:00"
- platform: time_pattern
minutes: "/1"
condition:
- condition: state
entity_id: input_select.victron_evcs_strategy
state: force_charge_now
- condition: template
value_template: >
{% set s = states.input_select.victron_evcs_strategy %}
{% set duree = (as_timestamp(now()) - as_timestamp(s.last_changed)) / 60 %}
{% set plafond = states('input_number.evcs_force_grid_max_minutes') | float(180) %}
{{ is_state('binary_sensor.victron_evcs_vehicle_connected', 'off') or duree > plafond }}
action:
- action: script.evcs_boost_off
- action: logbook.log
data:
name: EVCS
message: >
Boost batterie termine ({{ 'voiture debranchee' if is_state('binary_sensor.victron_evcs_vehicle_connected', 'off') else 'duree maximale' }}),
budget {{ states('input_text.victron_evcs_boost_budget') }}, SOC {{ states('sensor.victron_battery_soc') | round(0) }} %.
entity_id: input_select.victron_evcs_strategy

View File

@@ -409,7 +409,11 @@ const batteryRecoveryUrgent = !!nightPrev.batteryRecoveryUrgent;
const batteryRecoveryAllowedNow = !!nightPrev.batteryRecoveryAllowedNow; const batteryRecoveryAllowedNow = !!nightPrev.batteryRecoveryAllowedNow;
const batteryTargetReached = !!nightPrev.batteryTargetReached; const batteryTargetReached = !!nightPrev.batteryTargetReached;
const batteryAssistAllowed = !!nightPrev.batteryAssistAllowed; // Boost sur batterie (15/10/2026) : force_charge_now dans son budget emprunte
// le chemin batterie de la nuit, hors session de nuit. Le plancher (SOC requis
// prudent) et le budget au compteur sont juges dans WINDOWS_SOURCEV2.
const boostBatteryAvailable = !!nightPrev.boostBatteryAvailable;
const batteryAssistAllowed = !!nightPrev.batteryAssistAllowed || boostBatteryAvailable;
const nightGridTakeoverNeeded = !!nightPrev.nightGridTakeoverNeeded; const nightGridTakeoverNeeded = !!nightPrev.nightGridTakeoverNeeded;
const nightTakeoverLatched = !!nightPrev.nightTakeoverLatched; const nightTakeoverLatched = !!nightPrev.nightTakeoverLatched;
const vehicleChargeCompleted = !!nightPrev.vehicleChargeCompleted; const vehicleChargeCompleted = !!nightPrev.vehicleChargeCompleted;
@@ -836,6 +840,8 @@ const solarHoldOk =
// au-dessus de 35 %. // au-dessus de 35 %.
const gridAllowedBySoc = const gridAllowedBySoc =
strategy.forceGridRequested || strategy.forceGridRequested ||
// Boost (15/10) : budget batterie epuise ou nul -> EDF, quel que soit le SOC.
(strategy.forceChargeRequested && !!nightPrev.boostActive) ||
context.profile === 'night_hc' || context.profile === 'night_hc' ||
departureUrgentActive || departureUrgentActive ||
(context.profile === 'midday_hc_or_solar' && nightGridSessionCommitted) || (context.profile === 'midday_hc_or_solar' && nightGridSessionCommitted) ||
@@ -882,10 +888,11 @@ const nightBatterySurplusFloorPct = Number.isFinite(nightPrev.nightBatterySurplu
const batteryAssistNightStartOk = const batteryAssistNightStartOk =
context.sourceMode === 'battery_assist_night' && context.sourceMode === 'battery_assist_night' &&
commonSafetyStartOk && commonSafetyStartOk &&
nightSessionActive && (nightSessionActive || boostBatteryAvailable) &&
batteryAssistAllowed && batteryAssistAllowed &&
parsed.soc > batteryHardFloorPct && parsed.soc > batteryHardFloorPct &&
( (
boostBatteryAvailable ||
nightBatterySurplusAvailable nightBatterySurplusAvailable
? parsed.soc > nightBatterySurplusFloorPct ? parsed.soc > nightBatterySurplusFloorPct
: ( : (
@@ -897,11 +904,12 @@ const batteryAssistNightStartOk =
const batteryAssistNightHoldOk = const batteryAssistNightHoldOk =
context.sourceMode === 'battery_assist_night' && context.sourceMode === 'battery_assist_night' &&
commonSafetyHoldOk && commonSafetyHoldOk &&
nightSessionActive && (nightSessionActive || boostBatteryAvailable) &&
batteryAssistAllowed && batteryAssistAllowed &&
parsed.soc > batteryHardFloorPct && parsed.soc > batteryHardFloorPct &&
parsed.batteryCurrentA >= batteryDischargeHardDynamicA && parsed.batteryCurrentA >= batteryDischargeHardDynamicA &&
( (
boostBatteryAvailable ||
nightBatterySurplusAvailable nightBatterySurplusAvailable
? parsed.soc > nightBatterySurplusFloorPct ? parsed.soc > nightBatterySurplusFloorPct
: parsed.soc > gridTakeoverTriggerPct : parsed.soc > gridTakeoverTriggerPct
@@ -1175,6 +1183,12 @@ return [{
nightBudgetDeliveredKwh: nightPrev.nightBudgetDeliveredKwh ?? null, nightBudgetDeliveredKwh: nightPrev.nightBudgetDeliveredKwh ?? null,
nightBudgetReached: !!nightPrev.nightBudgetReached, nightBudgetReached: !!nightPrev.nightBudgetReached,
nightBudgetToWrite: nightPrev.nightBudgetToWrite ?? null, nightBudgetToWrite: nightPrev.nightBudgetToWrite ?? null,
boostActive: !!nightPrev.boostActive,
boostBatteryAvailable,
boostFloorPct: nightPrev.boostFloorPct ?? null,
boostBudgetKwh: nightPrev.boostBudgetKwh ?? null,
boostDeliveredKwh: nightPrev.boostDeliveredKwh ?? null,
boostBudgetToWrite: nightPrev.boostBudgetToWrite ?? null,
nightChargeMode: nightPrev.nightChargeMode || 'sans_edf', nightChargeMode: nightPrev.nightChargeMode || 'sans_edf',
nightCarWaitsNoGrid: !!nightPrev.nightCarWaitsNoGrid, nightCarWaitsNoGrid: !!nightPrev.nightCarWaitsNoGrid,
nightBatteryGridOnly: !!nightPrev.nightBatteryGridOnly, nightBatteryGridOnly: !!nightPrev.nightBatteryGridOnly,

View File

@@ -155,6 +155,12 @@ pushAction(
!!calls.helper_night_budget?.execute !!calls.helper_night_budget?.execute
); );
pushAction(
'helper_boost_budget',
calls.helper_boost_budget,
!!calls.helper_boost_budget?.execute
);
// ===================================================== // =====================================================
// DEMANDE RÉSEAU EDF SI SOURCE GRID // DEMANDE RÉSEAU EDF SI SOURCE GRID
// ===================================================== // =====================================================

View File

@@ -790,6 +790,7 @@ const sourceModeLabel =
context.sourceMode === 'hybrid_probe' ? 'Probe hybride' : context.sourceMode === 'hybrid_probe' ? 'Probe hybride' :
context.sourceMode === 'grid_hc_allowed' ? 'Réseau HC autorisé' : context.sourceMode === 'grid_hc_allowed' ? 'Réseau HC autorisé' :
context.sourceMode === 'grid_forced' ? 'Réseau forcé' : context.sourceMode === 'grid_forced' ? 'Réseau forcé' :
context.sourceMode === 'battery_assist_night' && night.boostBatteryAvailable ? 'Boost batterie' :
context.sourceMode === 'battery_assist_night' ? 'Assistance batterie nuit' : context.sourceMode === 'battery_assist_night' ? 'Assistance batterie nuit' :
context.sourceMode; context.sourceMode;
@@ -1439,6 +1440,17 @@ return [{
} }
}, },
// Boost sur batterie (15/10) : fige au premier cycle, efface a la sortie.
helper_boost_budget: {
execute: night.boostBudgetToWrite !== null && night.boostBudgetToWrite !== undefined,
domain: 'input_text',
service: 'set_value',
data: {
entity_id: 'input_text.victron_evcs_boost_budget',
value: night.boostBudgetToWrite ?? ''
}
},
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',

View File

@@ -171,6 +171,7 @@
"night_charge_mode": states("input_select.victron_evcs_night_charge_mode"), "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"), "balance_night_vehicle_budget_kwh": states("input_number.evcs_balance_night_vehicle_budget_kwh"),
"night_budget_prev": states("input_text.victron_evcs_night_budget"), "night_budget_prev": states("input_text.victron_evcs_night_budget"),
"boost_budget_prev": states("input_text.victron_evcs_boost_budget"),
"evcs_total_energy_kwh": states("sensor.evcs_hq2239dnt7p_total_energy"), "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"),

View File

@@ -535,6 +535,9 @@ const params = {
nightChargeMode: low(input.night_charge_mode || 'sans_edf') === 'complete' ? 'complete' : 'sans_edf', nightChargeMode: low(input.night_charge_mode || 'sans_edf') === 'complete' ? 'complete' : 'sans_edf',
balanceNightVehicleBudgetKwh: num(input.balance_night_vehicle_budget_kwh, NaN), balanceNightVehicleBudgetKwh: num(input.balance_night_vehicle_budget_kwh, NaN),
nightBudgetPrevRaw: cleanText(input.night_budget_prev), nightBudgetPrevRaw: cleanText(input.night_budget_prev),
// Boost sur batterie (15/10/2026) : « budget|index » fige au premier cycle de
// force_charge_now, efface a sa sortie (meme forme que le budget de nuit).
boostBudgetPrevRaw: cleanText(input.boost_budget_prev),
evcsTotalEnergyKwh: num(input.evcs_total_energy_kwh, NaN), 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.

View File

@@ -687,6 +687,53 @@ const nightBudgetReached =
nightBudgetDeliveredKwh >= nightBudget.budgetKwh - 0.05; nightBudgetDeliveredKwh >= nightBudget.budgetKwh - 0.05;
const nightChargeComplete = params.nightChargeMode === 'complete'; const nightChargeComplete = params.nightChargeMode === 'complete';
// =====================================================
// BOOST SUR BATTERIE (15/10/2026, decision du proprietaire)
// =====================================================
// Le 14/10 au soir, boost EDF pour la Volvo d'un invite : 11,5 kWh achetes en
// heures pleines (voiture 6,35, batterie maison 2,81, maison ~2,3) alors que la
// batterie etait a 86 % pour 56 % requis et que la nuit est passee sans EDF.
// `force_charge_now` (« charge maintenant ») donne desormais d'abord a la
// voiture l'energie de la batterie AU-DESSUS du SOC requis prudent du bilan
// (meme plancher que P12 et que la tolerance nuage du 12/10), puis EDF.
// Budget FIGE au premier cycle avec l'index du compteur de la borne, dans
// input_text.victron_evcs_boost_budget (« budget|index »), efface a la sortie ;
// arret au COMPTEUR (monotone, pas d'oscillateur). Bilan absent ou perime :
// budget 0, EDF tout de suite (jamais la batterie a l'aveugle). Les gardes de
// courant batterie restent en place (elles peuvent brider le debit).
const boostBudgetPrev = (() => {
const m = String(params.boostBudgetPrevRaw || '').match(/^\s*([\d.]+)\|([\d.]+)\s*$/);
return m ? { budgetKwh: Number(m[1]), refKwh: Number(m[2]) } : null;
})();
const boostActive = forceChargeRequested && parsed.evcsVehicleConnected && !isStopMode;
const boostFloorPct = Math.max(
batteryHardFloorPct,
balanceMorningTargetApplied && Number.isFinite(params.balanceRequiredSocPrudentPct)
? params.balanceRequiredSocPrudentPct
: Infinity,
);
const boostCaptureOk = boostActive && !boostBudgetPrev && Number.isFinite(params.evcsTotalEnergyKwh);
const boostBudget = !boostActive
? null
: boostBudgetPrev || (boostCaptureOk
? {
budgetKwh: Number.isFinite(boostFloorPct)
? Math.max(0, ((parsed.soc - boostFloorPct) / 100) * cfg.batteryUsableCapacityKwh)
: 0,
refKwh: params.evcsTotalEnergyKwh,
}
: null);
const boostBudgetToWrite = boostActive
? (boostCaptureOk ? `${Math.round(boostBudget.budgetKwh * 100) / 100}|${boostBudget.refKwh}` : null)
: (boostBudgetPrev ? '' : null);
const boostDeliveredKwh = boostBudget && Number.isFinite(params.evcsTotalEnergyKwh)
? Math.max(0, params.evcsTotalEnergyKwh - boostBudget.refKwh)
: null;
const boostBatteryAvailable =
boostActive && !!boostBudget && boostDeliveredKwh !== null &&
boostDeliveredKwh < boostBudget.budgetKwh - 0.05 &&
parsed.soc > boostFloorPct;
// Le verrou ne vaut QUE pendant la session de nuit (01/10/2026). Ecrit sous la // Le verrou ne vaut QUE pendant la session de nuit (01/10/2026). Ecrit sous la
// forme `prev || …`, il restait vrai pour toujours une fois pose ; invisible // forme `prev || …`, il restait vrai pour toujours une fois pose ; invisible
// tant que son ecriture n'atteignait pas HA (jamais relayee du 15/09 au 01/10). // tant que son ecriture n'atteignait pas HA (jamais relayee du 15/09 au 01/10).
@@ -1038,6 +1085,15 @@ else if (forceChargeRequested) {
sourceMode = 'solar_only'; sourceMode = 'solar_only';
} }
// Boost sur batterie (15/10) : la batterie dans son budget, puis EDF.
else if (boostBatteryAvailable) {
sourceMode = 'battery_assist_night';
}
else if (boostActive) {
sourceMode = 'grid_forced';
}
else if (nightSessionActive && batteryAssistAllowed) { else if (nightSessionActive && batteryAssistAllowed) {
sourceMode = 'battery_assist_night'; sourceMode = 'battery_assist_night';
} }
@@ -1319,6 +1375,12 @@ return [{
nightBudgetDeliveredKwh, nightBudgetDeliveredKwh,
nightBudgetReached, nightBudgetReached,
nightBudgetToWrite, nightBudgetToWrite,
boostActive,
boostBatteryAvailable,
boostFloorPct: Number.isFinite(boostFloorPct) ? boostFloorPct : null,
boostBudgetKwh: boostBudget ? boostBudget.budgetKwh : null,
boostDeliveredKwh,
boostBudgetToWrite,
nightChargeMode: params.nightChargeMode, nightChargeMode: params.nightChargeMode,
nightCarWaitsNoGrid, nightCarWaitsNoGrid,
nightBatteryGridOnly, nightBatteryGridOnly,

View File

@@ -144,6 +144,8 @@ function summarize(out) {
nightBatteryDoneService: calls.helper_night_battery_done?.execute ? calls.helper_night_battery_done.service : null, nightBatteryDoneService: calls.helper_night_battery_done?.execute ? calls.helper_night_battery_done.service : null,
// Budget voiture de la nuit (30/09) : valeur ecrite ce cycle, null sinon. // 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, nightBudgetWrite: calls.helper_night_budget?.execute ? calls.helper_night_budget.data.value : null,
// Boost sur batterie (15/10) : budget ecrit ce cycle, null sinon.
boostBudgetWrite: calls.helper_boost_budget?.execute ? calls.helper_boost_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

View File

@@ -1849,21 +1849,23 @@ export const scenarios = [
}, },
{ {
id: 'force-charge-nuit', id: 'force-charge-nuit',
label: 'force_charge_now la nuit (toggle HC ON) → démarrage manuel local (non-régression P7)', label: 'force_charge_now la nuit, bilan absent → budget batterie 0 → EDF tout de suite (boost du 15/10)',
time: NIGHT, time: NIGHT,
overrides: { overrides: {
...VEHICLE_NIGHT, victron_evcs_strategy: 'force_charge_now', ...VEHICLE_NIGHT, victron_evcs_strategy: 'force_charge_now',
soc_percent: '60', allow_grid_hc_night: 'on', soc_percent: '60', allow_grid_hc_night: 'on',
}, },
// Avant le 15/10 : 'solar_potential' / start_manual_local (la batterie a
// l'aveugle). Desormais, sans bilan exploitable, le boost ne prend JAMAIS la
// batterie : il demande EDF (ici en HC de nuit).
expect: { expect: {
profile: 'night_hc', profile: 'night_hc',
sourceMode: 'solar_potential', sourceMode: 'grid_forced',
state: 'start_manual_local_min_current', state: 'night_wait_grid_takeover',
decision: 'start', decision: 'hold',
desiredCharging: true, desiredCharging: false,
currentA: 6,
takeoverNeeded: true, takeoverNeeded: true,
edfOnAction: false, edfOnAction: true,
takeoverHelperService: 'turn_on', takeoverHelperService: 'turn_on',
}, },
}, },
@@ -3651,4 +3653,32 @@ export const scenarios = [
// Identique a l'ancien code (6458 W). // Identique a l'ancien code (6458 W).
expect: { gridSetpointW: 6458 }, expect: { gridSetpointW: 6458 },
}, },
{
id: 'boost-batterie-1410-dans-le-budget',
label: '14/10 20:40 rejoue en force_charge_now — SOC 87, requis prudent 82,2 : la batterie d abord (budget 1,44 kWh fige)',
time: '2026-10-14T20:40:00+02:00',
overrides: { ...VOLVO_1410, victron_evcs_strategy: 'force_charge_now', boost_budget_prev: '' },
expect: { sourceMode: 'battery_assist_night', desiredCharging: true, boostBudgetWrite: '1.44|4144' },
},
{
id: 'boost-batterie-1410-budget-atteint-edf',
label: 'meme soiree, budget 1,44 kWh deja donne au compteur : EDF prend le relais',
time: '2026-10-14T20:40:00+02:00',
overrides: { ...VOLVO_1410, victron_evcs_strategy: 'force_charge_now', boost_budget_prev: '1.44|4142.5' },
expect: { sourceMode: 'grid_forced', state: 'charging_hold_grid', desiredCharging: true, boostBudgetWrite: null },
},
{
id: 'boost-batterie-bilan-perime-edf',
label: 'boost, bilan perime (2 h) : budget 0, EDF tout de suite, jamais la batterie a l aveugle',
time: '2026-10-14T20:40:00+02:00',
overrides: { ...VOLVO_1410, victron_evcs_strategy: 'force_charge_now', boost_budget_prev: '', balance_last_run: '14/10 18:35' },
expect: { sourceMode: 'grid_forced', state: 'charging_hold_grid', desiredCharging: true, boostBudgetWrite: '0|4144' },
},
{
id: 'boost-batterie-efface-a-la-sortie',
label: 'sortie du boost (retour auto_solar_plus) : le budget fige est efface',
time: '2026-10-14T20:40:00+02:00',
overrides: { ...VOLVO_1410, victron_evcs_strategy: 'auto_solar_plus', boost_budget_prev: '1.44|4144' },
expect: { boostBudgetWrite: '' },
},
]; ];

View File

@@ -226,6 +226,8 @@ export const ORIGINE_PAR_SOURCE = {
'Potentiel solaire': 'en_charge_solaire', 'Potentiel solaire': 'en_charge_solaire',
'Probe hybride': 'en_charge_sonde', 'Probe hybride': 'en_charge_sonde',
'Assistance batterie nuit': 'en_charge_batterie', 'Assistance batterie nuit': 'en_charge_batterie',
// 15/10/2026 : force_charge_now dans son budget batterie.
'Boost batterie': 'en_charge_batterie',
'Réseau HC autorisé': 'en_charge_reseau', 'Réseau HC autorisé': 'en_charge_reseau',
'Réseau forcé': 'en_charge_reseau', 'Réseau forcé': 'en_charge_reseau',
}; };

File diff suppressed because one or more lines are too long