From c8a917b0f9f773582b0af0c1091f8f770bac361e Mon Sep 17 00:00:00 2001 From: 3ll3d00d Date: Tue, 26 Dec 2023 10:04:03 +0000 Subject: [PATCH] change to use state/availability/attributes topics --- cmdserver/mqtt.py | 23 ++++++++++++++++++---- cmdserver/pjcontroller.py | 38 +++++++++++++++++++++---------------- cmdserver/tivocontroller.py | 9 ++++++--- pyproject.toml | 2 +- 4 files changed, 48 insertions(+), 24 deletions(-) diff --git a/cmdserver/mqtt.py b/cmdserver/mqtt.py index 2025875..dc9af88 100644 --- a/cmdserver/mqtt.py +++ b/cmdserver/mqtt.py @@ -1,3 +1,4 @@ +import atexit import logging import paho.mqtt.client as mqtt @@ -7,8 +8,11 @@ class MQTT: def __init__(self, ip: str, port: int = 1883, user: str = None, cred: str = None): - logger.info(f'Initialising MQTT client {ip}:{port}') - self.__client = mqtt.Client(client_id='cmdserver') + import socket + hostname = socket.gethostname() + client_id = f'cmdserver-{hostname}' + logger.info(f'Initialising MQTT client {client_id} to {ip}:{port}') + self.__client = mqtt.Client(client_id=client_id) self.__client.on_connect = self.__on_connect self.__client.on_message = self.__on_message self.__client.on_disconnect = self.__on_disconnect @@ -16,8 +20,13 @@ def __init__(self, ip: str, port: int = 1883, user: str = None, cred: str = None self.__client.username_pw_set(user, password=cred) self.__client.enable_logger(logger) self.__client.connect_async(ip, port, 60) - from twisted.internet import reactor - reactor.callInThread(lambda: self.__client.loop_forever(timeout=5)) + self.__client.loop_start() + import atexit + atexit.register(self.shutdown) + + def shutdown(self): + logger.info('Shutting down MQTT client') + self.__client.loop_stop(force=True) def __on_connect(self, client, userdata, flags, rc): logger.info(f'Connected to MQTT [result: {rc}]') @@ -31,3 +40,9 @@ def __on_disconnect(self, client, userdata, rc): def publish(self, source: str, payload): logger.info(f'Publishing {source} -- {payload}') self.__client.publish(f'cmdserver/{source}', qos=2, payload=payload) + + def online(self, source: str): + self.publish(f'{source}/available', 'online') + + def offline(self, source: str): + self.publish(f'{source}/available', 'offline') diff --git a/cmdserver/pjcontroller.py b/cmdserver/pjcontroller.py index 1cf4790..ca20b93 100644 --- a/cmdserver/pjcontroller.py +++ b/cmdserver/pjcontroller.py @@ -42,21 +42,28 @@ def __update_state(self): try: self.__connect() power = self.__executor.get(cmd) - cmd = Command.Anamorphic - ana = self.__executor.get(cmd) - cmd = Command.PictureMode - pic = self.__executor.get(cmd) - cmd = Command.InstallationMode - install = self.__executor.get(cmd) - self.__state = { - 'powerState': power.name, - 'anamorphicMode': ana.name, - 'installationMode': install.name, - 'pictureMode': pic.name, - 'power': power == PowerState.LampOn, - 'hdr': pic == PictureMode.User5, - 'anamorphic': 'A' if ana == Anamorphic.A else 'B' if install == InstallationMode.TWO else None - } + if power == PowerState.LampOn: + cmd = Command.Anamorphic + ana = self.__executor.get(cmd) + cmd = Command.PictureMode + pic = self.__executor.get(cmd) + cmd = Command.InstallationMode + install = self.__executor.get(cmd) + self.__state = { + 'powerState': power.name, + 'anamorphicMode': ana.name, + 'installationMode': install.name, + 'pictureMode': pic.name, + 'power': power == PowerState.LampOn, + 'hdr': pic == PictureMode.User5, + 'anamorphic': 'A' if ana == Anamorphic.A else 'B' if install == InstallationMode.TWO else None + } + self.__mqtt.online('pj') + self.__mqtt.publish('pj/state', power.name) + self.__mqtt.publish('pj/attributes', json.dumps(self.__state)) + else: + self.__state = {**self.__state, 'powerState': power.name} + self.__mqtt.offline('pj') updated = True self.__disconnect() except CommandNack: @@ -64,7 +71,6 @@ def __update_state(self): except: logger.exception(f"Unexpected failure while executing cmd: {cmd}") return -1 - self.__mqtt.publish('pj', json.dumps(self.__state)) from twisted.internet import reactor reactor.callLater(0.5 if not updated else 30, self.__update_state) diff --git a/cmdserver/tivocontroller.py b/cmdserver/tivocontroller.py index e847f2b..219cd65 100644 --- a/cmdserver/tivocontroller.py +++ b/cmdserver/tivocontroller.py @@ -394,6 +394,8 @@ def __connect(self): self.__sock.settimeout(5) self.__sock.connect((self.address, self.port)) self.__sock.settimeout(None) + if self.__mqtt: + self.__mqtt.online(f'tivo/{self.name}') self.__status_thread = threading.Thread(name='TivoStatusReader', target=self.__read_from_socket, daemon=True) self.__status_thread.start() @@ -409,6 +411,8 @@ def disconnect(self): self.__sock = None else: logger.info(f"Ignoring disconnect {self.name} has no socket") + if self.__mqtt: + self.__mqtt.offline(f'tivo/{self.name}') def __send(self, message): """ The core output function. Re-connect if necessary, send message, sleep, and check for errors. """ @@ -498,9 +502,8 @@ def __read_from_socket(self): else: self.current_channel_num = -1 if last_ch != self.current_channel and self.__mqtt: - import json - self.__mqtt.publish(f'tivo/{self.name}', - json.dumps({'num': self.current_channel_num, 'name': self.current_channel})) + ch_name = CHANNELS.get(str(self.current_channel_num), 'Unknown') + self.__mqtt.publish(f'tivo/{self.name}/state', ch_name) logger.info(f"[{self.name}] Exiting status reader") @property diff --git a/pyproject.toml b/pyproject.toml index 56701d3..05c9230 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "ezmote-cmdserver" -version = "1.1.2" +version = "1.1.3" description = "A small webapp which can be used for web based home cinema automation" authors = ["3ll3d00d "] license = "MIT"