Zum Inhalt springen
Alles Automatisch

Home AssistantSnippets

KWL-Anlage per Modbus in Home Assistant einbinden

Meine Lüftungsanlage hängt im Netzwerk. Das wusste ich ein ganzes Jahr lang nicht. Erst ein Servicetechniker hat mich bei der Wartung darauf hingewiesen. Die Hersteller-App hat leider nur Fehlermeldungen ausgespuckt, also habe ich mir den Laptop meiner Frau geschnappt, ihn per USB an den Service-Port der Anlage angeschlossen und in der Installateur-Software nachgeschaut. Siehe da: eine statische IP-Adresse, die gar nicht in meinem Netzwerkbereich lag. Das korrigiert, 10 Minuten später lief alles.

Dann wollte ich natürlich mehr. Die Lüftung rauscht nachts manchmal ein bisschen laut, und das wollte ich automatisieren. Über die Hersteller-App geht das leider nicht. Also habe ich mich mit Modbus beschäftigt, um die komplette Steuerung in Home Assistant zu bekommen. Das hat mich ein paar graue Haare gekostet, weil es im Internet kaum vernünftige Anleitungen dazu gab. Damit du dir die sparen kannst, findest du hier alles Schritt für Schritt.

Was ist Modbus?

Modbus ist eine Kommunikationsschnittstelle, mit der Geräte untereinander Daten austauschen. Du kannst damit Werte auslesen (aktuelle Lüftungsstufe, Temperaturen, CO2-Gehalt) und Werte schreiben (Betriebsmodus umschalten, Lüftungsstufe ändern). Das läuft über TCP/IP, also ganz normal übers Netzwerk. Home Assistant hat eine native Modbus-Integration, du brauchst keine externe Erweiterung.

Die Anleitung hier zeigt das am Beispiel einer Maico WS 300 Flat A. Andere Anlagen funktionieren genauso, du brauchst nur die passende Modbus-Registertabelle von deinem Hersteller.

Was du dafür brauchst

Bevor du loslegst, ein paar Voraussetzungen:

1. Die IP-Adresse deiner Lüftungsanlage. Die Anlage muss im lokalen Netzwerk erreichbar sein. Teste das am einfachsten mit einem Ping: Öffne ein Terminal (oder die Eingabeaufforderung unter Windows) und tippe ping 10.10.146.32 (deine IP natürlich einsetzen). Wenn du eine Antwort bekommst, ist die Anlage erreichbar. Falls nicht: Prüfe, ob eine statische IP vergeben ist, die nicht in deinem Netzwerkbereich liegt. Bei mir war genau das das Problem.

2. Die Modbus-Registertabelle deines Herstellers. Das ist ein Dokument (oft ein PDF), in dem der Hersteller alle Modbus-Adressen auflistet. So eine Tabelle hat typischerweise diese Spalten:

  • Adresse/ID (z.B. 650) - die eindeutige Nummer, unter der ein Wert gespeichert ist
  • Beschreibung (z.B. "Aktuelle Lüftungsstufe") - was der Wert bedeutet
  • Berechtigung (Lesen/Schreiben) - ob du den Wert nur auslesen oder auch ändern darfst
  • Datentyp (z.B. uint16) - wie der Wert gespeichert ist
  • Wertebereich (z.B. 0-5) - welche Werte möglich sind, oft mit einer Legende (0 = Aus, 1 = Manuell, 2 = Auto-Zeit, ...)

Wichtig: Bei manchen Anlagen gibt es getrennte Adressen zum Lesen und zum Schreiben. Bei der Maico WS 300 ist z.B. Adresse 650 das Leseregister für die aktuelle Lüftungsstufe, aber Adresse 554 das Schreibregister, um die Lüftungsstufe zu ändern. Das steht in der Berechtigungs-Spalte der Tabelle.

3. Home Assistant mit Zugriff auf die Konfigurationsdateien (File Editor, Studio Code Server oder direkt per SSH).

Schritt 1: Modbus-Sensoren konfigurieren

Die Modbus-Konfiguration wird etwas länger. Ich empfehle dir, dafür eine eigene Datei im packages-Verzeichnis anzulegen, z.B. modbus.yaml. So bleibt deine configuration.yaml übersichtlich.

