Even though hc2mqtt was running, and showed active log lines, I stopped receiving the messages sometimes in the MQTT server and subscribed processes. Adding client.loop_forever() will auto-reconnect to the mqtt server in case of network loss / hickups. Seems to help for my setup. Docs: https://pypi.org/project/paho-mqtt/#network-loop
107 lines
2.3 KiB
Python
Executable File
107 lines
2.3 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# Contact Bosh-Siemens Home Connect devices
|
|
# and connect their messages to the mqtt server
|
|
import json
|
|
import sys
|
|
import time
|
|
from threading import Thread
|
|
|
|
import click
|
|
import paho.mqtt.client as mqtt
|
|
|
|
from HCDevice import HCDevice
|
|
from HCSocket import HCSocket, now
|
|
|
|
|
|
@click.command()
|
|
@click.argument("config_file")
|
|
@click.option("-h", "--mqtt_host", default="localhost")
|
|
@click.option("-p", "--mqtt_prefix", default="homeconnect/")
|
|
def hc2mqtt(config_file: str, mqtt_host: str, mqtt_prefix: str):
|
|
click.echo(f"Hello {config_file=} {mqtt_host=} {mqtt_prefix=}")
|
|
|
|
with open(config_file, "r") as f:
|
|
devices = json.load(f)
|
|
|
|
client = mqtt.Client()
|
|
client.connect(host=mqtt_host, port=1883, keepalive=70)
|
|
|
|
for device in devices:
|
|
mqtt_topic = mqtt_prefix + device["name"]
|
|
thread = Thread(target=client_connect, args=(client, device, mqtt_topic))
|
|
thread.start()
|
|
|
|
client.loop_forever()
|
|
|
|
|
|
# Map their value names to easier state names
|
|
topics = {
|
|
"OperationState": "state",
|
|
"DoorState": "door",
|
|
"RemainingProgramTime": "remaining",
|
|
"PowerState": "power",
|
|
"LowWaterPressure": "lowwaterpressure",
|
|
"AquaStopOccured": "aquastop",
|
|
"InternalError": "error",
|
|
"FatalErrorOccured": "error",
|
|
}
|
|
|
|
|
|
|
|
def client_connect(client, device, mqtt_topic):
|
|
host = device["host"]
|
|
|
|
state = {}
|
|
for topic in topics:
|
|
state[topics[topic]] = None
|
|
|
|
while True:
|
|
try:
|
|
ws = HCSocket(host, device["key"], device.get("iv",None))
|
|
dev = HCDevice(ws, device.get("features", None))
|
|
|
|
#ws.debug = True
|
|
ws.reconnect()
|
|
|
|
while True:
|
|
msg = dev.recv()
|
|
if msg is None:
|
|
break
|
|
if len(msg) > 0:
|
|
print(now(), msg)
|
|
|
|
update = False
|
|
for topic in topics:
|
|
value = msg.get(topic, None)
|
|
if value is None:
|
|
continue
|
|
|
|
# Convert "On" to True, "Off" to False
|
|
if value == "On":
|
|
value = True
|
|
elif value == "Off":
|
|
value = False
|
|
|
|
new_topic = topics[topic]
|
|
if new_topic == "remaining":
|
|
state["remainingseconds"] = value
|
|
value = "%d:%02d" % (value / 60 / 60, (value / 60) % 60)
|
|
|
|
state[new_topic] = value
|
|
update = True
|
|
|
|
if not update:
|
|
continue
|
|
|
|
msg = json.dumps(state)
|
|
print("publish", mqtt_topic, msg)
|
|
client.publish(mqtt_topic + "/state", msg)
|
|
|
|
except Exception as e:
|
|
print("ERROR", host, e, file=sys.stderr)
|
|
|
|
time.sleep(5)
|
|
|
|
if __name__ == "__main__":
|
|
hc2mqtt()
|