Revue glissante toutes les 15 min (alertes), recharge maximale jugee contre le possible

This commit is contained in:
Tallagrand Thierry
2026-10-10 15:07:37 +02:00
parent b9bdb44f4c
commit 3988a0a7f5
4 changed files with 146 additions and 10 deletions

View File

@@ -1280,6 +1280,55 @@ async function publierRevueHistorique(client) {
return 1;
}
// ---------------------------------------------------------------------
// REVUE GLISSANTE (10/10/2026, proprietaire) : les memes constats que la revue
// du matin, toutes les 15 min sur les 3 dernieres heures. Un constat « a
// examiner » nouveau devient une ALERTE : sensor.evcs_alerte_revue (etat = id),
// relayee par SPARK sur WhatsApp, historisee dans revue_alerte. La voiture
// bloquee reste a l'arbitre (pas de doublon). Un episode qui dure (EDF en heures
// pleines) ne donne qu'une alerte : on prolonge la ligne existante.
const CODES_GLISSANTS = new Set(['edf_heures_pleines', 'charge_max_bridee_en_cours', 'charge_max_bridee',
'batterie_sous_objectif_nuit', 'batterie_sous_objectif_midi']);
let revueGlissanteSchema = false;
async function revueGlissante(sql, client, st) {
if (!client) return 0;
if (!revueGlissanteSchema) {
await client.query(`CREATE TABLE IF NOT EXISTS revue_alerte (
id text PRIMARY KEY, code text, debut timestamptz, fin timestamptz, texte text, etat text, envoyee timestamptz DEFAULT now())`);
revueGlissanteSchema = true;
}
const hc = (id) => (st.get(id)?.state || '').slice(0, 5);
const fenetres = [
{ nom: 'nuit', debut: hc('input_datetime.victron_evcs_hc_night_start'), fin: hc('input_datetime.victron_evcs_hc_night_stop') },
{ nom: 'midi', debut: hc('input_datetime.victron_evcs_hc_midday_start'), fin: hc('input_datetime.victron_evcs_hc_midday_stop') },
];
const d = await donneesRevue(client, fenetres, Date.now(), 180);
d.enCours = true;
d.abonnementVa = Number(st.get('input_number.victron_grid_subscription_va')?.state) || 12000;
const { constats } = constatsRevue(d);
let n = 0;
for (const c of constats) {
if (c.gravite !== 'a_examiner' || !CODES_GLISSANTS.has(c.code)) continue;
if (c.code === 'edf_heures_pleines' && (c.chiffres?.minutes ?? 0) < 15) continue;
const { rows: [deja] } = await client.query(
`SELECT id FROM revue_alerte WHERE code = $1 AND fin >= $2 ORDER BY fin DESC LIMIT 1`,
[c.code, new Date(c.debut - 20 * 60000)]);
if (deja) { await client.query(`UPDATE revue_alerte SET fin = $2, texte = $3 WHERE id = $1`, [deja.id, new Date(c.fin), c.texte]); continue; }
const id = `${c.code}-${new Date(c.debut).toISOString().slice(0, 16)}`;
await client.query(`INSERT INTO revue_alerte (id, code, debut, fin, texte, etat) VALUES ($1,$2,$3,$4,$5,$6) ON CONFLICT DO NOTHING`,
[id, c.code, new Date(c.debut), new Date(c.fin), c.texte, c.etat || null]);
const { rows: hist } = await client.query(`SELECT id, code, texte, to_char(envoyee AT TIME ZONE 'Europe/Paris','DD/MM HH24:MI') a
FROM revue_alerte ORDER BY envoyee DESC LIMIT 10`);
await publierCapteur('sensor.evcs_alerte_revue', id, {
friendly_name: 'Alerte de la revue glissante', icon: 'mdi:alert-outline',
id, code: c.code, texte: c.texte, etat_systeme: c.etat || '', a: new Date().toISOString(), dernieres: hist,
});
await journaliser(sql, 'revue', `Alerte revue glissante : ${c.code}`, { id, texte: c.texte });
n++;
}
return n;
}
function decalageParis(jour) {
const d = new Date(`${jour}T12:00:00Z`);
const h = Number(new Intl.DateTimeFormat('en-GB', { timeZone: 'Europe/Paris', hour: '2-digit', hour12: false }).format(d));
@@ -2669,6 +2718,9 @@ async function cycle(client) {
arbitrage: DRY ? 0 : await arbitrer(sql, client, st).catch((e) => {
console.error('arbitrage :', e.message); return 0;
}),
revueGlissante: (DRY || new Date().getMinutes() % 15 !== 11) ? 0 : await revueGlissante(sql, client, st).catch((e) => {
console.error('revue glissante :', e.message); return 0;
}),
revue: DRY ? 0 : await revueDeLaJournee(sql, client, st).catch((e) => {
console.error('revue de la journee :', e.message); return 0;
}),