From cd8dd02989cbdcf3610317322e95dbff2e994f48 Mon Sep 17 00:00:00 2001 From: Patrick Schurig Date: Sat, 5 Sep 2026 07:40:26 +0200 Subject: [PATCH] =?UTF-8?q?docs:=20la=20journ=C3=A9e=20de=20reporting=20su?= =?UTF-8?q?it=20l'installation=20=E2=80=94=20et=20l'app=20prend=20celle=20?= =?UTF-8?q?du=20t=C3=A9l=C3=A9phone?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit +etm55 vérifié (posé le 04/09 18:21:08). Le taux constant est en ligne : la maquette porte le bon chiffrage — ×4,75 sur une fenêtre quotidienne, facteur ln(T·P/E) + 1 — et les deux interdits du régime `unmeasurable` : ni annoncer que l'achat va s'intensifier, ni lire `atMaximum: false` comme « tout va bien », qui signifie qu'il n'y a aucun étalement, donc rien qui puisse cesser. La troisième nature d'heure murale touche du code livré : `fetchDailyBalance()` et la baseline des ratios prennent minuit du TÉLÉPHONE, alors qu'une journée de reporting suit l'installation. Sur `.75` en Europe/London vue d'un téléphone français, entre minuit et 1 h l'app compte une journée que la box compte encore dans la précédente. L'app ne peut pas le corriger seule : `System.GetTime` publie un nom IANA, et un décalage ne s'en déduit pas sans base de fuseaux — qu'il faudrait embarquer pour recalculer une frontière que la box connaît, et qui resterait fausse les jours de changement d'heure. Demandé au moteur : publier le DÉBUT de la journée de reporting en cours, en epoch, à côté du fuseau. La divergence est écrite aux deux endroits du code en attendant. Noté sans conclure : le banc n'a aucune charge `unmeasurable`, donc la loi est déployée mais pas exerçable de bout en bout. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01GKM8FDNHZWogAsjjfB8pSw --- docs/BRIEF_plugin_depuis_maquettes.md | 42 +++++++++++++++++++ .../deux_passes_eco_confort_mockup.html | 19 +++++---- lib/services/energy_ratios.dart | 6 +++ lib/services/nymea_service.dart | 19 ++++++++- 4 files changed, 77 insertions(+), 9 deletions(-) diff --git a/docs/BRIEF_plugin_depuis_maquettes.md b/docs/BRIEF_plugin_depuis_maquettes.md index be6242f..d0b5c31 100644 --- a/docs/BRIEF_plugin_depuis_maquettes.md +++ b/docs/BRIEF_plugin_depuis_maquettes.md @@ -2,6 +2,48 @@ --- +## 2026-09-05 — le début de journée doit être PUBLIÉ, pas recalculé + +`+etm55` vérifié sur la box (posé le 04/09 à 18:21:08). Le taux constant est en ligne, la maquette +porte le bon chiffrage — **×4,75** sur une fenêtre quotidienne, `ln(T·P/E) + 1` — et les deux +interdits sont écrits à côté : sous `unmeasurable`, l'écran ne dira ni que l'achat va s'intensifier, +ni que `atMaximum: false` signifie que tout va bien. Il signifie qu'il n'y a **aucun étalement**, +donc rien qui puisse cesser. + +### Votre troisième nature d'heure touche du code déjà livré, et il ne peut pas se corriger seul + +La journée de reporting suit l'installation — d'accord, et c'est bien la bonne réponse. Mais nos +deux calculs journaliers prennent **minuit du téléphone** : `fetchDailyBalance()` par +`DateTime(y, m, d)`, et la baseline des ratios par un index de jour local. Sur `.75` en +`Europe/London` vue d'un téléphone français, **entre minuit et 1 h l'app compte une journée que la +box compte encore dans la précédente.** + +**Et l'app ne peut pas le corriger avec ce qui est publié.** `System.GetTime` donne le fuseau par +**nom IANA** ; un décalage ne s'en déduit pas sans base de données de fuseaux. Embarquer cette base +pour recalculer une frontière que la box connaît déjà serait le mauvais geste — et il resterait +faux les jours de changement d'heure, où la journée fait 23 ou 25 heures. + +**Ce qu'on demande, et c'est un champ** : le **début de la journée de reporting en cours**, en +epoch, publié à côté du fuseau. L'app soustrait alors deux points de log sur la bonne fenêtre sans +rien dériver. C'est la même règle que `counts` a réglée pour les compteurs : *publier la frontière, +ne pas la faire recalculer par chaque client* — trois clients la recalculeraient de trois façons, +et la seule qui compte est la vôtre. + +> Un décalage UTC seul suffirait presque, mais pas les jours de bascule. Le début de journée, lui, +> est juste par construction. + +D'ici là la divergence est **écrite dans le code**, aux deux endroits, pour que personne ne lise +« minuit du téléphone » comme un choix — et elle est bornée à une heure sur ce banc. + +### Noté sans conclure + +Le banc n'a aucune charge `unmeasurable` : la loi du taux constant est déployée mais pas exerçable +de bout en bout, et elle tient sur votre test unitaire et sa contre-épreuve. **Je ne conclurai donc +rien de son absence à l'écran** — c'est encore l'homogénéité du banc, et c'est exactement le cas +où une mesure manquante ressemble à une mesure réussie. + +--- + ## 2026-09-04 (soir) — deux natures d'heure murale : c'est une règle de STOCKAGE, pas d'affichage La décision « publier le fuseau, ni imposer ni déclarer forfait » est prise, et le `Changed` avec — diff --git a/docs/mockups/deux_passes_eco_confort_mockup.html b/docs/mockups/deux_passes_eco_confort_mockup.html index dfc4c85..7bdb53c 100644 --- a/docs/mockups/deux_passes_eco_confort_mockup.html +++ b/docs/mockups/deux_passes_eco_confort_mockup.html @@ -342,8 +342,8 @@ Avancement non mesurable : cette borne ne publie pas d'énergie de session. NON MESURABLE
- Reste 4,0 kWh à livrer en 5 h 13 — et ce taux ne peut que monter : rien - n'est soustrait de ce qui reste, donc l'achat s'accélère jusqu'à l'échéance. + Reste 4,0 kWh à livrer — taux constant (cible ÷ jour), il ne montera + pas et ne baissera pas : sans mesure, rien ne peut le corriger. L'obligation est servie ; elle ne pourra jamais être annoncée tenue. @@ -431,11 +431,16 @@ « 12:00 » vaut 13:00 sur une horloge française. Le fuseau se lit par System.GetTime : l'écran l'affiche à côté du champ et signale la divergence, plutôt que de choisir une horloge à la place de l'installateur. -
  • Sous unmeasurable, le plancher ne peut pas se refermer — mesuré le - 2026-09-01 sur quatre cycles : remainingWh figé à 4 000, remainingS qui - descend, gridW qui monte 755 → 767. Ce n'est pas un cas limite, c'est la - trajectoire garantie du régime : l'écran doit montrer reste et temps, pas - seulement les watts de l'instant, sans quoi « 767 W achetés » ne laisse pas deviner le mur.
  • +
  • Sous unmeasurable, le taux est CONSTANT depuis +etm55 — + cible ÷ jour, la fenêtre étant l'unité de la grandeur déclarée et non un réglage + (LM-1013-b-v). Le total acheté vaut alors exactement la cible. L'escalade mesurée le + 2026-09-01 (gridW 755 → 767, remainingWh figé) achetait + ×4,75 l'obligation sur une fenêtre quotidienne — le facteur suit + ln(T·P/E) + 1, donc il grandit avec la fenêtre : une échéance lointaine coûtait + plus, l'inverse de l'intuition. +
    Deux choses que l'écran ne peut donc plus dire sous ce régime : ni que l'achat va + s'intensifier, ni que atMaximum: false veut dire que tout va bien — il veut dire + qu'il n'y a aucun étalement, donc rien qui puisse cesser.
  • * « Commandé, pas encore mesuré » — et ce n'est pas une destination. Le champ budget.evReservedW est un terme de correction : la latence entre l'ordre et sa lecture au compteur. Il est affiché parce que la box le publie, jamais sommé. Son ancien diff --git a/lib/services/energy_ratios.dart b/lib/services/energy_ratios.dart index 0cc98bf..edf88f5 100644 --- a/lib/services/energy_ratios.dart +++ b/lib/services/energy_ratios.dart @@ -25,6 +25,12 @@ class EnergyRatios { /// ``` class EnergyRatiosInterim { // Baseline = cumuls au début de la période courante (minuit local / reseed). + // + // ⚠️ « local » = fuseau du TÉLÉPHONE, et une journée de reporting devrait suivre + // l'INSTALLATION (cf. `NymeaService.fetchDailyBalance`). Sur une box en `Europe/London` + // vue d'un téléphone français, la bascule de jour arrive une heure trop tôt. La cible + // Phase 2 — lire UN state de l'energymanager — fait disparaître le problème avec le + // calcul ; d'ici là, la divergence est connue et écrite. double? _baseProduction; double? _baseReturn; double? _baseConsumption; diff --git a/lib/services/nymea_service.dart b/lib/services/nymea_service.dart index ecd4498..e70830b 100644 --- a/lib/services/nymea_service.dart +++ b/lib/services/nymea_service.dart @@ -1001,8 +1001,23 @@ class NymeaService extends ChangeNotifier { /// /// 1. **Minuit LOCAL, et via les logs.** `GetPowerBalance` ne rend que des totaux depuis /// l'origine : il ne sait rien dire d'une journée. Seul `GetPowerBalanceLogs` permet - /// de prendre deux points et de les soustraire. `DateTime(y, m, d)` donne bien minuit - /// dans le fuseau du téléphone — pas UTC. + /// de prendre deux points et de les soustraire. `DateTime(y, m, d)` donne minuit dans + /// le fuseau **du téléphone** — pas UTC. + /// + /// ⚠️ **Et c'est justement le fuseau qu'il ne faudrait PAS prendre.** Une journée de + /// reporting suit **l'installation**, pas l'appareil qui regarde : c'est la troisième + /// nature d'heure murale, ni habitude client ni calendrier fournisseur (`CLAUDE.md`, + /// « Échéances »). Sur `.75`, en `Europe/London`, les taux journaliers de la box se + /// remettent à zéro à **01:00 heure française** — donc entre minuit et 1 h, cette méthode + /// compte une journée que la box compte encore dans la précédente. + /// + /// La correction ne peut pas se faire ici : le fuseau de la box est publié par nom IANA + /// (`System.GetTime`), et un décalage ne s'en **déduit pas** sans base de données de + /// fuseaux. Embarquer cette base pour recalculer une frontière que la box connaît déjà + /// serait le mauvais geste — c'est le **début de journée** qui doit être publié. Demandé + /// dans `docs/BRIEF_plugin_depuis_maquettes.md`. D'ici là, la divergence est **connue et + /// bornée à une heure sur ce banc**, et elle est écrite ici pour que personne ne lise + /// « minuit du téléphone » comme un choix. /// 2. **Les entrées de log ne portent PAS le préfixe `currentPower`.** Elles s'appellent /// `production`, `consumption`, `acquisition`, `storage`, à la différence de /// `GetPowerBalance`. Se tromper de clés ne produit **aucune erreur** : tout tombe sur