Falls du das packages-System noch nicht nutzt: Füge in deine configuration.yaml diese Zeile ein:

yaml
homeassistant:
  packages: !include_dir_named packages

Erstelle dann einen Ordner packages im selben Verzeichnis wie deine configuration.yaml. Alle YAML-Dateien, die du dort reinlegst, werden automatisch geladen.

Alternativ kannst du den gesamten Code auch direkt in deine configuration.yaml packen. Dann wird die Datei halt ein bisschen lang.

Hier ist die komplette Sensorkonfiguration für die KWL-Anlage. Lege diese Datei als packages/modbus.yaml an:

yaml
1modbus:
2  - name: ws300
3    type: tcp
4    host: 10.10.146.32  # Hier DEINE IP-Adresse eintragen
5    port: 502            # Standard-Port für Modbus TCP
6    sensors:
7      # Temperaturen (Adressen aus der Maico Registertabelle)
8      - name: "kwl_t_aul"          # Außenluft-Temperatur
9        unit_of_measurement: °C
10        slave: 1
11        address: 703
12        input_type: holding
13        data_type: int16
14        precision: 1
15        scale: 0.1
16
17      - name: "kwl_t_zu"           # Zuluft-Temperatur
18        unit_of_measurement: °C
19        slave: 1
20        address: 704
21        input_type: holding
22        data_type: int16
23        precision: 1
24        scale: 0.1
25
26      - name: "kwl_t_ab"           # Abluft-Temperatur
27        unit_of_measurement: °C
28        slave: 1
29        address: 705
30        input_type: holding
31        data_type: int16
32        precision: 1
33        scale: 0.1
34
35      - name: "kwl_t_fol"          # Fortluft-Temperatur
36        unit_of_measurement: °C
37        slave: 1
38        address: 706
39        input_type: holding
40        data_type: int16
41        precision: 1
42        scale: 0.1
43
44      # Betriebsdaten
45      - name: "kwl_betriebsart"    # 0=Aus, 1=Manuell, 2=Auto-Zeit, 3=Auto-Sensor
46        slave: 1
47        address: 550
48        input_type: holding
49        data_type: uint16
50
51      - name: "kwl_lueftungsstufe"  # 0=Aus, 1=Feuchteschutz, 2=Reduziert, 3=Nennlüftung, 4=Intensiv
52        slave: 1
53        address: 650
54        input_type: holding
55        data_type: uint16
56
57      # Drehzahlen und Volumenstrom
58      - name: "kwl_drehzahl_zu"
59        unit_of_measurement: "U/min"
60        slave: 1
61        address: 651
62        input_type: holding
63        data_type: uint16
64
65      - name: "kwl_drehzahl_ab"
66        unit_of_measurement: "U/min"
67        slave: 1
68        address: 652
69        input_type: holding
70        data_type: uint16
71
72      - name: "kwl_volumenstrom_zu"
73        unit_of_measurement: "m³/h"
74        slave: 1
75        address: 653
76        input_type: holding
77        data_type: uint16
78
79      - name: "kwl_volumenstrom_ab"
80        unit_of_measurement: "m³/h"
81        slave: 1
82        address: 654
83        input_type: holding
84        data_type: uint16
85
86      # Filterrestlaufzeiten (in Tagen)
87      - name: "kwl_restlaufzeit_filter_zu"
88        unit_of_measurement: "d"
89        slave: 1
90        address: 655
91        input_type: holding
92        data_type: uint16
93
94      - name: "kwl_restlaufzeit_filter_aul"
95        unit_of_measurement: "d"
96        slave: 1
97        address: 656
98        input_type: holding
99        data_type: uint16
100
101      - name: "kwl_restlaufzeit_filter_ab"
102        unit_of_measurement: "d"
103        slave: 1
104        address: 657
105        input_type: holding
106        data_type: uint16
107
108      # Luftqualität
109      - name: "kwl_rF_ab"          # Relative Feuchte Abluft
110        unit_of_measurement: "%"
111        slave: 1
112        address: 750
113        input_type: holding
114        data_type: uint16
115
116      - name: "kwl_CO2"            # CO2-Gehalt
117        unit_of_measurement: "ppm"
118        slave: 1
119        address: 755
120        input_type: holding
121        data_type: uint16
122
123      # Schaltzustände
124      - name: "kwl_schalt_zu"      # Zuluftventilator
125        slave: 1
126        address: 800
127        input_type: holding
128        data_type: uint16
129
130      - name: "kwl_schalt_ab"      # Abluftventilator
131        slave: 1
132        address: 801
133        input_type: holding
134        data_type: uint16
135
136      - name: "kwl_schalt_bypass"  # Bypass-Klappe
137        slave: 1
138        address: 802
139        input_type: holding
140        data_type: uint16

