Fix F: mémoire 'charge terminée' prioritaire sur les gardes (rebond rebranchement 09/08)
- DECISION: branche done/recovery_done remontée dans la cascade principale (avant mustStopHard) → le collant se réécrit chaque cycle, survit aux micro-charges de la VW et aux hard stops batterie - branche Fix E interne supprimée (remplacée par la branche haute) - golden 25→26 (night-hard-stop-necrase-pas-done) - HANDOFF §19
This commit is contained in:
41
HANDOFF.md
41
HANDOFF.md
@@ -855,3 +855,44 @@ Total attendu : EDF ON ~2-3 min UNE seule fois, puis silence.
|
|||||||
|
|
||||||
---
|
---
|
||||||
*Document mis à jour le : 09/08/2026 (~06:35) — Fix E déployé (EVCS + hystérésis), golden 25/25*
|
*Document mis à jour le : 09/08/2026 (~06:35) — Fix E déployé (EVCS + hystérésis), golden 25/25*
|
||||||
|
|
||||||
|
## 19. Session du 09/08/2026 (suite) — Fix F : la mémoire "charge terminée" est prioritaire sur les gardes
|
||||||
|
|
||||||
|
### Test de rebranchement utilisateur (~06:33, VW rebranchée en HC)
|
||||||
|
1. ✅ Fix E validé en réel : 06:51:00 `night_recovery_done_idle` latché,
|
||||||
|
06:51:03 `turn_off_recovery_done` → EDF coupé immédiatement (bypass min_on).
|
||||||
|
2. ❌ 06:53-06:56 : la VW a relancé une charge (status 2) qui, EDF OFF, tirait
|
||||||
|
sur la batterie (−47 A) → garde `mustStopHard` → état
|
||||||
|
`battery_current_hard_stop` ÉCRIT PAR-DESSUS le collant dans le helper →
|
||||||
|
completed perdu → re-P7 → EDF rallumé (hold_on_evcs_override, re-min_on 25).
|
||||||
|
→ Le collant ne survivait à AUCUN état émis par une branche plus prioritaire.
|
||||||
|
|
||||||
|
### Fix F (déployé 09/08 ~07:00, golden 26/26)
|
||||||
|
- DECISION : nouvelle branche dans la cascade PRINCIPALE, entre
|
||||||
|
`vehicle_not_connected` et `mustStopHard` :
|
||||||
|
`night_hc && vehicleChargeCompleted && !force*` → setOff avec l'état collant
|
||||||
|
(recovery_done/done_idle), `mustStop` si la borne est encore armée.
|
||||||
|
→ l'état collant est réécrit à CHAQUE cycle tant que VW branchée + fenêtre,
|
||||||
|
il survit aux micro-charges/gardes. Aucune perte de protection (le setOff
|
||||||
|
coupe chg/perm/latch comme un hard stop).
|
||||||
|
- La branche Fix E interne (session active) supprimée : remplacée par la
|
||||||
|
branche haute. La branche P8 historique (chaîne non-active) reste en filet.
|
||||||
|
- Golden 26 : `night-hard-stop-necrase-pas-done` (micro-charge −60 A sur
|
||||||
|
batterie avec prev=recovery_done → l'état reste recovery_done, stop ferme).
|
||||||
|
|
||||||
|
### Leçon d'architecture (pour le futur)
|
||||||
|
La "mémoire" portée par input_text.victron_evcs_surplus_state est fragile :
|
||||||
|
tout état émis l'écrase. Fix F la protège en réécrivant chaque cycle, mais la
|
||||||
|
solution PROPRE à terme est un helper dédié (input_boolean
|
||||||
|
victron_evcs_night_charge_done, package YAML + reload HA) si un nouveau cas
|
||||||
|
d'écrasement apparaît.
|
||||||
|
|
||||||
|
### Relecture de la nuit 08-09/08 (après coup)
|
||||||
|
La VW n'a pris que 5 kWh cette nuit, morcelés par les stops zombies (§18) :
|
||||||
|
elle n'était probablement PAS pleine. Les "micro-charges" du matin étaient de
|
||||||
|
vraies reprises. À 07:00 (post-Fix F) : charging_step_up_grid_hc = charge HC
|
||||||
|
nominale jusqu'à la fin de fenêtre 07:24. Le collant ne se posera que sur un
|
||||||
|
VRAI signal de fin (VDF no-demand ou status 3) — et tiendra désormais.
|
||||||
|
|
||||||
|
---
|
||||||
|
*Document mis à jour le : 09/08/2026 (~07:05) — Fix F déployé, golden 26/26*
|
||||||
|
|||||||
@@ -487,6 +487,38 @@ else if (!parsed.evcsDeviceConnected || !parsed.evcsVehicleConnected) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =====================================================
|
||||||
|
// Fix F (09/08/2026) : MÉMOIRE "CHARGE TERMINÉE" PRIORITAIRE.
|
||||||
|
// Incident 09/08 06:51→06:56 : la VW pleine relançait des micro-charges
|
||||||
|
// (sur batterie, EDF OFF) → la garde mustStopHard émettait
|
||||||
|
// 'battery_current_hard_stop' qui ÉCRASAIT l'état collant dans le helper
|
||||||
|
// → completed perdu au cycle suivant → re-P7 → EDF rallumé (rebond).
|
||||||
|
// Ici : tant que la session nuit est active et la charge terminée, l'état
|
||||||
|
// collant est réécrit à CHAQUE cycle, AU-DESSUS des gardes. Aucune perte de
|
||||||
|
// protection : ce setOff coupe la charge aussi fermement qu'un hard stop
|
||||||
|
// (chg/perm/latch OFF + mustStop si la borne est encore armée).
|
||||||
|
// =====================================================
|
||||||
|
else if (
|
||||||
|
context.profile === 'night_hc' &&
|
||||||
|
nightEvcs?.vehicleChargeCompleted &&
|
||||||
|
!manualLocalChargeAllowed &&
|
||||||
|
!strategy.forceGridRequested
|
||||||
|
) {
|
||||||
|
setOff({
|
||||||
|
stateName: nightEvcs?.nightRecoveryDone
|
||||||
|
? 'night_recovery_done_idle'
|
||||||
|
: 'night_session_done_idle',
|
||||||
|
decisionName: cloud.sessionObservedActive ? 'stop_vehicle_full_or_paused' : 'hold',
|
||||||
|
reasonText: nightEvcs?.nightRecoveryDone
|
||||||
|
? 'Charge véhicule terminée + batterie à la cible : veille nuit, réseau relâché'
|
||||||
|
: 'Charge véhicule terminée : veille nuit, réseau relâché (recharge batterie si sous cible)',
|
||||||
|
dynamic: false,
|
||||||
|
mustStopFlag: !!cloud.sessionObservedActive,
|
||||||
|
blockReason: 'none',
|
||||||
|
blockedUntilStamp: now.stamp,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
else if (safeguards.mustStopHard) {
|
else if (safeguards.mustStopHard) {
|
||||||
setOff({
|
setOff({
|
||||||
stateName:
|
stateName:
|
||||||
@@ -629,43 +661,18 @@ else if (cloud.sessionObservedActive) {
|
|||||||
const effectiveHoldConditionsOk =
|
const effectiveHoldConditionsOk =
|
||||||
holdConditionsOk || manualLocalHoldOverride;
|
holdConditionsOk || manualLocalHoldOverride;
|
||||||
|
|
||||||
// =================================================
|
|
||||||
// Fix E (09/08/2026) : CHARGE TERMINÉE PENDANT LA SESSION ACTIVE.
|
|
||||||
// Nuit 08-09/08 : status EVCS 3 "charged" → WINDOWS passe la source à
|
|
||||||
// 'blocked' (Fix D), mais ICI les branches source-lost prenaient la main
|
|
||||||
// (hold_min_run_source_lost 25 min puis stop_source_lost), l'état collant
|
|
||||||
// n'était JAMAIS écrit ; à l'ouverture du relais le statut retombe (3→1),
|
|
||||||
// completed redevenait faux → re-P7 → EDF rallumé → rebond ~30 min.
|
|
||||||
// On latche l'état collant AU PREMIER cycle où la fin de charge est vue,
|
|
||||||
// relais encore fermé, et on termine la session proprement (pas de min ON).
|
|
||||||
// =================================================
|
|
||||||
if (
|
|
||||||
context.profile === 'night_hc' &&
|
|
||||||
nightEvcs?.vehicleChargeCompleted &&
|
|
||||||
!manualLocalChargeAllowed &&
|
|
||||||
!strategy.forceGridRequested
|
|
||||||
) {
|
|
||||||
setOff({
|
|
||||||
stateName: nightEvcs?.nightRecoveryDone
|
|
||||||
? 'night_recovery_done_idle'
|
|
||||||
: 'night_session_done_idle',
|
|
||||||
decisionName: 'stop_vehicle_full_or_paused',
|
|
||||||
reasonText: 'Charge véhicule terminée en session active : arrêt propre, veille nuit collante',
|
|
||||||
dynamic: false,
|
|
||||||
mustStopFlag: false,
|
|
||||||
blockReason: 'none',
|
|
||||||
blockedUntilStamp: now.stamp,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// =================================================
|
// =================================================
|
||||||
// VEHICLE FULL / PAUSED - NUMERIC FILTER DECISION
|
// VEHICLE FULL / PAUSED - NUMERIC FILTER DECISION
|
||||||
|
// NB Fix F (09/08/2026) : le cas "charge terminée en session nuit" est
|
||||||
|
// désormais intercepté PLUS HAUT dans la cascade (mémoire prioritaire),
|
||||||
|
// avant les gardes. Ici ne restent que la détection VDF initiale et
|
||||||
|
// les autres sources.
|
||||||
// IMPORTANT:
|
// IMPORTANT:
|
||||||
// - uniquement en session active
|
// - uniquement en session active
|
||||||
// - uniquement si la source est réellement livrable
|
// - uniquement si la source est réellement livrable
|
||||||
// - sans utiliser le PV comme critère
|
// - sans utiliser le PV comme critère
|
||||||
// =================================================
|
// =================================================
|
||||||
else if (
|
if (
|
||||||
vehicleDemandFilter.evcsVehicleNoDemandSemantic &&
|
vehicleDemandFilter.evcsVehicleNoDemandSemantic &&
|
||||||
vehicleDemandFilter.sourceDeliverableForNoDemand
|
vehicleDemandFilter.sourceDeliverableForNoDemand
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -350,6 +350,33 @@ export const scenarios = [
|
|||||||
takeoverHelperService: 'turn_off',
|
takeoverHelperService: 'turn_off',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'night-hard-stop-necrase-pas-done',
|
||||||
|
label: 'Nuit HC 06:55, VW pleine relance une micro-charge sur batterie (−60 A) → le hard stop N\'ÉCRASE PAS le collant (Fix F)',
|
||||||
|
time: '2026-08-09T06:55:00+02:00',
|
||||||
|
overrides: {
|
||||||
|
...VEHICLE_NIGHT, soc_percent: '40', allow_grid_hc_night: 'on',
|
||||||
|
battery_current_a: '-60',
|
||||||
|
evcs_charging_switch: 'on',
|
||||||
|
charge_permission_now: 'on',
|
||||||
|
control_latch: 'on',
|
||||||
|
evcs_current_a: '6',
|
||||||
|
evcs_ac_power_w: '1400',
|
||||||
|
evcs_status_raw: '2',
|
||||||
|
prev_surplus_state: 'night_recovery_done_idle',
|
||||||
|
},
|
||||||
|
expect: {
|
||||||
|
profile: 'night_hc',
|
||||||
|
sourceMode: 'blocked',
|
||||||
|
state: 'night_recovery_done_idle',
|
||||||
|
decision: 'stop_vehicle_full_or_paused',
|
||||||
|
desiredCharging: false,
|
||||||
|
currentA: 6,
|
||||||
|
takeoverNeeded: false,
|
||||||
|
edfOnAction: false,
|
||||||
|
takeoverHelperService: 'turn_off',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
// ================= JOUR SOLAIRE =================
|
// ================= JOUR SOLAIRE =================
|
||||||
{
|
{
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user