''' Created on 23 janv. 2026 @author: denis ''' import json from threading import Thread, Event from celery import Task from celery.exceptions import Ignore from celery.utils.log import get_task_logger from redis import Redis from django.conf import settings from modules.mqttc import MqttBase as MqttClient RELAY_SUB_TOPIC = "relay/+/#" ZIGBEE_SUB_TOPIC = "zigbee2mqtt/#" class Mqttc: task = None conf = dict( host=settings.MQTT_HOST, port=settings.MQTT_PORT, username=settings.MQTT_USERNAME, password=settings.MQTT_PASSWORD, ca_cert=settings.MQTT_CA_CERT, keepalive=60, topic_base=f"{settings.MQTT_ORIGINE}", topic_subs=[ [RELAY_SUB_TOPIC, 0], #[ZIGBEE_SUB_TOPIC, 0], ] ) logger = get_task_logger(__name__) redis = Redis(host=settings.REDIS_HOST, port=settings.REDIS_PORT, db=0, decode_responses=True) mqttc = Mqttc() class MqttProcess(Task): def __init__(self): super().__init__() self.stop_event = Event() self.mqtt = MqttClient(on_messages=self._on_mqtt_message, **mqttc.conf) def __call__(self, *args, **kwargs): return self.start(*args, **kwargs) def start(self, *args, **kwargs): try: self.mqtt.startMQTT() self.start_redis_subscriber() except Exception as e: logger.error(e) raise Ignore() def stop(self): try: self.stop_event.set() self.mqtt.stopMQTT() logger.info(f"Listening stop.") except Exception as e: logger.error(e) def start_redis_subscriber(self): self.redis_subscriber = Thread(target=self._listen_to_redis, daemon=True) self.redis_subscriber.start() def _on_mqtt_message(self, topic, payload): try: #logger.info(f"---- on_mqtt_message {topic}: {payload}") if topic.startswith(RELAY_SUB_TOPIC[:-3]): uuid = topic.split('/')[1] redis.publish(f'relay_{uuid}', json.dumps({"type": "mqtt", "topic": topic, "payload": payload})) else: redis.publish('mqtt_message', json.dumps({"type": "mqtt", "topic": topic, "payload": payload})) except Exception as e: logger.error(f'on_mqtt_message: {e}') logger.error(topic) logger.error(payload) def _listen_to_redis(self): try: pubsub = redis.pubsub() pubsub.subscribe(f"mqtt_pub") logger.info(f"---- listen mqtt_message via redis") for message in pubsub.listen(): if self.stop_event.is_set(): break data = json.loads(str(message.get('data'))) if not isinstance(data, dict): continue if data.get("type") == "mqtt": self.mqtt._publish_message(data["topic"], **data["payload"]) finally: pubsub.unsubscribe() pubsub.close()