Files
Kivy_APP/mqtt_device.py
2025-07-25 08:08:11 +08:00

219 lines
8.4 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 threading
import time
import string
from threading import Thread
import menu_utils as utils
import paho.mqtt.client as mqtt
from print_color import *
#mqtt 消息处理基类, mqtt消息处理
class class_comm_mqtt_interface :
def __init__(self, name = "mqtt handler"):
self.name = name
def on_message(self, mqtt_thread, topic, message) :
return
def on_connect(self, mqtt_thread, userdata, flags, rc) :
return
#mqtt服务器连接处理
def mqtt_on_connect(client, userdata, flags, rc):
if rc == 0:
# 连接成功
print_normal_msg("Mqtt 服务器连接成功")
elif rc == 1:
# 协议版本错误
print_error_msg("协议版本错误")
elif rc == 2:
# 无效的客户端标识
print_error_msg("无效的客户端标识")
elif rc == 3:
# 服务器无法使用
print_error_msg("Mqtt 服务器无法使用")
elif rc == 4:
# 错误的用户名或密码
print_error_msg("错误的用户名或密码")
elif rc == 5:
# 未经授权
print_error_msg("未经授权")
#获取线程类 class_comm_mqtt_thread)
mqtt_thread : class_comm_mqtt_thread= userdata
unique_object : class_comm_mqtt_interface = None
#遍历所有unique_object, 通知其 on_connect 事件
for unique_object in mqtt_thread.unique_object_dict.values() :
if isinstance(unique_object, list) : #unique_object 可能是列表, 所以需要遍历
for each_object in unique_object:
if hasattr(each_object, "on_connect") :
each_object.on_connect(mqtt_thread, userdata, flags, rc)
elif hasattr(unique_object, "on_connect") :
unique_object.on_connect(mqtt_thread, userdata, flags, rc)
#mqtt接收到主题, 通过主题中包含的 unique_name, 定位到 uniuqe_object, 并调用 unique_object.on_message 函数
def mqtt_on_message(client, userdata, message):
#print("mqtt message:", message.topic, message.payload.decode("utf-8"))
#获取线程类 class_comm_mqtt_thread)
mqtt_thread : class_comm_mqtt_thread= userdata
unique_object : class_comm_mqtt_interface = None
for unique_name, search_unique_object in mqtt_thread.unique_object_dict.items() :
if unique_name in message.topic :
unique_object = search_unique_object
break
#mqtt线程本身无法处理对应的主题消息, 由mqtt 所对应的unique_object处理
if unique_object != None :
if isinstance(unique_object, list) : #unique_object 可能是列表, 所以需要遍历
for each_object in unique_object:
if hasattr(each_object, "on_message") :
each_object.on_message(mqtt_thread, message.topic, message.payload)
elif hasattr(unique_object, "on_message") :
unique_object.on_message(mqtt_thread, message.topic, message.payload)
class class_comm_mqtt_thread(Thread):
def __init__(self, user_name = "admin", password = "admin") :
Thread.__init__(self)
self.client = None
self.subscribe_list = []
self.publish_list = []
self.publish_list_lock = threading.Lock()
self.condition = threading.Condition()
self.stop_request = False
self.server = "127.0.0.1"
self.port = 1883
self.user_name = user_name
self.password = password
self.keepalive = 60
self.unique_object_dict = {} #key = unique_name, value = device_object
return
#unique_object: 为unique_object_subscribe_name对应的object, 在回调
def add_unique_object(self, unique_name : string, unique_object : class_comm_mqtt_interface) :
self.unique_object_dict[unique_name] = unique_object
#topic 中 需要包含
def subscribe(self, topic : string) :
if self.is_connect() and self.client:
if topic not in self.subscribe_list :
self.subscribe_list.append(topic)
self.client.subscribe(topic)
def set_mqtt_server(self, server = "127.0.0.1", port = 1883, keep_alive = 60.0, user_name = "admin", password = "admin") :
self.server = server
self.port = port
self.user_name = user_name
self.password = password
self.keepalive = keep_alive
#用于判断 mqtt_thread是否已经连接
def is_connect(self) :
if self.client == None :
return False
return self.client.is_connected()
def open(self):
try :
self.client = mqtt.Client()
self.client.user_data_set(self)
self.client.on_connect = mqtt_on_connect
self.client.on_message = mqtt_on_message
self.client.username_pw_set(self.user_name, self.password)
self.client.connect(self.server, self.port, self.keepalive)
except Exception as e :
print_error_msg(str(e) + "mqtt_server: ip=%s, port = %d"%(self.server, self.port))
if self.client: # 如果self.client已经被初始化了则断开连接
self.client.disconnect()
self.client = None
return None # 添加返回语句,告知调用者连接失败
return self.client
def close(self):
self.stop_request = True
def publish(self, topic, message) :
if self.is_connect :
self.publish_list_lock.acquire()
self.publish_list.append([topic, message])
self.publish_list_lock.release()
self.condition.acquire()
self.condition.notify()
self.condition.release()
return
def publish_wait(self, topic, message, timeout) :
if self.is_connect :
self.publish_list_lock.acquire()
self.publish_list.insert(0, [topic, message])
self.publish_list_lock.release()
self.condition.acquire()
self.condition.notify()
self.condition.release()
return
def run(self):
while self.stop_request == False :
print_warning_msg("mqtt 线程启动, 服务器端口:server = %s:%d"%(self.server, self.port))
wait_open_timeout = 0
self.subscribe_list = [] #取消订阅列表, 连接后重新订阅
while self.client == None and self.stop_request == False:
if wait_open_timeout == 0 :
print_warning_msg("mqtt连接中, 服务器端口:server = %s:%d"%(self.server, self.port))
self.open()
if self.client == None :
time.sleep(0.1)
wait_open_timeout += 0.1
if wait_open_timeout >= 5.0 :
wait_open_timeout = 0
time.sleep(0.2)
if self.client :
self.client.loop_start()
time.sleep(0.2)
while self.stop_request == False and self.client.is_connected() :
topic = None
topic_message = None
self.publish_list_lock.acquire()
if len(self.publish_list) > 0 :
topic_message = self.publish_list.pop(0)
topic = topic_message[0]
message = topic_message[1]
self.publish_list_lock.release()
if topic != None and message != None :
self.client.publish(topic, message)
self.condition.acquire()
if len(self.publish_list) == 0:
self.condition.wait(timeout = 0.1)
self.condition.release()
self.client.loop_stop()
self.client.disconnect()
self.client = None
print_warning_msg("mqtt连接断开, 准备重启mqtt连接")
print_error_msg("mqtt 线程停止")
if __name__ == "__main__":
object_mqtt1 = class_comm_mqtt_interface("object1 handler")
object_mqtt2 = class_comm_mqtt_interface("object2 handler")
global_mqtt_thread = class_comm_mqtt_thread()
global_mqtt_thread.set_mqtt_server(server = "127.0.0.1", port = 1883, keep_alive = 60, user_name="admin", password="admin")
global_mqtt_thread.add_unique_object("object1", object_mqtt1)
global_mqtt_thread.add_unique_object("object2", object_mqtt2)
global_mqtt_thread.start()