import logging
import paho.mqtt.client as mqtt
import random
+import ssl
import sys
import time
connected = False
ident = ""
bock_mqtt: 'BockMQTT'
+ burrow_mqtt: 'BurrowMQTT'
def __init__(self, config):
self.ident = str(config['uniqueIdentifier']).rjust(6, '0')
+ def status_notify(self, stat):
+ self.burrow_mqtt.send_status(stat)
+
def process_message(self, m):
if len(m) > 6 and m[0] == 0x30 and m[1] == 0x0a:
return self.process_report(m)
t_manual = val[3] / 2
t_auto = val[4] / 2
logger.info(f'Temp: desired={t_desired} actual={t_actual} analog={analog} manual={t_manual} auto={t_auto}')
+ self.burrow_mqtt.send_measurement(t_actual)
+
+
+def generic_mqtt_log(prefix, level, string):
+ msg = f'{prefix}: {string}'
+ if level == mqtt.MQTT_LOG_DEBUG:
+ logger.debug(msg)
+ elif level == mqtt.MQTT_LOG_WARNING:
+ logger.warning(msg)
+ elif level == mqtt.MQTT_LOG_ERROR:
+ logger.error(msg)
+ else:
+ logger.info(msg)
class BockMQTT:
mqc.ws_set_options("/wss")
mqc.tls_set_context()
mqc.username_pw_set(f'TSWIFI_{therm.ident}', config['mqttPass'])
- mqc.connect("mqtt.elbock.cz", 8081, 60)
- mqc.loop_start()
+
+ def start(self):
+ self.mqc.connect("mqtt.elbock.cz", 8081, 60)
+ self.mqc.loop_start()
def on_connect(self, mqc, userdata, flags, rc):
if rc == 0:
- logger.info('MQTT connected')
+ logger.info('BockMQTT connected')
self.connected = True
mqc.subscribe(self.in_topic, 0)
mqc.subscribe(self.out_topic, 0)
else:
- logger.warning(f'MQTT connect failed: rc={rc}')
+ logger.warning(f'BockMQTT connect failed: rc={rc}')
def on_disconnect(self, mqc, userdata, rc):
- logger.info(f'MQTT disconnected: rc={rc}')
+ logger.info(f'BockMQTT disconnected: rc={rc}')
self.connected = False
+ self.therm.status_notify('error')
def on_message(self, mqc, userdata, msg):
logger.debug(f'<< {msg.topic} ' + msg.payload.hex(' '))
logger.warning(f'Cannot parse message ({err}): {msg.payload.hex(" ")}')
def on_subscribe(self, mqc, userdata, mid, granted_qos):
- logger.debug(f'MQTT subscribed: mid={mid}')
+ logger.debug(f'BockMQTT subscribed: mid={mid}')
def on_log(self, mqc, userdata, level, string):
- if level == mqtt.MQTT_LOG_DEBUG:
- logger.debug(f'MQTT: {string}')
- elif level == mqtt.MQTT_LOG_WARNING:
- logger.warning(f'MQTT: {string}')
- elif level == mqtt.MQTT_LOG_ERROR:
- logger.error(f'MQTT: {string}')
- else:
- logger.info(f'MQTT: {string}')
+ generic_mqtt_log('BockMQTT', level, string)
def gen_client_id(self):
return 'APP_' + "".join(["abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRTUVWXYZ1234567890"[random.randrange(60)] for _ in range(18)])
sys.exit(1)
+class BurrowMQTT:
+
+ def __init__(self, sensor):
+ self.sensor = sensor
+ self.connected = False
+ self.status = '?'
+
+ mqc = mqtt.Client()
+ self.mqc = mqc
+
+ sctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
+ sctx.verify_mode = ssl.CERT_REQUIRED
+ sctx.load_cert_chain('/etc/burrow-mqtt/client.crt', '/etc/burrow-mqtt/client.key')
+ sctx.load_verify_locations(cafile='/etc/burrow-mqtt/ca.crt')
+ mqc.tls_set_context(sctx)
+
+ mqc.on_connect = self.on_connect
+ mqc.on_disconnect = self.on_disconnect
+ mqc.on_log = self.on_log
+
+ def start(self):
+ self.mqc.will_set(f"status/bocktherm/{self.sensor}", "dead", retain=True)
+ self.mqc.connect("burrow-mqtt", 8883)
+ self.send_status('init')
+ self.mqc.loop_start()
+
+ def on_connect(self, mqc, userdata, flags, rc):
+ if rc == 0:
+ logger.info('BurrowMQTT connected')
+ self.connected = True
+ else:
+ logger.warning(f'BurrowMQTT connect failed: rc={rc}')
+
+ def on_disconnect(self, mqc, userdata, rc):
+ logger.info(f'BurrowMQTT disconnected: rc={rc}')
+ self.connected = False
+
+ def on_log(self, mqc, userdata, level, string):
+ generic_mqtt_log('BurrowMQTT', level, string)
+
+ def send_status(self, stat):
+ if stat != self.status:
+ self.status = stat
+ self.mqc.publish(f"status/bocktherm/{self.sensor}", stat, retain=True)
+
+ def send_measurement(self, value):
+ if self.connected:
+ now = int(time.time())
+ self.mqc.publish(f'mill/thermostat/{self.sensor}', f'{value} {now}')
+ self.send_status('ok')
+
+
parser = argparse.ArgumentParser(description='A daemon watching Elektrobock thermostats')
parser.add_argument('--config', required=True, type=str, help='Configuration file from the web app (devices.json)')
parser.add_argument('--device', required=True, type=str, help='Device name as in the configuration file')
+parser.add_argument('--sensor', required=True, type=str, help='Sensor name in Burrow MQTT')
parser.add_argument('--debug', default=False, action='store_true', help='Log debug messages')
args = parser.parse_args()
therm = Thermostat(config)
therm.bock_mqtt = BockMQTT(therm)
+therm.burrow_mqtt = BurrowMQTT(args.sensor)
+therm.bock_mqtt.start()
+therm.burrow_mqtt.start()
time.sleep(1)