- New device kind Ventilation with driver Vallox (WebSocket protocol of the unit's web UI: READ_TABLES/WRITE_DATA, checksum, big-endian table); no migration (enums stored as text) - Read profile incl. remaining minutes, outdoor/supply/extract/exhaust air temperatures, humidity, CO2, fan speed; activate Home/Away/Boost/Fireplace (timed profiles use the duration configured on the unit) - Same SSRF protection as Shelly (shared connection handler), permissions, action log, audit - Admin dialog without generation/channel/credentials for ventilation, device card with values and profile buttons - Tests: unit (protocol vs. reference bytes, driver, loopback WebSocket, SSRF, rules), bUnit - ADR-0025, roadmap phase 19
5.1 KiB
ADR-0025: Haus – Lüftungsanlage Vallox MV (Profil, Temperaturen)
- Status: akzeptiert (Phase 19)
- Datum: 2026-10-16
Kontext
In der Hausverwaltung soll eine Lüftungsanlage angelegt werden können, konkret eine Vallox ValloPlus 350 MV. Ziel: das aktive Profil auslesen, die Temperaturen anzeigen und Profile aktivieren.
Die MV-Geräte haben keine dokumentierte REST-API. Ihre eingebaute Weboberfläche spricht mit dem Gerät über ein binäres WebSocket-Protokoll (ws://<gerät>/), das die Bibliothek
vallox_websocket_api (Grundlage der Home-Assistant-Integration „Vallox“) nachbildet. Modbus/RS-485 bräuchte zusätzliche Hardware.
Entscheidung
1. Eingliederung in das Geräte-Modell (ADR-0023)
- Neue Geräteart
HomeDeviceKind.Ventilation(„Lüftungsanlage“) und neuer TreiberHomeDriverType.ValloxhinterIHomeDeviceDriver. Damit gelten Räume, Pläne/Pins, Freigaben (ansehen/schalten), Aktionsprotokoll, Audit und SSRF-Schutz unverändert. Die Enums werden als Text gespeichert – keine Migration nötig. - Treiber und Art gehören zusammen (
HomeRules.IsValidDriverForKind): Vallox nur für Lüftungsanlagen, Shelly für alle anderen. Vallox nutzt immer „Generation“ 1, Kanal 0 und keine Anmeldung (die Weboberfläche hat keine); beim Speichern werden Benutzer/Passwort eines Vallox-Geräts verworfen. - Neue Befehle
ProfileHome,ProfileAway,ProfileBoost,ProfileFireplace(nur fürVentilationerlaubt). Ein Profilwechsel braucht wie Schalten die Stufe „Schalten“; „nur ansehen“ zeigt Werte und Profil. - Der Zustand bekommt optional
HomeVentilationDto(Profil, Restminuten, Außen-/Zu-/Ab-/Fortlufttemperatur, Lüfterstufe %, CO₂); Luftfeuchte steht im vorhandenen FeldHumidityPercent,TemperatureCist die Ablufttemperatur (Raumluft).
2. Protokoll (ValloxProtocol)
- Anfrage: 16-Bit-Wörter little-endian – Länge (Wörter nach dem Längenfeld, inkl. Prüfsumme), Befehl, Nutzdaten, Prüfsumme = Summe der Wörter davor mod 2¹⁶.
- Lesen:
READ_TABLES(246) →03 00 F6 00 00 00 F9 00; Antwort ist die komplette Datentabelle als 16-Bit-Wörter big-endian. Die genutzten Werte liegen in den ersten Adressbereichen (g_cyclone_general_info,g_cyclone_hw_state,g_cyclone_sw_state,g_cyclone_settings), die bei den Firmware-Ständen 2.0.16 und 2.0.22 identisch angeordnet sind; die Positionen sind daher fest hinterlegt (statt die Konstanten zur Laufzeit ausjs/bundle.jsdes Geräts zu lesen). Zu kurze/ungerade Antworten gelten als „kein Vallox“. - Temperaturen: Kelvin × 100 → °C (eine Nachkommastelle); 0/
FFFFoder unplausible Werte = Fühler fehlt. - Profil wie die Weboberfläche: Stoßlüften-, Kamin-, Extra-Timer > 0 (in dieser Reihenfolge) haben Vorrang, sonst
A_CYC_STATE0 = Zuhause, 1 = Abwesend, 2 = Automatik. TimerFFFF= ohne Zeitbegrenzung. - Schreiben:
WRITE_DATA(249) mit Adresse/Wert-Paaren, nach Adresse sortiert – exakt wieset_profileder Bibliothek: Zuhause/Abwesend setzenA_CYC_STATEund beenden alle Timer; Stoßlüften/Kamin setzen ihren Timer auf die am Gerät eingestellte Dauer (A_CYC_BOOST_TIME/A_CYC_FIREPLACE_TIME, dafür wird vorher gelesen; ohne Wert 30 bzw. 15 min) und beenden die anderen Timer. - Keine Wiederholungen (ein Profilbefehl soll nie doppelt laufen), eine WebSocket-Verbindung je Anfrage, Zeitlimit 4 s, Antwort ≤ 64 KB.
3. Netzwerk und SSRF
Die WebSocket-Verbindung nutzt denselben SocketsHttpHandler wie Shelly (HomeHttp.CreateHandler, als eigener HttpMessageInvoker – ein HttpClient würde die 101-Antwort puffern wollen): jede aufgelöste IP wird beim
Verbinden geprüft (nur Heimnetz, DNS-Rebinding), kein Proxy, keine Weiterleitungen. Fehler werden auf feste deutsche Meldungen abgebildet, nie Geräteinhalte.
4. Oberfläche
- Hausverwaltung → Gerät anlegen, Art „Lüftungsanlage“: nur Name, Symbol, Raum und Adresse; Hinweis auf Vallox MV/WebSocket; „Verbindung testen“ zeigt das Modell (z. B. „ValloPlus 350 MV“).
- Gerätekarte: Status „Profil: Stoßlüften · noch 25 min“, Messwerte als Liste (Außenluft, Zuluft, Abluft, Fortluft, Luftfeuchte, CO₂, Lüfter), Profil-Knöpfe Zuhause/Abwesend/Stoßlüften/Kamin
(
aria-pressedam aktiven Profil, gesperrt bei „nur ansehen“ oder offline). Aktualisierung wie alle Geräte alle 10 s.
Konsequenzen
- Ein neues Firmware-Layout könnte die festen Positionen verschieben; dann zeigt der Verbindungstest unplausible Werte bzw. „kein Vallox“, und die Positionen müssen ergänzt werden
(Alternative: Konstanten aus
js/bundle.jsdes Geräts lesen – bewusst nicht umgesetzt, solange beide bekannten Stände gleich sind). - Bewusst nicht umgesetzt: Profil „Extra“/„Automatik“ wählen, Dauer je Aufruf, Solltemperaturen und Lüfterstufen je Profil ändern, Filter-/Alarmanzeige, Verlauf (
LOG_RAW). Alles ließe sich über dieselben Befehle ergänzen. - Praxistest mit der echten Anlage steht aus; getestet ist gegen die Referenzwerte der Bibliothek, einen Fake-Transport und einen lokalen WebSocket-Server.