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:
@@ -360,7 +360,6 @@ const batteryMorningTargetPct =
|
||||
Number.isFinite(nightPrev.batteryMorningTargetPct)
|
||||
? nightPrev.batteryMorningTargetPct
|
||||
: params.evcsNightTargetWeakForecastPct;
|
||||
const advisorNightTargetApplied = !!nightPrev.advisorNightTargetApplied;
|
||||
const balanceMorningTargetApplied = !!nightPrev.balanceMorningTargetApplied;
|
||||
const nightGridSessionCommitted = !!nightPrev.nightGridSessionCommitted;
|
||||
const maxBatteryDischargePoints =
|
||||
@@ -1081,7 +1080,6 @@ return [{
|
||||
|
||||
batteryHardFloorPct,
|
||||
batteryMorningTargetPct,
|
||||
advisorNightTargetApplied,
|
||||
balanceMorningTargetApplied,
|
||||
nightGridSessionCommitted,
|
||||
maxBatteryDischargePoints,
|
||||
|
||||
@@ -1319,7 +1319,7 @@ else {
|
||||
// =====================================================
|
||||
if (nightEvcs?.nightSessionActive) {
|
||||
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)) {
|
||||
|
||||
@@ -141,10 +141,6 @@
|
||||
"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_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_energy_to_cover_kwh": states("input_number.evcs_balance_energy_to_cover_kwh"),
|
||||
|
||||
@@ -172,10 +172,12 @@ function parseChargingTimeToSec(s) {
|
||||
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
|
||||
// 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})$/);
|
||||
if (!m) return null;
|
||||
|
||||
@@ -464,17 +466,13 @@ const params = {
|
||||
// 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.
|
||||
// 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
|
||||
// ("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)),
|
||||
balanceLastRunMs: parseRunStampToMs(cleanText(input.balance_last_run)),
|
||||
|
||||
// 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,
|
||||
|
||||
@@ -268,31 +268,18 @@ const batteryMorningTargetRulePct =
|
||||
: params.evcsNightTargetWeakForecastPct;
|
||||
|
||||
// =====================================================
|
||||
// ADVISOR IA — PREMIER CÂBLAGE RÉEL (09/08/2026, HANDOFF §20)
|
||||
// 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é).
|
||||
// LE CONSEILLER NE FIXE PLUS LA CIBLE (retire le 13/09/2026)
|
||||
// =====================================================
|
||||
const ADVISOR_TARGET_MAX_AGE_MIN = 120;
|
||||
const advisorTargetAgeMin = minutesSince(params.advisorLastRunMs, nowMs);
|
||||
const advisorNightTargetApplied =
|
||||
params.advisorApplyNightTarget &&
|
||||
params.advisorStatusOk &&
|
||||
Number.isFinite(params.advisorNightTargetSocPct) &&
|
||||
advisorTargetAgeMin !== null &&
|
||||
advisorTargetAgeMin <= ADVISOR_TARGET_MAX_AGE_MIN;
|
||||
|
||||
const batteryMorningTargetBasePct =
|
||||
advisorNightTargetApplied
|
||||
? clamp(
|
||||
params.advisorNightTargetSocPct,
|
||||
Math.max(22, batteryHardFloorPct),
|
||||
90
|
||||
)
|
||||
: batteryMorningTargetRulePct;
|
||||
// Le premier cablage reel (09/08/2026, HANDOFF §20) faisait suivre a la cible
|
||||
// du matin `input_number.evcs_advisor_night_target_soc`, derriere un toggle,
|
||||
// un statut `ok`, une fraicheur de 120 min et un bornage.
|
||||
// Le 12/09 le conseiller est devenu OBSERVATEUR : il n'emet plus de cible, et
|
||||
// ce helper est fige depuis. Les quatre gardes continuaient pourtant de passer
|
||||
// toutes les quatre — la garde de fraicheur date le RUN, pas la VALEUR, et le
|
||||
// conseiller tourne toujours. Activer le toggle aurait donc applique un chiffre
|
||||
// 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 = batteryMorningTargetRulePct;
|
||||
|
||||
// =====================================================
|
||||
// CIBLE DU MATIN : UNE ENERGIE A COUVRIR, PAS UN PALIER (03/09/2026)
|
||||
@@ -1059,7 +1046,6 @@ return [{
|
||||
balanceTargetAgeMin:
|
||||
balanceTargetAgeMin === null ? null : Math.round(balanceTargetAgeMin * 10) / 10,
|
||||
batteryMorningTargetRulePct,
|
||||
advisorNightTargetApplied,
|
||||
maxBatteryDischargePoints,
|
||||
gridTakeoverTriggerPct,
|
||||
|
||||
|
||||
Reference in New Issue
Block a user