Le piège des accolades n'était pas un détail de chargingModeOf(). C'est la deuxième
occurrence en une semaine d'un motif qui se répétera : deux appels JSON-RPC de la même box,
portant le même objet, n'emploient pas la même convention, et RIEN ne le dit. Écrit comme
tel dans docs/UI_data_contract.md §9, avec renvoi depuis les deux sites de code et depuis
tools/rpc/README.md — là où quelqu'un croise deux réponses brutes.
Les occurrences, leur symptôme :
· GetPowerBalance (currentPowerProduction…) × GetPowerBalanceLogs (production…) →
tout tombe à zéro, l'historique paraît vide sur 7 960 échantillons bien présents
· GetChargingInfos (evChargerId sans accolades) × GetLoadConfig (id avec) →
« mode non lu » sur une borne parfaitement lue, et la note « hors arbitrage » muette
· famille voisine, même silence : currentPower* en W × total* en kWh, facteur 1000
Ce qui en fait un motif et pas trois anecdotes : le symptôme n'est JAMAIS une exception,
c'est une valeur neutre plausible, et un test unitaire qui construit ses deux côtés avec la
même convention passe aussi. D'où les trois gestes écrits au §9 — sonder les deux appels
côte à côte sur les charges utiles brutes, éprouver le rapprochement sur les deux formes
réelles, et se méfier d'un vide qui ne coûte rien à expliquer.
Et le lien avec une règle qu'on suivait déjà sans la relier à ça : une valeur neutre issue
d'un croisement raté est indiscernable d'une vraie absence. « Non lu » laisse une chance de
trouver le bug ; « 0 » l'enterre.
── Campagne V2C arrêtée, et la réserve sessionEnergy avec elle ────────────────
La Trydan non-Pro est en WiFi ESP32 sans repli filaire, lien inexploitable à deux mètres du
point d'accès : 70 % de scrutations avortées, 12 bascules en injoignable en vingt minutes.
Le modèle sort du catalogue ETM ; seule la Trydan Pro (port Ethernet) y reste.
La trace qui lève C1 — chargeEnergy à zéro AVEC un sessionEnergy qui continue — n'a donc
pas été prise et ne viendra pas de cette borne. Les notes restent en place telles quelles,
avec la raison mise à jour : elles seront levées sur une Trydan Pro. Aucun avancement de
charge affiché d'ici là.
164 tests, flutter analyze inchangé à 27 remarques.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SQbZKrWqsMFP1Lh2jjjd9f
23 KiB
ETM-PowerSync — Contrat de données UI (qui calcule quoi)
Compagnon de
DASHBOARD_SPEC.md. Tranche la question récurrente « qui calcule les valeurs affichées ? » pour chaque écran. Rev. 6 — ajout du §9 : deux réponses de la même box peuvent employer deux conventions sans qu'aucun signal ne le dise, et l'erreur est toujours muette. Deux occurrences en une semaine (clés de log sans préfixecurrentPower, identifiants de borne avec/sans accolades). Rev. 5 — sonde.75: réserve décision-2 levée (cumuls séparés) ; ajout de 3 garde-fous : 2 conventions de signe (§7.1), buckets par Δ-de-cumuls (§7.3), gestion reset compteurs (§2.1/§8.1) ; RP calquées sur le template nymea, Influx v1.6.7 confirmée. Rev. 4 — §8.3 corrigé : réutiliser l'InfluxDB nymea (pas SQLite), DB ETM dédié + rollups natifs (retention policies) + checkpoint local pour le contrôle vivant. Alerte : tag Dockerlatest→ InfluxDB 3 Core (72 h de rétention). Rev. 3 — ajout §7 (Héos data inputs & metering map) + §8 (persistance & historique : mesures brutes stockées / ratios dérivés / plan stocké). Rev. 2 — §2 corrigé après sonde terrain sur.75(nymead 1.15.2) :GetPowerBalanceLogsn'expose aucun ratio, seulement production/consumption/acquisition/storage + cumuls. La source canonique des ratios est donc le state du plugin energymanager, pas l'app, pas l'Energy experience nymea.
0. Principe directeur
L'app Flutter est un moteur de rendu, pas un moteur de calcul.
Source de vérité unique, comme INTERFACE_etmvariableload.md côté plugins.
Si l'app refait les maths de son côté, elle finit par contredire l'arbitre
(cf. Invariant 3 — charges pilotées au Grid mais hors surplus d'arbitrage ;
cf. phantom EV reservation — commandé vs mesuré). Un seul endroit calcule.
Frontière
| Catégorie | Où ça se calcule | Raison |
|---|---|---|
| Sens / couleur des flèches du flow | App (dérivé du signe d'un état) | trivial, non ambigu, instantané |
| Surplus d'arbitrage | energymanager plugin | respecte l'Invariant 3 |
| Auto-conso / autonomie / totaux jour | energymanager plugin (state) | nymea 1.15.2 ne logge pas les ratios (sonde .75) |
| Décisions / raisons en cours | energymanager (loadActions[]) |
l'arbitre est seul à savoir pourquoi |
| Plan de la journée (futur) | Héos (etm-powersync-eos) | seul à avoir forecast + MILP |
| Plan de la journée (passé) | nymea energy logs | historique réalisé |
Couches (rappel)
- nymea things → états instantanés bruts (P par compteur) + energy logs (historique).
- energymanager plugin → surplus (Invariant 3), décisions+raisons, ratios live.
- etm-powersync-eos (Héos) → forecast + plan + raisonnement tarifaire.
- App Flutter → rend 1+2+3. Ne dérive QUE le sens des flèches.
1. Flux énergétique (flow-card)
1.1 Direction & couleur — règles figées
| Nœud | Comportement | Sens des particules | Couleur |
|---|---|---|---|
| Solaire (PV) | producteur pur | toujours PV → hub | jaune #FEC113, jamais inversé |
| Maison | consommateur pur | toujours hub → Maison | bleu #31A3DD, jamais inversé |
| Réseau | bidirectionnel | import = Réseau→hub / export = hub→Réseau | import rouge (coût) · export vert atténué (revente faible) |
| Batterie | bidirectionnel | charge = hub→Bat / décharge = Bat→hub | décharge vert (aide) · charge neutre/bleu |
La convention de signe doit être explicite et documentée (un seul endroit). Sur la capture actuelle : Réseau en rouge vers le centre = import 2.4 kW ✓. Vérifier que le sens batterie reflète bien charge vs décharge.
1.2 Héos au centre — décision à prendre
Physiquement faux : Héos est le contrôleur, pas un nœud électrique. Le vrai point de couplage AC est au centre, Héos est à côté.
- Option A — garder Héos au centre comme « le cerveau ». Les lignes = la conscience/le contrôle, pas le câble. Métaphore assumée. Fort en branding. Acceptable car la carte parle de pilotage.
- Option B — nœud central = point de couplage (busbar AC neutre), Héos en badge/overlay. Physiquement correct, plus sobre.
→ Reco : A est défendable tant que l'animation respecte 1.1. Ne pas laisser les particules « traverser » Héos dans un sens physiquement impossible.
1.3 Mono vs multi-onduleur
- Le nœud Solaire du diagramme affiche TOUJOURS l'agrégat (somme). Ne jamais multiplier les nœuds dans le schéma — ça le casse visuellement.
- Le détail (tap sur
+) gère la multiplicité :- 1 onduleur → prod + strings si dispo.
- N onduleurs → agrégat en tête + liste par onduleur.
1.4 Détails Maison & compteur non mesuré (ex. PAC)
- Nœud Maison = consommation totale, dérivée :
Maison = PV + import_grid + décharge_bat − export_grid − charge_bat. - Le détail ne montre des sous-postes que pour les compteurs qui existent.
- Charge connue mais non mesurée (PAC sans compteur dédié) :
- ne jamais afficher un faux 0 ni une estimation inventée (anti-oversell) ;
- soit on l'omet, soit on affiche « non mesuré » explicitement.
- Décision implicite à acter : la décomposition par appareil nécessite un compteur par appareil. Pas de compteur PAC = pas de ligne PAC.
2. Cartes Auto-conso / Autonomie
- Agrégats sur une période → jamais calculés par l'app (sinon dérive selon le rythme de polling, et désaccord avec le bilan/logs).
- Réalité 1.15.2 (sonde
.75) :GetPowerBalanceLogsn'expose aucun ratio ni décomposition par bande — seulement production / consumption / acquisition / storage + cumuls. La prémisse « ratios déjà calculés backend » est donc fausse littéralement. - Source canonique = state du plugin energymanager (une seule source). Pas l'app, pas l'Energy experience. Justification : ce n'est pas un pis-aller, c'est le seul composant capable de calculer juste (voir ci-dessous).
2.1 Formules déterministes (depuis cumuls, zéro drift de polling)
autonomie = (consommation − import) / consommation
autoconsommation = (production − export) / production
- autonomie :
import= ΔtotalAcquisition. ✅ - autoconsommation :
export= ΔtotalReturn. ✅ RÉSERVE LEVÉE (sonde.75) : le réseau instantané est net-signé (un seul champacquisition), MAIS les cumulstotalAcquisition/totalReturnsont séparés. Donc les deux ratios sont dérivables des logs par deltas de cumuls — pas besoin que le plugin intègre import/export pour l'historique. - ⚠️ Compteurs = monotones requis. Δ d'un cumul n'est valide que si le compteur
ne reset jamais. Sur reset (restart nymead, re-add thing, rollover) → Δ < 0 :
détecter (
Δ < 0⇒ reset, reseed sur la nouvelle valeur, ne pas créer un bucket négatif). À gérer côté plugin et dans les CQ de rollup. - Ces formules sont correctes avec batterie : import/export au compteur réseau nettent déjà les flux batterie ; PV→batterie→maison compte comme autoconsommé (pas exporté). Pas de correction round-trip.
2.2 Bande autoconso instantanée (graphe Puissances)
- Même propriétaire :
selfConsumptionPower = max(production − max(export,0), 0). - À exposer en state plugin, pas dérivé app — sinon re-bug de signe à chaque
refonte (le
.abs()interim n'était qu'un pansement sur un calcul app-side).
3. Carte décisions — AVEC vs SANS Héos (frontière open-core)
La carte actuelle parle au futur : « coût réseau ce soir 0,22 € », « objectif 80 % pour 18h ». Ça suppose un forecast + un plan = Héos.
3.1 Avec Héos (tier Predict/AI)
Inchangé : raisonnement tarifaire, objectifs horaires, plan. Texte = sortie Héos.
3.2 Sans Héos (tier Community, rule-based)
Le rule-based n'a ni forecast ni plan. Il ne peut donc pas tenir ce discours.
- En-tête : « Pilotage automatique » (pas « Héos pilote »).
- Décisions exprimées au présent, réactives :
- « Surplus solaire 2.0 kW → chauffe-eau activé »
- « Pas de surplus → voiture en pause »
- Zéro promesse au futur (pas de « ce soir », pas de « objectif 18h »). Honnêteté : ne pas faire croire à une intelligence prédictive absente.
- Source du texte :
loadActions[]de l'energymanager (la raison additive qu'on a déjà figée), pas une reconstruction côté app.
3.3 Conséquence sur « Plan de la journée »
Voir §4 : sans Héos, la partie future (hachurée) disparaît. Surface d'upsell naturelle : « Activez Héos pour planifier la journée ».
4. Plan de la journée
- Passé (barres pleines) = énergie réalisée → nymea energy logs.
- Futur (barres hachurées) = Héos (etm-powersync-eos → socket → energymanager → state/endpoint exposé). L'app ne projette rien elle-même.
- Sans Héos : n'afficher que le passé. Pas de projection bricolée côté app.
- Légende (Maison / ECS / VE / Batterie / Réseau / Batt→maison) = catégories de l'allocation Héos ; mêmes clés que le plan, pas de remapping côté app.
5. Config — Things (placeholder actuel)
L'app n'est pas un fork de nymea-app → il faut réimplémenter les RPC
(Integrations.* : GetThings, GetThingClasses, GetVendors, DiscoverThings,
AddThing/PairThing/ConfirmPairing, EditThing, RemoveThing). C'est gros, et
nymea-app le fait déjà bien. Décision de périmètre à acter explicitement :
- Option MVP — liste read-only des things + actions simples (renommer, activer/désactiver, supprimer). 80 % de la complexité du wizard est dans l'ajout avec discovery/pairing/paramètres — on l'évite.
- Option ciblée — réimplémenter le wizard seulement pour TES classes (eastron, abbterra, v2c… dont tu maîtrises les params).
- Option hand-off — la config avancée reste dans nymea-app (installateur), l'app ETM se concentre sur l'experience énergie (client final).
→ Question vraie : le client final a-t-il besoin d'ajouter des things, ou c'est un acte installateur (toi/Mathieu) ? Si installateur-only, ne pas construire un demi-wizard.
6. Config — Protocoles → ModbusRTU master
Surface finie et bien définie, dont tes propres plugins compteurs dépendent (SDM, abbterra) → vaut le coup en natif.
ModbusRtu.GetSerialPorts→ lister les ports.GetModbusRtuMasters/AddModbusRtuMaster/Reconfigure…/Remove….- Params : serialPort, baudrate, parity, stopBits, dataBits.
→ Petit, fermé, et bloquant pour tes meters. Le construire avant le wizard Things.
7. Héos — data inputs & metering map
7.1 Règle de granularité
nymea ne stocke que ce qui est compté. Un consommateur n'a de série de
puissance que s'il est un thing avec un state currentPower (interfaces
smartmeter/energymeter/consumer/producer, logged: true).
→ La granularité d'optimisation Héos = la granularité de comptage.
⚠️ DEUX conventions de signe coexistent — ne pas les confondre (piège « fix » d'un faux bug) :
- Thing-level
currentPower: point de vue consommateur → négatif pour un producteur (le PV acurrentPower< 0). C'est la cause du bug autoconso /.abs(). - Power balance agrégé (
production/consumption/acquisition) :productionpositif,consumptionpositif,acquisitionnet signé (+ import / − export). (Sonde.75:acquisition = -231, et uncurrentPowerProductionpositif au niveau balance — normal, ce n'est PAS lecurrentPowerthing-level.)
Le signe est canonique des deux côtés — l'app ne le devine jamais ; elle ne dérive que le sens d'un flux à partir du signe (§1.1), rien d'autre.
7.2 Carte de comptage (état du parc)
| Consommateur | Thing ? | currentPower ? |
Héos optimise finement ? |
|---|---|---|---|
| Réseau (GRID) | ✅ | ✅ | référence (root meter) |
| PV / onduleur | ✅ | ✅ (négatif) | oui, par onduleur |
| Batterie | ✅ | ✅ | oui |
| VE (wallbox) | ✅ | ✅ | oui |
| ECS (relais SDM) | ✅ | ✅ ou déduit du niveau | oui |
| PAC | SG-Ready | ❌ sgReadyMode seul |
non — pilotable, pas mesurable |
| Clim (Zenkeo/Tuya) | bridge | ⚠️ seulement si DP Tuya puissance | partiel |
| Maison (base) | dérivé | résidu = total − charges pilotées | Maison_base |
- Trou PAC : SG-Ready n'expose que
sgReadyMode(Off/Low/Standard/High), aucune puissance. Sans compteur dédié, Héos pilote la PAC mais ne la mesure pas ; sa conso reste noyée dansMaison_base. - Clim : seulement si
clim_bridge.pyremonte un state puissance. - Production par panneau de toit : non. Par onduleur oui ; par string seulement si le plugin expose les states MPPT. Ne pas concevoir Héos en supposant une granularité panneau.
- Conséquence : toute optim PAC/clim fine est une décision matérielle (poser un compteur / exposer un DP), pas logicielle.
7.3 Alimentation de Héos — Route B (tranché)
- States = source live, lus en in-process par le plugin.
- energymanager = série historique canonique par consommateur/générateur, échantillonnée à la résolution du MPC (buckets 15 min), Invariant-3-correcte.
- logs nymea = filet / contrôle croisé, pas l'entrée primaire de Héos.
- Construire les buckets par Δ de compteurs, pas par intégration du signal live
(sonde
.75: les cumuls sont séparés) :- grid import/export du bucket = Δ
totalAcquisition/ ΔtotalReturn; - conso par appareil = Δ
thing.totalEnergyConsumed; - exact, pas de drift d'intégration. L'intégration du signal net-signé ne sert qu'au temps réel sous le bucket (affichage), pas à la série stockée.
- ⚠️ même gestion de reset qu'en §2.1/§8.1 (Δ < 0 ⇒ reset).
- grid import/export du bucket = Δ
- Justification Route B : la Route A (logs nymea bruts) impose le downsampling/ rétention de nymea sans contrôle du schéma ; le plugin reste seul à figer la décomposition Invariant-3 dans la série curée.
8. Persistance & historique
Deux classes de données aux cycles de vie opposés. C'est la règle centrale.
8.1 Mesures — stocker le brut, dériver les ratios
- On stocke le brut intégrable par bucket : production, consommation,
import, export (séparés !), + par charge pilotée, + charge/décharge batterie.
→ obtenu par Δ de cumuls (
totalProduction,totalReturn,totalConsumption,totalAcquisition,thing.totalEnergyConsumed), pas par intégration du signal live (§7.3). Gérer le reset (Δ < 0 ⇒ reseed). - Les ratios ne sont JAMAIS stockés comme donnée primaire — vues dérivées :
autonomie = (Σ conso − Σ import) / Σ conso
autoconsommation = (Σ prod − Σ export) / Σ prod
→ recalculables à la lecture pour n'importe quelle période (jour / semaine / mois / plage custom). Stocker des ratios figés = verrouillage de granularité.
8.2 Plan — stocker explicitement (non recalculable)
- Un ratio se reconstruit à l'infini depuis le brut. Un plan ne se recalcule jamais après coup : il dépendait des prévisions PV/conso/tarif à T0 et de la solution MILP de cet instant. → S'il n'est pas persisté au moment où il est produit, il est perdu.
- Schéma :
(produced_at, bucket_start, asset, planned_value [, inputs_hash]). → stockable dans Influx tagué parplan_run_id; le plan en cours d'exécution est en plus checkpointé localement (§8.3). - Cadence limitée : ne pas stocker chaque tick MPC. Garder un plan-of-record (ex. 1/h ou snapshot début+fin de journée), pas chaque itération.
- Débloque plan vs réalisé : overlay prévu/réalisé → confiance client + matière première du federated-learning-lite (erreur de prévision).
8.3 Store & rétention (réalité embarquée)
Réutiliser l'InfluxDB déjà présente (nymea s'en sert). L'argument « service en plus » ne tient pas : le coût est déjà payé. Influx est faite pour les séries ; ses retention policies + downsampling (CQ 1.x / tasks 2.x) font les rollups nativement → moins de code qu'un SQLite hand-rollé. Et configurer la rétention corrige au passage le « shard accumulation » qui faisait crash-looper l'instance (les shards s'empilaient faute de purge).
- DB / bucket ETM dédié — pas dans la base
nymeatestde nymea. Isole ta donnée des upgrades/migrations nymea et te donne ta propre rétention. - Calquer les paliers sur le template RP nymea existant (sonde
.75) plutôt que d'inventer :live 24h · minutes 7j · hours 3 ans · days 20 ans(+discrete 1 an). Cohérence opérationnelle, CQ alignées. - ⚠️ Ne pas écrire dans
autogen(DEFAULT, rétention ∞). C'est le vrai risque de croissance (pas un shard runaway :nymeatestn'a que 2 shards aujourd'hui). Router explicitement les writes ETM vers les RP tiers. - ⚠️ Version Influx :
.75est en v1.6.7 ✓ (pas 3 Core, pas de piège 72 h). Le tag Dockerlatestpointe désormais vers InfluxDB 3 Core (rétention 72 h + limite 5 DB en OSS) → pinner, ne jamais laisser un upgrade auto basculer. - Checkpoint local minuscule (fichier / petit SQLite) pour l'état de contrôle vivant (plan en cours d'exécution, dernier setpoint). Si Influx tombe, Héos ne doit ni hard-fail ni perdre le plan exécuté — dégradé propre, cohérent avec le L2 watchdog. Logging store down ≠ arbitrage down.
- Distinct du log engine nymea (filet brut générique) : la série dans le DB ETM est la série curée (Invariant-3, import/export scindés) dont dérivent Héos et l'historique client.
8.4 Read model de l'historique client
période choisie
→ agrège les mesures au palier de rollup correspondant
→ dérive autoconso / autonomie (§8.1)
→ overlay plan-of-record (§8.2) si dispo → vue « prévu vs réalisé »
Même donnée parcourue dans les deux sens du temps : passé = mesures réalisées, futur = plan Héos. La metering map §7.2 est le socle commun (entrée Héos + bandes du « Plan de la journée »).
9. Deux réponses de la même box, deux conventions — et aucun signal
Motif, pas anecdote. Deux appels JSON-RPC de la même box, portant la même grandeur ou le même objet, n'emploient pas forcément la même convention. Aucun schéma, aucune erreur, aucun journal ne le dit : la divergence est toujours muette, et elle se manifeste par un écran vide, un zéro, ou un « non lu » parfaitement crédible. Deux occurrences en une semaine, chacune découverte en croisant deux réponses.
Les occurrences connues
| Croisement | Convention A | Convention B | Symptôme si on les mélange |
|---|---|---|---|
Energy.GetPowerBalance × Energy.GetPowerBalanceLogs |
currentPowerProduction, currentPowerConsumption, … |
production, consumption, acquisition, storage — sans préfixe |
tout tombe sur le défaut 0 : l'historique paraît vide alors que la base porte 7 960 échantillons |
NymeaEnergy.GetChargingInfos × NymeaEnergy.GetLoadConfig |
evChargerId sans accolades — 4d1adafd-… |
id de charge avec accolades — {4d1adafd-…} |
aucune correspondance : l'écran affiche « mode non lu » sur une borne parfaitement lue, et la note « borne hors arbitrage » ne sort jamais |
(famille voisine, même silence) currentPower* en W × total* en kWh |
watts | kilowattheures | facteur 1000 : une journée de 78 kWh s'affiche « 78 Wh » |
La règle
Ne jamais rapprocher deux réponses RPC sur une clé ou un identifiant sans l'avoir
normalisé — et écrire la normalisation à un seul endroit, nommé. Dans cette app :
NymeaService.chargingModeOf() pour les identifiants, le bloc de clés de
fetchPowerBalanceLogs() pour les noms de champs. Une comparaison brute recopiée dans un
troisième écran rouvrira le même trou.
Comment on le trouve — et pourquoi il faut le chercher exprès
Le symptôme n'est jamais une exception : c'est une valeur neutre plausible. Un test unitaire qui construit ses deux côtés avec la même convention passe aussi. Trois gestes, dans cet ordre :
- Sonder les deux appels côte à côte et comparer les charges utiles brutes, pas les
modèles Dart —
dart tools/rpc/probe.dart 192.168.1.75 <Méthode>pour chacun. - Éprouver le rapprochement lui-même, sur les deux formes réelles. Les tests d'accolades
(
test/merged_config_screen_test.dart) sont écrits exactement pour ça, avec les deux graphies de la même borne. - Se méfier d'un vide qui ne coûte rien à expliquer. « Aucune donnée sur cette période », « mode non lu », « 0 W » : quand une lecture rend un neutre sur une installation qu'on sait vivante, la première hypothèse est le croisement, pas la box.
Ce que ça implique pour l'affichage
Une valeur neutre issue d'un croisement raté est indiscernable d'une vraie absence.
C'est la raison de fond de la règle « ne jamais afficher zéro pour une absence » qui
traverse EvChargerLive, DailyBalance et LoadMechanism : dire « non lu » laisse une
chance de découvrir le bug ; afficher 0 l'enterre.
Récap des décisions
- Héos au centre du flow : Option A — métaphore « cerveau » assumée (condition : animation respecte les sens figés §1.1, jamais de particule à contre-sens à travers Héos). ✅ tranché.
- Source des ratios : state du plugin energymanager (ni app, ni Energy
experience). Dérivation depuis cumuls via §2.1. Réserve levée (sonde
.75:totalAcquisition/totalReturnséparés) — dérivable des logs, le plugin n'a pas à intégrer pour l'historique. ✅ tranché. - Périmètre Things app : hand-off nymea-app + MVP read-only client ; ModbusRTU master en premier (§6, bloquant pour SDM/abbterra). Wizard ciblé seulement si vraiment nécessaire. ✅ tranché.
- Carte sans Héos : wording présent/réactif + masquage du futur, texte
issu de
loadActions[]. ✅ tranché. - Alimentation Héos : Route B — states (live) + série canonique energymanager (15 min, Invariant-3), logs nymea en filet. ✅ tranché.
- Persistance : mesures brutes stockées + ratios dérivés ; plan stocké explicitement (non recalculable) ; réutiliser l'InfluxDB existante (DB ETM dédié, rollups via retention policies) + checkpoint local pour l'état de contrôle vivant. ⚠️ pinner Influx en 1.x/2.x (pas 3 Core / 72 h). ✅ tranché.
Vérifié sur sonde (.75)
- ✅ PowerBalance : instantané net-signé (
acquisition), cumulstotalAcquisition/totalReturnséparés → ratios dérivables par Δ (§2.1). - ✅ Influx v1.6.7 (pas 3 Core). DB nymea =
nymeatest, RP existantes (live/minutes/hours/days/discrete), DEFAULT =autogen∞ (le vrai risque).
Reste ouvert (vrai)
- Confirmer les signes sur box réelle (
.120) —.75est statique/factice (totaux à 0). L'archi plugin=source rend l'app sign-agnostic, mais valider. - Carte de comptage §7.2 : décider produit par produit quels consommateurs non mesurés (PAC, clim) justifient un compteur matériel pour une optim fine.
- Gestion reset des compteurs (§2.1/§7.3/§8.1) : implémenter la détection Δ < 0 côté plugin et dans les CQ de rollup.