Bilan : prevision solaire VRM (selecteur de source), les deux sources enregistrees

Decision du proprietaire (28/09) : Forecast.Solar renvoie des totaux quasi
constants (~26 kWh) pour 40-47 reels ; VRM suivait mieux le reel sur 10 jours
(erreur 21 % contre 32 %, 14 % contre 36 % sur les 5 derniers). Le bilan
lit VRM des maintenant ; les deux previsions sont enregistrees (colonne
source, cle etendue) pour les comparer dans une semaine.
- input_select.evcs_balance_forecast_source (vrm | forecast_solar) = retour
  arriere en un geste ; helpers evcs_balance_vrm_* au format du bilan
- historisation : lecture VRM (jeton dans .env, jamais dans HA) toutes les
  15 min, vrmVersCourbes (jour et heure de Paris), tests 69/69
- modele du bilan conditionnel ; bilan 50/50, deploye
- evcs_prevision_contre_reel porte sur la source active

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:39:54 +02:00
parent 0686ef7e7d
commit 5a8e4afde0
6 changed files with 162 additions and 13 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, previsionNuit } 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, vrmVersCourbes } 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 }) {
@@ -317,6 +317,28 @@ for (const [nom, r, test] of imp) {
globalThis.__nConso = (globalThis.__nConso || 0) + pn.length;
}
// --- Prevision VRM -> courbes du bilan (heure de Paris) ---------------------
{
// 28/09 : 12:00 et 13:00 heure de Paris = 10:00 et 11:00 UTC ; 00:00 Paris = 22:00 UTC la veille.
const paires = [[Date.parse('2026-09-27T22:00:00Z'), 0], [Date.parse('2026-09-28T10:00:00Z'), 3580],
[Date.parse('2026-09-28T11:00:00Z'), 3740], [Date.parse('2026-09-29T10:00:00Z'), 5000]];
const c = vrmVersCourbes(paires, new Date('2026-09-27T23:30:00Z'));
const vc = [
['VRM : jour de Paris (28/09) et non UTC, 24 valeurs', c,
(x) => x.day0 === '2026-09-28' && x.today.horaire.length === 24],
['VRM : 10:00 UTC range a 12 h Paris, Wh -> kWh', c,
(x) => x.today.horaire[12] === 3.58 && x.today.horaire[13] === 3.74 && x.today.totalKwh === 7.3],
['VRM : demain separe, format CSV du bilan', c,
(x) => x.tomorrow.horaire[12] === 5 && x.today.csv.split(',').length === 24 && /^\d{2}\/\d{2} \d{2}:\d{2}$/.test(x.updated)],
['VRM : reponse vide -> ok false (le bilan garde sa source)', vrmVersCourbes([], new Date()), (x) => x.ok === false],
];
for (const [nom, x, test] of vc) {
const ok = test(x); if (!ok) { ko++; console.log(JSON.stringify(x).slice(0, 300)); }
console.log(`${ok ? 'OK ' : 'KO '} ${nom}`);
}
globalThis.__nConso = (globalThis.__nConso || 0) + vc.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);