etm-powersync-energy-plugin.../docs/BRIEF_depuis_plugin.md
Patrick Schurig d57a0184f3 docs(brief): ce que 3g-2 change pour l'app
Quatre points, émis vers l'agent app.

Le deuxième est le plus utile pour lui : la mise en garde « pour une borne,
allocatedW est la décision de l'arbitre et non l'état de la borne » TOMBE.
L'arbitre commande seul depuis +etm23 — 9 commandes sur la fenêtre du banc, 9
par lui, 0 par le proxy. allocationIsCommand rend true partout, les branches
conditionnelles peuvent disparaître.

Avec une réserve qu'il faut lui laisser : l'allocation reste ce qui a été
COMMANDÉ, pas ce que la borne TIRE. Ce qu'il peut enfin affirmer, c'est que
personne d'autre ne commande. L'écart commande/réalité se lit dans la charge
utile `mechanism`, pas dans allocatedW.

Les trois autres : loads[] ⊆ GetLoadConfig rétabli (2 → 4 entrées sur le banc,
avec la forme d'une entrée evcharger et la neutralité de l'aller-retour) ;
EV_GRID_START {budgetW, floorW, gridW} avec sa comptabilité partagée — clé à
prévoir, mais PAS ENCORE VUE sur machine, donc pas d'écran à bâtir autour ;
et le rang de borne, qui se classe au glisser-déposer sur une seule liste.

La réserve sur le rang par défaut est signalée explicitement parce qu'elle le
concerne : avant tout réglage, l'ordre affiché est un artefact, pas un choix.
À ne pas présenter comme un réglage tant que le point n'est pas tranché.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017TVywtayEeoRJ2yWUW4iZj
2026-08-27 13:15:10 +02:00

7.9 KiB
Raw Blame History

Brief agent app — ce que 3g-2 change pour l'écran

Émis par : l'agent plugin, après 3g-2 · Date : 2026-08-27 Banc : .75, plugin 1.15.2+etm24, nymea 1.15.2+202606191336~trixie1 Contexte : docs/RELEVE_3g2.md (ce dépôt) porte les traces machine, cycle par cycle. Contrat : INTERFACE.md fait autorité — ce brief ne fait qu'en signaler les mouvements.

Quatre points. Le deuxième retire une mise en garde que l'app portait, et il est le plus intéressant pour vous : du code conditionnel peut disparaître.


1. loads[] ⊆ GetLoadConfig est RÉTABLI

3g-1 avait rompu l'invariant sans le signaler : les bornes entraient dans loads[] de GetLoadTelemetry sans figurer dans aucune GetLoadConfig. C'était exactement la charge fantôme que le lot B-bis avait supprimée, réapparue par l'autre bout — et vous vous appuyez sur cet invariant pour résoudre libellé, domaine et rang de chaque charge publiée.

Depuis +etm23, toute borne détectée reçoit d'office une entrée LoadConfig. Sur le banc, GetLoadConfig est passé de 2 à 4 entrées au premier cycle après la mise à jour :

chauffe-eau              adapter=relay-router     prio=1  domain=ecs
PAC banc                 adapter=sg-ready         prio=2  domain=heating
Simulated wallbox        adapter=evcharger        prio=1  domain=ev      ← nouvelle
Terra AC Charger (TCP)   adapter=evcharger        prio=1  domain=ev      ← nouvelle

Forme d'une entrée evcharger : id (le ThingId de la borne), adapter: "evcharger", mode: "dynamic", domain: "ev", plus label / priority / enabled. Aucune charge utile — pas de relays, pas de sgReady, pas de powerLevels/maxPowerW/minPowerW, pas de minOnS/minOffS. Les limites d'une borne viennent du Thing et changent avec le véhicule branché ; les déclarer en configuration en ferait une seconde source de vérité.

Rien à faire de votre côté pour que ça marche : l'aller-retour GetLoadConfig → SetLoadConfig verbatim est neutre, vérifié sur machine — l'objet relu est identique et aucun adaptateur n'est reconstruit.

Le sens de l'inclusion reste le même : GetLoadConfig peut contenir des charges absentes de loads[]. Pour une borne, ça veut dire hors arbitrage — pas de voiture assignée, mode manuel, ou aucun véhicule branché (ce dernier cas depuis +etm24). Une borne configurée absente de loads[] se lit « pas arbitrée en ce moment », jamais « perdue ».


2. ⚠️ La mise en garde sur allocatedW des bornes TOMBE

Vous portiez : « pour une borne, allocatedW est la décision de l'arbitre et non l'état de la borne ». C'était juste, et ça ne l'est plus.

Le défaut derrière cette mise en garde : jusqu'à +etm22, l'arbitre décidait et publiait, puis adjustEvChargers() — le chemin d'exécution hérité de l'amont — re-décidait derrière lui et commandait autre chose. La décision publiée n'atteignait pas le matériel.

