Chauffe-eau : reprise de 16 h a 20 h apres coupure en pleine chauffe, mesure sur 10 min ; bilan HC de midi
This commit is contained in:
@@ -11,10 +11,14 @@ const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..')
|
||||
const CHAINE = ['NORMALIZE', 'OBSERVATION', 'ENERGY_MODEL', 'BASE_DECISION', 'ARBITRATION', 'OUTPUT_BUILDER', 'BUILD_ACTIONS'];
|
||||
const code = Object.fromEntries(CHAINE.map((n) => [n, fs.readFileSync(path.join(ROOT, `src/water-heater/${n}.js`), 'utf8')]));
|
||||
|
||||
function executer(snapshot) {
|
||||
function executer(snapshot, fixedMs = null) {
|
||||
let item = snapshot, sorties = {};
|
||||
const D = fixedMs === null ? Date : class extends Date {
|
||||
constructor(...a) { if (a.length === 0) super(fixedMs); else super(...a); }
|
||||
static now() { return fixedMs; }
|
||||
};
|
||||
for (const n of CHAINE) {
|
||||
const sb = { $input: { first: () => ({ json: item }), all: () => [{ json: item }] }, $env: {}, console };
|
||||
const sb = { $input: { first: () => ({ json: item }), all: () => [{ json: item }] }, $env: {}, console, Date: D };
|
||||
vm.createContext(sb);
|
||||
const out = vm.runInContext(`(function(){ ${code[n]} })()`, sb, { timeout: 5000 });
|
||||
sorties[n] = out;
|
||||
@@ -75,7 +79,7 @@ for (const c of cas) {
|
||||
}
|
||||
// Coupe = 0 W meme si le compteur remonte en retard (07/10 : « arret — 1595 W »).
|
||||
{
|
||||
const stamp = new Date(Date.now() - 5 * 60000).toLocaleString('sv-SE', { timeZone: 'Europe/Paris' });
|
||||
const stamp = new Date(Date.now() - 10 * 60000).toLocaleString('sv-SE', { timeZone: 'Europe/Paris' });
|
||||
const s = executer({ ...BASE, water_heater_switch: 'off', water_heater_energy_total_kwh: '18.88', energy_total_prev_kwh: '18.75', energy_prev_at: stamp });
|
||||
const o = s.OBSERVATION[0].json.observation;
|
||||
if (o.observedPowerW === 0 && o.observedRegime === 'off') { ok++; console.log('✅ coupe-zero-watt'); }
|
||||
@@ -85,7 +89,7 @@ for (const c of cas) {
|
||||
{
|
||||
const nowMin = (() => { const p = new Intl.DateTimeFormat('fr-FR', { timeZone: 'Europe/Paris', hour: '2-digit', minute: '2-digit', hour12: false }).format(new Date()).split(':'); return Number(p[0]) * 60 + Number(p[1]); })();
|
||||
const hm = (m) => { const x = ((m % 1440) + 1440) % 1440; return `${String(Math.floor(x / 60)).padStart(2, '0')}:${String(x % 60).padStart(2, '0')}:00`; };
|
||||
const stamp = new Date(Date.now() - 5 * 60000).toLocaleString('sv-SE', { timeZone: 'Europe/Paris' });
|
||||
const stamp = new Date(Date.now() - 10 * 60000).toLocaleString('sv-SE', { timeZone: 'Europe/Paris' });
|
||||
const fenetre = { hc_midday_start: hm(nowMin - 30), hc_midday_stop: hm(nowMin + 60), hc_night_start: hm(nowMin + 300), hc_night_stop: hm(nowMin + 600) };
|
||||
const base = { ...BASE, ...fenetre, grid_state: 'on', hc_session_committed: 'on', water_heater_switch: 'on',
|
||||
water_heater_energy_total_kwh: '18.65', energy_total_prev_kwh: '18.60', energy_prev_at: stamp }; // 600 W : pompe a chaleur
|
||||
@@ -100,12 +104,40 @@ for (const c of cas) {
|
||||
};
|
||||
verif('alerte-boost-pompe-a-chaleur-en-hc', {}, true);
|
||||
verif('alerte-boost-auto-arrete-0-w-en-hc', { water_heater_energy_total_kwh: '18.60' }, true);
|
||||
verif('alerte-boost-resistance-pas-d-alerte', { water_heater_energy_total_kwh: '18.75' }, false);
|
||||
verif('alerte-boost-resistance-pas-d-alerte', { water_heater_energy_total_kwh: '18.80' }, false);
|
||||
verif('alerte-boost-resistance-deja-vue-dans-la-fenetre', { water_heater_energy_total_kwh: '18.60',
|
||||
alerte_prev: JSON.stringify({ active: false, since: debut, max_w: 1235 }) }, false);
|
||||
verif('alerte-boost-debut-de-fenetre-attente', { hc_midday_start: hm(nowMin - 5) }, false);
|
||||
verif('alerte-boost-edf-ouvert-pas-d-alerte', { grid_state: 'off' }, false);
|
||||
}
|
||||
// 07/10 : mesure sur >= 9,5 min (compteur Tuya ~10 min) ; reference non avancee sur 5 min.
|
||||
{
|
||||
const st5 = new Date(Date.now() - 5 * 60000).toLocaleString('sv-SE', { timeZone: 'Europe/Paris' });
|
||||
const s = executer({ ...BASE, ecs_nuit: 'off', water_heater_energy_total_kwh: '18.60', energy_total_prev_kwh: '18.60',
|
||||
energy_prev_at: st5, observed_power_helper_w: '2300', observed_regime_helper: 'boost_high' });
|
||||
const o = s.OBSERVATION[0].json.observation;
|
||||
const ref = s.BUILD_ACTIONS.map((x) => x.json).find((c) => c.data?.entity_id === 'input_number.victron_water_heater_energy_total_prev_kwh');
|
||||
if (o.observedPowerW === 2300 && !ref) { ok++; console.log('✅ mesure-5-min-garde-la-puissance-et-la-reference'); }
|
||||
else { ko++; console.log(`❌ mesure-5-min-garde-la-puissance-et-la-reference | ${o.observedPowerW} W ref=${!!ref}`); }
|
||||
}
|
||||
// 07/10 : coupure en pleine chauffe a la fin des HC -> reprise de 16 h a 20 h meme au-dela de 1,5 kWh.
|
||||
{
|
||||
const s1 = executer({ ...BASE, hc_session_committed: 'off', water_heater_switch: 'on', observed_power_helper_w: '2300',
|
||||
pv_power_w: '1500', house_ac_power_w: '3500' });
|
||||
const fd1 = s1.ARBITRATION[0].json.finalDecision;
|
||||
const ecrit = s1.BUILD_ACTIONS.map((x) => x.json).find((c) => c.data?.entity_id === 'input_text.victron_water_heater_coupe_en_chauffe');
|
||||
if (fd1.powerSwitchAction === 'turn_off' && fd1.coupeEnChauffe && ecrit) { ok++; console.log('✅ coupe-en-pleine-chauffe-memorisee'); }
|
||||
else { ko++; console.log(`❌ coupe-en-pleine-chauffe-memorisee | ${fd1.powerSwitchAction} ${fd1.coupeEnChauffe} ${!!ecrit}`); }
|
||||
const soir = Date.parse('2026-10-07T17:00:00+02:00');
|
||||
const s2 = executer({ ...BASE, water_heater_switch: 'off', off_jour_faible_prev: 'on', ecs_jour_kwh: '2.7', coupe_en_chauffe: '2026-10-07 14:25' }, soir);
|
||||
const fd2 = s2.ARBITRATION[0].json.finalDecision;
|
||||
if (fd2.powerSwitchAction === 'turn_on' && fd2.jourFaibleState === 'jour_faible_securite_soir') { ok++; console.log('✅ reprise-du-soir-apres-coupure-en-chauffe'); }
|
||||
else { ko++; console.log(`❌ reprise-du-soir-apres-coupure-en-chauffe | ${fd2.powerSwitchAction} ${fd2.jourFaibleState}`); }
|
||||
const s3 = executer({ ...BASE, water_heater_switch: 'off', off_jour_faible_prev: 'on', ecs_jour_kwh: '2.7', coupe_en_chauffe: '2026-10-06 14:25' }, soir);
|
||||
const fd3 = s3.ARBITRATION[0].json.finalDecision;
|
||||
if (fd3.powerSwitchAction === 'none' && fd3.jourFaibleState === 'jour_faible_coupe') { ok++; console.log('✅ coupure-en-chauffe-de-la-veille-ignoree'); }
|
||||
else { ko++; console.log(`❌ coupure-en-chauffe-de-la-veille-ignoree | ${fd3.powerSwitchAction} ${fd3.jourFaibleState}`); }
|
||||
}
|
||||
// Prevision forte = le reste du jour seulement (06/10 : demain fort ne rend plus forte une journee faible).
|
||||
{
|
||||
const s = executer({ ...BASE, ecs_nuit: 'off', today_remaining_kwh: '8', tomorrow_kwh: '30' });
|
||||
|
||||
Reference in New Issue
Block a user