/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
170 lines
8.1 KiB
Markdown
170 lines
8.1 KiB
Markdown
# 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 :
|
||
|
||
```dart
|
||
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é** |
|
||
|
||
> `valves` est au schéma d'`AddZone` et de `SetZoneThings`, mais `verifyThingIds` ne 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) :
|
||
|
||
```sh
|
||
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
|
||
|
||
1. **Le drapeau `zoneStatus` est un ensemble, pas un état.** `WindowOpen` + `BadAir`
|
||
peuvent être vrais ensemble. Un écran qui affiche « le » statut choisira lequel taire —
|
||
c'est une décision d'interface, à prendre explicitement.
|
||
2. **`vocsensor` et `pm25sensor` sont acceptés comme sondes d'ambiance**, et `ZoneInfo`
|
||
publie `voc` et `pm25`. 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 ?
|
||
3. **`valves` — exposé ou pas ?** Voir la réserve du §3.
|
||
4. **Le rattachement d'appareils appartient-il à cet écran ou au mode installateur ?**
|
||
`AddZone` et `SetZoneThings` sont `PermissionScopeAdmin` ; les six autres sont
|
||
`PermissionScopeControlThings`. La box sépare déjà les deux : l'écran devrait suivre.
|
||
5. **Le lien avec les charges pilotées reste à définir.** La PAC du banc est une charge
|
||
`sg-ready` arbitrée par le waterfall ; une zone est un objet du contrat
|
||
`AirConditioning`. **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.
|
||
6. **Tier `Auto`.** Les zones sont derrière ce palier ; `pro_lock_badge.dart` existe déjà.
|
||
|
||
---
|
||
|
||
## 6. Ordre de marche proposé
|
||
|
||
1. Installer les deux paquets sur `.75` et créer le banc minimal du §4.
|
||
2. Écrire la sonde `tools/rpc/zones.dart` — instantané + écoute des trois notifications,
|
||
comme `telemetry_watch.dart`. **Aucun écran avant elle** : c'est elle qui dira ce que la
|
||
box publie vraiment quand une fenêtre s'ouvre.
|
||
3. Modéliser `ZoneInfo` en lecture seule, avec la règle maison — omis, jamais nul.
|
||
4. 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.
|
||
5. Maquette, validation avec Patrick, puis l'écran.
|