Tableau Energie : batterie par integration de la puissance (compteurs GX empoisonnes), historique importe
This commit is contained in:
12
HANDOFF.md
12
HANDOFF.md
@@ -1608,6 +1608,18 @@ reseau + decharge - charge) : elle inclut la borne et les pertes de l'onduleur.
|
|||||||
2,8 (28,73), 03/10 27,5 + 5,3 (32,72). Sauvegarde `.storage/energy.bak-20261004-sudouest`.
|
2,8 (28,73), 03/10 27,5 + 5,3 (32,72). Sauvegarde `.storage/energy.bak-20261004-sudouest`.
|
||||||
⚠️ **A verifier le 04/10** : la premiere heure compilee par HA (02:00) doit prolonger la
|
⚠️ **A verifier le 04/10** : la premiere heure compilee par HA (02:00) doit prolonger la
|
||||||
somme importee sans saut (stats journalieres du 04/10 sud/ouest ~ production reelle).
|
somme importee sans saut (stats journalieres du 04/10 sud/ouest ~ production reelle).
|
||||||
|
- **Source batterie remplacee (04/10 ~01:35, alerte de SPARK)** : les compteurs GX
|
||||||
|
`gx_device_dc_battery_charge/discharge_energy` sont EMPOISONNES (fiche agent §5ter) — sauts
|
||||||
|
verifies dans les statistiques : -195 kWh (23/08), -133 (03/09), -78 (14/09), -154 (23/09).
|
||||||
|
Remplaces par l'integrale de la puissance mesuree : gabarits `sensor.batterie_puissance_de_charge`
|
||||||
|
/ `_de_decharge` (max(±`victron_battery_power`, 0), dans `evcs_energie_trackers.yaml`) +
|
||||||
|
deux ENTREES HA « Integrale de Riemann » (creees par l'API config_entries/flow : en YAML
|
||||||
|
il aurait fallu redemarrer HA en pleine session de nuit) `sensor.batterie_energie_chargee`
|
||||||
|
/ `_dechargee` (gauche, kWh, sous-intervalle 1 min). Historique horaire importe depuis la
|
||||||
|
table `mesure` (04/09 -> 03/10 23:00Z, `tools/ponctuel/20261004-import-batterie.js`).
|
||||||
|
Recoupe : 03/10 19,33 / 20,51 contre GX 19,25 / 20,58 ; 23/09 21,4 / 23,3 (GX -154).
|
||||||
|
`energy/validate` vide. Sauvegarde `.storage/energy.bak-20261004-batterie`.
|
||||||
|
⚠️ A verifier aussi au matin : continuite des sommes apres la 1re heure compilee par HA.
|
||||||
|
|
||||||
---
|
---
|
||||||
*Document mis a jour le : 04/10/2026 (~01:10) — kilometrage des vehicules (km/kWh, capacite, releves de reference, agent cable 15/15) ; a verifier le 04/10 au matin : nuit du budget JEEP ; concierge : vehicule non confirme demande, heure de saisie ; Grafana vehicules en tableau ; Grafana vehicules : ZERO et Invite ajoutes, session 16:46 reetiquetee ZERO ; prevision SOC 10 h ~35 % ; concierge fiable : niveau note par le script, une ligne, dedoublonnage, simulation par drapeau ; agent : message incompris = question, bourse sur demande explicite (banc final 6/6) ; a verifier : nuit du samedi 03 au dimanche 04/10 (budget < besoin JEEP), cron orange-cloture lundi 05/10 apres 17:40, comparaison VRM / Forecast.Solar lundi 05/10*
|
*Document mis a jour le : 04/10/2026 (~01:10) — kilometrage des vehicules (km/kWh, capacite, releves de reference, agent cable 15/15) ; a verifier le 04/10 au matin : nuit du budget JEEP ; concierge : vehicule non confirme demande, heure de saisie ; Grafana vehicules en tableau ; Grafana vehicules : ZERO et Invite ajoutes, session 16:46 reetiquetee ZERO ; prevision SOC 10 h ~35 % ; concierge fiable : niveau note par le script, une ligne, dedoublonnage, simulation par drapeau ; agent : message incompris = question, bourse sur demande explicite (banc final 6/6) ; a verifier : nuit du samedi 03 au dimanche 04/10 (budget < besoin JEEP), cron orange-cloture lundi 05/10 apres 17:40, comparaison VRM / Forecast.Solar lundi 05/10*
|
||||||
|
|||||||
@@ -30,3 +30,34 @@ template:
|
|||||||
icon: mdi:solar-panel
|
icon: mdi:solar-panel
|
||||||
availability: "{{ states('sensor.mppt_450_200_hq2449yr9pt_tracker_solar_4_yield_today') | is_number }}"
|
availability: "{{ states('sensor.mppt_450_200_hq2449yr9pt_tracker_solar_4_yield_today') | is_number }}"
|
||||||
state: "{{ states('sensor.mppt_450_200_hq2449yr9pt_tracker_solar_4_yield_today') | float | round(2) }}"
|
state: "{{ states('sensor.mppt_450_200_hq2449yr9pt_tracker_solar_4_yield_today') | float | round(2) }}"
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# BATTERIE POUR LE TABLEAU ENERGIE (04/10/2026)
|
||||||
|
# ⚠️ Les compteurs GX `gx_device_dc_battery_charge_energy` / `_discharge_energy`
|
||||||
|
# sont EMPOISONNES (state_class total, ils se figent puis sautent : -195 kWh le
|
||||||
|
# 23/08, -133 le 03/09, -78 le 14/09, -154 le 23/09 dans les statistiques) —
|
||||||
|
# signale par SPARK, fiche de l'agent §5ter. On integre donc la PUISSANCE
|
||||||
|
# batterie mesuree, separee en charge et decharge. Recoupe le 03/10 : 19,33 /
|
||||||
|
# 20,57 kWh contre 19,25 / 20,58 pour les compteurs GX ce jour-la.
|
||||||
|
# Historique importe depuis la table `mesure` (PostgreSQL, depuis le 04/09).
|
||||||
|
# =====================================================
|
||||||
|
- sensor:
|
||||||
|
- name: "Batterie - puissance de charge"
|
||||||
|
unique_id: evcs_batterie_puissance_charge
|
||||||
|
unit_of_measurement: W
|
||||||
|
device_class: power
|
||||||
|
state_class: measurement
|
||||||
|
availability: "{{ states('sensor.victron_battery_power') | is_number }}"
|
||||||
|
state: "{{ [states('sensor.victron_battery_power') | float, 0] | max }}"
|
||||||
|
- name: "Batterie - puissance de decharge"
|
||||||
|
unique_id: evcs_batterie_puissance_decharge
|
||||||
|
unit_of_measurement: W
|
||||||
|
device_class: power
|
||||||
|
state_class: measurement
|
||||||
|
availability: "{{ states('sensor.victron_battery_power') | is_number }}"
|
||||||
|
state: "{{ [0 - states('sensor.victron_battery_power') | float, 0] | max }}"
|
||||||
|
|
||||||
|
# Les deux integrales (« Batterie - energie chargee / dechargee ») sont des
|
||||||
|
# ENTREES HA (aide « Integrale de Riemann », creees par l'API le 04/10) : en YAML
|
||||||
|
# elles auraient exige un redemarrage de HA. Methode gauche, kWh, 3 decimales,
|
||||||
|
# sous-intervalle max 1 min.
|
||||||
|
|||||||
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