@Sescandell, ich arbeite gerade an einem PR für den Pilotdraht für die Thermostat-Integration und mein QUBINO-Gerät gibt nur einen Dimmer zurück, und je nach Wert entspricht dies einem Zustand des Pilotdrahts.
Gibt es eine Möglichkeit, Modi statt eines Dimmers in der Integration zu haben? Vielen Dank im Voraus.
Unten eine Analyse von Claude:
# Qubino Flush Pilot (ZMNHJD): Unterstützung für den Heizkörper mit Pilotdraht
> Spezifikation der externen Z-Wave-Integration. Sie basiert auf dem Framework der
> externen Integrationen des Gladys-Monorepos (`docs/specs/external-integrations/`):
> Geräte werden über `POST /discovered_device` veröffentlicht (C.3, SDK
> `publishDiscoveredDevices`), Befehle kommen über
> `external-integration.device.set-value` (C.4), und Zustände werden über
> `POST /state` (B.6) gemeldet.
## 1. Problem
Der Qubino Flush Pilot (ZMNHJD) steuert einen Heizkörper mit Pilotdraht. Dies geschieht über
seinen **Multilevel Switch** (CC 38): Jeder Bereich von Werten entspricht einem
Pilotdraht-Befehl. Heute wird die Integration wie seine Geräteklasse veröffentlicht, d.h. als Dimmer (Position 0–99 %, Zustand ein/aus, „letzten Wert wiederherstellen“).
Folgen:
- Der Benutzer sieht „30 %“, obwohl der Heizkörper im **Eco-Modus** ist;
- Der Thermostat kann ihn nicht steuern. Sein Pilotdraht-Aktor
(`THERMOSTAT_PILOT_WIRE_FEATURE`, Thermostat-Spezifikation C.1.1) akzeptiert nur eine
Funktion `heater` / `pilot-wire-mode`;
- Szenen, Dashboard und HomeKit sehen einen Dimmer, keinen Befehl.
Die Übersetzung von Level → Befehl ist spezifisch für dieses Produkt: Sie gehört daher zur
Integration, die dieses Produkt kennt. Der Thermostat, wie der Rest von Gladys,
sieht nur den Standardtyp.
## 2. Gerät identifizieren
| Feld | Wert |
|---|---|
| `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 » |
**Die Geräteklasse ist nicht verwendbar.** Generic 17 / specific 1
(« Multilevel Switch, Dimmer ») ist die Klasse aller Dimmer. Ihre Verwendung
würde jeden Dimmer in einen Pilotdraht verwandeln. Das Gerät wird daher durch seine
**Produktkennung** (`manufacturerId` + `productType` + `productId`) identifiziert, die
**vor** jeder Regel basierend auf der Geräteklasse überprüft wird.
## 3. Veröffentlichtes Gerät
Der Knoten veröffentlicht **eine einzige** steuerbare Funktion anstelle derjenigen des
Dimmers:
| Feld | Wert |
|---|---|
| `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`: Das Modul sendet `currentValue` nach jeder Änderung, einschließlich eines Drucks auf seine eigenen Tasten |
| `keep_history` | `true` |
| Wertquelle | CC 38 `currentValue`, Endpunkt 0 |
**Nicht veröffentlicht** für dieses Produkt:
- Die Funktionen des Dimmers (`position`, der `status` ein/aus abgeleitet vom
Level, `restorePrevious`). „Letzten Wert wiederherstellen“ würde dem Heizkörper einen
willkürlichen Befehl senden;
- Der explizite Binary Switch (CC 37). Die Integration entfernt ihn bereits von jedem Knoten
der einen Multilevel Switch hat;
- `Up` / `Down` / `duration` / `event` (CC 38), wie heute bei allen Knoten.
Unverändert: Die Konfigurationsparameter (CC 112: Eingabetypen, Modus der Eingaben 11/12/13, Zustand nach Stromausfall 30). Sie bleiben außerhalb des Geltungsbereichs
(Abschnitt 8).
## 4. Befehl schreiben (Gladys → Gerät)
Bei `external-integration.device.set-value` für diese Funktion ist `value` ein `PILOT_WIRE_MODE`. Er wird als Level durch den Befehl `set` des Multilevel Switch (CC 38, Endpunkt 0) geschrieben:
| Befehl (`PILOT_WIRE_MODE`) | Wert | Geschriebenes Level |
|---|---|---|
| `OFF` (aus) | 0 | 0 |
| `FROST_PROTECTION` (Frostschutz) | 1 | 20 |
| `ECO` | 2 | 30 |
| `COMFORT_2` (Komfort −2 °C) | 4 | 40 |
| `COMFORT_1` (Komfort −1 °C) | 3 | 50 |
| `COMFORT` (Komfort) | 5 | 99 |
- Die geschriebenen Levels sind die am Modul gemessenen: 0 / 20 / 30 / 40 / 50 / 99.
- Jeder andere Wert erhält ein **command-result mit Fehler** („unbekannter Pilotdraht-Befehl“), und nichts wird an das Modul gesendet.
- **Kein optimistischer Zustand.** Der Zustand wird gemeldet, wenn das Modul durch
`currentValue` bestätigt (Abschnitt 5), nicht beim Senden des Befehls. Ein Heizkörper, der den Frame verpasst hat, sollte nicht so aussehen, als hätte er gehorcht.
## 5. Befehl lesen (Gerät → Gladys)
Bei jeder Aktualisierung von `currentValue` auf der CC 38 wird das Level **nach Bereich** gelesen, und der Befehl wird über `POST /state` gemeldet:
| Level | Gemeldeter Befehl |
|---|---|
| 0–10 | `OFF` |
| 11–20 | `FROST_PROTECTION` |
| 21–30 | `ECO` |
| 31–40 | `COMFORT_2` |
| 41–50 | `COMFORT_1` |
| 51–99 | `COMFORT` |
| anderes (z. B. 255, ein nicht numerischer Wert) | nichts wird gemeldet |
Das Lesen nach Bereich statt nach exaktem Wert ist unerlässlich: Das Modul kann einen beliebigen Level eines Bereichs zurückgeben. Ein Druck auf seine Taste wurde bei **60** vor 99 beobachtet, und es handelt sich um einen Komfortbefehl.
`targetValue` wird nicht gelesen: `currentValue` ist das, was das Modul tatsächlich anwendet.
## 6. Geräte, die vor dieser Änderung erstellt wurden
Ein bereits in Gladys als Dimmer erstellter Knoten behält seine Dimmer-Funktionen, bis er nicht vom Entdeckungsschirm aus aktualisiert wird. Die Aktualisierung ersetzt sie durch die Pilotdraht-Funktion: gleiche `external_id` des Geräts, neue `external_id` der Funktion.
- Der Verlauf der alten Dimmer-Funktionen wird nicht übernommen. Levels und Befehle sind nicht die gleichen Werte.
- Szenen und Widgets des Dashboards, die auf die alte Dimmer-Funktion zeigten, müssen manuell auf die neue Funktion neu verknüpft werden. Die Gerätemigration (`device-migration.md`) verschiebt die Selektoren von einer Funktion zur anderen, aber ein „30 %“ in einer Szene würde nicht einen Befehl bedeuten.
- Ein Thermostat (virtuell, `THERMOSTAT_PILOT_WIRE_FEATURE`) wird anschließend in seinem Bearbeitungsformular auf die neue Funktion konfiguriert. Nichts anderes auf der Thermostat-Seite: Die Zuordnung von Preset → Befehl ist in der Thermostat-Spezifikation, C.1.1.
## 7. Tests
- **Entdeckung:**
- Ein Knoten mit der `deviceId` `345-81-4` und der Klasse 17-1 veröffentlicht genau eine
Funktion `heater` / `pilot-wire-mode`, ohne Position, Zustand,
`restorePrevious` oder Binary Switch;
- Ein Knoten der Klasse 17-1 mit **einer anderen** Produktkennung wird immer noch als Dimmer veröffentlicht (keine Regression).
- **Schreiben:** Jeder der sechs Befehle erzeugt ein `set` CC 38 mit seinem Level, und ein unbekannter Befehl ergibt ein command-result mit Fehler, ohne etwas zu senden.
- **Lesen:** Die Grenzen der Bereiche (0, 10, 11, 20, 21, 30, 31, 40, 41, 50, 51,
99), das beobachtete 60 → `COMFORT`, und 255 / −1 / ein nicht numerischer Wert melden nichts.
- **Zustandsrückmeldung:** Nach einem Schreibvorgang wird kein Zustand gemeldet, bis
`currentValue` nicht eingetroffen ist.
## 8. Außerhalb des Geltungsbereichs
- Die Konfigurationsparameter CC 112 (Modi der Tasten, Zustand nach Stromausfall).
- Andere Qubino-Referenzen zum Pilotdraht, solange ihre Produktkennung nicht bekannt ist und nicht bestätigt ist, dass sie die gleichen Levels verwenden. Jede wird explizit zur Liste der Produkte hinzugefügt, niemals über die Geräteklasse.
- Jede Regelungslogik: Die Integration übersetzt die Befehle, der Thermostat entscheidet darüber.
## 9. Manuelle Überprüfung
1. Aktualisieren Sie den Knoten „Heizkörper (Büro)“ vom Entdeckungsschirm: Eine einzige Funktion „Pilotdraht“ erscheint.
2. Vom Gerät aus jeden Befehl senden und das Level in zwave-js-ui überprüfen: Aus 0, Frostschutz 20, Eco 30, Komfort −2 40, Komfort −1 50, Komfort 99.
3. Drücken Sie die Taste des Moduls: Der in Gladys angezeigte Befehl folgt (60 → Komfort).
4. Im Thermostat-Formular diese Funktion als Pilotdraht-Aktor auswählen, dann Eco im Widget auswählen: Das Modul geht auf 30.
```## 10. Offene Punkte
- **Strandgrenzen.** Die Beschriftungen (0/20/30/40/50/99) sind gemessen. Die
Lesebereiche stammen aus der Qubino-Dokumentation und müssen noch in der
Dokumentation des ZMNHJD überprüft werden.
- **Komfort-Nummerierung −1 / −2.** `PILOT_WIRE_MODE` gibt `COMFORT_1 = 3` und
`COMFORT_2 = 4` zurück. Die Tabelle im Abschnitt 4 folgt der Konstante, nicht der
Reihenfolge der Stufen (40 = Komfort −2, 50 = Komfort −1).