+etm23 ferme ça. Une charge, un commandeur : les actions EV du waterfall sont dispatchées vers l'adaptateur, et les bornes ainsi commandées sortent du chemin proxy. Mesuré sur machine : 9 commandes émises à la borne sur la fenêtre d'observation, 9 par l'arbitre, 0 par le proxy, et 6 cycles sur 6 portent la ligne « commandée par le waterfall, pas de re-décision ici ».

Conséquence pour vous : allocationIsCommand doit rendre true partout, et les branches conditionnelles qui en dépendaient peuvent disparaître.

Une réserve, et elle est petite mais réelle : l'allocation reste ce que l'arbitre a commandé, pas ce que la borne tire. Un plafond matériel, un véhicule qui refuse ou un câble débranché feront toujours diverger les deux. Ce que vous pouvez enfin affirmer, c'est que personne d'autre ne commande. Pour l'écart commande/réalité, la charge utile mechanism de la borne porte chargingEnabled, currentA, phaseCount et pluggedIn — c'est là qu'il se lit, pas dans allocatedW.


3. Nouvelle clé ARB : EV_GRID_START

EV_GRID_START { budgetW, floorW, gridW }        funding: "grid"

Une borne qui DÉMARRE en soutirant au réseau. Le surplus ne paie pas son plancher, mais le réglage acquisitionTolerance (défaut 0,5) autorise l'appoint : à 0,5, une borne qui exige 4 140 W démarre dès 2 070 W de surplus et tire le reste du réseau.

gridW = floorW − budgetW est ce qui est acheté. C'est le chiffre qui fait de cette ligne une décision, et pas un effet de bord : il mérite d'être montré, pas rangé dans un repli.

Comptabilité — c'est le seul cas où l'allocatedW d'une charge se partage entre les deux compteurs du budget : budgetW vient du surplus et entre dans budget.allocatedW, gridW vient du réseau et entre dans budget.evReservedW. budgetW + gridW == allocatedW, toujours. Si vous réconciliez la somme des allocations avec le budget, c'est la ligne à traiter à part.

Borné par construction : le démarrage exige du surplus réel et consomme tout le budget restant, donc au plus une borne par cycle peut soutirer.

Pas encore vu sur machine. Guetté six cycles au banc, jamais fabriqué : le budget de la borne est passé de 385 W à 2 350 W sans s'arrêter dans la fenêtre de tolérance. Le motif est éprouvé par la simulation. Prévoyez la clé, mais ne construisez pas d'écran autour d'une chose que le terrain n'a pas encore montrée.

Seconde clé du même lot, plus rare : PHASE_LIMIT { limitW, requiredW } — c'est la limite de phase qui interdit, pas le budget. Deux causes, deux gestes : l'une se règle en délestant la maison ou en revoyant l'abonnement, l'autre en attendant le soleil.


4. Le rang d'une borne est configurable, et il se classe avec les autres

LoadConfig.priority, comme toute autre charge. Il n'y a pas de second système de priorité et il n'y en aura pas : un classement propre aux bornes ne saurait pas exprimer « VE1 > ECS > VE2 », et deux classements qui ne peuvent pas s'interclasser sont un défaut, pas deux fonctionnalités. ChargingInfo ne porte donc aucun champ de rang.

Le glisser-déposer marche donc sur une seule liste, bornes comprises, et se pose par SetLoadConfig comme le reste. Vérifié sur machine, y compris l'inversion de rang entre deux charges.

Le tri est total : à rang égal, l'identifiant départage. Laquelle est servie est donc reproductible d'un cycle à l'autre, même avant tout réglage.

Réserve sur le rang par défaut, et elle vous concerne. À la création automatique, la borne reçoit « le plus petit rang existant moins un, borné à 1 ». Quand une charge occupe déjà le rang 1 — c'est le cas du banc — l'intention « en tête » dégénère en égalité : les deux bornes et le chauffe-eau sont tous à 1. Sans conséquence sur la reproductibilité, mais l'ordre affiché à l'installateur avant qu'il n'ait rien réglé n'est pas un choix, c'est un artefact. Ne le présentez pas comme un réglage tant que le point n'est pas tranché côté moteur (docs/RELEVE_3g2.md §3.2). Les vrais rangs se posent à la mise en service, par vous.


Ce qui n'a PAS changé, et qu'il ne faut pas déduire

  • L'échéance de départ et le tarif dynamique restent au proxy, financés au réseau (funding: "grid", motifs EV_DEADLINE / EV_SPOT_MARKET). Leur puissance vit dans budget.evReservedW, pas dans budget.allocatedW.
  • chargingState de ChargingInfo garde son sens et reste publié par l'arbitre pour les bornes qu'il commande.
  • SetChargingInfo n'est toujours pas partiel — l'objet remplace le stocké, et un champ writable omis retombe sur son défaut. La description publiée le dit désormais, et INTERFACE.md en donne la table. Lire → modifier → renvoyer complet.
  • repeatDays va de 1 (lundi) à 7 (dimanche), pas de 0 à 6. La documentation disait le contraire ; le code a toujours refusé le 0.