sensor.evcs_consommation_jour_kwh : consommation du jour (sortie AC du MultiPlus), comme VRM

Delta depuis minuit de ac_in_1->ac_out + inverter->ac_out : 25,2 kWh a
17:11 le 26/09 pour ~25 dans VRM. Remise a zero -> indisponible, compteur
muet -> partiel. Tests 59/59, mutation qui mord.

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-26 17:13:35 +02:00
parent f5f23c2464
commit affdcb3b43
3 changed files with 83 additions and 5 deletions

View File

@@ -473,3 +473,49 @@ export function importJour(courant, minuit) {
return { etat: 'indisponible', attributs: { statut: 'indisponible', ...commun,
explication: 'Compteurs d\'energie muets ou remis a zero : import du jour inconnu.' } };
}
// ---------------------------------------------------------------------
// Consommation du jour (« Consommation Total » de VRM), 26/09/2026
// ---------------------------------------------------------------------
// Ce que la sortie AC du MultiPlus a delivre depuis minuit : maison ET borne
// (la borne est cablee sur la sortie AC, comme dans VRM). Deux sources :
// depuis le reseau (ac_in_1 -> ac_out) et depuis l'onduleur (inverter ->
// ac_out, c'est-a-dire solaire + batterie). Verifie le 26/09 a 17:11 :
// 0,6 + 24,6 = 25,2 kWh pour ~25 affiches par VRM a 17 h. Compteurs VE.Bus a
// 0,1 kWh pres, sans last_reset : une valeur INFERIEURE a celle de minuit est
// une remise a zero (redemarrage du MultiPlus), jamais une conso negative.
export const COMPTEURS_CONSO = [
['depuis_reseau', 'sensor.airtria_mpii_v1_energy_from_ac_in_1_to_ac_out'],
['depuis_onduleur', 'sensor.airtria_mpii_v1_energy_from_inverter_to_ac_out'],
];
export function consoJour(courant, minuit) {
const detail = {};
const muets = [];
const remis = [];
let total = 0;
for (const [nom, id] of COMPTEURS_CONSO) {
const d = delta(courant[id], minuit[id]);
if (d.remis) { remis.push(nom); detail[nom] = null; continue; }
if (d.muet) { muets.push(nom); detail[nom] = null; continue; }
detail[nom] = Math.round(d.v * 10) / 10;
total += d.v;
}
total = Math.round(total * 10) / 10;
const commun = { detail_kwh: detail };
if (remis.length) {
return { etat: 'indisponible', attributs: { statut: 'indisponible', ...commun,
explication: 'Compteur du MultiPlus remis a zero depuis minuit : consommation du jour inconnue.' } };
}
if (muets.length === COMPTEURS_CONSO.length) {
return { etat: 'indisponible', attributs: { statut: 'indisponible', ...commun,
explication: 'Compteurs de consommation muets : consommation du jour inconnue.' } };
}
if (muets.length) {
return { etat: total, attributs: { statut: 'partiel', compteurs_muets: muets, ...commun,
explication: `Consommation partielle : au moins ${total} kWh depuis minuit (compteur ${muets.join(', ')} muet).` } };
}
return { etat: total, attributs: { statut: 'complet', ...commun,
explication: `${total} kWh consommes depuis minuit (maison et borne), dont ` +
`${detail.depuis_reseau} depuis le reseau.` } };
}

View File

@@ -30,7 +30,7 @@ import path from 'node:path';
import { fileURLToPath } from 'node:url';
import pg from 'pg';
import { texteRapport, envoyer, donneesNuit, texteDepuis } from './rapport-nuit.mjs';
import { diagnosticPv, etatCellules, productionJour, chargeSolaire, bilanNuit, etatReseau, importJour, minuitLocal, COMPTEURS_IMPORT, COMPTEUR_EDF } from './diagnostics-agent.mjs';
import { diagnosticPv, etatCellules, productionJour, chargeSolaire, bilanNuit, etatReseau, importJour, minuitLocal, COMPTEURS_IMPORT, COMPTEUR_EDF, consoJour, COMPTEURS_CONSO } from './diagnostics-agent.mjs';
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
const ONCE = process.argv.includes('--once');
@@ -1875,6 +1875,9 @@ async function publierDiagnosticPv(st) {
// renvoie en tete l'etat en vigueur au debut de la fenetre, donc un compteur
// immobile (contacteur ouvert toute la soiree) a bien une valeur.
const IDS_IMPORT = [...COMPTEURS_IMPORT, COMPTEUR_EDF];
// La consommation du jour (26/09) lit ses compteurs de sortie AC au meme minuit.
const IDS_CONSO = COMPTEURS_CONSO.map(([, id]) => id);
const IDS_MINUIT = [...new Set([...IDS_IMPORT, ...IDS_CONSO])];
let minuitCache = { jour: null, valeurs: null };
async function valeursAMinuit() {
const minuit = minuitLocal(new Date());
@@ -1883,7 +1886,7 @@ async function valeursAMinuit() {
const debut = new Date(minuit.getTime() - 6 * 3600e3).toISOString();
const r = await fetch(
`${HA_URL}/api/history/period/${debut}?end_time=${encodeURIComponent(jour)}` +
`&filter_entity_id=${IDS_IMPORT.join(',')}&minimal_response&no_attributes`,
`&filter_entity_id=${IDS_MINUIT.join(',')}&minimal_response&no_attributes`,
{ headers: { Authorization: `Bearer ${HA_TOKEN}` }, signal: AbortSignal.timeout(15000) },
);
if (!r.ok) throw new Error(`historique HA ${r.status}`);
@@ -1895,7 +1898,7 @@ async function valeursAMinuit() {
if (id) valeurs[id] = nums.length ? nums[nums.length - 1] : null;
}
// On ne met en cache qu'une lecture complete : sinon on reessaie au cycle suivant.
if (IDS_IMPORT.every((id) => Number.isFinite(valeurs[id]))) minuitCache = { jour, valeurs };
if (IDS_MINUIT.every((id) => Number.isFinite(valeurs[id]))) minuitCache = { jour, valeurs };
return valeurs;
}
@@ -1912,6 +1915,15 @@ async function publierImportJour(st) {
unit_of_measurement: typeof ij.etat === 'number' ? 'kWh' : undefined, ...ij.attributs,
calcule_a: new Date().toISOString(),
});
// Consommation du jour (« Consommation Total » de VRM) : sortie AC du MultiPlus.
const cc = {};
for (const id of IDS_CONSO) { const v = Number(st.get(id)?.state); cc[id] = Number.isFinite(v) ? v : null; }
const cj = consoJour(cc, minuit);
await publierCapteur('sensor.evcs_consommation_jour_kwh', cj.etat, {
friendly_name: 'EVCS — consommation du jour (maison et borne)', icon: 'mdi:home-lightning-bolt',
unit_of_measurement: typeof cj.etat === 'number' ? 'kWh' : undefined, ...cj.attributs,
calcule_a: new Date().toISOString(),
});
return 1;
}