Le bouton Configurer ne peut pas être un formulaire unique. SG-Ready est une
LoadConfig comme le routeur de relais ; la borne de recharge et les zones de climatisation
n'en sont pas du tout — elles vivent sur d'autres namespaces, avec d'autres champs et d'autres tiers.
Deux écarts relevés en introspectant .75 (plugin 1.15.2+etm15) :
① le ChargingInfo réellement déployé ne porte ni mode, ni minCurrent,
ni targetSoc, ni endTime — les noms écrits dans CLAUDE.md ne sont pas
ceux de la box. ② AirConditioning expose 8 méthodes, pas 3.
power — taper un UUID au doigt est une erreur
garantie. Il résout nom → ThingId et n'ajoute aucun champ au contrat.relays[] vide · un powerW ≤ 0 · un même Thing sur deux lignes ·
un mode autre que fixed. Le motif n'apparaît qu'au journal de la box —
le formulaire doit donc valider avant d'envoyer.
Aucun champ n'existe côté box. SetLoadConfig n'accepte que
adapter · enabled · id · label · mode · priority · domain · maxPowerW · minOffS · minOnS ·
needs · powerLevels · relays · sgReady. nymea rejette toute clé inconnue avant le
handler : inventer meterThingId ferait échouer l'enregistrement de toutes les
charges. Ici le besoin est le plus fort des trois
mécanismes : la box estime la consommation depuis les paliers déclarés, elle ne la
mesure pas.
mode doit valoir fixed — la box refuse toute autre valeur sur
ce mécanisme. Le champ n'a donc pas à être proposé : il est déterminé par le choix du mécanisme.sameHardware() : reconstruction de l'adaptateur
et réarmement des verrous à froid — contrairement à label, domain,
priority et enabled, qui passent en mise à jour sur place..75 : trois relais 500 / 1 000 / 2 000 W, huit paliers,
maxStageW: 3 500 — la télémétrie l'a confirmé pendant le passage sur appareil.Aucun champ n'existe côté box. SetLoadConfig n'accepte que
adapter · enabled · id · label · mode · priority · domain · maxPowerW · minOffS · minOnS ·
needs · powerLevels · relays · sgReady, et nymea rejette toute clé inconnue avant
le handler. Ici la question se double : l'interface
remonte déjà la puissance réelle de l'appareil — un compteur externe mesurerait-il autre
chose ?
L'app ne propose plus ce mode — le plugin lui-même le qualifie de legacy — mais
elle ne le réécrit pas en douce : basculer une charge de fixed vers
dynamic change l'arbitrage réel, et cela demande un geste explicite.
La conversion exige aussi une
puissance nominale, que la déclaration en paliers ne porte pas : la box refuse
dynamic sans maxPowerW, et refuse powerLevels avec.
etmvariableload : un seul appareil, une consigne en watts, aucun palier.
relays[] y est interdit — la box refuse en bloc.
fixed existe encore côté box — « multipalier natif, legacy »
dans les mots du plugin. L'app doit savoir le lire sans le proposer : une config déployée
qui l'utilise ne doit pas être convertie par le simple fait d'ouvrir l'écran.sgReady.states[] ne stocke qu'une liste de relais par état, sans nom ni ordre.
Les deux étiquettes sont une convention de cet écran, et elles se retrouvent à la lecture :
SG1 = le contact fermé en état 1 (blocage), SG2 = celui fermé en état 3
(recommandation). C'est l'encodage SG-Ready standard, et c'est celui du banc.
UNUSABLE_ENCODING et la charge sort de
l'arbitrage définitivement (ECS-110). Le formulaire doit le refuser avant l'envoi.
estimatedPowerW sert de base au recrédit de budget et au choix d'état : une
valeur fausse ne décale pas seulement la PAC, elle décale l'allocation de tout le waterfall en
aval. À relever sur la plaque signalétique, puis à mesurer sous les deux régimes.
Aucun champ n'existe côté box. SetLoadConfig n'accepte que adapter · enabled · id · label · mode · priority · domain · maxPowerW · minOffS · minOnS · needs · powerLevels · relays · sgReady. nymea rejette toute clé inconnue avant le handler : inventer meterThingId ferait échouer l'enregistrement de toutes les charges.
LoadConfig, elle est arbitrée par le
waterfall, elle apparaît dans GetLoadTelemetry, elle a un rang et un domaine.
sameHardware() :
reconstruction de l'adaptateur et réarmement des verrous à froid.relays[] à
l'enregistrement : la liste des contacts fermés pour cet état.ChargingModeEco · Min+PV → ChargingModeEcoWithMinCurrent ·
Boost → ChargingModeNormalChargingModeEcoWithTargetTime /
ChargingModeEcoMinWithTargetTime
chargingMode — d'où l'importance de ne pas laisser croire
que ce bouton agit à l'instant.Le mode existe, le réglage n'existe pas. ChargingModeEcoWithMinCurrent est
bien dans l'énumération de la box, mais ChargingInfo n'a aucun champ de courant
minimum — ni minCurrent, ni équivalent. Soit la valeur est fixée ailleurs (paramètre
du Thing borne), soit le champ manque. À trancher avec l'agent plugin avant de livrer ce
mode : proposer un réglage qui ne part nulle part serait pire que de ne pas le proposer.
Aucun champ n'existe côté box. ChargingInfo ne porte que chargingMode · evChargerId · assignedCarId · dailySpotMarketPercentage · endDateTime · repeatDays · spotMarketChargingEnabled · targetPercentage, plus chargingState en lecture. Rien pour un compteur — et la borne mesure déjà, ce qui pose la question de quelle mesure fait foi.
LoadConfig. Le véhicule n'a ni adapter, ni
priority, ni domain — et il n'apparaît pas dans
GetLoadTelemetry en beta : il est décidé en amont du waterfall, et sa puissance est
seulement réservée dans budget.evReservedW. Il rejoindra loads[] à
l'étape 3g.
CLAUDE.md sont périmés. La box déploie
chargingMode (pas mode), targetPercentage (pas
targetSoc), endDateTime en Uint (pas endTime), plus
assignedCarId, repeatDays et deux champs spot market. À corriger dans
CLAUDE.md.NymeaEnergy.*, pas EnergyPlugin.*.Aucun champ n'existe côté box. ZoneInfo rattache des indoorSensors et outdoorSensors — des sondes de température, pas de consommation. Un compteur de zone est un champ à ajouter, et il faudra dire s'il mesure la zone ou l'appareil qui la chauffe.
TemperatureWeekSchedule reste
à introspecter, le type n'est pas détaillé dans le schéma de cette box.AirConditioning.GetZones renvoie zones: [] sur .75.
L'état vide ci-dessous est donc le premier écran que verra un installateur.
Une zone regroupe des thermostats, des vannes et des sondes sous une même consigne. Sans zone, la climatisation n'est pas pilotée par l'énergie.
LoadConfig, ni ChargingInfo. Une zone n'a pas de
rang de service ni de domaine — c'est un regroupement de Things sous une consigne de température.
CLAUDE.md : s'ajoutent
AddZone, RemoveZone, SetZoneName,
SetZoneThings et SetZoneStandbySetpoint. Le CRUD complet est donc
possible depuis l'app.ZoneInfo est
r: — on écrit par les six méthodes Set*, jamais par un objet complet.ZoneInfo ne relie une zone à une
LoadConfig. La PAC SG-Ready et les zones vivent côte à côte sans se connaître — si
l'ordre de service doit tenir compte des zones, c'est une question de conception, pas de câblage.SetZoneThings. On
n'envoie que celles qu'on a touchées — les autres sont optionnelles et restent en place.SetZoneThings prend une liste d'UUID sans contrainte
d'unicité déclarée. Tant que ce n'est pas éprouvé sur la box, l'app signale l'appartenance
existante sans bloquer, et ne prétend pas connaître la règle.
.75 ne portent aucune interface thermostat, vanne ou
sonde de température — il n'y a pas de matériel HVAC dessus. Les appareils ci-dessus sont
fictifs : cet écran n'est pas éprouvable en l'état, et la première vérification à faire est
d'y brancher un thermostat réel.
Le filtre, lui, existe déjà. .75 porte les interfaces
energymeter, smartmeter, smartmeterconsumer et
smartmeterproducer : le jour où le champ est ajouté, l'app saura proposer les bons
appareils sans table maintenue à la main. C'est le champ de destination qui manque, pas la
façon de choisir.
ThingClass.interfaces est une
liste en lecture sur chaque classe ; s'en servir évite la table de correspondance codée en dur que
le brief interdit — et qui vieillirait à chaque plugin ajouté..75 : sur 784 chaînes,
le français en traduit zéro. Les displayName sont des identifiants anglais, à
afficher tels quels.