Skip to content

Instantly share code, notes, and snippets.

@JavanXD
Last active December 4, 2025 22:38
Show Gist options
  • Select an option

  • Save JavanXD/a3e8911e69f3a27a81eeeb80414bb6ab to your computer and use it in GitHub Desktop.

Select an option

Save JavanXD/a3e8911e69f3a27a81eeeb80414bb6ab to your computer and use it in GitHub Desktop.
SchwörerHaus WGT BIC VentCube Fresh Home Assistant Integration via modbus
# Helpful information:
# https://github.com/Excodibur/ioBroker.schwoerer-ventcube/blob/master/src/lib/schwoerer/parameters.ts
# https://github.com/fgoettel/wgt/blob/main/wgt/lueftungsanlage.py
# https://knx-user-forum.de/forum/öffentlicher-bereich/knx-eib-forum/diy-do-it-yourself/1822296-modbus-schwörer-heizung?p=1906252#post1906252
##################
# MODBUS SENSORS #
##################
modbus:
- name: BIC_VentCube
delay: 2
timeout: 3
type: tcp
host: !secret wgt_ip
port: 502
sensors:
- name: VentCube Betriebsart
slave: 1
unique_id: ventcube_betriebsart
address: 100
# Translated with template sensor
# Translated with input_select Automation
- name: VentCube Manuelle Luftstufe
slave: 1
unique_id: ventcube_manuelle_luftstufe
address: 101
# Translated with input_select Automation
- name: VentCube Aktuelle Luftstufe
slave: 1
unique_id: ventcube_aktuelle_luftstufe
address: 102
- name: VentCube Status Stoßlüftung
slave: 1
unique_id: ventcube_status_stosslueftung
address: 111
# Translated with template sensor
- name: VentCube Restlaufzeit Stoßlüftung
slave: 1
unique_id: ventcube_restlaufzeit_stosslueftung
address: 112
unit_of_measurement: min
device_class: duration
min_value: 0
max_value: 60
- name: VentCube Status Wärmepumpe
slave: 1
unique_id: ventcube_status_waermepumpe
address: 114
# Translated with template sensor
- name: VentCube Status Nachheizregister
slave: 1
unique_id: ventcube_status_nachheizregister
address: 116
# Translated with template sensor
- name: VentCube Status Gebläse Zuluft
slave: 1
unique_id: ventcube_status_geblaese_zuluft
address: 117
# Translated with template sensor
- name: VentCube Status Gebläse Abluft
slave: 1
unique_id: ventcube_status_geblaese_abluft
address: 118
# Translated with template sensor
- name: VentCube Bypass Zustand
slave: 1
unique_id: ventcube_bypass_zustand
address: 123
# Translated with template sensor
- name: VentCube Zustand Außenklappe
slave: 1
unique_id: ventcube_zustand_aussenklappe
address: 131
# Translated with template sensor
- name: VentCube Status Vorheizregister
slave: 1
unique_id: ventcube_status_vorheizregister
address: 133
# Translated with template sensor
- name: VentCube aktuelle Luftleistung Zuluft
slave: 1
unique_id: ventcube_aktuelle_luftleistung_zuluft
address: 142
state_class: measurement
unit_of_measurement: "%"
min_value: 0
max_value: 100
scale: 1
precision: 0
- name: VentCube aktuelle Luftleistung Abluft
unique_id: ventcube_aktuelle_luftleistung_abluft
slave: 1
address: 143
state_class: measurement
unit_of_measurement: "%"
min_value: 0
max_value: 100
scale: 1
precision: 0
- name: VentCube aktuelle Drehzahl Zuluft
unique_id: ventcube_aktuelle_drehzahl_zuluft
slave: 1
address: 144
state_class: measurement
unit_of_measurement: "rpm"
min_value: 0
max_value: 10000
precision: 0
- name: VentCube aktuelle Drehzahl Abluft
unique_id: ventcube_aktuelle_drehzahl_abluft
slave: 1
address: 145
state_class: measurement
unit_of_measurement: "rpm"
min_value: 0
max_value: 10000
precision: 0
- name: VentCube T2 Temperatur nach Vorheizregister
slave: 1
unique_id: ventcube_t2_temperatur_nach_vorheizregister
unit_of_measurement: °C
device_class: temperature
address: 201
scale: 0.1
precision: 1
- name: VentCube T3 Temperatur vor Nacherwärmung
slave: 1
unique_id: ventcube_t3_temperatur_vor_nacherwaermung
unit_of_measurement: °C
device_class: temperature
address: 202
scale: 0.1
precision: 1
- name: VentCube T4 Temperatur nach Nacherwärmung
slave: 1
unique_id: ventcube_t4_temperatur_nach_nacherwaermung
unit_of_measurement: °C
device_class: temperature
address: 203
scale: 0.1
precision: 1
- name: VentCube T5 Temperatur Abluft
slave: 1
unique_id: ventcube_t5_temperatur_abluft
unit_of_measurement: °C
device_class: temperature
address: 204
scale: 0.1
precision: 1
- name: VentCube T6 Temperatur im Wärmetauscher
slave: 1
unique_id: ventcube_t6_temperatur_im_waermetauscher
unit_of_measurement: °C
device_class: temperature
address: 205
scale: 0.1
precision: 1
- name: VentCube T10 Temperatur Außen
slave: 1
unique_id: ventcube_t10_temperatur_aussen
unit_of_measurement: °C
device_class: temperature
address: 209
scale: 0.1
precision: 1
- name: VentCube Heiz- Kühlfunktion
slave: 1
unique_id: ventcube_heiz_kuehlfunktion
address: 230
# Translated with template sensor
# Translated with input_select Automation
- name: VentCube Wärmepumpe Heizen
slave: 1
unique_id: ventcube_wp_heizen
address: 231
- name: VentCube Wärmepumpe Kühlen
slave: 1
unique_id: ventcube_wp_kuehlen
address: 232
- name: VentCube Druckwächter aktiv
slave: 1
unique_id: ventcube_druckwachter_aktiv
address: 242
# Translated with template sensor (binary_sensor)
- name: VentCube EVU Sperre aktiv
slave: 1
unique_id: ventcube_evu_sperre_aktiv
address: 243
# Translated with template sensor (binary_sensor)
- name: VentCube Wartungstür offen
slave: 1
unique_id: ventcube_wartungstur_offen
address: 244
# Translated with template sensor (binary_sensor)
- name: VentCube Gerätefilter verschmutzt
slave: 1
unique_id: ventcube_geratefilter_verschmutzt
address: 245
# Translated with template sensor (binary_sensor)
- name: VentCube Vorgelagerter Filter verschmutzt
slave: 1
unique_id: ventcube_vorgelagerter_filter_verschmutzt
address: 246
# Translated with template sensor (binary_sensor)
- name: VentCube Zuluft zu kalt
slave: 1
unique_id: ventcube_zuluft_zu_kalt
address: 254
# Translated with template sensor (binary_sensor)
- name: VentCube Restlaufzeit Gerätefilter
slave: 1
unique_id: ventcube_restlaufzeit_geratefilter
address: 265
unit_of_measurement: d
min_value: 0
max_value: 255
device_class: duration
- name: VentCube Temperatur Wohnzimmer IST
slave: 1
unique_id: ventcube_temperatur_wohnzimmer_ist
unit_of_measurement: °C
device_class: temperature
address: 360
scale: 0.1
precision: 1
min_value: 0
max_value: 100
switches:
- name: VentCube Freigabe WP auf Heizen
slave: 1
address: 231
command_on: 0x1 # Freigabe
command_off: 0x0 # Gesperrt
write_type: holdings
verify:
input_type: holding
state_on: 0x1
state_off: 0x0
delay: 5
unique_id: ventcube_set_waermepumpe_heizen
- name: VentCube Freigabe WP auf Kühlen
slave: 1
address: 232
command_on: 0x1 # Freigabe
command_off: 0x0 # Gesperrt
write_type: holdings
verify:
input_type: holding
state_on: 0x1
state_off: 0x0
delay: 5
unique_id: ventcube_set_waermepumpe_kuehlen
climates:
- name: "VentCube Soll-Temperatur"
unique_id: ventcube_soll_temperatur
slave: 1
address: 400
max_temp: 30
min_temp: 10
offset: 0
precision: 0
scale: 0.1
target_temp_register: 400
target_temp_write_registers: true
temp_step: 1
temperature_unit: °C
- name: "VentCube Basis-Temperatur"
unique_id: ventcube_basis_temperatur
slave: 1
address: 420
max_temp: 30
min_temp: 18
offset: 0
precision: 0
scale: 0.1
target_temp_register: 420
target_temp_write_registers: true
temp_step: 1
temperature_unit: °C
#####################################################
# Select Options which require separate Automations #
#####################################################
input_select:
ventcube_manuelle_luftstufe:
name: VentCube Manuelle Luftstufe
options:
- "0 - Aus"
- "1 - Stufe 1"
- "2 - Stufe 2"
- "3 - Stufe 3"
- "4 - Stufe 4"
- "5 - Automatik"
- "6 - Linearbetrieb"
icon: mdi:fan
ventcube_betriebsart:
name: VentCube Betriebsart
options:
- "0 - Aus"
- "1 - Handbetrieb"
- "2 - Winterbetrieb"
- "3 - Sommerbetrieb"
- "4 - Sommer Abluft"
icon: mdi:fan
ventcube_heiz_kuehlfunktion:
name: VentCube Heiz- Kühlfunktion
options:
- "0 - Aus"
- "1 - Heizen"
- "2 - Kühlen"
- "3 - Auto T-Außen"
- "4 - Auto Digitaler Eingang"
icon: mdi:fan
####################
# TEMPLATE SENSORS #
####################
sensor:
- platform: template
sensors:
ventcube_betriebsart_text:
unique_id: ventcube_betriebsart_text
friendly_name: "VentCube Betriebsart"
value_template: >
{% set mapper = {
'0': 'Aus',
'1': 'Handbetrieb',
'2': 'Winterbetrieb',
'3': 'Sommerbetrieb',
'4': 'Sommer Abluft'} %}
{% set state = states.sensor.ventcube_betriebsart.state %}
{{ mapper[state] if state in mapper else 'Unknown' }}
ventcube_bypass_zustand_text:
unique_id: ventcube_bypass_zustand_text
friendly_name: "VentCube Zustand Bypass"
value_template: >
{% set mapper = {
'0': 'Geschlossen',
'1': 'Offen (Kühlen)',
'2': 'Offen (Heizen)'} %}
{% set state = states.sensor.ventcube_bypass_zustand.state %}
{{ mapper[state] if state in mapper else 'Unknown' }}
ventcube_zustand_aussenklappe_text:
unique_id: ventcube_zustand_aussenklappe_text
friendly_name: "VentCube Zustand Außenklappe"
value_template: >
{% set mapper = {
'0': 'Geschlossen',
'1': 'Offen'} %}
{% set state = states.sensor.ventcube_zustand_aussenklappe.state %}
{{ mapper[state] if state in mapper else 'Unknown' }}
ventcube_status_waermepumpe_text:
unique_id: ventcube_status_waermepumpe_text
friendly_name: "VentCube Status Wärmepumpe"
value_template: >
{% set mapper = {
'0': 'Aus',
'5': 'WP Heizen',
'49': 'WP Kühlen'} %}
{% set state = states.sensor.ventcube_status_waermepumpe.state %}
{{ mapper[state] if state in mapper else 'Unknown' }}
ventcube_heiz_kuehlfunktion_text:
unique_id: ventcube_heiz_kuehlfunktion_text
friendly_name: "VentCube Status Heiz- Kühlfunktion"
value_template: >
{% set mapper = {
'0': 'Aus',
'1': 'Heizen',
'2': 'Kühlen',
'3': 'Auto T-Außen',
'4': 'Auto Digitaler Eingang'} %}
{% set state = states.sensor.ventcube_heiz_kuehlfunktion.state %}
{{ mapper[state] if state in mapper else 'Unknown' }}
ventcube_status_nachheizregister_text:
unique_id: ventcube_status_nachheizregister_text
friendly_name: "VentCube Status Nachheizregister"
value_template: >
{% set mapper = {
'0': 'Inaktiv',
'1': 'Aktiv'} %}
{% set state = states.sensor.ventcube_status_nachheizregister.state %}
{{ mapper[state] if state in mapper else 'Unknown' }}
ventcube_status_vorheizregister_text:
unique_id: ventcube_status_vorheizregister_text
friendly_name: "VentCube Status Vorheizregister"
value_template: >
{% set mapper = {
'0': 'Aus',
'1': 'VHR1 Aktiv',
'2': 'VHR2 Aktiv',
'3': 'VHR1+2 Aktiv'} %}
{% set state = states.sensor.ventcube_status_vorheizregister.state %}
{{ mapper[state] if state in mapper else 'Unknown' }}
ventcube_status_stosslueftung_text:
unique_id: ventcube_status_stosslueftung_text
friendly_name: "VentCube Status Stoßlüftung"
value_template: >
{% set mapper = {
'0': 'Inaktiv',
'1': 'Aktiv'} %}
{% set state = states.sensor.ventcube_status_stosslueftung.state %}
{{ mapper[state] if state in mapper else 'Unknown' }}
ventcube_status_geblaese_zuluft_text:
unique_id: ventcube_status_geblaese_zuluft_text
friendly_name: "VentCube Status Gebläse Zuluft"
value_template: >
{% set mapper = {
'0': 'Deaktiviert',
'1': 'Anlaufphase',
'2': 'Aktiv',
'5': 'Standby',
'6': 'Fehler'} %}
{% set state = states.sensor.ventcube_status_geblaese_zuluft.state %}
{{ mapper[state] if state in mapper else 'Unknown' }}
ventcube_status_geblaese_abluft_text:
unique_id: ventcube_status_geblaese_abluft_text
friendly_name: "VentCube Status Gebläse Abluft"
value_template: >
{% set mapper = {
'0': 'Deaktiviert',
'1': 'Anlaufphase',
'2': 'Aktiv',
'5': 'Standby',
'6': 'Fehler'} %}
{% set state = states.sensor.ventcube_status_geblaese_abluft.state %}
{{ mapper[state] if state in mapper else 'Unknown' }}
template:
- binary_sensor:
- name: "VentCube Meldung Druckwächter Aktiv"
unique_id: ventcube_meldung_druckwachter_aktiv
device_class: problem
state: >
{% set mapper = {
'0': 'off',
'1': 'on'} %}
{% set state = states.sensor.ventcube_druckwachter_aktiv.state %}
{{ mapper[state] if state in mapper else 'Unknown' }}
- name: "VentCube Meldung EVU Sperre aktiv"
unique_id: ventcube_meldung_evu_sperre_aktiv
device_class: problem
state: >
{% set mapper = {
'0': 'off',
'1': 'on'} %}
{% set state = states.sensor.ventcube_evu_sperre_aktiv.state %}
{{ mapper[state] if state in mapper else 'Unknown' }}
- name: "VentCube Meldung Wartungstür offen"
unique_id: ventcube_meldung_wartungstur_offen
device_class: problem
state: >
{% set mapper = {
'0': 'off',
'1': 'on'} %}
{% set state = states.sensor.ventcube_wartungstur_offen.state %}
{{ mapper[state] if state in mapper else 'Unknown' }}
- name: "VentCube Meldung Gerätefilter verschmutzt"
unique_id: ventcube_meldung_geratefilter_verschmutzt
device_class: problem
state: >
{% set mapper = {
'0': 'off',
'1': 'on'} %}
{% set state = states.sensor.ventcube_geratefilter_verschmutzt.state %}
{{ mapper[state] if state in mapper else 'Unknown' }}
- name: "VentCube Meldung Vorgelagerter Filter verschmutzt"
unique_id: ventcube_meldung_vorgelagerter_filter_verschmutzt
device_class: problem
state: >
{% set mapper = {
'0': 'on',
'1': 'off'} %}
{% set state = states.sensor.ventcube_vorgelagerter_filter_verschmutzt.state %}
{{ mapper[state] if state in mapper else 'Unknown' }}
- name: "VentCube Meldung Zuluft Zu Kalt"
unique_id: ventcube_meldung_zuluft_zu_kalt
device_class: problem
state: >
{% set mapper = {
'0': 'off',
'1': 'on'} %}
{% set state = states.sensor.ventcube_zuluft_zu_kalt.state %}
{{ mapper[state] if state in mapper else 'Unknown' }}
@tobse91
Copy link

