sensor.evcs_prevision_nuit : la nuit a venir, uniquement depuis le bilan et des etats lus

Incident 27-28/09 : l'agent presentait le surplus solaire de demain comme
de l'energie batterie et lisait une projection de jour du controleur la
nuit. Ce capteur ne relaie que le bilan (meme arbitre que la decision de
nuit) ; bilan > 30 min -> indisponible. Tests 65/65.

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-28 01:27:04 +02:00
parent dfd99ca957
commit 0686ef7e7d
3 changed files with 104 additions and 2 deletions

View File

@@ -2,7 +2,7 @@
// Les cas PV reprennent les gammes du banc OpenClaw (HANDOFF §77) : G3, G4, G5, G7.
// node tests/diagnostics-agent/run.mjs
import fs from 'node:fs';
import { diagnosticPv, etatCellules, productionJour, chargeSolaire, bilanNuit, etatReseau, importJour, COMPTEURS_IMPORT, COMPTEUR_EDF, MPPT_MODES, ORIGINE_PAR_SOURCE, consoJour, COMPTEURS_CONSO, projectionSoir } from '../../tools/diagnostics-agent.mjs';
import { diagnosticPv, etatCellules, productionJour, chargeSolaire, bilanNuit, etatReseau, importJour, COMPTEURS_IMPORT, COMPTEUR_EDF, MPPT_MODES, ORIGINE_PAR_SOURCE, consoJour, COMPTEURS_CONSO, projectionSoir, previsionNuit } 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 }) {
@@ -287,6 +287,36 @@ for (const [nom, r, test] of imp) {
globalThis.__nConso = (globalThis.__nConso || 0) + pj.length;
}
// --- Prevision de la nuit : releve reel du 28/09 01:25 ----------------------
{
const base = () => new Map(Object.entries({
'input_text.evcs_balance_status': 'ok', 'input_text.evcs_balance_last_run': '28/09 01:25',
'input_number.evcs_balance_energy_to_cover_kwh': '5.47', 'input_number.evcs_balance_grid_energy_needed_kwh': '5.77',
'input_boolean.evcs_balance_grid_needed': 'on', 'input_text.evcs_balance_crossing_hour': '09 h',
'input_number.evcs_balance_required_soc': '40.2', 'sensor.victron_battery_soc': '21',
'sensor.evcs_reseau': 'raccorde', 'input_boolean.victron_evcs_night_grid_session_committed': 'on',
'binary_sensor.victron_evcs_vehicle_connected': 'off',
// pieges : valeurs internes qui ne doivent JAMAIS apparaitre
'input_number.victron_evcs_projected_end_soc_after_charge': '73.7', 'input_number.evcs_balance_vehicle_surplus_kwh': '26.95',
}).map(([k, v]) => [k, { state: v }]));
const t = new Date('2026-09-27T23:30:00Z'); // 01:30 a Paris
const pn = [
['nuit 28/09 : 5,77 kWh EDF, 5,47 a couvrir, retour 09 h, aucune voiture', previsionNuit(base(), t),
(r) => r.etat === 5.77 && r.attributs.voiture === 'aucune' && /5.77 kWh a prendre sur EDF/.test(r.attributs.explication)],
['jamais 73,7 ni 26,95 dans la prevision (incident 27/09)', previsionNuit(base(), t),
(r) => !/73\.7|26\.95/.test(JSON.stringify(r))],
['bilan perime (> 30 min) -> indisponible', previsionNuit(base(), new Date('2026-09-28T00:30:00Z')),
(r) => r.etat === 'indisponible'],
['reseau non necessaire -> 0 et « la batterie suffit »', (() => { const m = base(); m.set('input_boolean.evcs_balance_grid_needed', { state: 'off' }); return previsionNuit(m, t); })(),
(r) => r.etat === 0 && /batterie suffit/.test(r.attributs.explication)],
];
for (const [nom, r, test] of pn) {
const ok = test(r); if (!ok) { ko++; console.log(JSON.stringify(r)); }
console.log(`${ok ? 'OK ' : 'KO '} ${nom}`);
}
globalThis.__nConso = (globalThis.__nConso || 0) + pn.length;
}
const n = (globalThis.__nConso || 0) + cas.length + cel.length + prod.length + charge.length + 1 + bn.length + res.length + imp.length;
console.log(`\n${n - ko}/${n}`);
process.exit(ko ? 1 : 0);