/bug-report était un stub. Un champ libre seul produit « ça ne marche pas », et l'aller-retour pour obtenir versions, charges et état d'arbitrage coûte des jours. Tout ce que l'app SAIT est donc joint d'office : version du paquet, hôte et état de connexion, ligne de versions du schéma, les charges déclarées avec adaptateur / rang / domaine, et le dernier cycle publié. Deux choix qui ne sont pas cosmétiques : - LES DEUX IDENTITÉS DU BUDGET sont dans le rapport, avec leur verdict. Elles valent souvent plus que la description du symptôme : portées fausses, elles désignent le moteur ; portées vraies, elles désignent l'écran. Sans elles, le premier échange consiste à les demander. - Aucun secret n'y entre : ni PIN installateur même haché, ni jeton, ni mot de passe. Un rapport voyage — courriel, capture, fil de discussion — et ce qui y entre en sort. Les UUID de Things restent : ce sont eux qui permettent de recouper avec le journal de la box, et ils n'ont aucune valeur hors de l'installation. Les absences gardent leur sens, comme partout ailleurs : « aucune télémétrie reçue » n'est pas un arbitrage à zéro, « budget ABSENT » n'est pas un budget de zéro watt, et un financement omis se dit omis. Pas d'envoi automatique : il n'existe aucun service de collecte, et un bouton « Envoyer » sans destinataire donnerait le sentiment que quelqu'un l'a reçu. Le rapport se copie, ce qui est vérifiable. package_info_plus est ajouté plutôt qu'une constante de version recopiée à la main : une constante dérive de pubspec.yaml en silence, et un rapport qui annonce la mauvaise version envoie chercher un défaut dans un code qui n'est pas celui-là. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016vrTVifar2GN5rtUh89Wkq
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@192.168.1.75
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.