110 lines
3.0 KiB
Python
110 lines
3.0 KiB
Python
'''
|
|
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()
|
|
|