Le conseiller ne fixe plus la cible du matin
Le premier cablage reel (§20, 09/08) faisait suivre a la cible SOC du matin `input_number.evcs_advisor_night_target_soc`, derriere quatre gardes : toggle, statut ok, fraicheur de 120 minutes, bornage [22, 90]. Depuis que le conseiller est devenu observateur le 12/09, il n emet plus de cible et ce helper est fige a 55 %. Les quatre gardes continuaient pourtant de passer toutes les quatre, parce que la garde de fraicheur date le RUN et non la VALEUR : le conseiller tourne toujours, donc son horodatage est frais. Activer le toggle aurait applique un chiffre perime sans qu aucune garde ne s y oppose. Retire : les quatre parametres d INPUT_PARSE, le bloc de WINDOWS_SOURCEV2, le passe-plat de BATTERY_CLOUD_LOCKS, la trace (ADVISOR) de DECISION et les quatre champs du gabarit de snapshot. Le cablage du BILAN (§39) est intact. `parseAdvisorRunToMs` devient `parseRunStampToMs` : le bilan publie le meme format et reste son seul appelant. Golden 98 → 96. Les trois scenarios du cablage sont remplaces par un seul, `advisor-cible-ignoree`, qui pinne l ABSENCE de cablage : toutes les conditions de l ancienne regle reunies, et la cible doit rester celle des regles de prevision. Mutation : cablage restaure → il tombe, avec « target=22% (ADVISOR) » dans la raison ; retire → 96/96. Gabarit re-rendu contre Home Assistant : 196 champs, JSON valide, aucun null. Pousse en production, cycle suivant en succes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
This commit is contained in:
27
HANDOFF.md
27
HANDOFF.md
@@ -5964,9 +5964,30 @@ traverse. Si le toggle `evcs_advisor_apply_night_target` est active, la cible de
|
|||||||
la nuit devient un 55 fige d hier matin.
|
la nuit devient un 55 fige d hier matin.
|
||||||
|
|
||||||
La garde de fraicheur ne protege donc pas ce qu elle croit proteger : elle date
|
La garde de fraicheur ne protege donc pas ce qu elle croit proteger : elle date
|
||||||
le RUN, pas la VALEUR. Le toggle est OFF aujourd hui. Le cablage est devenu du
|
le RUN, pas la VALEUR.
|
||||||
code mort qui ne peut que se tromper — a retirer (trois scenarios golden), mais
|
|
||||||
c est une decision du proprietaire, §20 etant un jalon qu il avait valide.
|
**RETIRE le 13/09/2026 sur decision du proprietaire.** Les quatre parametres
|
||||||
|
d INPUT_PARSE, le bloc de WINDOWS_SOURCEV2, le passe-plat de BATTERY_CLOUD_LOCKS,
|
||||||
|
la trace `(ADVISOR)` de DECISION_ENGINEV2 et les quatre champs du gabarit de
|
||||||
|
snapshot. `batteryMorningTargetBasePct` vaut desormais simplement la regle de
|
||||||
|
prevision ; le cablage du BILAN (§39), lui, est intact et continue de ne pouvoir
|
||||||
|
que RELEVER cette cible.
|
||||||
|
`parseAdvisorRunToMs` est renommee `parseRunStampToMs` : elle sert encore au
|
||||||
|
bilan, qui publie le meme format, mais son nom designait un appelant disparu.
|
||||||
|
|
||||||
|
Golden 98 → 96 : les trois scenarios du cablage (applique / perime / toggle OFF)
|
||||||
|
sont remplaces par UN seul, `advisor-cible-ignoree`, qui pinne l ABSENCE de
|
||||||
|
cablage — toutes les conditions de l ancienne regle reunies, et la cible doit
|
||||||
|
rester celle des regles. Preuve par mutation : cablage restaure → ce scenario
|
||||||
|
tombe avec `target=22% (ADVISOR)` dans la raison ; retire → 96/96.
|
||||||
|
Gabarit re-rendu contre Home Assistant : 196 champs, JSON valide, aucun null,
|
||||||
|
plus aucun champ advisor.
|
||||||
|
|
||||||
|
⚠️ RESTE : les cinq helpers eux-memes existent toujours cote Home Assistant et
|
||||||
|
la carte « Conseiller IA » affiche encore « Cible SOC matin (agent) : 55 % »,
|
||||||
|
figee depuis le 12/09. Plus rien ne la lit, mais un chiffre fige affiche comme
|
||||||
|
une recommandation courante est exactement le fantome qui a cree le danger
|
||||||
|
ci-dessus. A nettoyer (paquet + carte).
|
||||||
|
|
||||||
---
|
---
|
||||||
*Document mis a jour le : 13/09/2026 — campagne conseiller : quatre defauts du prompt corriges, incidents 39/40, table `observation`*
|
*Document mis a jour le : 13/09/2026 — campagne conseiller : quatre defauts du prompt corriges, incidents 39/40, table `observation`*
|
||||||
|
|||||||
@@ -360,7 +360,6 @@ const batteryMorningTargetPct =
|
|||||||
Number.isFinite(nightPrev.batteryMorningTargetPct)
|
Number.isFinite(nightPrev.batteryMorningTargetPct)
|
||||||
? nightPrev.batteryMorningTargetPct
|
? nightPrev.batteryMorningTargetPct
|
||||||
: params.evcsNightTargetWeakForecastPct;
|
: params.evcsNightTargetWeakForecastPct;
|
||||||
const advisorNightTargetApplied = !!nightPrev.advisorNightTargetApplied;
|
|
||||||
const balanceMorningTargetApplied = !!nightPrev.balanceMorningTargetApplied;
|
const balanceMorningTargetApplied = !!nightPrev.balanceMorningTargetApplied;
|
||||||
const nightGridSessionCommitted = !!nightPrev.nightGridSessionCommitted;
|
const nightGridSessionCommitted = !!nightPrev.nightGridSessionCommitted;
|
||||||
const maxBatteryDischargePoints =
|
const maxBatteryDischargePoints =
|
||||||
@@ -1081,7 +1080,6 @@ return [{
|
|||||||
|
|
||||||
batteryHardFloorPct,
|
batteryHardFloorPct,
|
||||||
batteryMorningTargetPct,
|
batteryMorningTargetPct,
|
||||||
advisorNightTargetApplied,
|
|
||||||
balanceMorningTargetApplied,
|
balanceMorningTargetApplied,
|
||||||
nightGridSessionCommitted,
|
nightGridSessionCommitted,
|
||||||
maxBatteryDischargePoints,
|
maxBatteryDischargePoints,
|
||||||
|
|||||||
@@ -1319,7 +1319,7 @@ else {
|
|||||||
// =====================================================
|
// =====================================================
|
||||||
if (nightEvcs?.nightSessionActive) {
|
if (nightEvcs?.nightSessionActive) {
|
||||||
reason.push(
|
reason.push(
|
||||||
`Nuit EVCS: target=${round1(nightEvcs.batteryMorningTargetPct)}%${nightEvcs.advisorNightTargetApplied ? ' (ADVISOR)' : ''}${nightEvcs.balanceMorningTargetApplied ? ' (BILAN)' : ''} | trigger réseau=${round1(nightEvcs.gridTakeoverTriggerPct)}%`
|
`Nuit EVCS: target=${round1(nightEvcs.batteryMorningTargetPct)}%${nightEvcs.balanceMorningTargetApplied ? ' (BILAN)' : ''} | trigger réseau=${round1(nightEvcs.gridTakeoverTriggerPct)}%`
|
||||||
);
|
);
|
||||||
|
|
||||||
if (Number.isFinite(nightEvcs.nightSessionStartSocPct)) {
|
if (Number.isFinite(nightEvcs.nightSessionStartSocPct)) {
|
||||||
|
|||||||
@@ -141,10 +141,6 @@
|
|||||||
"prev_surplus_state": states("input_text.victron_evcs_surplus_state"),
|
"prev_surplus_state": states("input_text.victron_evcs_surplus_state"),
|
||||||
"evcs_night_session_start_soc": states("input_text.victron_evcs_night_session_start_soc"),
|
"evcs_night_session_start_soc": states("input_text.victron_evcs_night_session_start_soc"),
|
||||||
"evcs_night_session_start_at": states("input_text.victron_evcs_night_session_start_at"),
|
"evcs_night_session_start_at": states("input_text.victron_evcs_night_session_start_at"),
|
||||||
"advisor_apply_night_target": states("input_boolean.evcs_advisor_apply_night_target"),
|
|
||||||
"advisor_night_target_soc": states("input_number.evcs_advisor_night_target_soc"),
|
|
||||||
"advisor_status": states("input_text.evcs_advisor_status"),
|
|
||||||
"advisor_last_run": states("input_text.evcs_advisor_last_run"),
|
|
||||||
|
|
||||||
"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"),
|
||||||
|
|||||||
@@ -172,10 +172,12 @@ function parseChargingTimeToSec(s) {
|
|||||||
return matched ? sec : null;
|
return matched ? sec : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Advisor IA : input_text.evcs_advisor_last_run au format "DD/MM HH:mm"
|
// Horodatage "DD/MM HH:mm" publie par le bilan energetique
|
||||||
|
// (input_text.evcs_balance_last_run). Le conseiller employait le meme format ;
|
||||||
|
// son cablage a ete retire le 13/09/2026, la fonction sert desormais au bilan.
|
||||||
// (pas d'année). On suppose l'année courante ; si le résultat est dans le
|
// (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.
|
// futur (> 1 jour), c'est un passage d'année → on retire un an.
|
||||||
function parseAdvisorRunToMs(s) {
|
function parseRunStampToMs(s) {
|
||||||
const m = (s ?? '').toString().trim().match(/^(\d{2})\/(\d{2}) (\d{2}):(\d{2})$/);
|
const m = (s ?? '').toString().trim().match(/^(\d{2})\/(\d{2}) (\d{2}):(\d{2})$/);
|
||||||
if (!m) return null;
|
if (!m) return null;
|
||||||
|
|
||||||
@@ -464,17 +466,13 @@ const params = {
|
|||||||
// Advisor IA — premier câblage réel (09/08/2026, HANDOFF §20) :
|
// Advisor IA — premier câblage réel (09/08/2026, HANDOFF §20) :
|
||||||
// cible SOC matin recommandée, appliquée UNIQUEMENT si le toggle est ON.
|
// cible SOC matin recommandée, appliquée UNIQUEMENT si le toggle est ON.
|
||||||
// Garde-fous consommés dans WINDOWS_SOURCEV2 (statut ok + fraîcheur + bornes).
|
// Garde-fous consommés dans WINDOWS_SOURCEV2 (statut ok + fraîcheur + bornes).
|
||||||
advisorApplyNightTarget: low(input.advisor_apply_night_target || 'off') === 'on',
|
|
||||||
advisorNightTargetSocPct: num(input.advisor_night_target_soc, NaN),
|
|
||||||
advisorStatusOk: cleanText(input.advisor_status).toLowerCase() === 'ok',
|
|
||||||
advisorLastRunMs: parseAdvisorRunToMs(cleanText(input.advisor_last_run)),
|
|
||||||
|
|
||||||
// BILAN ENERGETIQUE (03/09/2026). Meme format d'horodatage que l'advisor
|
// BILAN ENERGETIQUE (03/09/2026). Meme format d'horodatage que l'advisor
|
||||||
// ("DD/MM HH:mm"), d'ou la reutilisation du parseur.
|
// ("DD/MM HH:mm"), d'ou la reutilisation du parseur.
|
||||||
balanceRequiredSocPct: num(input.balance_required_soc, NaN),
|
balanceRequiredSocPct: num(input.balance_required_soc, NaN),
|
||||||
balanceEnergyToCoverKwh: num(input.balance_energy_to_cover_kwh, NaN),
|
balanceEnergyToCoverKwh: num(input.balance_energy_to_cover_kwh, NaN),
|
||||||
balanceStatusOk: cleanText(input.balance_status).toLowerCase() === 'ok',
|
balanceStatusOk: cleanText(input.balance_status).toLowerCase() === 'ok',
|
||||||
balanceLastRunMs: parseAdvisorRunToMs(cleanText(input.balance_last_run)),
|
balanceLastRunMs: parseRunStampToMs(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,
|
||||||
|
|||||||
@@ -268,31 +268,18 @@ const batteryMorningTargetRulePct =
|
|||||||
: params.evcsNightTargetWeakForecastPct;
|
: params.evcsNightTargetWeakForecastPct;
|
||||||
|
|
||||||
// =====================================================
|
// =====================================================
|
||||||
// ADVISOR IA — PREMIER CÂBLAGE RÉEL (09/08/2026, HANDOFF §20)
|
// LE CONSEILLER NE FIXE PLUS LA CIBLE (retire le 13/09/2026)
|
||||||
// La cible SOC matin suit la recommandation de l'advisor UNIQUEMENT si :
|
|
||||||
// - toggle input_boolean.evcs_advisor_apply_night_target ON (rollback 1 clic)
|
|
||||||
// - dernier run advisor en statut 'ok'
|
|
||||||
// - recommandation fraîche (≤ 120 min, l'advisor tourne toutes les 15 min)
|
|
||||||
// - valeur bornée [max(22, hard floor), 90]
|
|
||||||
// Sinon : règles forecast historiques (comportement inchangé).
|
|
||||||
// =====================================================
|
// =====================================================
|
||||||
const ADVISOR_TARGET_MAX_AGE_MIN = 120;
|
// Le premier cablage reel (09/08/2026, HANDOFF §20) faisait suivre a la cible
|
||||||
const advisorTargetAgeMin = minutesSince(params.advisorLastRunMs, nowMs);
|
// du matin `input_number.evcs_advisor_night_target_soc`, derriere un toggle,
|
||||||
const advisorNightTargetApplied =
|
// un statut `ok`, une fraicheur de 120 min et un bornage.
|
||||||
params.advisorApplyNightTarget &&
|
// Le 12/09 le conseiller est devenu OBSERVATEUR : il n'emet plus de cible, et
|
||||||
params.advisorStatusOk &&
|
// ce helper est fige depuis. Les quatre gardes continuaient pourtant de passer
|
||||||
Number.isFinite(params.advisorNightTargetSocPct) &&
|
// toutes les quatre — la garde de fraicheur date le RUN, pas la VALEUR, et le
|
||||||
advisorTargetAgeMin !== null &&
|
// conseiller tourne toujours. Activer le toggle aurait donc applique un chiffre
|
||||||
advisorTargetAgeMin <= ADVISOR_TARGET_MAX_AGE_MIN;
|
// perime sans qu'aucune garde ne s'y oppose. Un cablage qui ne peut plus que se
|
||||||
|
// tromper se retire ; le scenario `advisor-cible-ignoree` le verifie.
|
||||||
const batteryMorningTargetBasePct =
|
const batteryMorningTargetBasePct = batteryMorningTargetRulePct;
|
||||||
advisorNightTargetApplied
|
|
||||||
? clamp(
|
|
||||||
params.advisorNightTargetSocPct,
|
|
||||||
Math.max(22, batteryHardFloorPct),
|
|
||||||
90
|
|
||||||
)
|
|
||||||
: batteryMorningTargetRulePct;
|
|
||||||
|
|
||||||
// =====================================================
|
// =====================================================
|
||||||
// CIBLE DU MATIN : UNE ENERGIE A COUVRIR, PAS UN PALIER (03/09/2026)
|
// CIBLE DU MATIN : UNE ENERGIE A COUVRIR, PAS UN PALIER (03/09/2026)
|
||||||
@@ -1059,7 +1046,6 @@ return [{
|
|||||||
balanceTargetAgeMin:
|
balanceTargetAgeMin:
|
||||||
balanceTargetAgeMin === null ? null : Math.round(balanceTargetAgeMin * 10) / 10,
|
balanceTargetAgeMin === null ? null : Math.round(balanceTargetAgeMin * 10) / 10,
|
||||||
batteryMorningTargetRulePct,
|
batteryMorningTargetRulePct,
|
||||||
advisorNightTargetApplied,
|
|
||||||
maxBatteryDischargePoints,
|
maxBatteryDischargePoints,
|
||||||
gridTakeoverTriggerPct,
|
gridTakeoverTriggerPct,
|
||||||
|
|
||||||
|
|||||||
@@ -140,12 +140,16 @@ export const scenarios = [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
// ===== ADVISOR IA — premier câblage réel (09/08/2026, HANDOFF §20) =====
|
// ===== LE CONSEILLER NE FIXE PLUS LA CIBLE (13/09/2026) =====
|
||||||
// Référence : night-soc-sous-cible (SOC 30 < cible règle 35 → grid_forced).
|
// Les trois scenarios du premier cablage (applique / perime / toggle OFF)
|
||||||
// Avec la cible advisor 22 APPLIQUÉE : SOC 30 ≥ 22 → grid_hc_allowed.
|
// sont remplaces par celui-ci, qui pinne l'ABSENCE de cablage : toutes les
|
||||||
|
// conditions de l'ancienne regle sont reunies — toggle ON, statut ok,
|
||||||
|
// horodatage frais, valeur dans les bornes — et la cible doit rester celle
|
||||||
|
// des regles de prevision. Si quelqu'un recable un jour, ce test tombe.
|
||||||
|
// Reference : night-soc-sous-cible (SOC 30 < cible regle 35 → grid_forced).
|
||||||
{
|
{
|
||||||
id: 'night-advisor-target-applique',
|
id: 'advisor-cible-ignoree',
|
||||||
label: 'Nuit HC, SOC 30, advisor cible 22 appliquée (toggle ON, ok, frais) → hc_allowed au lieu de grid_forced',
|
label: 'Nuit HC, SOC 30, helpers advisor au complet et frais → IGNORES, cible des regles (grid_forced)',
|
||||||
time: NIGHT,
|
time: NIGHT,
|
||||||
overrides: {
|
overrides: {
|
||||||
...VEHICLE_NIGHT, soc_percent: '30', allow_grid_hc_night: 'on',
|
...VEHICLE_NIGHT, soc_percent: '30', allow_grid_hc_night: 'on',
|
||||||
@@ -154,52 +158,6 @@ export const scenarios = [
|
|||||||
advisor_status: 'ok',
|
advisor_status: 'ok',
|
||||||
advisor_last_run: '08/08 01:20',
|
advisor_last_run: '08/08 01:20',
|
||||||
},
|
},
|
||||||
expect: {
|
|
||||||
profile: 'night_hc',
|
|
||||||
sourceMode: 'grid_hc_allowed',
|
|
||||||
state: 'night_wait_grid_takeover',
|
|
||||||
decision: 'hold',
|
|
||||||
desiredCharging: false,
|
|
||||||
currentA: 6,
|
|
||||||
takeoverNeeded: true,
|
|
||||||
edfOnAction: true,
|
|
||||||
takeoverHelperService: 'turn_on',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'night-advisor-target-stale',
|
|
||||||
label: 'Nuit HC, SOC 30, advisor cible 22 mais recommandation > 120 min → fallback règles (grid_forced)',
|
|
||||||
time: NIGHT,
|
|
||||||
overrides: {
|
|
||||||
...VEHICLE_NIGHT, soc_percent: '30', allow_grid_hc_night: 'on',
|
|
||||||
advisor_apply_night_target: 'on',
|
|
||||||
advisor_night_target_soc: '22',
|
|
||||||
advisor_status: 'ok',
|
|
||||||
advisor_last_run: '07/08 20:00',
|
|
||||||
},
|
|
||||||
expect: {
|
|
||||||
profile: 'night_hc',
|
|
||||||
sourceMode: 'grid_forced',
|
|
||||||
state: 'night_wait_grid_takeover',
|
|
||||||
decision: 'hold',
|
|
||||||
desiredCharging: false,
|
|
||||||
currentA: 6,
|
|
||||||
takeoverNeeded: true,
|
|
||||||
edfOnAction: true,
|
|
||||||
takeoverHelperService: 'turn_on',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'night-advisor-toggle-off',
|
|
||||||
label: 'Nuit HC, SOC 30, advisor cible 22 mais toggle APPLIQUER OFF → règles inchangées (grid_forced)',
|
|
||||||
time: NIGHT,
|
|
||||||
overrides: {
|
|
||||||
...VEHICLE_NIGHT, soc_percent: '30', allow_grid_hc_night: 'on',
|
|
||||||
advisor_apply_night_target: 'off',
|
|
||||||
advisor_night_target_soc: '22',
|
|
||||||
advisor_status: 'ok',
|
|
||||||
advisor_last_run: '08/08 01:20',
|
|
||||||
},
|
|
||||||
expect: {
|
expect: {
|
||||||
profile: 'night_hc',
|
profile: 'night_hc',
|
||||||
sourceMode: 'grid_forced',
|
sourceMode: 'grid_forced',
|
||||||
@@ -212,11 +170,6 @@ export const scenarios = [
|
|||||||
takeoverHelperService: 'turn_on',
|
takeoverHelperService: 'turn_on',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
// ===== P9 09/08/2026 : charge réseau avant départ (hors HC) + sélecteur véhicule =====
|
|
||||||
// VW départ 08:50 (helper existant), JEEP départ 06:30 (nouveau helper).
|
|
||||||
// À 08:00 (morning_solar, PV nul) : VW → fenêtre départ active (50 min) ;
|
|
||||||
// JEEP → départ passé depuis 90 min → rien.
|
|
||||||
{
|
{
|
||||||
id: 'p9-depart-vw-grid',
|
id: 'p9-depart-vw-grid',
|
||||||
label: 'Matin 08:00, VW sélectionnée, départ 08:50, toggle P9 ON, SOC 45, PV nul → réseau autorisé + EDF demandé',
|
label: 'Matin 08:00, VW sélectionnée, départ 08:50, toggle P9 ON, SOC 45, PV nul → réseau autorisé + EDF demandé',
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user