diff --git a/handler.py b/handler.py index 8362545..b099e96 100644 --- a/handler.py +++ b/handler.py @@ -2,6 +2,8 @@ import aiomqtt import asyncio import inspect import paho +import signal +from dataclasses import dataclass from command import ( Command, @@ -11,20 +13,43 @@ from command import ( ) +@dataclass +class MQTTConfig: + host: str + port: int = 1883 + username: str | None = None + password: str | None = None + keepalive: int = 60 + + class MQTTHandler: def __init__( self, - mqtt_client: aiomqtt.Client, + mqtt_config: MQTTConfig, handler_id: str, ): self.handler_id = handler_id - self.mqtt_client = mqtt_client + self.mqtt_config = mqtt_config self.topic_base = f"asset/{handler_id}" + self.status_topic = f"{self.topic_base}/status" self.command_topic = f"{self.topic_base}/command" self.property_topic = f"{self.topic_base}/property" + self._shutdown_event = asyncio.Event() + will = aiomqtt.Will( + topic=self.status_topic, payload="OFFLINE", qos=1, retain=True + ) + + self.mqtt_client = aiomqtt.Client( + self.mqtt_config.host, + port=self.mqtt_config.port, + identifier=handler_id, + protocol=paho.mqtt.client.MQTTv5, + will=will, + ) + def get_available_commands(self): commands = {} for base in self.__class__.__mro__: @@ -93,6 +118,14 @@ class MQTTHandler: command_name = topic.removeprefix(f"{self.command_topic}/") await self.execute_command(command_name, payload, message.properties) + async def shutdown_watcher(self): + await self._shutdown_event.wait() + await self.mqtt_client.publish(self.status_topic, "OFFLINE", qos=1, retain=True) + + def stop(self): + self._shutdown_event.set() + signal.signal(signal.SIGINT, signal.SIG_DFL) + async def run(self): INTERVAL = 5 while True: @@ -101,7 +134,12 @@ class MQTTHandler: await client.subscribe(f"{self.command_topic}/+") await self.publish_commands() - tasks = [self.mqtt_command_writer_task()] + # announce that we are online + await client.publish( + self.status_topic, "ONLINE", qos=1, retain=True + ) + + tasks = [self.mqtt_command_writer_task(), self.shutdown_watcher()] # Inspect instance methods for attr_name in dir(self): diff --git a/main.py b/main.py index ea7bf12..3be8907 100755 --- a/main.py +++ b/main.py @@ -4,26 +4,18 @@ import aiomqtt import aioserial import asyncio import paho -import uuid import socket +import signal from ubxhandler import UBXHandler +from handler import MQTTConfig BAUD = 115200 async def main(): handler_id = f"example-gps-{socket.gethostname()}" - mqtt_host = "127.0.0.1" - mqtt_port = 1883 - - client_id = f"{handler_id}-{uuid.uuid4()}" - mqtt_client = aiomqtt.Client( - mqtt_host, - port=mqtt_port, - identifier=client_id, - protocol=paho.mqtt.client.MQTTv5, - ) + mqtt_config = MQTTConfig(host="127.0.0.1", port=1883) serial_port = aioserial.AioSerial( port="/tmp/ttyV0", @@ -31,7 +23,9 @@ async def main(): timeout=0.05, # 50 ms ) - handler = UBXHandler(mqtt_client, handler_id, serial_port) + handler = UBXHandler(mqtt_config, handler_id, serial_port) + + signal.signal(signal.SIGINT, lambda signum, frame: handler.stop()) await handler.run()