Files
net-server/endpoint/mqtt_client.py
2025-10-27 19:05:54 +08:00

137 lines
4.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import paho.mqtt.client as mqtt
import uuid
from config.logger_config import logger
from config.setting import settings
class MQTTClient:
def __init__(self):
self.broker_host = settings.mqtt_host
self.broker_port = settings.mqtt_port
self.client_id = self.generate_client_id()
self.client = mqtt.Client(client_id=self.client_id)
# 注册回调函数
self.client.on_connect = self._on_connect
self.client.on_disconnect = self._on_disconnect
self.client.on_message = self._on_message
# 存储消息处理器的字典,键为主题,值为处理函数
self.message_handlers = {}
self.connected = False
def _on_connect(self, client, userdata, flags, rc):
"""连接回调函数"""
self.connected = rc == 0
if self.connected:
logger.info(f"成功连接到MQTT broker {self.broker_host}:{self.broker_port}")
else:
logger.error(f"连接MQTT broker失败错误代码: {rc}")
def _on_disconnect(self, client, userdata, rc):
"""断开连接回调函数"""
self.connected = False
if rc != 0:
logger.warning(f"意外断开与MQTT broker的连接错误代码: {rc}")
else:
logger.info("已与MQTT broker断开连接")
def _on_message(self, client, userdata, msg):
"""消息接收回调函数"""
logger.info(f"收到消息: {msg.topic}")
try:
if msg.topic in self.message_handlers:
self.message_handlers[msg.topic](client, msg)
else:
logger.warning(f"未找到 {msg.topic} 的消息处理器")
except Exception as e:
logger.error(f"处理消息时出错: {str(e)}", exc_info=True)
@staticmethod
def generate_client_id(prefix: str = "client") -> str:
"""生成唯一客户端ID"""
uuid_str = str(uuid.uuid4()).split('-')[0]
return f"{prefix}-{uuid_str}"
def add_message_handler(self, topic, handler):
"""添加消息处理器"""
if topic in self.message_handlers:
logger.warning(f"主题 {topic} 已存在处理器,将被覆盖")
self.message_handlers[topic] = handler
logger.info(f"为主题 {topic} 注册了消息处理器")
logger.debug(f"当前消息处理器: {self.message_handlers.keys()}")
def connect(self):
"""连接到MQTT服务器"""
try:
self.client.connect(self.broker_host, self.broker_port)
self.start_loop()
return True
except Exception as e:
logger.error(f"连接MQTT broker {self.broker_host}:{self.broker_port}时发生错误: {str(e)}", exc_info=True)
return False
def disconnect(self):
"""断开与MQTT服务器的连接"""
try:
self.stop_loop()
self.client.disconnect()
logger.info("正在断开与MQTT broker的连接")
except Exception as e:
logger.error(f"断开连接时发生错误: {str(e)}", exc_info=True)
def subscribe(self, topic, qos=0):
"""订阅主题"""
try:
result, mid = self.client.subscribe(topic, qos)
if result == mqtt.MQTT_ERR_SUCCESS:
logger.info(f"已订阅主题: {topic} (QoS: {qos})")
return True
else:
logger.error(f"订阅主题 {topic} 失败,错误代码: {result}")
return False
except Exception as e:
logger.error(f"订阅主题时发生错误: {str(e)}", exc_info=True)
return False
def publish(self, topic, payload, qos=0, retain=False):
"""发布消息到指定主题"""
if not self.connected:
logger.warning("未连接到MQTT broker无法发布消息")
return False
try:
result = self.client.publish(topic, payload, qos, retain)
result.wait_for_publish()
if result.rc == mqtt.MQTT_ERR_SUCCESS:
logger.debug(f"已发布消息到主题 {topic}: {payload}")
return True
else:
logger.error(f"发布消息到主题 {topic} 失败,错误代码: {result.rc}")
return False
except Exception as e:
logger.error(f"发布消息时发生错误: {str(e)}", exc_info=True)
return False
def start_loop(self):
"""启动MQTT网络循环"""
try:
self.client.loop_start()
logger.info("已启动MQTT网络循环")
except Exception as e:
logger.error(f"启动网络循环时发生错误: {str(e)}", exc_info=True)
def stop_loop(self):
"""停止MQTT网络循环"""
try:
self.client.loop_stop()
logger.info("已停止MQTT网络循环")
except Exception as e:
logger.error(f"停止网络循环时发生错误: {str(e)}", exc_info=True)
mqtt_client = MQTTClient()