Capteurs production du jour et relais de charge pour l'agent vocal (G1/G9, G6/G7)

sensor.evcs_production_jour_kwh (somme des 3 yield_today, remises a zero
decalees gerees) et sensor.evcs_charge_solaire (relais de la decision du
controleur, pas un second arbitre). Tests 26/26 + mutations.

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 01:18:35 +02:00
parent 83c790d9b3
commit 30193a1d27
4 changed files with 202 additions and 4 deletions

View File

@@ -1,7 +1,7 @@
// 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';
import { diagnosticPv, etatCellules, productionJour, chargeSolaire, 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 }) {
@@ -65,5 +65,68 @@ for (const [nom, row, test] of cel) {
if (!ok) ko++;
console.log(`${ok ? 'OK ' : 'KO '} ${nom}`);
}
console.log(`\n${cas.length + cel.length - ko}/${cas.length + cel.length}`);
// --- Production du jour (G1, G9) ---------------------------------------
const MIDI = new Date('2026-09-24T12:00:00Z'); // 14:00 a Paris
const NUIT = new Date('2026-09-24T22:40:00Z'); // 00:40 a Paris le 25
function rend(v1, v2, v3, change = '2026-09-24T11:59:00Z') {
const m = new Map();
[['sensor.airtria_mppt1_yield_today', v1], ['sensor.mppt_450_200_hq2449yr9pt_yield_today', v2],
['sensor.v1_yield_today', v3]].forEach(([id, v]) => {
const [val, lc] = Array.isArray(v) ? v : [v, change];
m.set(id, { state: val === null ? 'unavailable' : String(val), last_changed: lc });
});
// un sous-tracker present ne doit JAMAIS etre additionne
m.set('sensor.mppt_450_200_hq2449yr9pt_tracker_solar_1_yield_today', { state: '20.0', last_changed: change });
return m;
}
const prod = [
['G1 somme des trois (45,1 du 24/09), sous-tracker ignore', rend(9.45, 32.71, 2.97), MIDI,
(r) => r.etat === 45.1 && r.attributs.statut === 'complet'],
['G9 un chargeur unavailable -> partiel, somme du reste, muet nomme', rend(9.45, 32.71, null), MIDI,
(r) => r.etat === 42.2 && r.attributs.statut === 'partiel' && r.attributs.chargeurs_muets.join() === 'v1'],
['tous muets -> indisponible', rend(null, null, null), MIDI, (r) => r.etat === 'indisponible'],
['00:40 : un chargeur pas encore remis a zero (valeur d hier) -> compte 0',
rend(['0.0', '2026-09-24T22:37:00Z'], ['32.71', '2026-09-24T17:30:00Z'], ['0.0', '2026-09-24T22:37:00Z']), NUIT,
(r) => r.etat === 0 && r.attributs.pas_encore_remis_a_zero.join() === 'mppt_450_200'],
['heure d ete : 23:30 Paris le 24 = encore aujourd hui', rend(9.45, 32.71, 2.97, '2026-09-24T17:30:00Z'),
new Date('2026-09-24T21:30:00Z'), (r) => r.etat === 45.1],
];
for (const [nom, etats, t, test] of prod) {
const ok = test(productionJour(etats, t));
if (!ok) { ko++; console.log(JSON.stringify(productionJour(etats, t))); }
console.log(`${ok ? 'OK ' : 'KO '} ${nom}`);
}
// --- Charge voiture : RELAIS du controleur (G6, G7) --------------------
function borne({ branche = 'on', p = 0, source = 'Solaire', raison = 'Excedent negatif | Profil=x', pv = 2000, conso = 3854, modes = ACT }) {
const m = st({ pv, conso, reseau: 0, modes });
const put = (id, v) => m.set(id, { state: String(v) });
put('binary_sensor.victron_evcs_vehicle_connected', branche);
put('sensor.victron_evcs_ac_power', p);
put('input_text.victron_evcs_source_mode', source);
put('input_text.victron_evcs_surplus_reason', raison);
put('input_select.victron_evcs_strategy', 'auto_solar_plus');
return m;
}
const charge = [
['G6 branchee, pas en charge -> en_attente + raison du controleur, excedent explicatif',
borne({ source: 'Bloqué', raison: 'Excedent insuffisant | Profil=outside_window' }),
(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'],
['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' }),
(r) => r.etat === 'en_attente' && r.attributs.diagnostic_pv === 'bridage_normal'],
['borne illisible -> indetermine', (() => { const m = borne({}); m.set('sensor.victron_evcs_ac_power', { state: 'unavailable' }); return m; })(),
(r) => r.etat === 'indetermine'],
];
for (const [nom, etats, test] of charge) {
const ok = test(chargeSolaire(etats));
if (!ok) { ko++; console.log(JSON.stringify(chargeSolaire(etats))); }
console.log(`${ok ? 'OK ' : 'KO '} ${nom}`);
}
const n = cas.length + cel.length + prod.length + charge.length;
console.log(`\n${n - ko}/${n}`);
process.exit(ko ? 1 : 0);