Die IP-Adresse bei host musst du auf deine Anlage anpassen. Den Port 502 kannst du in der Regel so lassen, das ist der Standard für Modbus TCP.

Woher kommen die Adressen? Aus der Modbus-Registertabelle von Maico. Adresse 703 ist dort als "Außenlufttemperatur" beschrieben, 704 als "Zulufttemperatur" und so weiter. Wenn du eine andere Anlage hast, schlag die passenden Adressen in deiner Registertabelle nach.

Schritt 2: Template-Sensoren für lesbare Werte

Die Modbus-Sensoren liefern dir erstmal nur Zahlen. Eine 3 bei der Betriebsart sagt dir ohne Tabelle gar nichts. Also brauchen wir Template-Sensoren, die diese Zahlen in lesbare Texte übersetzen.

Füge diesen Code in eine eigene Datei packages/sensors.yaml ein (oder ergänze eine bestehende):

yaml
1template:
2  - sensor:
3      - name: "KWL Betriebsmodus"
4        state: >
5          {% set mode = states('sensor.kwl_betriebsart') | int(0) %}
6          {% if mode == 0 %}Aus
7          {% elif mode == 1 %}Manuell
8          {% elif mode == 2 %}Auto-Zeit
9          {% elif mode == 3 %}Auto-Sensor
10          {% elif mode == 4 %}ECO Zuluft
11          {% elif mode == 5 %}ECO Abluft
12          {% else %}Unbekannt{% endif %}
13
14      - name: "KWL Lüftungsstufe"
15        state: >
16          {% set stufe = states('sensor.kwl_lueftungsstufe') | int(0) %}
17          {% if stufe == 0 %}Aus
18          {% elif stufe == 1 %}Feuchteschutz
19          {% elif stufe == 2 %}Reduziert
20          {% elif stufe == 3 %}Nennlüftung
21          {% elif stufe == 4 %}Intensiv
22          {% else %}Unbekannt{% endif %}
23
24      - name: "KWL Bypass"
25        state: >
26          {% set bypass = states('sensor.kwl_schalt_bypass') | int(0) %}
27          {% if bypass == 0 %}Zu
28          {% elif bypass == 1 %}Auf
29          {% else %}Unbekannt{% endif %}
30
31      - name: "KWL Wärmerückgewinnung"
32        unit_of_measurement: "%"
33        state: >
34          {% set t_ab = states('sensor.kwl_t_ab') %}
35          {% set t_aul = states('sensor.kwl_t_aul') %}
36          {% set t_zu = states('sensor.kwl_t_zu') %}
37          {% if t_ab in ['unavailable','unknown']
38             or t_aul in ['unavailable','unknown']
39             or t_zu in ['unavailable','unknown'] %}
40            0
41          {% else %}
42            {% set ab = t_ab | float(0) %}
43            {% set aul = t_aul | float(0) %}
44            {% set zu = t_zu | float(0) %}
45            {% if (ab - aul) != 0 %}
46              {{ (((zu - aul) / (ab - aul)) * 100) | round(0) }}
47            {% else %}
48              0
49            {% endif %}
50          {% endif %}

Woher kommen die Werte für das Mapping? Wieder aus der Registertabelle. Bei Maico steht dort z.B. bei der Betriebsart: 0 = Aus, 1 = Manuell, 2 = Auto-Zeit, 3 = Auto-Sensor, 4 = ECO Zuluft, 5 = ECO Abluft. Diese Zuordnung habe ich einfach in die Template-Sensoren übernommen.

Die Wärmerückgewinnung berechnet sich aus den drei Temperaturen: (Zuluft - Außenluft) / (Abluft - Außenluft) * 100. Wenn die Anlage aus ist oder ein Sensor nicht verfügbar, gibt der Sensor einfach 0 zurück.