tobse91 commented Nov 26, 2025

Hallo zusammen, danke an @Maigus2510 für den Link zum Gist und euch allen für die Vorarbeiten sowie das Teilen eurer Konfiguration 👍 Ich konnte mich zwischenzeitlich an die Integration unserer VentCube Fresh machen und habe für unseren HA einige Änderungen an der ursprünglichen Quelle vorgenommen, aber auch die input_selects optimiert, die Status in Text überführen und den ausgewählten Wert rückübermitteln, sodass man keine Animationen mehr dafür benötigt. Auch die führenden Nummern (bspw. "3 - Stufe 3") sind entfallen.

Damit ich Werte nicht doppelt und dreifach definieren muss (bspw. die Lüftungsstufen, die an mehreren Sensoren/Selects vorkommen), habe ich Jinja-Templates (Makros) geschrieben, die man in einer Datei in "custom_templates" ablegt.

Hier ein paar markante Unterschiede zu den o.g. Konfigurationen:

* unique_ids von Deutsch in Englisch übersetzt -> Persönliche Geschmackssache

* input_select -> Template select (aufgrund der Trigger und `select_option`, siehe Beschreibung unten)

* Luftstufe -> Lüftungsstufe und ein paar andere Anpassungen

* Neue Adressen/Sensoren eingeführt (aus der oben schon referenzierten [ioBroker-Quelle](https://github.com/Excodibur/ioBroker.schwoerer-ventcube/blob/master/src/lib/schwoerer/parameters.ts)) – auch teilweise welche, die mich nicht betreffen (bspw. Erdwärmetauscher), da bin ich vielleicht etwas pedantisch 😄

* An den Template-Selects setze ich außerdem `default_entity_id` ein, damit die vorgegebene ID auch tatsächlich so von Home Assistant übernommen wird (siehe Doku; gilt nur solange, wie es noch keine Entität mit diesem Namen gibt). Hilft, wenn man sich darauf verlassen muss, dass sich zwei Entitäten finden.
[...]
select:
  - name: VentCube Betriebsart
    default_entity_id: select.ventcube_operation_mode
    unique_id: ventcube_operation_mode
[...]

Viele Grüße Benjamin

Das ist echt sehr gut, vielleicht lohnt es sich ein eigenes Repo oder Fork zu erstellen?

Danke für deine Arbeit. Werde ich testen.

@bbbenjie
Copy link

bbbenjie commented Nov 28, 2025

Vielen Dank für euer Feedback!

@tobse91, an das Repo dachte ich auch schon, um zumindest Änderungen besser nachvollziehen zu können. Aktuell bin ich wieder mit ganz anderen Dingen in HA beschäftigt, d.h. größere Änderungen meinerseits stehen nicht an.

@Markus1010RT, das klingt nach dem "Henne-Ei-Problem", das ich bei mir hatte:
Sobald ich meine Template-Entitäten via Entwicklerwerkzeuge neu geladen hatte, sind sie auf Unknown zurückgesprungen. Das betrifft folgende Einschränkung seitens Home Assistant:

The state, including attributes, of trigger-based sensors and binary sensors is restored when Home Assistant is restarted. The state of other trigger-based template entities is not restored.
Quelle: https://www.home-assistant.io/integrations/template/#trigger-based-template-entities

In diesem Fall hilft es, direkt nach dem Neuladen der Template-Entitäten die Modbus-Entitäten ebenfalls neu zu laden ("Modbus"-Eintrag in den Entwicklerwerkzeugen, bzw. "modbus.reload" als Aktion). Gilt auch bei HA-Neustarts.
Ich habe mir dafür eine Animation geschrieben, die mir das abnimmt:

alias: Modbus neu laden bei HAOS-Neustart und Neuladen von Template-Entitäten
description: ""
triggers:
  - trigger: homeassistant
    event: start
  - trigger: event
    event_type: event_template_reloaded
conditions: []
actions:
  - action: modbus.reload
    metadata: {}
    data: {}
mode: single

Vielleicht trifft es das beschriebene Problem? Ich bin gespannt.

@Markus1010RT
Copy link

Hi,

also ich habe es heute mal mit dem neu laden des modbus versucht, aber nach wie vor sieht es eher schlecht aus.

Screenshot 2025-11-28 201524

Was mich auch ein wenig wundert ist, dass ich alles doppelt und dreifach habe :D ich vermute aber, das kommt von meinen diversen versuchen des neu hinzufuegens der modbus integration.

Ich hab die Einstellungen am Bedienteil auch nochmals geprüft. die ip stimmt und modbus tcp ist auch aktviert

@bbbenjie
Copy link

Hi @Markus1010RT, danke dir.
Nur um sicher zu gehen: Ich gehe davon aus, du hast deine VentCube nach Aktivieren von Modbus via TCP/IP neugestartet? Hier im Thread steht was von Sicherung raus/rein, aber es geht auch per Schwörer-Bedienteil: Solange man sich noch im Service-Modus befindet -> Einstellungen -> Grundeinstellungen -> 11. Datensatz verwalten -> 6. Geräte Neustart Leistungsteil; ich habe sicherheitshalber auch "7. Geräte Neustart BT-S2" ausgeführt.

Ich konnte mich direkt nach Aktivieren von Modbus TCP/IP auf einem Unix-Betriebssystem via netcat davon überzeugen, dass der Port nun offen ist (via nc -vz <ip> 502, also bspw. nc -vz 192.168.1.123 502). Eben nochmal getestet, erhalte ich mittlerweile nur noch einen Connection Timeout, obwohl sich HA weiterhin erfolgreich verbinden kann. Wenn du per netcat eine erfolgreiche Verbindung aufbauen kannst, prima! Beim Ergebnis "Connection Timeout" stehen die Chancen jedoch 50:50.
Du kannst aber auch mit Modbus-Tools prüfen, ob du einzelne Adressen abrufen kannst (oder, für Fortgeschrittene, wahlweise direkt per netcat mit Modbus kommunizieren). Dann hättest du wenigstens Gewissheit, ob es an HA oder der Lüftungsanlage liegt. Ich hatte mal Tools recherchiert, aber noch keines ausgetestet.

Ansonsten, was sagt Home Assistant zur Verbindung? Gibt es entsprechende Einträge im Log?
Andernfalls ggf. das Loglevel temporär hochdrehen, siehe https://www.home-assistant.io/integrations/modbus/ Kapitel "Opening an issue", und danach wahlweise HA neustarten oder die Modbus-YAML-Konfiguration neu laden.

@tobse91
Copy link

tobse91 commented Dec 4, 2025

@bbbenjie

Habe deine .yml und .jinja erstellt und die IP angepasst. Die Sensoren funktionieren als Zahl, aber leider nicht als Text:

grafik

Wenn die Zustände ausgelesen werden können wie man sieht, wieso werden die Text Sensoren nicht angezeigt?

Zudem kann ich bei den neuen Auswahlfeldern leider nichts auswählen:

grafik

Gruß Tobias

@bbbenjie
Copy link

bbbenjie commented Dec 4, 2025

Hi @tobse91,
nur um sicher zu gehen: ich gehe davon aus, dass die Macros unter /custom_templates/ abgelegt wurden und Home Assistant danach neugestartet wurde? So sieht die Struktur bei mir aus:

grafik

Du kannst die Funktionstüchtigkeit der Macros testen, indem du bspw. folgenden Schnipsel unter Entwicklerwerkzeuge > Template einfügst:

{% from 'schwoererhaus_ventcube_fresh.jinja' import ventcube_operation_mode as func %}
{{ func('values') }}

Erscheint dort folgende Ausgabe, können die Macros als Fehlerursache ausgeschlossen werden:
grafik

Da dein Dropdown leer ist, das genannte Macro aber die Listeneinträge für das betroffene Feld erzeugen soll, vermute ich die Fehlerursache an dieser Stelle.

Der Modbus-Sensor für die Betriebsart hat tatsächlich die ID "sensor.ventcube_operation_mode", wie vom Template-Select so erwartet?

Viele Grüße
Benjamin

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment