Files
EVCS/tools/ha-history.mjs
Tallagrand Thierry bfa8a5ffd8 Les fantomes du conseiller sont retires
Six helpers que plus personne n ecrivait depuis la specialisation du 12/09
restaient affiches sur la carte du tableau EVCS Master comme des
recommandations courantes : strategie, charge du soir, divergence, cible SOC
matin figee a 55 %, plafond courant, et le toggle qui appliquait la cible.
C est exactement ce fantome qui a rendu le cablage dangereux — la garde de
fraicheur datait le run, pas la valeur.

Retires du paquet et de la carte, sauvegardes dans SAVE/. La carte est
reecrite pour ce que le conseiller fait desormais : gravite, ce qu il voit,
ce qui cloche, la piste et sa confiance.

Le conseiller relisait aussi SA PROPRE strategie precedente — figee depuis
le 12/09, et parsee sans jamais servir dans le prompt. Retiree de son
snapshot et de BUILD_PROMPT.

Apres rechargement des trois domaines : dix helpers restants, exactement
ceux que l observateur ecrit. Les compteurs ont survecu (8 cycles calmes,
0 signalement), ce qui valide la suppression des `initial:` du matin meme.

Gabarit du conseiller re-rendu contre Home Assistant : 48 champs, JSON
valide, aucun null. Pousse.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
2026-09-13 12:39:39 +02:00

85 lines
3.0 KiB
JavaScript

#!/usr/bin/env node
// Usage: node tools/ha-history.mjs <entity_id>[,<entity_id>...] [debut] [fin]
// node tools/ha-history.mjs sensor.victron_battery_soc 2026-08-25T00:00 2026-08-25T10:00
// node tools/ha-history.mjs input_boolean.evcs_advisor_enabled -48h
//
// Lit l'historique d'états via l'API REST de Home Assistant (jeton dans .env,
// même mécanique que tools/ha-service.mjs).
//
// ⚠️ PIÈGE VÉRIFIÉ : /api/history/period ne renvoie QU'UNE SEULE JOURNÉE si
// end_time est omis, sans le signaler. Ce script impose donc toujours les deux
// bornes.
//
// Les MCP du projet ne donnent que l'état courant : pour toute analyse
// a posteriori (qui a changé quoi, et quand), il faut l'historique.
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
function loadToken() {
if (process.env.HA_TOKEN) return process.env.HA_TOKEN;
const envPath = path.join(ROOT, '.env');
if (!fs.existsSync(envPath)) {
console.error('Jeton introuvable : ni $HA_TOKEN, ni fichier .env.');
process.exit(1);
}
for (const line of fs.readFileSync(envPath, 'utf8').split('\n')) {
const m = line.match(/^\s*HA_TOKEN\s*=\s*(.+?)\s*$/);
if (m) return m[1].replace(/^["']|["']$/g, '');
}
console.error('HA_TOKEN absent du fichier .env');
process.exit(1);
}
const HA_URL = process.env.HA_URL || 'http://10.10.10.17:8123';
const entities = (process.argv[2] || '').split(',').filter(Boolean);
if (!entities.length) {
console.error('Usage: node tools/ha-history.mjs <entity_id>[,...] [debut|-Nh] [fin]');
process.exit(1);
}
function parseBound(arg, fallback) {
if (!arg) return fallback;
const rel = arg.match(/^-(\d+)h$/);
if (rel) return new Date(Date.now() - Number(rel[1]) * 3600e3);
return new Date(arg);
}
const end = parseBound(process.argv[4], new Date());
const start = parseBound(process.argv[3], new Date(end.getTime() - 24 * 3600e3));
const url =
`${HA_URL}/api/history/period/${start.toISOString()}` +
`?end_time=${encodeURIComponent(end.toISOString())}` +
`&filter_entity_id=${encodeURIComponent(entities.join(','))}` +
`&minimal_response&significant_changes_only`;
const res = await fetch(url, { headers: { Authorization: `Bearer ${loadToken()}` } });
if (!res.ok) {
console.error(`HTTP ${res.status} — ${await res.text()}`);
process.exit(1);
}
const series = await res.json();
const fmt = (iso) =>
new Date(iso).toLocaleString('fr-FR', {
timeZone: 'Europe/Paris',
day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit',
});
console.log(`Fenêtre : ${fmt(start.toISOString())} → ${fmt(end.toISOString())} (heure de Paris)\n`);
for (const rows of series) {
if (!rows.length) continue;
console.log(`=== ${rows[0].entity_id} (${rows.length} points) ===`);
let prev = null;
for (const r of rows) {
if (r.state === prev) continue;
console.log(` ${fmt(r.last_changed || r.last_updated)} ${r.state}`);
prev = r.state;
}
console.log('');
}