Schritt 3: Konfiguration prüfen und neu starten

Bevor du Home Assistant neu startest, prüfe erst, ob deine Konfiguration fehlerfrei ist. Das geht so:

  1. Öffne Home Assistant und gehe zu Einstellungen > System > Allgemein
  2. Klicke oben rechts auf die drei Punkte und wähle Konfiguration prüfen
  3. Warte, bis die Prüfung abgeschlossen ist

Wenn dort ein Fehler auftaucht, stimmt etwas in deiner YAML-Datei nicht. Meistens ist es ein Einrückungs-Fehler. YAML ist da wahnsinnig empfindlich.

Wenn die Prüfung erfolgreich war, klicke auf Neu starten. Ein schnelles Neuladen reicht hier leider nicht, weil die Modbus-Integration einen vollständigen Neustart braucht.

Schritt 4: Prüfen, ob die Sensoren da sind

Nach dem Neustart kontrollierst du, ob alles funktioniert hat:

  1. Gehe zu Werkzeuge > Zustände (bis 2026.7 Entwicklerwerkzeuge)
  2. Tippe oben ins Suchfeld kwl ein
  3. Du solltest jetzt alle Sensoren sehen, die du angelegt hast

Die Modbus-Sensoren (z.B. sensor.kwl_betriebsart) zeigen dir die rohen Zahlenwerte. Die Template-Sensoren (z.B. sensor.kwl_betriebsmodus) zeigen dir den übersetzten Text wie "Auto-Sensor" oder "Intensiv".

Wenn keine Sensoren auftauchen: Prüfe, ob die IP-Adresse stimmt und ob deine Anlage im Netzwerk erreichbar ist (Ping-Test, siehe oben). Schau auch ins Home Assistant Log unter Einstellungen > System > Protokolle, dort findest du Fehlermeldungen zur Modbus-Verbindung.

Schritt 5: Dashboard aufbauen

Jetzt wird es sichtbar. Gehe auf dein Dashboard, klicke auf die drei Punkte oben rechts, dann auf Dashboard bearbeiten und Karte hinzufügen.

Zuerst eine Entities-Karte, die dir alle wichtigen Werte auf einen Blick zeigt:

yaml
1type: entities
2title: Wohnraumlüftung
3entities:
4  - entity: sensor.kwl_t_aul
5    name: Außenluft
6    icon: mdi:thermometer
7  - entity: sensor.kwl_t_zu
8    name: Zuluft
9    icon: mdi:thermometer
10  - entity: sensor.kwl_t_ab
11    name: Abluft
12    icon: mdi:thermometer
13  - entity: sensor.kwl_t_fol
14    name: Fortluft
15    icon: mdi:thermometer
16  - type: divider
17  - entity: sensor.kwl_volumenstrom_zu
18    name: Volumenstrom Zuluft
19    icon: mdi:fan
20  - entity: sensor.kwl_volumenstrom_ab
21    name: Volumenstrom Abluft
22    icon: mdi:fan
23  - entity: sensor.kwl_drehzahl_zu
24    name: Drehzahl Zuluft
25  - entity: sensor.kwl_drehzahl_ab
26    name: Drehzahl Abluft
27  - type: divider
28  - entity: sensor.kwl_co2
29    name: CO2
30    icon: mdi:molecule-co2
31  - entity: sensor.kwl_rf_ab
32    name: Relative Feuchte Abluft
33    icon: mdi:water-percent
34  - type: divider
35  - entity: sensor.kwl_betriebsmodus
36    name: Betriebsmodus
37    icon: mdi:cog
38  - entity: sensor.kwl_lueftungsstufe_2
39    name: Lüftungsstufe
40    icon: mdi:fan
41  - entity: sensor.kwl_bypass
42    name: Bypass
43    icon: mdi:valve
44  - entity: sensor.kwl_warmeruckgewinnung
45    name: Wärmerückgewinnung
46    icon: mdi:heat-wave
47  - type: divider
48  - entity: sensor.kwl_restlaufzeit_filter_zu
49    name: Filter Zuluft (Tage)
50    icon: mdi:air-filter
51  - entity: sensor.kwl_restlaufzeit_filter_aul
52    name: Filter Außenluft (Tage)
53    icon: mdi:air-filter
54  - entity: sensor.kwl_restlaufzeit_filter_ab
55    name: Filter Abluft (Tage)
56    icon: mdi:air-filter

