class Thermostat:
connected = False
ident = ""
- in_topic = ""
- out_topic = ""
- # mqc = mqtt client
+ bock_mqtt: 'BockMQTT'
+
+ def __init__(self, config):
+ self.ident = str(config['uniqueIdentifier']).rjust(6, '0')
def process_message(self, m):
if len(m) > 6 and m[0] == 0x30 and m[1] == 0x0a:
logger.info(f'Temp: desired={t_desired} actual={t_actual} analog={analog} manual={t_manual} auto={t_auto}')
-def on_connect(mqc, therm, flags, rc):
- if rc == 0:
- logger.info('MQTT connected')
- therm.connected = True
- mqc.subscribe(therm.in_topic, 0)
- mqc.subscribe(therm.out_topic, 0)
- else:
- logger.warning(f'MQTT connect failed: rc={rc}')
-
-
-def on_disconnect(mqc, therm, rc):
- logger.info(f'MQTT disconnected: rc={rc}')
- therm.connected = False
-
-
-def on_message(mqc, therm, msg):
- logger.debug(f'<< {msg.topic} ' + msg.payload.hex(' '))
-
- if msg.topic == therm.out_topic:
- err = therm.process_message(msg.payload)
- if err:
- logger.warning(f'Cannot parse message ({err}): {msg.payload.hex(" ")}')
-
-
-def on_subscribe(mqc, therm, mid, granted_qos):
- logger.debug(f'MQTT subscribed: mid={mid}, granted={granted_qos}')
-
-
-def on_log(mqc, therm, 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}')
+class BockMQTT:
+
+ def __init__(self, therm: Thermostat):
+ self.therm = therm
+ self.in_topic = f'TSWIFI/I/{therm.ident}'
+ self.out_topic = f'TSWIFI/O/{therm.ident}'
+ self.connected = False
+
+ mqc = mqtt.Client(transport='websockets', client_id=self.gen_client_id())
+ self.mqc = mqc
+ mqc.on_message = self.on_message
+ mqc.on_connect = self.on_connect
+ mqc.on_disconnect = self.on_disconnect
+ mqc.on_subscribe = self.on_subscribe
+ mqc.on_log = self.on_log
+
+ 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 on_connect(self, mqc, userdata, flags, rc):
+ if rc == 0:
+ logger.info('MQTT 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}')
+
+ def on_disconnect(self, mqc, userdata, rc):
+ logger.info(f'MQTT disconnected: rc={rc}')
+ self.connected = False
+
+ def on_message(self, mqc, userdata, msg):
+ logger.debug(f'<< {msg.topic} ' + msg.payload.hex(' '))
+
+ if msg.topic == self.out_topic:
+ err = self.therm.process_message(msg.payload)
+ if err:
+ 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}')
+
+ 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}')
+ def gen_client_id(self):
+ return 'APP_' + "".join(["abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRTUVWXYZ1234567890"[random.randrange(60)] for _ in range(18)])
-def gen_client_id():
- return 'APP_' + "".join(["abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRTUVWXYZ1234567890"[random.randrange(60)] for _ in range(18)])
+ def send_request(self):
+ # Request message sent by the web interface, but with a random message ID
+ request = b'\x10\x0a' + random.randbytes(2) + b'\x00\x24\x20\x01\x00\x00\x20\x02\x00\x00\x20\x03\x00\x00\x20\x06\x00\x00\x20\x07\x00\x00\x20\x05\x00\x00\x20\x09\x00\x00\x20\x0b\x00\x00\x20\x0c\x00\x00'
+ self.mqc.publish('TSWIFI/I/024299', request)
def read_device_config(config_file, device_name):
sys.exit(1)
-def init_therm(config):
- therm = Thermostat()
- therm.ident = str(config['uniqueIdentifier']).rjust(6, '0')
- therm.in_topic = f'TSWIFI/I/{therm.ident}'
- therm.out_topic = f'TSWIFI/O/{therm.ident}'
-
- mqc = mqtt.Client(transport='websockets', client_id=gen_client_id(), userdata=therm)
- mqc.on_message = on_message
- mqc.on_connect = on_connect
- mqc.on_disconnect = on_disconnect
- mqc.on_subscribe = on_subscribe
- mqc.on_log = on_log
-
- 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()
-
- therm.mqc = mqc
- return therm
-
-
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')
logger = logging.getLogger('bocktherm')
-therm = init_therm(config)
+therm = Thermostat(config)
+therm.bock_mqtt = BockMQTT(therm)
+
time.sleep(1)
while True:
- if therm.connected:
+ if therm.bock_mqtt.connected:
logger.debug('Sending request')
- # Request message sent by the web interface, but with a random message ID
- request = b'\x10\x0a' + random.randbytes(2) + b'\x00\x24\x20\x01\x00\x00\x20\x02\x00\x00\x20\x03\x00\x00\x20\x06\x00\x00\x20\x07\x00\x00\x20\x05\x00\x00\x20\x09\x00\x00\x20\x0b\x00\x00\x20\x0c\x00\x00'
- therm.mqc.publish('TSWIFI/I/024299', request)
+ therm.bock_mqtt.send_request()
time.sleep(60)
else:
time.sleep(5)