La fiche OpenClaw basculait G5 de 7/7 a 1/7 sur un ajout sans rapport : les deux jugements sortent du modele. sensor.evcs_pv_diagnostic (import teste avant bridage) et sensor.evcs_cellules (perime => aucune valeur visible), publies meme quand le cycle echoue. Tests 15/15 + mutations. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011uJ47NxgfpGnuuMr3f2n7Z
70 lines
3.9 KiB
JavaScript
70 lines
3.9 KiB
JavaScript
// 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, MPPT_MODES } 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 }) {
|
|
const m = new Map();
|
|
const put = (id, v) => m.set(id, { entity_id: id, state: v === null ? 'unavailable' : String(v) });
|
|
put('sensor.victron_pv_power_system', pv);
|
|
put('sensor.victron_consumption_power_l1', conso);
|
|
put('sensor.victron_grid_power_l1', reseau);
|
|
put('sensor.victron_battery_soc', soc);
|
|
put('sensor.victron_battery_current', courant);
|
|
put('switch.edf_general_ok_switch', edf);
|
|
const liste = Array.isArray(modes) ? modes : MPPT_MODES.map(() => modes);
|
|
MPPT_MODES.forEach((id, i) => put(id, liste[i]));
|
|
return m;
|
|
}
|
|
|
|
const cas = [
|
|
['G3 batterie pleine, 7 brides, import nul -> bridage normal',
|
|
st({ pv: 1570, conso: 1500, reseau: 0, soc: 97, courant: 1, modes: LIM }), 'bridage_normal'],
|
|
['G4 vraie baisse : 7 a fond, SOC 69, +25 A -> ressource limitee',
|
|
st({ pv: 1600, conso: 400, reseau: 0, soc: 69, courant: 25, modes: ACT }), 'ressource_limitee'],
|
|
['G5 brides MAIS import ~ conso -> substitution',
|
|
st({ pv: 300, conso: 1200, reseau: 1150, soc: 97, courant: 0, edf: 'on', modes: LIM }), 'substitution_edf'],
|
|
['G7 un seul bride, import nul -> bridage normal (ressource dispo)',
|
|
st({ pv: 5200, conso: 2000, reseau: 0, soc: 92, courant: 60, modes: [LIM, ACT, ACT, ACT, ACT, ACT, ACT] }), 'bridage_normal'],
|
|
['bruit du compteur (60 W) contacteur ferme : pas une substitution',
|
|
st({ pv: 1500, conso: 1400, reseau: 60, soc: 96, edf: 'on', modes: LIM }), 'bridage_normal'],
|
|
['un seul bride suffit a signer la substitution si le reseau importe',
|
|
st({ pv: 3000, conso: 3500, reseau: 900, edf: 'on', modes: [LIM, ACT, ACT, ACT, ACT, ACT, ACT] }), 'substitution_edf'],
|
|
['tous a fond + import -> reseau en appoint, pas une anomalie',
|
|
st({ pv: 2000, conso: 3500, reseau: 1500, edf: 'on', modes: ACT }), 'reseau_en_appoint'],
|
|
['nuit : PV 0, tous off -> pas de production',
|
|
st({ pv: 0, conso: 600, reseau: 0, modes: 'off' }), 'pas_de_production'],
|
|
['nuit + reseau ferme : toujours pas de substitution',
|
|
st({ pv: 0, conso: 600, reseau: 600, edf: 'on', modes: 'off' }), 'pas_de_production'],
|
|
['reseau indisponible -> indetermine (ne pas conclure)',
|
|
st({ pv: 1500, conso: 1400, reseau: null, modes: LIM }), 'indetermine'],
|
|
['modes illisibles en journee -> indetermine',
|
|
st({ pv: 1500, conso: 1400, reseau: 0, modes: 'unavailable' }), 'indetermine'],
|
|
];
|
|
|
|
let ko = 0;
|
|
for (const [nom, etats, attendu] of cas) {
|
|
const r = diagnosticPv(etats);
|
|
const ok = r.etat === attendu;
|
|
if (!ok) ko++;
|
|
console.log(`${ok ? 'OK ' : 'KO '} ${nom}${ok ? '' : ` (obtenu ${r.etat})`}`);
|
|
}
|
|
|
|
const cel = [
|
|
['releve frais -> ecart et module publies', { spread_max: 21, weakest: 'K220803C30160323', age_min: 1 },
|
|
(r) => r.etat === 21 && r.attributs.module_le_plus_sensible === 'K220803C30160323'],
|
|
['releve a 30 min (limite) -> encore frais', { spread_max: 5, weakest: 'Y1', age_min: 30 }, (r) => r.etat === 5],
|
|
['G13b releve a 42 min -> perime, AUCUNE valeur visible', { spread_max: 21, weakest: 'K220803C30160323', age_min: 42 },
|
|
(r) => r.etat === 'perime' && !('module_le_plus_sensible' in r.attributs)
|
|
&& !JSON.stringify(r).includes('21,') && !JSON.stringify(r).includes('K2208')],
|
|
['table vide -> muet', { spread_max: null, weakest: null, age_min: null }, (r) => r.etat === 'muet'],
|
|
];
|
|
for (const [nom, row, test] of cel) {
|
|
const ok = test(etatCellules(row));
|
|
if (!ok) ko++;
|
|
console.log(`${ok ? 'OK ' : 'KO '} ${nom}`);
|
|
}
|
|
console.log(`\n${cas.length + cel.length - ko}/${cas.length + cel.length}`);
|
|
process.exit(ko ? 1 : 0);
|