Um diese Karte anzulegen: Klicke auf Karte hinzufügen, suche nach Manuell, klicke drauf und füge den YAML-Code per Copy & Paste ein.

Direkt darunter kommen die Steuerungs-Buttons. Die nutzen modbus.write_register, um Werte direkt an die Anlage zu schicken:

yaml
1type: horizontal-stack
2cards:
3  - type: button
4    name: Aus
5    icon: mdi:fan-off
6    show_name: true
7    show_icon: true
8    tap_action:
9      action: perform-action
10      perform_action: modbus.write_register
11      data:
12        address: 550
13        unit: 1
14        value:
15          - 0
16        hub: ws300
17
18  - type: button
19    name: Manuell
20    icon: mdi:fan
21    show_name: true
22    show_icon: true
23    tap_action:
24      action: perform-action
25      perform_action: modbus.write_register
26      data:
27        address: 550
28        unit: 1
29        value:
30          - 1
31        hub: ws300
32
33  - type: button
34    name: Auto-Sensor
35    icon: mdi:fan-auto
36    show_name: true
37    show_icon: true
38    tap_action:
39      action: perform-action
40      perform_action: modbus.write_register
41      data:
42        address: 550
43        unit: 1
44        value:
45          - 3
46        hub: ws300

Und eine zweite Reihe für die Lüftungsstufen. Hier wird an eine andere Adresse geschrieben, weil Betriebsmodus (Adresse 550) und Lüftungsstufe (Adresse 554) bei der Maico getrennte Schreibregister sind:

yaml
1type: horizontal-stack
2cards:
3  - type: button
4    name: Feuchteschutz
5    icon: mdi:fan-speed-1
6    show_name: true
7    show_icon: true
8    tap_action:
9      action: perform-action
10      perform_action: modbus.write_register
11      data:
12        address: 554
13        unit: 1
14        value:
15          - 1
16        hub: ws300
17
18  - type: button
19    name: Nennlüftung
20    icon: mdi:fan-speed-2
21    show_name: true
22    show_icon: true
23    tap_action:
24      action: perform-action
25      perform_action: modbus.write_register
26      data:
27        address: 554
28        unit: 1
29        value:
30          - 3
31        hub: ws300
32
33  - type: button
34    name: Intensiv
35    icon: mdi:fan-speed-3
36    show_name: true
37    show_icon: true
38    tap_action:
39      action: perform-action
40      perform_action: modbus.write_register
41      data:
42        address: 554
43        unit: 1
44        value:
45          - 4
46        hub: ws300

Den hub-Wert (ws300) musst du auf den Namen anpassen, den du oben in der Modbus-Konfiguration vergeben hast.

Nach einem Button-Klick dauert es ein paar Sekunden, bis sich die Werte im Dashboard aktualisieren. Das ist normal, die Modbus-Register werden nicht in Echtzeit abgefragt.

Schritt 6: Automatisierungen bauen

Wenn die Grundlagen stehen, kannst du anfangen, Automatisierungen zu bauen. Zwei Beispiele, die bei mir im Alltag laufen:

Leise lüften nachts: Um 22:30 Uhr schaltet die Anlage in den manuellen Modus und auf Feuchteschutz (die leiseste Stufe). Um 6:00 Uhr morgens geht sie zurück auf Auto-Sensor.

yaml
1alias: "Lüftung: Leise lüften"
2mode: single
3triggers:
4  - at: "22:30:00"
5    id: Nachtmodus
6    platform: time
7  - at: "06:00:00"
8    id: Auto-Modus
9    platform: time
10actions:
11  - choose:
12      - conditions:
13          - condition: trigger
14            id:
15              - Nachtmodus
16        sequence:
17          # Erst auf Manuell schalten (Betriebsmodus)
18          - action: modbus.write_register
19            data:
20              address: 550
21              unit: 1
22              value:
23                - 1
24              hub: ws300
25          # Dann Feuchteschutz-Stufe setzen (Lüftungsstufe)
26          - action: modbus.write_register
27            data:
28              address: 554
29              unit: 1
30              value:
31                - 1
32              hub: ws300
33      - conditions:
34          - condition: trigger
35            id:
36              - Auto-Modus
37        sequence:
38          # Morgens zurück auf Auto-Sensor
39          - action: modbus.write_register
40            data:
41              address: 550
42              unit: 1
43              value:
44                - 3
45              hub: ws300

