Tableau Energie : batterie par integration de la puissance (compteurs GX empoisonnes), historique importe
This commit is contained in:
38
tools/ponctuel/20261004-import-batterie.js
Normal file
38
tools/ponctuel/20261004-import-batterie.js
Normal file
@@ -0,0 +1,38 @@
|
||||
// Historique horaire charge/decharge batterie depuis PostgreSQL -> statistiques HA (IMPORT=1 pour ecrire).
|
||||
const { Client } = require('pg');
|
||||
(async () => {
|
||||
const c = new Client(); await c.connect();
|
||||
const fin = '2026-10-03T23:00:00Z'; // creation des integrales a 23:30Z : l'heure 23:00Z est compilee par HA
|
||||
const { rows } = await c.query(`
|
||||
WITH p AS (SELECT ts, valeur v, least(extract(epoch FROM lead(ts) OVER (ORDER BY ts) - ts), 300) dt
|
||||
FROM mesure WHERE cle = 'sensor.victron_battery_power' AND ts >= '2026-09-04T00:00Z' AND ts < $1)
|
||||
SELECT date_trunc('hour', ts) h, sum(greatest(v,0)*dt)/3.6e6 ch, sum(greatest(-v,0)*dt)/3.6e6 de
|
||||
FROM p WHERE dt IS NOT NULL GROUP BY 1 ORDER BY 1`, [fin]);
|
||||
await c.end();
|
||||
let sc = 0, sd = 0; const ch = [], de = [];
|
||||
for (const r of rows) {
|
||||
sc += Number(r.ch); sd += Number(r.de);
|
||||
ch.push({ start: r.h.toISOString(), state: 0, sum: Math.round(sc * 1000) / 1000 });
|
||||
de.push({ start: r.h.toISOString(), state: 0, sum: Math.round(sd * 1000) / 1000 });
|
||||
}
|
||||
const jour = (s, a, b) => { const x = s.filter(e => e.start >= a && e.start < b); const i = s.indexOf(x[0]); return (x.at(-1).sum - (i ? s[i - 1].sum : 0)).toFixed(2); };
|
||||
console.log('heures', rows.length, ch[0].start, '->', ch.at(-1).start, 'total charge', sc.toFixed(1), 'decharge', sd.toFixed(1));
|
||||
console.log('03/10', jour(ch, '2026-10-02T22', '2026-10-03T22'), jour(de, '2026-10-02T22', '2026-10-03T22'));
|
||||
console.log('23/09', jour(ch, '2026-09-22T22', '2026-09-23T22'), jour(de, '2026-09-22T22', '2026-09-23T22'));
|
||||
if (process.env.IMPORT !== '1') return;
|
||||
const ws = new WebSocket(process.env.HA_URL.replace(/^http/, 'ws') + '/api/websocket');
|
||||
let id = 1; const pend = {};
|
||||
const call = (m) => new Promise(r => { const i = id++; pend[i] = r; ws.send(JSON.stringify({ id: i, ...m })); });
|
||||
ws.onmessage = async (e) => {
|
||||
const m = JSON.parse(e.data);
|
||||
if (m.type === 'auth_required') return ws.send(JSON.stringify({ type: 'auth', access_token: process.env.HA_TOKEN }));
|
||||
if (m.type !== 'auth_ok') { if (pend[m.id]) { pend[m.id](m); delete pend[m.id]; } return; }
|
||||
for (const [sid, nom, s] of [['sensor.batterie_energie_chargee', 'Batterie - energie chargee', ch],
|
||||
['sensor.batterie_energie_dechargee', 'Batterie - energie dechargee', de]]) {
|
||||
const r = await call({ type: 'recorder/import_statistics', metadata: { has_mean: false, has_sum: true, name: nom,
|
||||
source: 'recorder', statistic_id: sid, unit_of_measurement: 'kWh' }, stats: s });
|
||||
console.log('import', sid, r.success, JSON.stringify(r.error || ''));
|
||||
}
|
||||
ws.close();
|
||||
};
|
||||
})();
|
||||
Reference in New Issue
Block a user