Capteur de charge : origine explicite par libelle (incident 25/09, batterie publiee en solaire)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011uJ47NxgfpGnuuMr3f2n7Z
This commit is contained in:
Tallagrand Thierry
2026-09-25 12:05:04 +02:00
parent 13d9640130
commit beed8028ca
3 changed files with 65 additions and 6 deletions

View File

@@ -1,7 +1,8 @@
// Tests des diagnostics publies pour l'agent vocal (tools/diagnostics-agent.mjs).
// Les cas PV reprennent les gammes du banc OpenClaw (HANDOFF §77) : G3, G4, G5, G7.
// node tests/diagnostics-agent/run.mjs
import { diagnosticPv, etatCellules, productionJour, chargeSolaire, MPPT_MODES } from '../../tools/diagnostics-agent.mjs';
import fs from 'node:fs';
import { diagnosticPv, etatCellules, productionJour, chargeSolaire, MPPT_MODES, ORIGINE_PAR_SOURCE } from '../../tools/diagnostics-agent.mjs';
const LIM = 'voltage_current_limited', ACT = 'mppt_active';
function st({ pv, conso, reseau, soc = 80, courant = 0, edf = 'off', modes }) {
@@ -114,6 +115,14 @@ const charge = [
(r) => r.etat === 'en_attente' && r.attributs.raison_controleur === 'Excedent insuffisant' && r.attributs.excedent_w === -1854],
['en charge sur source solaire -> en_charge_solaire', borne({ p: 3600, source: 'Solaire' }), (r) => r.etat === 'en_charge_solaire'],
['en charge source reseau -> en_charge_reseau', borne({ p: 3600, source: 'Réseau HC autorisé' }), (r) => r.etat === 'en_charge_reseau'],
// Incident du 25/09 01:25-06:00 : JEEP sur batterie la nuit, publie « solaire ».
['INCIDENT 25/09 : assistance batterie nuit -> en_charge_batterie, JAMAIS solaire',
borne({ p: 1198, source: 'Assistance batterie nuit', pv: 0, conso: 900, modes: 'off' }),
(r) => r.etat === 'en_charge_batterie' && !/solaire/i.test(r.attributs.explication.split('(')[0])],
['sonde hybride -> en_charge_sonde', borne({ p: 2300, source: 'Probe hybride' }), (r) => r.etat === 'en_charge_sonde'],
['potentiel solaire -> en_charge_solaire', borne({ p: 2300, source: 'Potentiel solaire' }), (r) => r.etat === 'en_charge_solaire'],
['reseau force -> en_charge_reseau', borne({ p: 3600, source: 'Réseau forcé' }), (r) => r.etat === 'en_charge_reseau'],
['libelle inconnu -> en_charge sans origine devinee', borne({ p: 3600, source: 'nouveau_mode' }), (r) => r.etat === 'en_charge'],
['non branchee -> non_branchee', borne({ branche: 'off' }), (r) => r.etat === 'non_branchee'],
['G7 excedent positif et bride, mais controleur bloque -> en_attente (on RELAIE, on ne rejuge pas)',
borne({ pv: 5000, conso: 1500, modes: LIM, source: 'Bloqué', raison: 'Vehicule plein' }),
@@ -127,6 +136,16 @@ for (const [nom, etats, test] of charge) {
console.log(`${ok ? 'OK ' : 'KO '} ${nom}`);
}
const n = cas.length + cel.length + prod.length + charge.length;
// Chaque libelle publie par le controleur doit avoir une origine explicite :
// lu dans SON code, pour qu'un libelle ajoute la-bas fasse tomber ce test.
const srcCtrl = fs.readFileSync(new URL('../../src/nodes/HA_SERVICE_CALLS_OUTPUT.js', import.meta.url), 'utf8');
const bloc = srcCtrl.slice(srcCtrl.indexOf('const sourceModeLabel ='), srcCtrl.indexOf('context.sourceMode;', srcCtrl.indexOf('const sourceModeLabel =')));
const libelles = [...bloc.matchAll(/\? '([^']+)'/g)].map((m) => m[1]).filter((l) => l !== 'Bloqué');
const nonCouverts = libelles.filter((l) => !ORIGINE_PAR_SOURCE[l]);
const okLib = libelles.length >= 6 && nonCouverts.length === 0;
if (!okLib) ko++;
console.log(`${okLib ? 'OK ' : 'KO '} les ${libelles.length} libelles de source du controleur ont une origine${okLib ? '' : ` (manquent : ${nonCouverts.join(', ') || 'table introuvable'})`}`);
const n = cas.length + cel.length + prod.length + charge.length + 1;
console.log(`\n${n - ko}/${n}`);
process.exit(ko ? 1 : 0);