Revue : etat des leviers joint a chaque constat, transmis au conseiller et historise
This commit is contained in:
@@ -796,6 +796,7 @@ async function migrer(client) {
|
||||
chiffres jsonb,
|
||||
PRIMARY KEY (jour, code, debut)
|
||||
)`);
|
||||
await client.query('ALTER TABLE revue_constat ADD COLUMN IF NOT EXISTS etat text');
|
||||
await client.query(`
|
||||
CREATE TABLE IF NOT EXISTS revue_piste (
|
||||
jour date NOT NULL,
|
||||
@@ -1195,13 +1196,13 @@ async function revueDeLaJournee(sql, client, st) {
|
||||
await publierCapteur('sensor.evcs_revue_jour', jour, {
|
||||
friendly_name: 'Revue de la journee',
|
||||
a_examiner: aExaminer,
|
||||
constats: r.constats.map((c) => ({ code: c.code, gravite: c.gravite, texte: c.texte, contexte: c.contexte })),
|
||||
constats: r.constats.map((c) => ({ code: c.code, gravite: c.gravite, texte: c.texte, contexte: c.contexte, etat: c.etat || '' })),
|
||||
texte: r.texte,
|
||||
});
|
||||
for (const c of r.constats) {
|
||||
await sql(`INSERT INTO revue_constat (jour, code, gravite, debut, fin, texte, contexte, chiffres)
|
||||
VALUES ($1,$2,$3,$4,$5,$6,$7,$8) ON CONFLICT DO NOTHING`,
|
||||
[jour, c.code, c.gravite, new Date(c.debut), new Date(c.fin), c.texte, c.contexte, JSON.stringify(c.chiffres || {})]);
|
||||
await sql(`INSERT INTO revue_constat (jour, code, gravite, debut, fin, texte, contexte, chiffres, etat)
|
||||
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9) ON CONFLICT DO NOTHING`,
|
||||
[jour, c.code, c.gravite, new Date(c.debut), new Date(c.fin), c.texte, c.contexte, JSON.stringify(c.chiffres || {}), c.etat || null]);
|
||||
}
|
||||
await journaliser(sql, 'revue', `Revue de la journee : ${aExaminer} point(s) a examiner`, { jour, texte: r.texte });
|
||||
await publierRevueHistorique(client);
|
||||
|
||||
@@ -65,6 +65,33 @@ function plages(debut, fin, pred) {
|
||||
return out;
|
||||
}
|
||||
|
||||
// RELEVE DE L'ETAT a un instant (08/10, proprietaire) : le conseiller ne voyait
|
||||
// que la raison du controleur au debut de l'episode, et ses pistes du 08/10
|
||||
// etaient fausses faute de voir l'ACM a 30 A, la consigne tenue ou le mode
|
||||
// « sans EDF ». Chaque constat porte donc l'etat des leviers a ce moment-la.
|
||||
function etatA(d, t) {
|
||||
const v = (serie, unite, dec = 0) => {
|
||||
const x = serie ? aInstant(serie, t) : null;
|
||||
return x === null || !Number.isFinite(Number(x)) ? 'inconnu' : `${Math.round(Number(x) * 10 ** dec) / 10 ** dec}${unite}`;
|
||||
};
|
||||
let x = null; for (const r of d.decisions || []) { if (r.ts <= t) x = r; else break; }
|
||||
const mode = d.modeNuit ? aInstant(d.modeNuit, t) : null;
|
||||
return `a ${hhmm(t)} : ` + [
|
||||
`SOC ${v(d.soc, ' %')}`,
|
||||
`maison ${v(d.maisonW, ' W')}`,
|
||||
`reseau ${v(d.reseauW, ' W')}`,
|
||||
`consigne reseau ${v(d.consigneW, ' W')}`,
|
||||
`courant de charge max fixe par l'ACM ${v(d.acmA, ' A')}`,
|
||||
`borne ${v(d.borneW, ' W')}`,
|
||||
`session HC engagee ${x ? (x.session_engagee ? 'oui' : 'non') : 'inconnu'}`,
|
||||
`mode de nuit ${mode || 'inconnu'}`,
|
||||
`budget voiture sans EDF ${v(d.budgetKwh, ' kWh', 2)}`,
|
||||
`SOC requis (bilan) ${v(d.requis, ' %', 1)}`,
|
||||
`cible du matin ${x && Number.isFinite(Number(x.cible_matin_pct)) ? `${x.cible_matin_pct} %` : 'inconnu'}`,
|
||||
`controleur ${x ? `${x.etat} / ${x.source_mode}` : 'inconnu'}`,
|
||||
].join(', ');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {object} d
|
||||
* debut, fin : ms
|
||||
@@ -107,6 +134,7 @@ export function constatsRevue(d) {
|
||||
+ (socDebut !== null ? `, batterie a ${Math.round(socDebut)} % a la fermeture` : '')
|
||||
+ (ouverture?.auteur ? ` ; ferme par ${ouverture.auteur}` : '') + '.',
|
||||
chiffres: { minutes: Math.round(min), kwh: kwh === null ? null : Math.round(kwh * 100) / 100, soc: socDebut },
|
||||
etat: etatA(d, p.debut),
|
||||
contexte: (aInstant(d.decisions.map((x) => ({ ts: x.ts, v: x.raison })), p.debut) || '').slice(0, 400),
|
||||
});
|
||||
}
|
||||
@@ -127,6 +155,7 @@ export function constatsRevue(d) {
|
||||
debut: p.debut, fin: p.fin,
|
||||
texte: `Voiture branchee mais bloquee de ${hhmm(p.debut)} a ${hhmm(p.fin)} (${duree(min)}) alors qu'EDF etait ferme en heures creuses (etat ${x.etat}).`,
|
||||
chiffres: { minutes: Math.round(min) },
|
||||
etat: etatA(d, p.debut + MIN),
|
||||
contexte: (x.raison || '').slice(0, 400),
|
||||
});
|
||||
}
|
||||
@@ -156,6 +185,7 @@ export function constatsRevue(d) {
|
||||
texte: `Heures creuses de midi en charge maximale (jour faible) : batterie ${soc0 === null ? '?' : Math.round(soc0)} % -> ${Math.round(soc)} %`
|
||||
+ (soc0 === null ? '.' : ` (+${f1((soc - soc0) * KWH_PAR_POINT)} kWh).`),
|
||||
chiffres: { socDebut: soc0, socFin: soc },
|
||||
etat: etatA(d, t - 60 * MIN),
|
||||
contexte: (x.raison || '').slice(0, 400),
|
||||
});
|
||||
continue;
|
||||
@@ -168,6 +198,8 @@ export function constatsRevue(d) {
|
||||
debut: t, fin: t,
|
||||
texte: `Fin des heures creuses de ${f.nom} (${hhmm(t)}) : batterie a ${Math.round(soc)} % pour ${f1(objectif)} % vises, il manquait ${f1(manque * KWH_PAR_POINT)} kWh.`,
|
||||
chiffres: { soc, objectif, manqueKwh: Math.round(manque * KWH_PAR_POINT * 10) / 10 },
|
||||
// Milieu de la fenetre : la ou la recharge aurait du se faire.
|
||||
etat: etatA(d, t - (f.nom === 'nuit' ? 3 * 60 : 60) * MIN),
|
||||
contexte: (x.raison || '').slice(0, 400),
|
||||
});
|
||||
}
|
||||
@@ -212,6 +244,15 @@ export async function donneesRevue(client, fenetres, finMs) {
|
||||
debut, fin, fenetres, contacteur, decisions,
|
||||
edfKwh: await serie('sensor.edf_general_ok_energie_totale'),
|
||||
reseauW: await serie('sensor.victron_grid_power_l1'),
|
||||
maisonW: await serie('sensor.victron_consumption_power_l1'),
|
||||
borneW: await serie('sensor.victron_evcs_ac_power'),
|
||||
consigneW: await serie('number.gx_device_ac_power_setpoint'),
|
||||
acmA: await serie('sensor.victron_max_charge_current_setting'),
|
||||
budgetKwh: await serie('input_number.evcs_balance_night_vehicle_budget_kwh'),
|
||||
modeNuit: (await q(`SELECT ts, v FROM (
|
||||
(SELECT ts, detail->>'apres' v FROM evenement WHERE detail->>'entite'='input_select.victron_evcs_night_charge_mode' AND ts < $1 ORDER BY ts DESC LIMIT 1)
|
||||
UNION ALL (SELECT ts, detail->>'apres' v FROM evenement WHERE detail->>'entite'='input_select.victron_evcs_night_charge_mode' AND ts >= $1 AND ts < $2)) s ORDER BY ts`, [d0, d1]))
|
||||
.map((r) => ({ ts: ms(r), v: r.v })),
|
||||
soc: await serie('sensor.victron_battery_soc'),
|
||||
requis: await serie('input_number.evcs_balance_required_soc'),
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user