From 02424085653d11bfdce5d8b2b5694faef1f3d4ef Mon Sep 17 00:00:00 2001 From: DigiH Date: Wed, 19 Jun 2024 14:10:50 +0200 Subject: [PATCH] Tracker Sync Tracker Sync across gateways to avoid intermittent AWAY statuses --- TheengsGateway/__init__.py | 7 +++++ TheengsGateway/ble_gateway.py | 56 +++++++++++++++++++++++------------ TheengsGateway/discovery.py | 11 ++++++- 3 files changed, 54 insertions(+), 20 deletions(-) diff --git a/TheengsGateway/__init__.py b/TheengsGateway/__init__.py index ece2e39..2846a82 100644 --- a/TheengsGateway/__init__.py +++ b/TheengsGateway/__init__.py @@ -19,6 +19,7 @@ """ import sys +import uuid from pathlib import Path from .ble_gateway import run @@ -48,6 +49,12 @@ def main() -> None: if configuration["discovery_topic"].endswith("/sensor"): configuration["discovery_topic"] = configuration["discovery_topic"][:-7] + # Get the MAC address of the gateway. + mac_address = uuid.UUID(int=uuid.getnode()).hex[-12:] + configuration["gateway_id"] = ":".join( + [mac_address[i : i + 2] for i in range(0, 12, 2)] + ).upper() + if not configuration["host"]: sys.exit("MQTT host is not specified") diff --git a/TheengsGateway/ble_gateway.py b/TheengsGateway/ble_gateway.py index 0c8b3dd..94b5c37 100644 --- a/TheengsGateway/ble_gateway.py +++ b/TheengsGateway/ble_gateway.py @@ -151,6 +151,7 @@ def on_connect( retain=True, ) self.subscribe(self.configuration["subscribe_topic"]) + self.subscribe("theengs/internal/#") else: logger.error( "Failed to connect to MQTT broker %s:%d reason code: %s", @@ -226,28 +227,45 @@ def subscribe(self, sub_topic: str) -> None: """Subscribe to MQTT topic .""" def on_message(client, userdata, msg) -> None: # noqa: ANN001,ARG001 - logger.info( - "Received `%s` from `%s` topic", - msg.payload.decode(), - msg.topic, - ) - try: - msg_json = json.loads(msg.payload.decode()) - except (json.JSONDecodeError, UnicodeDecodeError) as exception: - logger.warning( - "Invalid JSON message %s: %s", msg.payload.decode(), exception - ) - return + # Theengs internal + if "theengs/internal/" in msg.topic: + # Evaluate trackersync messages + if msg.topic == "theengs/internal/trackersync": + msg_json = json.loads(msg.payload) + logger.debug("trackersync message: %s", msg_json) + + if ( + msg_json["gatewayid"] != self.configuration["gateway_id"] + and msg_json["tracker"] in self.discovered_trackers + ): + self.discovered_trackers[msg_json["tracker"]].time = 0 + logger.info("Tracker %s disassociated", msg_json["tracker"]) + + logger.info("Discovered Trackers: %s", self.discovered_trackers) - try: - msg_json["id"] = self.rpa2id(msg_json["id"]) - except KeyError: - logger.warning( - "JSON message %s doesn't contain id", msg.payload.decode() + else: + logger.info( + "Received `%s` from `%s` topic", + msg.payload.decode(), + msg.topic, ) - return + try: + msg_json = json.loads(msg.payload.decode()) + except (json.JSONDecodeError, UnicodeDecodeError) as exception: + logger.warning( + "Invalid JSON message %s: %s", msg.payload.decode(), exception + ) + return + + try: + msg_json["id"] = self.rpa2id(msg_json["id"]) + except KeyError: + logger.warning( + "JSON message %s doesn't contain id", msg.payload.decode() + ) + return - self.decode_advertisement(msg_json) + self.decode_advertisement(msg_json) self.client.subscribe(sub_topic) self.client.on_message = on_message diff --git a/TheengsGateway/discovery.py b/TheengsGateway/discovery.py index 69ca8c4..dd3d976 100644 --- a/TheengsGateway/discovery.py +++ b/TheengsGateway/discovery.py @@ -272,8 +272,17 @@ def copy_pub_device(self, device: dict) -> dict: self.discovered_trackers[device["id"]] = TnM( round(time()), device["model_id"] ) - logger.debug("Discovered Trackers: %s", self.discovered_trackers) + # Publish trackersync message + message = json.dumps( + {"gatewayid": self.configuration["gateway_id"], "tracker": device["id"]} + ) + self.publish( + message, + "theengs/internal/trackersync", + ) + + logger.debug("Discovered Trackers: %s", self.discovered_trackers) pub_device_copy = device.copy() # Remove "track" if PUBLISH_ADVDATA is 0 if not self.configuration["publish_advdata"] and "track" in pub_device_copy: