I had to change the modbus integration a little bit otherwise i run into a lot of timeout issues:
Generate script
import argparse
from pathlib import Path
# ==========================================
# 1. CONFIGURE YOUR SLAVES HERE
# ==========================================
slaves = [
{"id": 2, "prefix": "Lüftung Buero Nora", "slug": "bn"},
{"id": 3, "prefix": "Lüftung Buero Oli", "slug": "bo"},
{"id": 4, "prefix": "Lüftung Kinderzimmer", "slug": "kz"},
{"id": 5, "prefix": "Lüftung Schlafzimmer", "slug": "sz"},
{"id": 6, "prefix": "Lüftung Wohnzimmer", "slug": "wz"},
]
# ==========================================
# 2. DEFINE THE SENSOR TEMPLATE
# ==========================================
# This list contains the logic from your original config, minus 'name' and 'slave'.
sensors_template = [
{"suffix": "Modus", "address": 41100, "data_type": "int16", "scan_interval": 3},
{
"suffix": "Modus Zuluft",
"address": 41101,
"data_type": "int16",
"scan_interval": 5,
},
{
"suffix": "Frostschutzfunktion",
"address": 41018,
"data_type": "int16",
"scan_interval": 60,
},
{
"suffix": "Ablufttemperatur",
"address": 41000,
"data_type": "float32",
"device_class": "temperature",
"unit": "°C",
"scan_interval": 60,
"precision": 1,
"swap": "word",
},
{
"suffix": "Außenlufttemperatur",
"address": 41002,
"data_type": "float32",
"device_class": "temperature",
"unit": "°C",
"scan_interval": 60,
"precision": 1,
"swap": "word",
},
{
"suffix": "Fortlufttemperatur",
"address": 41004,
"data_type": "float32",
"device_class": "temperature",
"unit": "°C",
"scan_interval": 60,
"precision": 1,
"swap": "word",
},
{
"suffix": "Feuchte Abluft",
"address": 41006,
"data_type": "int16",
"device_class": "humidity",
"unit": "%",
"scan_interval": 60,
},
{
"suffix": "CO² Abluft",
"address": 41007,
"data_type": "int16",
"device_class": "carbon_dioxide",
"unit": "ppm",
"scan_interval": 60,
},
{
"suffix": "Zulufttemperatur",
"address": 41009,
"data_type": "float32",
"device_class": "temperature",
"unit": "°C",
"scan_interval": 60,
"precision": 1,
"swap": "word",
},
{
"suffix": "Feuchte Zuluft",
"address": 41011,
"data_type": "int16",
"device_class": "humidity",
"unit": "%",
"scan_interval": 60,
},
{
"suffix": "Lüfterstufe Abluft",
"address": 41020,
"data_type": "int16",
"device_class": "volume_flow_rate",
"unit": "m³/h",
"scan_interval": 5,
},
{
"suffix": "Lüfterstufe Zuluft",
"address": 41021,
"data_type": "int16",
"device_class": "volume_flow_rate",
"unit": "m³/h",
"scan_interval": 5,
},
{
"suffix": "Zeit bis Filterwechsel",
"address": 41027,
"data_type": "int16",
"device_class": "duration",
"unit": "d",
"scan_interval": 60,
},
{
"suffix": "Modus General",
"address": 41120,
"data_type": "int16",
"scan_interval": 3600,
},
{
"suffix": "Rel. Feuchte Startpunkt",
"address": 42000,
"data_type": "int16",
"device_class": "humidity",
"unit": "%",
"scan_interval": 5,
},
{
"suffix": "Min. Lüftungsstufe Feuchteregelung",
"address": 42001,
"data_type": "int16",
"scan_interval": 60,
},
{
"suffix": "Max. Lüftungsstufe Feuchteregelung",
"address": 42002,
"data_type": "int16",
"scan_interval": 60,
},
{
"suffix": "CO² Startpunkt",
"address": 42003,
"data_type": "int16",
"device_class": "carbon_dioxide",
"unit": "ppm",
"scan_interval": 60,
},
{
"suffix": "Min. Lüftungsstufe CO²-Regelung",
"address": 42004,
"data_type": "int16",
"scan_interval": 60,
},
{
"suffix": "Max. Lüftungsstufe CO²-Regelung",
"address": 42005,
"data_type": "int16",
"scan_interval": 60,
},
]
def clean_string(input_str):
"""Helper to make clean Unique IDs"""
return (
input_str.lower()
.replace(" ", "_")
.replace("ä", "ae")
.replace("ö", "oe")
.replace("ü", "ue")
.replace("²", "2")
.replace(".", "")
.replace("-", "_")
)
if __name__ == "__main__":
arguments = argparse.ArgumentParser(
description="Generate sensor configurations for Home Assistant MODBUS."
)
arguments.add_argument(
"--out_file",
type=Path,
default="modbus.yaml",
help="The path to the output YAML file.",
)
args = arguments.parse_args()
with args.out_file.open("w", encoding="utf-8") as f:
f.write(f"# Auto-generated Modbus config for {len(slaves)} slaves.\n")
f.write("# DO NOT EDIT MANUALLY - Update the Python script instead.\n\n")
for slave in slaves:
f.write("# ---------------------------------------------------------\n")
f.write(f"# SLAVE {slave['id']}: {slave['prefix']}\n")
f.write("# ---------------------------------------------------------\n")
for s in sensors_template:
# Generate Name
full_name = f"{slave['prefix']} {s['suffix']}"
# Generate Unique ID (e.g., mb_sz_3_co2_abluft)
# Including slave ID in unique_id ensures no conflicts if you move devices later
clean_suffix = clean_string(s["suffix"])
unique_id = f"mb_{slave['slug']}_{slave['id']}_{clean_suffix}"
# Write YAML block
f.write(f'- name: "{full_name}"\n')
f.write(f" unique_id: {unique_id}\n")
f.write(f" slave: {slave['id']}\n")
f.write(f" address: {s['address']}\n")
f.write(f" data_type: {s['data_type']}\n")
f.write(f" scan_interval: {s['scan_interval']}\n")
# Optional fields
if "device_class" in s:
f.write(f" device_class: {s['device_class']}\n")
if "unit" in s:
f.write(f' unit_of_measurement: "{s["unit"]}"\n')
if "precision" in s:
f.write(f" precision: {s['precision']}\n")
if "swap" in s:
f.write(f" swap: {s['swap']}\n")
f.write("\n") # Empty line between sensors
print(
f"Success! File '{args.out_file}' has been created with {len(slaves) * len(sensors_template)} sensors."
)
print("You can now include this file in your configuration.yaml.")