Du siehst hier, dass für die Nacht zwei Befehle nötig sind: Erst den Betriebsmodus auf Manuell (Adresse 550, Wert 1), dann die Stufe auf Feuchteschutz (Adresse 554, Wert 1). Morgens reicht ein einziger Befehl, weil Auto-Sensor sich die Stufe selbst regelt.

Stoßlüften nach dem Duschen: Wenn die Luftfeuchtigkeit im Bad über 60% steigt, schaltet die Anlage für 15 Minuten auf Intensiv. Danach geht sie je nach Tageszeit in den passenden Modus zurück.

yaml
1alias: "Lüftung: Stoßlüften nach Duschen"
2mode: single
3triggers:
4  - type: humidity
5    entity_id: sensor.DEIN_FEUCHTIGKEITSSENSOR  # z.B. sensor.bad_humidity
6    above: 60
7    for:
8      minutes: 2
9    platform: device
10actions:
11  # Intensivlüftung starten
12  - action: modbus.write_register
13    data:
14      address: 554
15      unit: 1
16      value:
17        - 4
18      hub: ws300
19  # 15 Minuten warten
20  - delay:
21      minutes: 15
22  # Danach: je nach Tageszeit den richtigen Modus wiederherstellen
23  - choose:
24      # Nachts (22:00-06:00): zurück in den leisen Feuchteschutz
25      - conditions:
26          - condition: time
27            after: "22:00:00"
28            before: "06:00:00"
29        sequence:
30          - action: modbus.write_register
31            data:
32              address: 550
33              unit: 1
34              value:
35                - 1
36              hub: ws300
37          - action: modbus.write_register
38            data:
39              address: 554
40              unit: 1
41              value:
42                - 1
43              hub: ws300
44      # Tagsüber: zurück auf Auto-Sensor
45      - conditions:
46          - condition: time
47            after: "06:00:00"
48            before: "22:00:00"
49        sequence:
50          - action: modbus.write_register
51            data:
52              address: 550
53              unit: 1
54              value:
55                - 3
56              hub: ws300

Den Platzhalter sensor.DEIN_FEUCHTIGKEITSSENSOR musst du durch die Entity-ID deines Feuchtigkeitssensors ersetzen. Die findest du wieder unter Werkzeuge > Zustände.

Was du noch wissen solltest

Lese- vs. Schreibregister: Bei der Maico sind die Adressen zum Lesen und Schreiben teilweise unterschiedlich. Die aktuelle Lüftungsstufe liest du über Adresse 650, aber zum Ändern schreibst du an Adresse 554. Das steht in der Berechtigungs-Spalte der Registertabelle. Wenn du eine andere Anlage hast, prüfe dort, welche Adressen Schreibrechte haben.

Eigene Buttons bauen: Du kannst dir beliebige weitere Buttons zusammenbauen. Schau in deine Registertabelle, welche Werte du wohin schreiben darfst. Zum Beispiel könntest du mit einem Button die Stoßlüftung starten oder den ECO-Modus aktivieren.

Weitere Sensoren auslesen: In der Registertabelle findest du noch viel mehr Werte, die du auslesen könntest, z.B. Betriebsstunden der Lüftung, Relais-Status der Nachheizung oder den Wärmetauscher-Status. Ergänze dafür einfach weitere Sensoren in deiner modbus.yaml nach dem gleichen Muster.

Hast du deine Lüftungsanlage auch in Home Assistant eingebunden, oder planst du das noch? Schreib gerne in die Kommentare, welche Anlage du nutzt und ob du irgendwo hängen geblieben bist.

Diskussion im Forum

Hast du Fragen oder Ideen zu diesem Thema?

Diskutiere im Forum

Video teilen

Community

Unterstütze den Kanal

Hat dir der Beitrag geholfen? Es gibt zwei Wege, etwas zurückzugeben.