前言
本文介绍了如何使用Python编写一个简单的MQTT发布者和订阅者类来封装MQTT客户端。通过这两个类,我们可以轻松地连接到MQTT服务器并发布/订阅消息到指定主题。封装MQTT客户端可以简化开发过程,使得连接和发布/订阅消息变得更加简单。
一、安装paho-mqtt
pip install paho-mqtt
二、发布封装
import paho.mqtt.client as mqtt
import json
class MQTTPublisher:
"""MQTT发布消息的类"""
def __init__(self, host, port=1883, client_id="", username=None, password=None):
"""
构造函数,用于初始化 MQTT 客户端的连接信息
:param host: str,MQTT 服务器地址
:param port: int,MQTT 服务器端口,默认为1883
:param client_id: str,MQTT 客户端 ID,默认为空
:param username: str,MQTT 服务器用户名(可选)
:param password: str,MQTT 服务器密码(可选)
"""
self.host = host
self.port = port
self.client = mqtt.Client(client_id=client_id)
# 如果提供了用户名和密码,就设置 MQTT 客户端的认证信息
if username and password:
self.client.username_pw_set(username, password)
def on_connect(self, client, userdata, flags, rc):
"""
连接成功回调函数,会在 MQTT 客户端连接成功时被调用
:param client: MQTT 客户端实例
:param userdata: 用户数据
:param flags: 标志位
:param rc: 返回码
- 返回码说明:
* 0:连接成功
* 1:协议版本不正确
* 2:客户端标识符无效
* 3:服务器不可用
* 4:用户名或密码不正确
* 5:未经授权
"""
rc_status = [
"连接成功", "协议版本不正确", "客户端标识符无效", "服务器不可用", "用户名或密码不正确", "未经授权"]
print("connect:", rc_status[rc], rc)
def connect(self):
"""
连接 MQTT 服务器
"""
# 设置连接成功回调函数
self.client.on_connect = self.on_connect
# 连接MQTT服务器,keepalive为60秒
self.client.connect(self.host, self.port, keepalive=60)
# 启动一个单独的线程来处理网络流量和消息接收
self.client.loop_start()
def disconnect(self):
"""
断开 MQTT 服务器连接
"""
self.client.disconnect()
def publish(self, topic, message, qos=0):
"""
发布 MQTT 消息到指定主题
:param topic: MQTT 消息主题
:param message: MQTT 消息内容,需要将其转换成JSON字符串
:param qos: MQTT 消息质量等级,默认为0
- qos说明:
* 0:最多一次,不保证消息能够被接收到
* 1:至少一次,确保消息至少被接收到一次,可能会重复发送
* 2:恰好一次,确保消息只被接收到一次,但可能会增加网络负载
"""
# 连接 MQTT 服务器
self.connect()
# 将消息内容转换成JSON字符串,然后使用'gb2312'编码
message_str = json.dumps(message, ensure_ascii=False).encode('gb2312')
# 发布MQTT消息到指定主题,并指定质量等级
self.client.publish(topic, message_str, qos=qos)
# 停止循环处理网络流量和消息接收
self.client.loop_stop()
if __name__ == "__main__":
# 设置MQTT服务器地址,客户端 ID
publisher = MQTTPublisher("test.mosquitto.org", client_id="my_client_id")
# 发布MQTT消息到指定主题(项目中mqtt协议如果有固定部分,建议封装到publish方法中,传入data即可), 质量等级为1
message = {
"user": "admin",
"password": 123
}
publisher.publish("topic/test", message, 1)
# 主线程结束,子线程会自动断开MQTT连接,如主线程一直运行,需要关闭mqtt连接时,调用disconnect()方法断开连接
publisher.disconnect()
三、订阅封装
import paho.mqtt.client as mqtt
import json
class MQTTSubscriber:
"""MQTT订阅消息的类"""
def __init__(self, host, port=1883, client_id="", username=None, password=None):
"""初始化 MQTT 客户端的连接信息"""
# MQTT 服务器的地址
self.host = host
# MQTT 服务器的端口号,默认为 1883
self.port = port
# 创建一个 MQTT 客户端对象,传入客户端 ID
self.client = mqtt.Client(client_id=client_id)
# 如果提供了用户名和密码,就设置 MQTT 客户端的认证信息
if username and password:
self.client.username_pw_set(username, password)
# 设置自动重连的时间间隔,最小为 1 秒,最大为 120 秒
self.client.reconnect_delay_set(min_delay=1, max_delay=120)
def on_connect(self, client, userdata, flags, rc):
"""连接成功回调函数"""
# 打印连接结果,0 表示成功,其他值表示失败
print("connect:", rc)
# 订阅指定主题的消息,传入主题和消息质量等级
self.client.subscribe(self.topic, self.qos)
def on_message(self, client, userdata, msg):
"""
订阅消息回调函数,当收到订阅的消息时被调用
:param client: MQTT客户端实例
:param userdata: 用户自定义数据
:param msg: 收到的消息对象
"""
try:
# 将消息中的JSON字符串转换为Python字典对象
message = json.loads(msg.payload.decode('gb2312'))
except ValueError:
# 如果无法转换为Python字典对象,则直接使用字符串格式
message = msg.payload.decode('gb2312')
# 打印收到的消息的主题和内容
print(f"主题: {msg.topic} 消息: {message}")
def subscribe(self, topic, qos=0):
"""连接 MQTT 服务器,并订阅消息"""
# 订阅的主题
self.topic = topic
# 消息质量等级
self.qos = qos
# 设置连接成功回调函数
self.client.on_connect = self.on_connect
# 设置订阅消息回调函数
self.client.on_message = self.on_message
# 连接MQTT服务器,keepalive为60秒,表示每隔60秒发送一次心跳包
self.client.connect(self.host, self.port, keepalive=60)
# 使用loop_forever()方法保持连接并接收消息,直到断开连接或出现异常
self.client.loop_forever()
if __name__ == "__main__":
# 设置MQTT服务器地址,客户端 ID
subscriber = MQTTSubscriber("test.mosquitto.org", client_id="my_client_id")
# 连接MQTT服务器,并订阅消息,传入主题和消息质量等级
subscriber.subscribe(topic="topic/test", qos=1)
四、获取订阅的数据
- mqtt_subscriber.py
import paho.mqtt.client as mqtt
import json
class MQTTSubscriber:
"""MQTT订阅消息的类"""
def __init__(self, host, port=1883, client_id="", username=None, password=None):
"""初始化 MQTT 客户端的连接信息"""
# MQTT 服务器的地址
self.host = host
# MQTT 服务器的端口号,默认为 1883
self.port = port
# 创建一个 MQTT 客户端对象,传入客户端 ID
self.client = mqtt.Client(client_id=client_id)
# 如果提供了用户名和密码,就设置 MQTT 客户端的认证信息
if username and password:
self.client.username_pw_set(username, password)
# 设置自动重连的时间间隔,最小为 1 秒,最大为 120 秒
self.client.reconnect_delay_set(min_delay=1, max_delay=120)
# 初始化消息
self.message = None
def on_connect(self, client, userdata, flags, rc):
"""连接成功回调函数"""
# 打印连接结果,0 表示成功,其他值表示失败
print("connect:", rc)
# 订阅指定主题的消息,传入主题和消息质量等级
self.client.subscribe(self.topic, self.qos)
def on_message(self, client, userdata, msg):
"""订阅消息回调函数,当收到订阅的消息时被调用"""
try:
# 将消息中的JSON字符串转换为Python字典对象
self.message = json.loads(msg.payload.decode('gb2312'))
except ValueError:
# 如果无法转换为Python字典对象,则直接使用字符串格式
self.message = msg.payload.decode('gb2312')
# 打印收到的消息的主题和内容
print(f"主题: {msg.topic} 消息: {self.message}")
def get_message(self):
"""获取最新的消息"""
return self.message
def subscribe(self, topic, qos=0):
"""连接 MQTT 服务器,并订阅消息"""
# 订阅的主题
self.topic = topic
# 消息质量等级
self.qos = qos
# 设置连接成功回调函数
self.client.on_connect = self.on_connect
# 设置订阅消息回调函数
self.client.on_message = self.on_message
# 连接MQTT服务器,keepalive为60秒,表示每隔60秒发送一次心跳包
self.client.connect(self.host, self.port, keepalive=60)
# 启动一个新的线程来处理网络交互
self.client.loop_start()
def disconnect(self):
"""断开 MQTT 服务器连接"""
# 断开连接
self.client.disconnect()
# 停止线程
self.client.loop_stop()
from mqtt_publisher import MQTTPublisher
from mqtt_subscriber import MQTTSubscriber
import time
# 订阅消息
subscriber = MQTTSubscriber("test.mosquitto.org", client_id="my_client_id")
subscriber.subscribe(topic="topic/test", qos=1)
# 发布消息
publisher = MQTTPublisher("test.mosquitto.org", client_id="my_client_id_1")
publisher.publish("topic/test", "I posted a message", 1)
# 等待3秒以确保消息被接收
time.sleep(3)
# 获取最新的消息
message = subscriber.get_message()
print(message)