Files
Rbm.FamStack/docs/adr/0025-haus-lueftung-vallox.md
T
openclaw 70f1890641 feat: Phase 19 Haus - Vallox MV ventilation unit (profile, temperatures, profile switching)
- 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
2026-10-16 20:04:14 +02:00

5.1 KiB
Raw Blame History

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 Treiber HomeDriverType.Vallox hinter IHomeDeviceDriver. 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ür Ventilation erlaubt). 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 Feld HumidityPercent, TemperatureC ist 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 aus js/bundle.js des Geräts zu lesen). Zu kurze/ungerade Antworten gelten als „kein Vallox“.
  • Temperaturen: Kelvin × 100 → °C (eine Nachkommastelle); 0/FFFF oder 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_STATE 0 = Zuhause, 1 = Abwesend, 2 = Automatik. Timer FFFF = ohne Zeitbegrenzung.
  • Schreiben: WRITE_DATA (249) mit Adresse/Wert-Paaren, nach Adresse sortiert – exakt wie set_profile der Bibliothek: Zuhause/Abwesend setzen A_CYC_STATE und 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-pressed am 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.js des 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.