141 lines
11 KiB
JavaScript
141 lines
11 KiB
JavaScript
#!/usr/bin/env node
|
|
// Tests de la revue de la journee (tools/revue-jour.mjs, 08/10/2026).
|
|
// Donnees synthetiques calquees sur la journee du 07 au 08/10.
|
|
import { constatsRevue } from '../../tools/revue-jour.mjs';
|
|
|
|
const T = (s) => Date.parse(`2026-10-${s}+02:00`);
|
|
const F = [{ nom: 'nuit', debut: '01:24', fin: '07:24' }, { nom: 'midi', debut: '12:24', fin: '14:24' }];
|
|
const base = () => ({
|
|
debut: T('07T07:25:00'), fin: T('08T07:25:00'), fenetres: F,
|
|
contacteur: [{ ts: T('07T07:25:00'), v: 'off' }],
|
|
edfKwh: [{ ts: T('07T07:00:00'), v: 100 }],
|
|
reseauW: [{ ts: T('07T07:25:00'), v: 0 }],
|
|
decisions: [{ ts: T('07T07:25:00'), profil: 'outside_window', source_mode: 'Solaire', etat: 'idle', session_engagee: false, cible_matin_pct: 30, raison: 'r' }],
|
|
soc: [{ ts: T('07T07:25:00'), v: 40 }],
|
|
requis: [{ ts: T('07T07:25:00'), v: 30 }],
|
|
});
|
|
|
|
let echecs = 0;
|
|
const ok = (id, cond, info = '') => { if (cond) console.log(`✅ ${id}`); else { echecs++; console.log(`❌ ${id} ${info}`); } };
|
|
const codes = (r) => r.constats.map((c) => c.code).join(',');
|
|
|
|
{ const r = constatsRevue(base());
|
|
ok('rien-a-signaler', r.constats.length === 0 && /Aucun des cas surveilles/.test(r.texte) && /seuls ces cas sont verifies/.test(r.texte), r.texte); }
|
|
|
|
{ // 07/10 18:06 -> 01:24, 8,3 kWh, ferme par l'automatisation SoC < 22 %
|
|
const d = base();
|
|
d.contacteur.push({ ts: T('07T18:04:27'), v: 'on', auteur: 'Victron - Grid ON si SoC < 22%' });
|
|
d.reseauW.push({ ts: T('07T18:06:00'), v: 1800 }, { ts: T('08T07:24:30'), v: 0 });
|
|
d.edfKwh.push({ ts: T('07T18:05:00'), v: 100 }, { ts: T('08T01:24:00'), v: 108.3 }, { ts: T('08T07:24:00'), v: 113 });
|
|
d.soc.push({ ts: T('07T18:00:00'), v: 21 });
|
|
const r = constatsRevue(d); const c = r.constats.find((x) => x.code === 'edf_heures_pleines');
|
|
// 13/10 : kWh = puissance reseau mesuree (1 800 W x 438 min = 13,14 kWh), plus le compteur du disjoncteur.
|
|
ok('hp-releve-0710', !!c && c.chiffres.minutes === 438 && c.chiffres.kwh === 13.14 && /18:06 a 01:24/.test(c.texte)
|
|
&& /Grid ON si SoC < 22%/.test(c.texte) && r.constats.filter((x) => x.code === 'edf_heures_pleines').length === 1, JSON.stringify(r.constats)); }
|
|
|
|
{ const d = base(); // reseau 4 min en heures pleines : ignore
|
|
d.reseauW.push({ ts: T('07T19:00:00'), v: 900 }, { ts: T('07T19:04:00'), v: 0 });
|
|
ok('hp-breve-ignoree', constatsRevue(d).constats.length === 0); }
|
|
|
|
{ const d = base(); // reseau en heures creuses seulement : rien
|
|
d.reseauW.push({ ts: T('08T01:24:00'), v: 2000 }, { ts: T('08T07:24:00'), v: 0 });
|
|
ok('hc-pas-un-constat', constatsRevue(d).constats.length === 0, codes(constatsRevue(d))); }
|
|
|
|
{ const d = base(); // ecart de 3 min dans une fermeture : une seule plage
|
|
d.reseauW.push({ ts: T('07T19:00:00'), v: 900 }, { ts: T('07T19:30:00'), v: 0 }, { ts: T('07T19:33:00'), v: 900 }, { ts: T('07T20:00:00'), v: 0 });
|
|
const r = constatsRevue(d); ok('hp-ecart-bref-fusionne', r.constats.length === 1 && r.constats[0].chiffres.minutes === 60, JSON.stringify(r.constats.map((x) => x.chiffres))); }
|
|
|
|
const sessionNuit = (d, etat, source = 'Bloqué') => {
|
|
d.contacteur.push({ ts: T('08T01:23:50'), v: 'on' });
|
|
d.decisions.push({ ts: T('08T01:24:00'), profil: 'night_hc', source_mode: source, etat, session_engagee: true, cible_matin_pct: 30.7, raison: 'Nuit sans autorisation HC réseau' },
|
|
{ ts: T('08T05:14:00'), profil: 'night_hc', source_mode: 'Réseau forcé', etat: 'charging_hold_grid', session_engagee: true, cible_matin_pct: 30.7, raison: 'x' });
|
|
d.soc.push({ ts: T('08T07:00:00'), v: 30 });
|
|
};
|
|
{ const d = base(); sessionNuit(d, 'night_no_grid_hc_lock');
|
|
const r = constatsRevue(d); const c = r.constats.find((x) => x.code === 'voiture_bloquee_session_hc');
|
|
ok('voiture-bloquee-0810', !!c && c.chiffres.minutes === 230 && /01:24 a 05:14/.test(c.texte), JSON.stringify(r.constats)); }
|
|
{ const d = base(); sessionNuit(d, 'night_recovery_done_idle');
|
|
ok('voiture-pleine-pas-un-constat', !codes(constatsRevue(d)).includes('voiture_bloquee')); }
|
|
{ const d = base(); sessionNuit(d, 'vehicle_not_connected');
|
|
ok('pas-de-voiture-pas-un-constat', !codes(constatsRevue(d)).includes('voiture_bloquee')); }
|
|
|
|
{ const d = base(); sessionNuit(d, 'night_no_grid_hc_lock');
|
|
d.decisions[d.decisions.length - 1].cible_matin_pct = 40; // objectif 40, SOC 30 a 07:24
|
|
const c = constatsRevue(d).constats.find((x) => x.code === 'batterie_sous_objectif_nuit');
|
|
ok('nuit-sous-objectif', !!c && c.chiffres.manqueKwh === 3 && /il manquait 3 kWh/.test(c.texte), JSON.stringify(c)); }
|
|
{ const d = base(); sessionNuit(d, 'night_no_grid_hc_lock'); // objectif 30,7, SOC 30 : moins de 2 points
|
|
ok('nuit-objectif-tenu', !codes(constatsRevue(d)).includes('batterie_sous_objectif')); }
|
|
|
|
const sessionMidi = (d, requis) => {
|
|
d.decisions.push({ ts: T('07T12:24:00'), profil: 'midday_hc_or_solar', source_mode: 'Réseau HC autorisé', etat: 'x', session_engagee: true, cible_matin_pct: 30, raison: 'm' },
|
|
{ ts: T('07T14:25:00'), profil: 'outside_window', source_mode: 'Solaire', etat: 'idle', session_engagee: false, cible_matin_pct: 30, raison: 'r' });
|
|
d.soc.push({ ts: T('07T12:20:00'), v: 31 }, { ts: T('07T14:20:00'), v: 35 });
|
|
d.requis.push({ ts: T('07T12:25:00'), v: requis });
|
|
};
|
|
{ const d = base(); sessionMidi(d, 43.6);
|
|
const c = constatsRevue(d).constats.find((x) => x.code === 'batterie_sous_objectif_midi');
|
|
ok('midi-sous-objectif-0710', !!c && /35 % pour 43,6 % vises, il manquait 2,6 kWh/.test(c.texte), JSON.stringify(c)); }
|
|
{ const d = base(); sessionMidi(d, 100);
|
|
const r = constatsRevue(d); const c = r.constats.find((x) => /charge_max/.test(x.code));
|
|
// 10/10 : 31 -> 35 % en 2 h (+1,2 kWh) quand l'abonnement en permettait ~13 kWh = le 07/10, recharge BRIDEE.
|
|
ok('midi-charge-max-bridee-0710', !!c && c.code === 'charge_max_bridee' && c.gravite === 'a_examiner' && /31 % -> 35 % \(\+1,2 kWh/.test(c.texte) && !codes(r).includes('sous_objectif'), JSON.stringify(r.constats)); }
|
|
|
|
{ const d = base(); sessionMidi(d, 43.6);
|
|
d.acmA = [{ ts: T('07T12:00:00'), v: 30 }]; d.consigneW = [{ ts: T('07T12:30:00'), v: 5198 }];
|
|
d.modeNuit = [{ ts: T('07T12:00:00'), v: 'sans_edf' }];
|
|
const c = constatsRevue(d).constats.find((x) => x.code === 'batterie_sous_objectif_midi');
|
|
ok('etat-joint-au-constat', !!c && /a 13:24/.test(c.etat) && /ACM 30 A/.test(c.etat) && /consigne reseau 5198 W/.test(c.etat)
|
|
&& /mode de nuit sans_edf/.test(c.etat) && /session HC engagee oui/.test(c.etat) && /budget voiture sans EDF inconnu/.test(c.etat), c && c.etat); }
|
|
|
|
// 10/10 : recharge maximale jugee contre le possible. Releve du 09/10 : maison ~2,2 kW,
|
|
// 49 -> 62 % (+3,9 kWh) sur 2 h ; possible ~ min(7,3 ; 10,8 - 2,2) x 0,92 x 2 = 13,4 kWh.
|
|
{ const d = base(); sessionMidi(d, 100);
|
|
d.soc = [{ ts: T('07T12:20:00'), v: 49 }, { ts: T('07T14:20:00'), v: 62 }];
|
|
d.maisonW = [{ ts: T('07T12:00:00'), v: 2200 }];
|
|
const c = constatsRevue(d).constats.find((x) => /charge_max/.test(x.code));
|
|
ok('charge-max-bridee-a-examiner', c && c.code === 'charge_max_bridee' && c.gravite === 'a_examiner' && /13,4 kWh permis/.test(c.texte), c && c.texte); }
|
|
{ const d = base(); sessionMidi(d, 100);
|
|
d.soc = [{ ts: T('07T12:20:00'), v: 40 }, { ts: T('07T14:20:00'), v: 75 }];
|
|
d.maisonW = [{ ts: T('07T12:00:00'), v: 2200 }];
|
|
const c = constatsRevue(d).constats.find((x) => /charge_max/.test(x.code));
|
|
ok('charge-max-normale-info', c && c.code === 'charge_max_midi' && c.gravite === 'info', c && c.texte); }
|
|
{ const d = base(); sessionMidi(d, 100);
|
|
d.soc = [{ ts: T('07T12:20:00'), v: 49 }, { ts: T('07T13:30:00'), v: 52 }];
|
|
d.maisonW = [{ ts: T('07T12:00:00'), v: 2200 }];
|
|
d.debut = T('07T11:30:00'); d.fin = T('07T13:30:00'); d.enCours = true;
|
|
const c = constatsRevue(d).constats.find((x) => x.code === 'charge_max_bridee_en_cours');
|
|
ok('charge-max-bridee-en-cours', c && /depuis 12:24/.test(c.texte) && c.gravite === 'a_examiner', JSON.stringify(constatsRevue(d).constats.map((x) => x.code))); }
|
|
|
|
// 13/10 : EDF demande mais absent. Releve du 12-13/10 : session engagee a 01:24,
|
|
// reseau 0 W, batterie a -900 W, contacteur rearme au levier a 05:58.
|
|
const nuitEdfAbsent = () => { const d = base();
|
|
d.sessionNuit = [{ ts: T('07T07:25:00'), v: 'off' }, { ts: T('08T01:24:00'), v: 'on' }, { ts: T('08T07:24:00'), v: 'off' }];
|
|
d.batterieW = [{ ts: T('07T07:25:00'), v: 0 }, { ts: T('08T01:25:00'), v: -900 }, { ts: T('08T05:58:00'), v: 1500 }];
|
|
d.soc.push({ ts: T('08T01:25:00'), v: 36 }, { ts: T('08T05:58:00'), v: 26 });
|
|
return d; };
|
|
{ const r = constatsRevue(nuitEdfAbsent()); const c = r.constats.find((x) => x.code === 'edf_absent_session');
|
|
ok('edf-absent-1213', c && c.gravite === 'a_examiner' && /ABSENT de 01:25 a 05:58/.test(c.texte) && /36 % -> 26 %/.test(c.texte) && c.chiffres.kwh === 4.1 && /session HC engagee oui/.test(c.etat) && !/Aucun des cas/.test(r.texte), JSON.stringify(r.constats)); }
|
|
{ const d = nuitEdfAbsent(); d.reseauW.push({ ts: T('08T01:25:00'), v: 2300 }, { ts: T('08T07:24:00'), v: 0 });
|
|
ok('edf-present-rien', !constatsRevue(d).constats.some((x) => x.code === 'edf_absent_session')); }
|
|
{ const d = nuitEdfAbsent(); d.sessionNuit = [{ ts: T('07T07:25:00'), v: 'off' }];
|
|
ok('pas-demande-rien', !constatsRevue(d).constats.some((x) => x.code === 'edf_absent_session')); }
|
|
{ const d = nuitEdfAbsent(); d.sessionNuit = [{ ts: T('07T07:25:00'), v: 'off' }];
|
|
d.verrouHysteresis = [{ ts: T('07T07:25:00'), v: 'off' }, { ts: T('08T01:24:00'), v: 'on' }];
|
|
ok('verrou-hysteresis-absent', constatsRevue(d).constats.some((x) => x.code === 'edf_absent_session' && /hysteresis/.test(x.texte))); }
|
|
// 12/10 : VW payee par la batterie (16:16-16:44, borne 3,4 kW, batterie -3,6 kW).
|
|
const vwBatterie = (batt = -3600, source = 'Solaire') => { const d = base();
|
|
d.decisions.push({ ts: T('07T16:16:00'), profil: 'outside_window', source_mode: source, etat: 'hold_min_run', session_engagee: false, cible_matin_pct: 30, raison: 'Maintien jusqu au temps mini ON' });
|
|
d.borneW = [{ ts: T('07T07:25:00'), v: 0 }, { ts: T('07T16:16:00'), v: 3363 }, { ts: T('07T16:44:00'), v: 0 }];
|
|
d.batterieW = [{ ts: T('07T07:25:00'), v: 0 }, { ts: T('07T16:16:00'), v: batt }, { ts: T('07T16:44:00'), v: 0 }];
|
|
return d; };
|
|
{ const c = constatsRevue(vwBatterie()).constats.find((x) => x.code === 'voiture_payee_par_batterie');
|
|
ok('vw-payee-1210', c && /de 16:16 a 16:44/.test(c.texte) && c.chiffres.kwh === 1.57 && /hold_min_run/.test(c.texte), JSON.stringify(c)); }
|
|
ok('vw-solaire-pur-rien', !constatsRevue(vwBatterie(600)).constats.some((x) => x.code === 'voiture_payee_par_batterie'));
|
|
ok('vw-sur-reseau-rien', !constatsRevue(vwBatterie(-3600, 'Réseau HC autorisé')).constats.some((x) => x.code === 'voiture_payee_par_batterie'));
|
|
{ const d = base(); d.interventions = [{ ts: T('08T05:58:00'), texte: 'contacteur EDF ferme hors du systeme (levier ou appli)' }];
|
|
const r = constatsRevue(d);
|
|
ok('intervention-info', r.constats.length === 1 && r.constats[0].gravite === 'info' && /Intervention a 05:58/.test(r.texte)); }
|
|
|
|
console.log(echecs ? `\n${echecs} ECHEC(S)` : '\nREVUE OK');
|
|
process.exit(echecs ? 1 : 0);
|