P11: reset du collant 'plein' au changement de véhicule (charging_time)

- incident 12/08: JEEP chargée -> débranchée -> VW branchée bloquée par le
  collant night_recovery_done_idle de la JEEP
- snapshot +evcs_charging_time, INPUT_PARSE parseChargingTimeToSec
- WINDOWS: sessionFresh (<=90s) neutralise vehicleChargeCompleted/
  dayVehicleFullIdle/departureChargeDone/evcsStatusCharged
- golden 36->39, validé live 05:00:30 (VW débloquée: recovery_done -> wait_grid_takeover)
- HANDOFF §23 + MANUEL reset collant
This commit is contained in:
Tallagrand Thierry
2026-08-12 05:01:26 +02:00
parent 819eafd4d4
commit 5bc9784583
7 changed files with 167 additions and 3 deletions

View File

@@ -25,6 +25,7 @@
"evcs_command_current_a": states("number.victron_evcs_set_current_command"),
"evcs_current_a": states("sensor.victron_evcs_current"),
"evcs_ac_power_w": states("sensor.victron_evcs_ac_power"),
"evcs_charging_time": states("sensor.victron_evcs_charging_time"),
"evcs_charging_switch": states("switch.victron_evcs_charging"),
"evcs_auto_start_switch": states("switch.victron_evcs_auto_start"),

View File

@@ -158,6 +158,20 @@ function cleanText(v, fallback = '') {
return s;
}
// P11 (12/08/2026) : durée de charge EVCS "1h 49m 53s" / "8m 27s" / "0s"
// → secondes. Repart de 0 à chaque NOUVELLE connexion physique d'un véhicule
// (débranchement JEEP → branchement VW) → signal de reset du collant "plein".
function parseChargingTimeToSec(s) {
const t = (s ?? '').toString().toLowerCase();
if (!t) return null;
let sec = 0;
let matched = false;
const h = t.match(/(\d+)\s*h/); if (h) { sec += Number(h[1]) * 3600; matched = true; }
const m = t.match(/(\d+)\s*m/); if (m) { sec += Number(m[1]) * 60; matched = true; }
const s2 = t.match(/(\d+)\s*s/); if (s2){ sec += Number(s2[1]); matched = true; }
return matched ? sec : null;
}
// Advisor IA : input_text.evcs_advisor_last_run au format "DD/MM HH:mm"
// (pas d'année). On suppose l'année courante ; si le résultat est dans le
// futur (> 1 jour), c'est un passage d'année → on retire un an.
@@ -257,6 +271,7 @@ const parsed = {
evcsCurrentRealA: Math.max(0, num(input.evcs_current_a, 0)),
evcsAcPowerW: Math.max(0, num(input.evcs_ac_power_w, 0)),
evcsChargingTimeSec: parseChargingTimeToSec(input.evcs_charging_time),
evcsChargingSwitchOn: low(input.evcs_charging_switch || 'off') === 'on',
evcsAutoStartSwitchOn: low(input.evcs_auto_start_switch || 'off') === 'on',

View File

@@ -345,6 +345,19 @@ const nightTakeoverPrev =
// débranchement (state vehicle_not_connected) ou à la fin de la fenêtre nuit.
const prevSurplusState = (input.prev_surplus_state ?? '').toString().trim().toLowerCase();
// P11 (12/08/2026) : RESET du collant "véhicule plein" au CHANGEMENT DE
// VÉHICULE. Incident 12/08 : JEEP chargée → night_recovery_done_idle collant ;
// débranchement JEEP + branchement VW → l'état collant a survécu et bloquait
// la VW (« charge terminée » = celle de la JEEP, pas de la VW).
// Signal fiable : sensor.victron_evcs_charging_time repart de 0 à chaque
// nouvelle connexion physique. Sous ~90 s → session neuve → on neutralise le
// collant pour laisser le système RETESTER le véhicule fraîchement branché.
const P11_FRESH_SESSION_MAX_SEC = 90;
const sessionFresh =
parsed.evcsVehicleConnected &&
Number.isFinite(parsed.evcsChargingTimeSec) &&
parsed.evcsChargingTimeSec <= P11_FRESH_SESSION_MAX_SEC;
// Fix D (08/08/2026) : le statut natif EVCS "charged" (3) vaut aussi fin de
// charge, sans attendre le VehicleDemandFilter (désarmé si la session a été
// stoppée par une garde, ex battery_current_hard_stop → détection tardive
@@ -353,12 +366,16 @@ const prevSurplusState = (input.prev_surplus_state ?? '').toString().trim().toLo
// sur un glitch de statut pendant une vraie charge. NB : le statut retombe
// (3→1/6) dès l'ouverture du relais → la persistance est assurée par l'état
// collant écrit par DECISION pendant la session (voir Fix E DECISION).
// P11 : sur une session neuve, on ignore aussi un éventuel statut 3 résiduel
// (le temps que la borne renégocie avec le nouveau véhicule).
const evcsStatusCharged =
!sessionFresh &&
Number.parseFloat(parsed.evcsStatusRaw) === 3 &&
Math.max(0, parsed.evcsAcPowerW || 0) <= 300;
const vehicleChargeCompleted =
nightSessionActive &&
!sessionFresh &&
(
prevSurplusState === 'vehicle_full_or_paused' ||
prevSurplusState === 'night_session_done_idle' ||
@@ -415,6 +432,7 @@ const departureDonePrev =
const departureChargeDone =
departureWindowActive &&
!sessionFresh &&
(departureDonePrev || evcsStatusCharged);
const departureUrgentActive =
@@ -446,6 +464,7 @@ const dayVehicleFullPrev =
const dayVehicleFullIdle =
parsed.evcsVehicleConnected &&
!sessionFresh &&
!inNightHcWindow &&
!isStopMode &&
!forceGridRequested &&
@@ -851,6 +870,9 @@ return [{
// P10
dayVehicleFullIdle,
// P11
sessionFresh,
}
}
}];