Le banc `hems` est renuméroté (192.168.1.75 → 10.42.60.21). Portés : les 11 sondes `tools/rpc/*` et leur README, les 3 tests on-device, le `hint` de l'écran Installations, les procédures de CLAUDE.md et des deux documents de cadrage. Ce qui n'est PAS touché, et c'est délibéré : les relevés datés (RELEVE_LOTC, RECAP, Prompt 3g2, maquettes) et les fixtures `hems75_*.json`. Un relevé daté dit ce qui a été observé ce jour-là ; le réécrire échange une trace contre une cohérence de surface. CLAUDE.md porte la note qui fait le lien : `.75` et `hems75` désignent la même machine. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
8.1 KiB
Cadrage — écran des zones de climatisation
Date : 2026-08-27 · Banc : .75, nymea 1.15.2+202606191336~trixie1
Objet : ce qu'il faut sur le banc pour rendre l'écran exerçable, avant d'écrire une
ligne de code d'affichage.
Ce document ne propose pas de maquette. C'est un cadrage : il dit ce qui existe, ce qui manque, et quelles décisions doivent être prises avant de coder. La maquette se valide avec Patrick, comme tout nouvel écran.
1. Où en est l'écran aujourd'hui
lib/screens/ac_screen.dart, 1 105 lignes. Il appelle exactement une méthode du
contrat : AirConditioning.GetZones, et seulement pour en compter le résultat
(_zonesSurLaBox). Tout le reste est de la maquette :
const _Zone(name: 'Salon', currentTemp: 19.5, targetTemp: 21.0, …),
const _Zone(name: 'Chambre', currentTemp: 18.0, targetTemp: 19.0, …),
const _Zone(name: 'Bureau', currentTemp: 20.0, targetTemp: 22.0, …),
const _Zone(name: 'Cuisine', currentTemp: 21.5, targetTemp: 21.0, …),
Quatre pièces, huit températures, un état SG-Ready et deux consignes ECS — aucun de ces nombres ne vient de la box. C'est le même défaut que le SOC véhicule à 62 %, en plus grand : des grandeurs physiques crédibles, affichées comme des mesures.
.75 déclare zéro zone (GetZones → zones: []). L'écran affiche donc quatre pièces
là où l'installation n'en connaît aucune.
2. Le contrat, tel que la box le publie
Huit méthodes, trois notifications (ZoneAdded · ZoneChanged · ZoneRemoved).
ZoneInfo est presque entièrement en lecture (r:) — température, humidité, PM2.5,
COV, consigne courante, dérogation et sa fin, zoneStatus, et les six listes d'appareils.
On n'écrit jamais un objet complet : on écrit par les six Set*.
| Écriture | Ce qu'elle pose |
|---|---|
AddZone(name, o:thermostats, o:valves, o:indoorSensors, o:outdoorSensors, o:windowSensors, o:notifications) |
crée |
RemoveZone(zoneId) |
supprime |
SetZoneName(zoneId, name) |
renomme |
SetZoneThings(zoneId, …les six listes…) |
rattache |
SetZoneSetpointOverride(zoneId, mode, setpointOverride, o:minutes) |
dérogation manuelle |
SetZoneStandbySetpoint(zoneId, …) |
consigne de réduit |
SetZoneWeekSchedule(zoneId, …) |
planning 7 jours |
SetpointOverrideMode : None · Timed · Unlimited · Eventual.
ZoneStatusFlag : None · TimeScheduleActive · SetpointOverrideActive ·
WindowOpen · BadAir · HighHumidity — un drapeau, donc combinable.
Le planning est un TemperatureWeekSchedule = 7 × TemperatureDaySchedule =
liste de {startTime, endTime, temperature}.
3. ⚠️ Le banc ne peut PAS héberger une zone — et ce n'est pas « il manque un appareil »
Vérifié le 2026-08-27 sur les 58 classes déclarées par .75 : aucune classe ne
porte l'une des interfaces qu'une zone exige. Pas « aucun appareil créé » — aucune classe,
donc aucun plugin installé ne sait en créer un.
Les huit plugins installés sont : AbbB2x, AbbTerra, GpioController, SunSpec,
eastron, energySimulation, genericEnergy, mqttclient. Tous énergie ou entrées/
sorties : rien de thermique, rien de capteur d'ambiance.
Ce que chaque emplacement exige exactement
Lu dans airconditioningmanager.cpp:605 (verifyThingIds), qui refuse par
AirConditioningErrorInvalidThingType :
| Emplacement | Interface exigée |
|---|---|
thermostats |
thermostat |
windowSensors |
closablesensor |
indoorSensors + outdoorSensors |
temperaturesensor ou humiditysensor ou vocsensor ou pm25sensor |
notifications |
notifications |
valves |
aucune — non vérifié |
valvesest au schéma d'AddZoneet deSetZoneThings, maisverifyThingIdsne le reçoit pas : la box accepte n'importe quel ThingId dans cet emplacement sans le contrôler. À ne pas exposer comme un choix guidé tant que le point n'est pas tranché — un champ que la box accepte sans vérifier produit une configuration qui « marche » et ne fait rien.
4. Ce qu'il faut sur le banc — la liste courte
Trois paquets, tous présents dans le dépôt apt du banc (apt-cache search
le 2026-08-27) :
ssh etm@10.42.60.21
sudo apt install nymea-plugin-generic-heatingcooling \
nymea-plugin-generic-sensors
# optionnel, pour le drapeau WindowOpen :
# les capteurs d'ouverture sont DÉJÀ dans generic-sensors (voir tableau)
Ce que ces deux paquets apportent, vérifié dans
nymea-plugins-genericthings/*/integrationplugin*.json :
| Classe à créer | Interfaces | Remplit |
|---|---|---|
| Generic thermostat | thermostat, temperaturesensor |
thermostats — et sert aussi de sonde |
| Generic temperature sensor | temperaturesensor |
indoorSensors / outdoorSensors |
| Generic humidity sensor | humiditysensor |
indoorSensors |
| Generic door or window sensor | closablesensor |
windowSensors → drapeau WindowOpen |
Les paquets *-simulation (heating-simulation, sensors-simulation,
closables-simulation) sont une alternative : ils animent leurs valeurs au lieu de les
laisser fixes, ce qui est préférable pour voir un écran vivre. Les classes generic*, elles,
sont pilotables à la main — préférable pour provoquer un état précis (fenêtre ouverte,
humidité haute) sans attendre.
Recommandation : les deux. generic* pour fabriquer un cas à volonté, *-simulation
pour regarder l'écran bouger tout seul.
Le banc minimal qui exerce tout le contrat
Deux zones, parce qu'une seule ne montre ni le tri ni le cas « la pièce d'à côté » :
| Zone | Contenu | Ce qu'elle rend exerçable |
|---|---|---|
| Salon | 1 thermostat + 1 capteur d'humidité + 1 capteur d'ouverture | dérogation, planning, WindowOpen, HighHumidity |
| Chambre | 1 thermostat seul | le cas pauvre : aucune sonde d'ambiance, et l'écran doit le dire au lieu d'afficher des tirets |
Plus un capteur de température déclaré outdoorSensors, pour que la distinction
intérieur/extérieur ne reste pas théorique.
5. Ce qui doit être tranché avant de coder
- Le drapeau
zoneStatusest un ensemble, pas un état.WindowOpen+BadAirpeuvent être vrais ensemble. Un écran qui affiche « le » statut choisira lequel taire — c'est une décision d'interface, à prendre explicitement. vocsensoretpm25sensorsont acceptés comme sondes d'ambiance, etZoneInfopublievocetpm25. La qualité d'air entre donc dans cet écran par la porte du contrat. Est-ce qu'on l'affiche, ou est-ce qu'on la garde pour plus tard ?valves— exposé ou pas ? Voir la réserve du §3.- Le rattachement d'appareils appartient-il à cet écran ou au mode installateur ?
AddZoneetSetZoneThingssontPermissionScopeAdmin; les six autres sontPermissionScopeControlThings. La box sépare déjà les deux : l'écran devrait suivre. - Le lien avec les charges pilotées reste à définir. La PAC du banc est une charge
sg-readyarbitrée par le waterfall ; une zone est un objet du contratAirConditioning. Les deux ne se connaissent pas. L'écran actuel les mélange (un bloc SG-Ready sous les pièces), et ce mélange n'a aucun support dans le contrat. À trancher avant de le reconduire. - Tier
Auto. Les zones sont derrière ce palier ;pro_lock_badge.dartexiste déjà.
6. Ordre de marche proposé
- Installer les deux paquets sur
.75et créer le banc minimal du §4. - Écrire la sonde
tools/rpc/zones.dart— instantané + écoute des trois notifications, commetelemetry_watch.dart. Aucun écran avant elle : c'est elle qui dira ce que la box publie vraiment quand une fenêtre s'ouvre. - Modéliser
ZoneInfoen lecture seule, avec la règle maison — omis, jamais nul. - Retirer les quatre pièces de maquette. Tant que le modèle n'est pas branché, un écran vide qui dit « aucune zone déclarée » est plus juste que quatre pièces inventées.
- Maquette, validation avec Patrick, puis l'écran.