It took some time, but now I have wrote a python script, to read the data from a serial port and publish these via mqtt to HA.
In configuration.yaml some sensors have to be defined.
mqtt:
sensor:
#ELV Sensoren =========================================
# Schlafzimmer
- name: "Schlafzimmer Temperatur"
state_topic: "stat/Elv/Schlafzimmer/Temperatur"
icon: mdi:thermometer
state_class: measurement
device_class: temperature
unit_of_measurement: "°C"
- name: "Schlafzimmer Feuchtigkeit"
state_topic: "stat/Elv/Schlafzimmer/Feuchtigkeit"
icon: mdi:cloud-percent
state_class: measurement
device_class: humidity
unit_of_measurement: "%"
# HomeOffice
- name: "HomeOffice Temperatur"
state_topic: "stat/Elv/HomeOffice/Temperatur"
icon: mdi:thermometer
state_class: measurement
device_class: temperature
unit_of_measurement: "°C"
- name: "HomeOffice Feuchtigkeit"
state_topic: "stat/Elv/HomeOffice/Feuchtigkeit"
icon: mdi:cloud-percent
state_class: measurement
device_class: humidity
unit_of_measurement: "%"
# Kinderzimmer
- name: "Kinderzimmer Temperatur"
state_topic: "stat/Elv/Kinderzimmer/Temperatur"
icon: mdi:thermometer
state_class: measurement
device_class: temperature
unit_of_measurement: "°C"
- name: "Kinderzimmer Feuchtigkeit"
state_topic: "stat/Elv/Kinderzimmer/Feuchtigkeit"
icon: mdi:cloud-percent
state_class: measurement
device_class: humidity
unit_of_measurement: "%"
# Bad Oben
- name: "Bad Oben Temperatur"
state_topic: "stat/Elv/Bad Oben/Temperatur"
icon: mdi:thermometer
state_class: measurement
device_class: temperature
unit_of_measurement: "°C"
- name: "Bad Oben Feuchtigkeit"
state_topic: "stat/Elv/Bad Oben/Feuchtigkeit"
icon: mdi:cloud-percent
state_class: measurement
device_class: humidity
unit_of_measurement: "%"
# Küche
- name: "Küche Temperatur"
state_topic: "stat/Elv/Küche/Temperatur"
icon: mdi:thermometer
state_class: measurement
device_class: temperature
unit_of_measurement: "°C"
- name: "Küche Feuchtigkeit"
state_topic: "stat/Elv/Küche/Feuchtigkeit"
icon: mdi:cloud-percent
state_class: measurement
device_class: humidity
unit_of_measurement: "%"
# Esszimmer
- name: "Esszimmer Temperatur"
state_topic: "stat/Elv/Esszimmer/Temperatur"
icon: mdi:thermometer
state_class: measurement
device_class: temperature
unit_of_measurement: "°C"
- name: "Esszimmer Feuchtigkeit"
state_topic: "stat/Elv/Esszimmer/Feuchtigkeit"
icon: mdi:cloud-percent
state_class: measurement
device_class: humidity
unit_of_measurement: "%"
# Wohnzimmer
- name: "Wohnzimmer Temperatur"
state_topic: "stat/Elv/Wohnzimmer/Temperatur"
icon: mdi:thermometer
state_class: measurement
device_class: temperature
unit_of_measurement: "°C"
- name: "Wohnzimmer Feuchtigkeit"
state_topic: "stat/Elv/Wohnzimmer/Feuchtigkeit"
icon: mdi:cloud-percent
state_class: measurement
device_class: humidity
unit_of_measurement: "%"
# Bad unten
- name: "Bad Unten Temperatur"
state_topic: "stat/Elv/Bad Unten/Temperatur"
icon: mdi:thermometer
state_class: measurement
device_class: temperature
unit_of_measurement: "°C"
- name: "Bad Unten Feuchtigkeit"
state_topic: "stat/Elv/Bad Unten/Feuchtigkeit"
icon: mdi:cloud-percent
state_class: measurement
device_class: humidity
unit_of_measurement: "%"
# Außen-Kombisensor
- name: "Außen (ELV)"
state_topic: "stat/Elv/Kombisensor/Temperatur"
icon: mdi:thermometer
state_class: measurement
device_class: temperature
unit_of_measurement: "°C"
- name: "Außen Feuchtigkeit"
state_topic: "stat/Elv/Kombisensor/Feuchtigkeit"
icon: mdi:cloud-percent
state_class: measurement
device_class: humidity
unit_of_measurement: "%"
- name: "Windgeschwindigkeit"
state_topic: "stat/Elv/Kombisensor/Windgeschwindigkeit"
icon: mdi:weather-windy
state_class: measurement
device_class: wind_speed
unit_of_measurement: "km/h"
- name: "Wippenschläge"
state_topic: "stat/Elv/Kombisensor/Wippenschläge"
icon: mdi:weather-rainy
state_class: measurement
- name: "Regen"
state_topic: "stat/Elv/Kombisensor/Regen"
icon: mdi:weather-rainy
state_class: measurement
- name: "Regenmenge"
state_topic: "stat/Elv/Kombisensor/Regenmenge"
icon: mdi:weather-rainy
state_class: measurement
- name: "Tagesregenmenge"
state_topic: "stat/Elv/Kombisensor/Tagesregenmenge"
icon: mdi:weather-rainy
state_class: measurement
- name: "Heartbeat (ELV)"
unique_id: "Heartbeat ELV"
state_topic: "stat/Elv/Heartbeat"
icon: mdi:heart-pulse
ELVWde1.py (which is actually runs on a windows pc)
#!/usr/bin/python3
# -*-coding:Utf-8 -*
# Programm, dass die Wetterdaten vom ELV WDE1 ausliest
# Programm erstellt von René Janaczeck
# Version: 06.01.2024 20:46
# USB-Wetterdatenempfänger USB-WDE1
# Der USB-WDE1 kann die Daten aller folgend aufgeführten Wettersensoren empfangen.
# - Funk-Kombi-Sensor KS 300
# - Funk-Kombi-Sensor KS 200
# - Funk-Temperatursensor S 300 IA, Sensor abgesetzt
# - Funk-Temperatur- und Luftfeuchtesensor S 300 TH, Sensoren intern
# - Funk-Temperatur- und Luftfeuchtesensor ASH 2200, Sensoren intern
# - Funk-Pool-Sensor PS 50
# Die Wettersensoren senden ihre Daten unregelmäßig alle 2,5 bis 3 Minuten.
# Kleinste mögliche Temperatur ist -29,9 [°C] (je nach Sensor kann diese aber nicht erreicht werden – der PS50 geht z. B. nur bis 0°C).
# Größte mögliche Temperatur ist +79,9 [°C] (je nach Sensor kann diese aber nicht erreicht werden – der PS50 geht z. B. nur bis +69,9°C).
# Der Wertebereich für die Luftfeuchtigkeit geht von 0 bis 99 [%] (ohne Nachkommastelle)
# Der Wertebereich für die Windgeschwindigkeit geht von 0,0 bis 199,9 [km/h].
# Signalisiert die Sofort-Erkennung des Kombisensors „Regen“, ist der entsprechende Wert gleich 1, ansonsten ist dieser 0.
# Der WDE1 liefert Daten entweder im OpenFormat (*) oder im Textformat
# LogView Format
# '$1;1;;22,8;22,8;22,7;22,9;20,6;20,6;21,4;20,0;42;35;43;41;42;41;41;41;1,0;88;2,5;503;0;0\r\n'
# - $1;1;Zeitstempel (ohne); # Startsequenz
# - Temp Sensor1; ...; Temp Sensor8; # Zuerst 8 Temperaturen
# - Feuchte Sensor1; ...; Feuchte Sensor8; # dann 8 Feuchtigkeiten
# - Temp. Kombisensor; Feuchte Kombisensor; Windgeschwindigkeit; Niederschlag (Wippenschläge); Regen (Ja=1, Nein=0); Stopzeichen 0<cr><lf>
# - 0\r\n # abschließende Zeichenfolge
# Textformat
# Sensor 1: 21,2 C; 37 %
# ...
# Sensor 8: 22,4 C
# Kombi-S.: 16,0 C; 42 %; 8,0 km/h; 455 Takte; Regen: Ja
# Dieses Script setzt das LogView / OpenFormat voraus.
import serial
from datetime import datetime
import time
import logging
import paho.mqtt.client as mqtt
# Comport Parameter
COMPORT='COM6'
#BAUDRATE=9600 # Default Einstellung
BAUDRATE=38400 # Muss auf dem WDE1 eingestellt werden, damit die Baudrate genutzt werden kann
TimeOut = 30
Parity='N'
DataBits=8
StopBits=1
# MQTT Broker Parameter
Mqtt_Broker_Address = '192.168.1.2'
Mqtt_Port = 1883
Mqtt_User = "mqttuser"
Mqtt_Password = "mqttpassword"
LogFileName = 'C:\\Messwerte\\ELV USB-WDE1\\ELV.log'
# In welchem Intervall sollen die Daten gelesen werden?
# Min 150 - 180 Sekunden, siehe Text oben
Intervall = 300
# List für die MQTT Topics
# wird später ergänzt mit den Werten
ElvMqttTopics = [
'stat/Elv/Schlafzimmer/Temperatur',
'stat/Elv/HomeOffice/Temperatur',
'stat/Elv/Kinderzimmer/Temperatur',
'stat/Elv/Bad Oben/Temperatur',
'stat/Elv/Küche/Temperatur',
'stat/Elv/Esszimmer/Temperatur',
'stat/Elv/Bad Unten/Temperatur',
'stat/Elv/Wohnzimmer/Temperatur',
'stat/Elv/Schlafzimmer/Feuchtigkeit',
'stat/Elv/HomeOffice/Feuchtigkeit',
'stat/Elv/Kinderzimmer/Feuchtigkeit',
'stat/Elv/Bad Oben/Feuchtigkeit',
'stat/Elv/Küche/Feuchtigkeit',
'stat/Elv/Esszimmer/Feuchtigkeit',
'stat/Elv/Bad Unten/Feuchtigkeit',
'stat/Elv/Wohnzimmer/Feuchtigkeit',
'stat/Elv/Kombisensor/Temperatur',
'stat/Elv/Kombisensor/Feuchtigkeit',
'stat/Elv/Kombisensor/Windgeschwindigkeit',
'stat/Elv/Kombisensor/Wippenschläge',
'stat/Elv/Kombisensor/Regen',
'stat/Elv/Kombisensor/Regenmenge',
'stat/Elv/Kombisensor/Tagesregenmenge'
]
# Dieses Topic dient als Heartbeat, wann das letzte Mal die Daten gesendet wurden
HeartBeat_Topic = 'stat/Elv/Heartbeat'
# Dient zur Ausgabe in einer Log-Datei
def log(what):
logging.info(what)
# Send Data to MQTT Broker
def Publish_MQTT_Data(Topic, Data):
# Verbindung zum MQTT Broker herstellen
Mqtt_Client = mqtt.Client()
Mqtt_Client.username_pw_set(Mqtt_User, Mqtt_Password)
try:
Mqtt_Client.connect(Mqtt_Broker_Address, Mqtt_Port)
except Exception as e:
log('Connection Error while trying to connect to MQTT Broker, ' + str(e))
pass
# Send Data to MQTT Broker
try:
Mqtt_Client.publish(topic=Topic, payload=Data, qos=1, retain=True)
# Im Protokoll ausgeben
log('Published ' + str(Topic) + ': ' + str(Data))
except Exception as e:
log("Can't publish MQTT Message to " + str(Topic) + ' with Data ' + str(Data) + ', ' + str(e))
# Close Connection to MQTT Broker
Mqtt_Client.disconnect()
class ElvWde1():
# Klasse für den Elv WDE1 Wetterdatenempfänger
# Die Befehle müssen als Text (ASCII-Zeichen) zum USB-WDE1 gesendet werden.
# Verbindungsparameter siehe oben
def __init__(self):
#log('Initialize Class ElvWde1')
pass
def OpenPort(self):
#log('Try to open Comport ' + str(COMPORT))
try:
SerialPort = serial.Serial(port=COMPORT, baudrate=BAUDRATE, bytesize=DataBits, timeout=TimeOut, parity=Parity, stopbits=StopBits)
except serial.SerialException as var :
log("Can't open Comport " + str(COMPORT))
return False
else:
log('Serial Port ' + COMPORT + ' opened ...')
return SerialPort
def ClosePort(self, SerialPort):
if (SerialPort.is_open == True):
SerialPort.close()
log('Serial Port ' + str(COMPORT) + ' closed.')
def ReadDataAndPublish(self):
serPort = self.OpenPort()
if (serPort != False and serPort.is_open == True):
# Max 30 sek versuchen, Daten zu lesen, damit nicht ewig die Schleife läuft
# insbesondere wenn die Daten nicht mit '$1;1;;' starten
maxTime = time.time() + 30
# Daten von der seriellen Schnittstelle lesen
#log('Try to read data from Comport ' + str(COMPORT))
data = serPort.readline()
# Daten wurden gelesen, starten diese auch mit '$1;1;;' ?
# Es kommt gelegentlich vor, dass diese nicht mit '$1;1;;' starten,
# dann erneut versuchen, wenn nicht maxTime abgelaufen ist ...
while time.time() < maxTime and not (data.startswith(b'$1;1;;')):
log(str(data) + " data starts not with b'$1;1;;', try again ...")
data = serPort.readline()
#log('Data from Serial Port ' + str(COMPORT) + ', ' + str(data))
# seriellen Port wieder schließen
self.ClosePort(serPort)
# Daten in Ascii umwandeln
ElvData = data.decode('Ascii')
# $1;1;'' entfernen
ElvData = ElvData.replace('$1;1;;','')
# '0\r\n' entfernen
ElvData = ElvData.replace('0\r\n','')
# Kommatas in Punkte umwandeln, damit Home Assistant damit arbeiten kann
ElvData = ElvData.replace(',','.')
# Daten in ein Array umwandeln, damit sie sich leichter verarbeiten lassen
ElvData = ElvData.split(';')
# ElvMqttTopics und Daten zusammen bringen (zip) und in ein Dictonary (dict) umwandeln
# => Key (MQTT Topic) = value
ElvDict = dict(zip(ElvMqttTopics, ElvData))
#log(str(ElvDict))
# In einer Schleife key (MQTT Topic) und Value ermitten und dann per MQTT publishen
for key, value in ElvDict.items():
Publish_MQTT_Data(Topic=key, Data=value)
# Heartbeat publishen, damit man weiß, wann zuletzt gepublisht wurde
# Dient zur Kontrolle, ob das Script noch läuft/Daten liefert
Publish_MQTT_Data(Topic=HeartBeat_Topic, Data=datetime.now().strftime("%d.%m.%Y %H:%M"))
# Starte das Programm
# Logging konfigurieren
logging.basicConfig(format='%(asctime)s %(message)s', datefmt='%d.%m.%Y %H:%M:%S ', level=logging.INFO, filename=LogFileName)
# Abbruchbedingung für die While Schleife
Ende = False
# Class ElvWde1 instanzieren
a = ElvWde1()
# regelmäßig Daten vom serial port lesen
try:
while not Ende:
# Daten vom serial Port lesen und publishen
a.ReadDataAndPublish()
# Pause, für Intervall Sekunden, siehe oben
time.sleep(Intervall)
except (KeyboardInterrupt,SystemExit):
# Wenn Strg-C oder ein Exit auftritt, Schleife beenden
ende=True
pass
log ('Programm beendet')