@Sescandell, je suis en train de faire un PR pour le fil pilote pour l’integration Thermostat et mon device QUBINO retourne seulement un variateur et en fonction de la valeur cela correspond à un état du fil pilote.
Est-ce qu’il y a un moyen d’avoir des modes plutot que variateur dans l’integration? Je te remercie par avance.
Ci dessous une analyse de Claude:
# Qubino Flush Pilot (ZMNHJD) : support du radiateur à fil pilote
> Spec de l'intégration externe Z-Wave. Elle s'appuie sur le framework des
> intégrations externes du monorepo Gladys (`docs/specs/external-integrations/`) :
> les devices sont publiés par `POST /discovered_device` (C.3, SDK
> `publishDiscoveredDevices`), les commandes arrivent par
> `external-integration.device.set-value` (C.4), et les états remontent par
> `POST /state` (B.6).
## 1. Problème
Le Qubino Flush Pilot (ZMNHJD) pilote un radiateur à fil pilote. Il le fait par
son **Multilevel Switch** (CC 38) : chaque plage de niveaux correspond à un
ordre fil pilote. Aujourd'hui, l'intégration le publie comme ce que dit sa
classe de device, c'est-à-dire un variateur (position 0–99 %, état on/off,
« restaurer la valeur précédente »).
Conséquences :
- l'utilisateur voit « 30 % » alors que le radiateur est en **Éco** ;
- le thermostat ne peut pas le piloter. Son actionneur fil pilote
(`THERMOSTAT_PILOT_WIRE_FEATURE`, spec thermostat C.1.1) n'accepte qu'une
fonctionnalité `heater` / `pilot-wire-mode` ;
- les scènes, le dashboard et HomeKit voient un variateur, pas un ordre.
La traduction niveau → ordre est propre à ce produit : elle appartient donc à
l'intégration qui connaît ce produit. Le thermostat, comme le reste de Gladys,
ne voit que le type standard.
## 2. Identifier le device
| Champ | Valeur |
|---|---|
| `manufacturerId` | 345 (`0x0159`, Qubino) |
| `productType` | 4 (`0x0004`) |
| `productId` | 81 (`0x0051`) |
| `deviceId` zwave-js | `345-81-4` |
| `deviceClass` | basic 4, generic 17, specific 1 |
| config zwave-js | `0x0159/zmnhjd.json`, label `ZMNHJD`, « Flush Pilot » |
**La classe de device n'est pas utilisable.** Generic 17 / specific 1
(« Multilevel Switch, variateur ») est la classe de tous les variateurs. S'en
servir transformerait chaque variateur en fil pilote. Le device est donc
identifié par son **identifiant produit** (`manufacturerId` + `productType` +
`productId`), vérifié **avant** toute règle basée sur la classe de device.
## 3. Device publié
Le nœud publie **une seule** fonctionnalité actionnable à la place de celles du
variateur :
| Champ | Valeur |
|---|---|
| `category` | `heater` (`DEVICE_FEATURE_CATEGORIES.HEATER`) |
| `type` | `pilot-wire-mode` (`DEVICE_FEATURE_TYPES.HEATER.PILOT_WIRE_MODE`) |
| `min` / `max` | `0` / `5` (`PILOT_WIRE_MODE.OFF` … `PILOT_WIRE_MODE.COMFORT`) |
| `read_only` | `false` |
| `has_feedback` | `true` : le module renvoie `currentValue` après chaque changement, y compris un appui sur ses propres boutons |
| `keep_history` | `true` |
| valeur source | CC 38 `currentValue`, endpoint 0 |
**Non publiés** pour ce produit :
- les fonctionnalités du variateur (`position`, l'`état` on/off déduit du
niveau, `restorePrevious`). « Restaurer la valeur précédente » renverrait au
radiateur un ordre arbitraire ;
- le Binary Switch explicite (CC 37). L'intégration le retire déjà de tout nœud
qui a un Multilevel Switch ;
- `Up` / `Down` / `duration` / `event` (CC 38), comme aujourd'hui sur tous les
nœuds.
Inchangés : les paramètres de configuration (CC 112 : types d'entrée, mode des
entrées 11/12/13, état après coupure de courant 30). Ils restent hors périmètre
(section 8).
## 4. Écrire un ordre (Gladys → device)
Sur `external-integration.device.set-value` pour cette fonctionnalité, `value`
est un `PILOT_WIRE_MODE`. Il est écrit sous forme de niveau par la commande
`set` du Multilevel Switch (CC 38, endpoint 0) :
| Ordre (`PILOT_WIRE_MODE`) | Valeur | Niveau écrit |
|---|---|---|
| `OFF` (arrêt) | 0 | 0 |
| `FROST_PROTECTION` (hors-gel) | 1 | 20 |
| `ECO` | 2 | 30 |
| `COMFORT_2` (confort −2 °C) | 4 | 40 |
| `COMFORT_1` (confort −1 °C) | 3 | 50 |
| `COMFORT` (confort) | 5 | 99 |
- Les niveaux écrits sont ceux mesurés sur le module : 0 / 20 / 30 / 40 / 50 / 99.
- Toute autre valeur reçoit un **command-result en échec** (« ordre fil pilote
inconnu »), et rien n'est envoyé au module.
- **Pas d'état optimiste.** L'état est remonté quand le module confirme par
`currentValue` (section 5), pas à l'envoi de la commande. Un radiateur qui a
raté la trame ne doit pas avoir l'air d'avoir obéi.
## 5. Lire un ordre (device → Gladys)
À chaque mise à jour de `currentValue` sur la CC 38, le niveau est lu **par
plage**, et l'ordre est remonté par `POST /state` :
| Niveau | Ordre remonté |
|---|---|
| 0–10 | `OFF` |
| 11–20 | `FROST_PROTECTION` |
| 21–30 | `ECO` |
| 31–40 | `COMFORT_2` |
| 41–50 | `COMFORT_1` |
| 51–99 | `COMFORT` |
| autre (par ex. 255, une valeur non numérique) | rien n'est remonté |
La lecture par plage plutôt que par valeur exacte est indispensable : le module
peut renvoyer n'importe quel niveau d'une plage. Un appui sur son bouton a été
observé à **60** avant 99, et c'est bien un ordre confort.
`targetValue` n'est pas lu : `currentValue` est ce que le module applique
réellement.
## 6. Devices créés avant ce changement
Un nœud déjà créé dans Gladys comme variateur garde ses fonctionnalités de
variateur tant qu'il n'est pas mis à jour depuis l'écran de découverte. La mise
à jour les remplace par la fonctionnalité fil pilote : même `external_id` de
device, nouvel `external_id` de fonctionnalité.
- L'historique des anciennes fonctionnalités variateur n'est pas repris. Des
niveaux et des ordres ne sont pas les mêmes valeurs.
- Les scènes et les widgets du dashboard qui pointaient sur l'ancienne
fonctionnalité variateur sont à re-pointer à la main. La migration de device
(`device-migration.md`) déplace les sélecteurs d'une fonctionnalité à une
autre, mais un « 30 % » dans une scène ne voudrait pas dire un ordre.
- Un thermostat (virtuel, `THERMOSTAT_PILOT_WIRE_FEATURE`) se configure ensuite
sur la nouvelle fonctionnalité dans son formulaire d'édition. Rien d'autre
côté thermostat : la correspondance preset → ordre est dans la spec
thermostat, C.1.1.
## 7. Tests
- **Découverte :**
- un nœud de `deviceId` `345-81-4` et de classe 17-1 publie exactement une
fonctionnalité `heater` / `pilot-wire-mode`, sans position, état,
`restorePrevious` ni Binary Switch ;
- un nœud de classe 17-1 avec **un autre** identifiant produit est toujours
publié comme un variateur (non-régression).
- **Écriture :** chacun des six ordres produit un `set` CC 38 avec son niveau, et
un ordre inconnu donne un command-result en échec, sans rien envoyer.
- **Lecture :** les bornes des plages (0, 10, 11, 20, 21, 30, 31, 40, 41, 50, 51,
99), le 60 observé → `COMFORT`, et 255 / −1 / une valeur non numérique ne
remontent rien.
- **Retour d'état :** après une écriture, aucun état n'est remonté tant que
`currentValue` n'est pas arrivé.
## 8. Hors périmètre
- Les paramètres de configuration CC 112 (modes des boutons, état après coupure
de courant).
- Les autres références Qubino à fil pilote, tant que leur identifiant produit
n'est pas connu et qu'il n'est pas confirmé qu'elles utilisent les mêmes
niveaux. Chacune est ajoutée explicitement à la liste des produits, jamais
par la classe de device.
- Toute logique de régulation : l'intégration traduit les ordres, c'est le
thermostat qui les décide.
## 9. Vérification manuelle
1. Mettre à jour le nœud « Radiateur (Bureau) » depuis l'écran de découverte :
une seule fonctionnalité « fil pilote » apparaît.
2. Depuis le device, envoyer chaque ordre et vérifier le niveau dans
zwave-js-ui : arrêt 0, hors-gel 20, éco 30, confort −2 40, confort −1 50,
confort 99.
3. Appuyer sur le bouton du module : l'ordre affiché dans Gladys suit (60 →
confort).
4. Dans le formulaire du thermostat, choisir cette fonctionnalité comme
actionneur fil pilote, puis choisir Éco dans le widget : le module passe à 30.
## 10. Points ouverts
- **Bornes des plages.** Les écritures (0/20/30/40/50/99) sont mesurées. Les
plages de lecture viennent de la documentation Qubino et restent à vérifier
sur la documentation du ZMNHJD.
- **Numérotation confort −1 / −2.** `PILOT_WIRE_MODE` donne `COMFORT_1 = 3` et
`COMFORT_2 = 4`. Le tableau de la section 4 suit la constante, pas l'ordre des
niveaux (40 = confort −2, 50 = confort −1).
