rapport-nuit : l'import etait extrapole sur les heures futures de la fenetre
Signale par la session SPARK via les compteurs d'energie Victron : le rapport du 24/09 annoncait 4,2 kWh importes contre ~1,6 mesure. Cause reelle (verifiee en base) : le rapport tourne a 06:47 mais sa fenetre va jusqu'a 10:00 ; l'ancienne methode (grille generate_series 1 min + derniere valeur connue + sum/60000) reportait la derniere puissance connue sur les ~3 h futures -> import fantome. Ce n'est PAS la cadence d'echantillonnage (donnees eparses, 130 pts/961 min) et les compteurs d'energie ne sont pas dans la table mesure (seul grid_power_l1). Fix : integration ponderee par l'intervalle reel entre points (cap 300 s, jamais d'extrapolation apres le dernier echantillon) et fenetre plafonnee a now(). Applique aux 4 grandeurs integrees (importe/injecte/voiture/batterie_chargee). Verifie : 1,60 kWh sur fenetre complete (= compteurs), 1,19 en simulation 06:47. Tous les rapports depuis le 08/09 surestimaient ces kWh ; le reste (SOC, fermetures, vehicule, injection) etait juste. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GwpFpy2aQ2rJok6tNQSbVj
This commit is contained in:
@@ -76,23 +76,30 @@ export async function texteRapport(client, jour = new Date()) {
|
|||||||
AND ts >= $1 AND ts < $2 ORDER BY ts`, [debut, fin]);
|
AND ts >= $1 AND ts < $2 ORDER BY ts`, [debut, fin]);
|
||||||
const fermetures = bascules.filter((b) => b.apres === 'on');
|
const fermetures = bascules.filter((b) => b.apres === 'on');
|
||||||
|
|
||||||
|
// Integration ponderee par l'intervalle REEL entre points (cap 300 s pour
|
||||||
|
// qu'un trou n'extrapole rien), et fenetre plafonnee a now(). Le rapport
|
||||||
|
// tourne a 06:47 alors que la fenetre va jusqu'a 10:00 : l'ancienne methode
|
||||||
|
// (grille generate_series 1 min + derniere valeur connue + sum/60000)
|
||||||
|
// reportait la derniere puissance connue sur les ~3 h FUTURES de la fenetre
|
||||||
|
// et surestimait l'import (3,8 kWh reconstitue au lieu de 1,6 mesure, nuit du
|
||||||
|
// 24/09, signale par la session SPARK via les compteurs d'energie Victron).
|
||||||
|
// NE JAMAIS revenir a sum(x)/60000 sur une grille qui depasse maintenant :
|
||||||
|
// elle integre du futur. La ponderation par lead(ts) n'a pas de point apres
|
||||||
|
// le dernier echantillon, donc elle n'extrapole jamais.
|
||||||
const { rows: [e] } = await q(
|
const { rows: [e] } = await q(
|
||||||
`WITH mn AS (SELECT generate_series($1::timestamptz, $2::timestamptz, interval '1 minute') t),
|
`WITH b AS (SELECT $1::timestamptz d, LEAST($2::timestamptz, now()) f),
|
||||||
j AS (SELECT mn.t,
|
g AS (SELECT valeur v, LEAST(EXTRACT(EPOCH FROM (lead(ts) OVER (ORDER BY ts) - ts)), 300) dt
|
||||||
(SELECT valeur FROM mesure m WHERE m.cle = 'sensor.victron_grid_power_l1'
|
FROM mesure, b WHERE cle = 'sensor.victron_grid_power_l1' AND ts >= d AND ts < f),
|
||||||
AND m.ts <= mn.t ORDER BY m.ts DESC LIMIT 1) g,
|
ev AS (SELECT valeur v, LEAST(EXTRACT(EPOCH FROM (lead(ts) OVER (ORDER BY ts) - ts)), 300) dt
|
||||||
(SELECT valeur FROM mesure m WHERE m.cle = 'sensor.victron_evcs_ac_power'
|
FROM mesure, b WHERE cle = 'sensor.victron_evcs_ac_power' AND ts >= d AND ts < f),
|
||||||
AND m.ts <= mn.t ORDER BY m.ts DESC LIMIT 1) v,
|
ba AS (SELECT valeur v, LEAST(EXTRACT(EPOCH FROM (lead(ts) OVER (ORDER BY ts) - ts)), 300) dt
|
||||||
(SELECT valeur FROM mesure m WHERE m.cle = 'sensor.victron_battery_power'
|
FROM mesure, b WHERE cle = 'sensor.victron_battery_power' AND ts >= d AND ts < f)
|
||||||
AND m.ts <= mn.t ORDER BY m.ts DESC LIMIT 1) b
|
SELECT (SELECT coalesce(sum(GREATEST(v,0)*dt) FILTER (WHERE dt IS NOT NULL),0)/3600000.0 FROM g) AS importe,
|
||||||
FROM mn)
|
(SELECT coalesce(sum(GREATEST(-v,0)*dt) FILTER (WHERE dt IS NOT NULL),0)/3600000.0 FROM g) AS injecte,
|
||||||
SELECT coalesce(sum(g) FILTER (WHERE g > 0), 0) / 60000.0 AS importe,
|
(SELECT coalesce(sum(GREATEST(v,0)*dt) FILTER (WHERE dt IS NOT NULL),0)/3600000.0 FROM ev) AS voiture,
|
||||||
coalesce(-sum(g) FILTER (WHERE g < 0), 0) / 60000.0 AS injecte,
|
(SELECT coalesce(sum(GREATEST(v,0)*dt) FILTER (WHERE dt IS NOT NULL),0)/3600000.0 FROM ba) AS batterie_chargee,
|
||||||
coalesce(sum(v) FILTER (WHERE v > 0), 0) / 60000.0 AS voiture,
|
(SELECT count(*) FROM g WHERE v < 0) AS points_negatifs,
|
||||||
coalesce(sum(b) FILTER (WHERE b > 0), 0) / 60000.0 AS batterie_chargee,
|
(SELECT min(v) FROM g) AS pire_injection`, [debut, fin]);
|
||||||
count(*) FILTER (WHERE g < 0) AS points_negatifs,
|
|
||||||
min(g) AS pire_injection
|
|
||||||
FROM j`, [debut, fin]);
|
|
||||||
|
|
||||||
if (!fermetures.length) {
|
if (!fermetures.length) {
|
||||||
dire('Le contacteur est reste ouvert toute la nuit : aucune energie achetee au reseau.');
|
dire('Le contacteur est reste ouvert toute la nuit : aucune energie achetee au reseau.');
|
||||||
|
|||||||
Reference in New Issue
Block a user