Advisor: premier câblage réel — cible SOC matin (toggle, bornes, fraîcheur 120min)
- nouveau toggle input_boolean.evcs_advisor_apply_night_target (package + carte, OFF par défaut) - snapshot/INPUT_PARSE: advisor_apply/target/status/last_run (+parseAdvisorRunToMs DD/MM HH:mm) - WINDOWS: batteryMorningTargetPct = advisor si ON+ok+frais, clamp [max(22,hardFloor),90], sinon règles forecast; traçabilité '(ADVISOR)' dans la reason DECISION - golden 26→29 (appliqué / stale / toggle off) - HANDOFF §20 (surveillance + rollback 3 niveaux)
This commit is contained in:
@@ -158,6 +158,33 @@ function cleanText(v, fallback = '') {
|
||||
return s;
|
||||
}
|
||||
|
||||
// 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.
|
||||
function parseAdvisorRunToMs(s) {
|
||||
const m = (s ?? '').toString().trim().match(/^(\d{2})\/(\d{2}) (\d{2}):(\d{2})$/);
|
||||
if (!m) return null;
|
||||
|
||||
const nowMsLocal = Date.now();
|
||||
const year = Number(
|
||||
new Intl.DateTimeFormat('fr-FR', { timeZone: 'Europe/Paris', year: 'numeric' })
|
||||
.format(new Date(nowMsLocal))
|
||||
);
|
||||
|
||||
const build = (y) => {
|
||||
const guessUtc = Date.UTC(y, Number(m[2]) - 1, Number(m[1]), Number(m[3]), Number(m[4]), 0);
|
||||
const off1 = getTzOffsetMs(guessUtc, 'Europe/Paris');
|
||||
let ts = guessUtc - off1;
|
||||
const off2 = getTzOffsetMs(ts, 'Europe/Paris');
|
||||
if (off2 !== off1) ts = guessUtc - off2;
|
||||
return ts;
|
||||
};
|
||||
|
||||
let ts = build(year);
|
||||
if (ts - nowMsLocal > 24 * 3600 * 1000) ts = build(year - 1);
|
||||
return ts;
|
||||
}
|
||||
|
||||
function finiteOrNull(v) {
|
||||
return Number.isFinite(v) ? v : null;
|
||||
}
|
||||
@@ -336,6 +363,14 @@ const params = {
|
||||
allowGridHcNight: low(input.allow_grid_hc_night || 'off') === 'on',
|
||||
allowGridHcMidday: low(input.allow_grid_hc_midday || 'off') === 'on',
|
||||
|
||||
// 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)),
|
||||
|
||||
probeEnabled: low(input.probe_enabled || 'off') === 'on',
|
||||
probeMinutes: Math.max(1, num(input.probe_minutes, 3)),
|
||||
probeRetryMinutes: Math.max(5, num(input.probe_retry_minutes, 45)),
|
||||
|
||||
Reference in New Issue
Block a user