MicroPython保姆级教程:umqtt.simple/robust 库对比, 改造更稳定的 MQTT 客户端
这里,我们使用了 pypi(Python Package Index)共享 Python 软件包平台上两个 MicroPython 环境中用于实现 MQTT 协议的库:micropython-umqtt.simple 和 micropython-umqtt.robust,它们为 MicroPython 提供了 MQTT 协议的客 + 户端功能,但在设计目标和特性上有所不同:
-
micropython-umqtt.simple:是一个简单的MQTT客户端库,专为MicroPython环境设计,基于原始的MQTT协议进行实现,它实现了MQTT协议的基本功能,适用于资源有限的设备。- 提供基本的
MQTT客户端功能,包括连接到MQTT代理、发布消息和订阅主题 - 适合资源有限的嵌入式设备,不包含额外的复杂功能或冗余代码
- 支持
MQTT 3.1.1协议版本的核心功能,如连接、发布、订阅和消息接收
其地址为:https://pypi.org/project/micropython-umqtt.simple/#description。
- 提供基本的

-
micropython-umqtt.robust:是基于micropython-umqtt.simple的一个扩展版本,旨在增强 MQTT 客户端在不稳定网络条件下的鲁棒性,它解决了在umqtt.simple中可能遇到的一些问题,如网络中断和重新连接的处理。-
增强了对不稳定网络的支持,提供了更强的错误处理和重新连接机制
-
具有详细的日志功能,可以帮助调试和监控 MQTT 客户端的状态
-
内置了自动重连功能,以应对网络中断或连接丢失的情况
其地址为:https://pypi.org/project/micropython-umqtt.robust/。![2.png]()
-
micropython-umqtt.simple 代码如下:
# Python env : MicroPython v1.23.0 on Wiznet W5500
# -*- coding: utf-8 -*-
# @Time : 2024/8/9 上午11:01
# @Author : 李清水
# @File : umqttsimple.py
# @Description : 实现一个简单的MQTT客户端类
# ======================================== 导入相关模块 ========================================
# 导入用于网络连接的模块
import usocket as socket
# 导入用于处理字节流和二进制数据的模块
import ustruct as struct
# 导入用于进制转换的模块
from ubinascii import hexlify
# 导入时间相关的模块
import time
# ======================================== 全局变量 ============================================
# ======================================== 功能函数 ============================================
# ======================================== 自定义类 ============================================
# 定义一个 MQTT 异常类,用于处理 MQTT 操作中的错误
class MQTTException(Exception):
'''
自定义 MQTT 异常类,用于处理 MQTT 协议操作中的错误。
该类继承自 Python 内置的 Exception 类,用于在 MQTT 客户端操作中抛出特定错误。
'''
pass
# 定义一个 MQTT 客户端类,用于实现 MQTT 协议的基本操作
class MQTTClient:
"""
MQTTClient 类,用于实现 MQTT 协议的基本操作,包括连接服务器、发布消息、订阅主题、处理消息等。
该类封装了 MQTT 协议的客户端功能,支持与 MQTT 服务器进行通信,并提供了消息发布、订阅、遗嘱消息设置等功能。
支持 SSL/TLS 加密连接,并允许设置心跳时间、用户名和密码等参数。
Attributes:
client_id (int): 客户端 ID,用于标识客户端。
server (str): MQTT 服务器地址。
port (int): MQTT 服务器端口,默认为 0(自动选择默认端口)。
user (str): 用户名,默认为 None。
password (str): 密码,默认为 None。
keepalive (int): 心跳时间,默认为 0。
ssl (bool): 是否使用 SSL/TLS 加密连接,默认为 False。
ssl_params (dict): SSL/TLS 参数,默认为空字典。
sock (socket): 客户端与服务器通信的套接字。
pid (int): 报文 ID,用于标识 MQTT 报文。
cb (callable): 消息回调函数,用于处理接收到的消息。
lw_topic (str): 遗嘱消息的主题,默认为 None。
lw_msg (str): 遗嘱消息的内容,默认为 None。
lw_qos (int): 遗嘱消息的 QoS 级别,默认为 0。
lw_retain (bool): 遗嘱消息是否保留,默认为 False。
Methods:
__init__(self, client_id, server, port=0, user=None, password=None, keepalive=0, ssl=False, ssl_params={}):
初始化 MQTTClient 类实例。
_send_str(self, s):
发送字符串数据到服务器。
_recv_len(self):
接收可变长度整数,用于解析 MQTT 报文的长度字段。
set_callback(self, f):
设置消息回调函数。
set_last_will(self, topic, msg, retain=False, qos=0):
设置遗嘱消息。
connect(self, clean_session=True):
连接到 MQTT 服务器。
disconnect(self):
断开与 MQTT 服务器的连接。
ping(self):
发送心跳请求(PINGREQ)。
publish(self, topic, msg, retain=False, qos=0):
发布消息到指定主题。
subscribe(self, topic, qos=0):
订阅指定主题。
wait_msg(self):
等待并处理单个传入的 MQTT 消息。
check_msg(self):
检查是否有来自服务器的挂起消息。
"""
def __init__(self, client_id: int, server: str, port: int = 0, user: str = None, password: str = None,
keepalive: int = 0, ssl: bool = False, ssl_params: dict = {}) -> None:
'''
初始化 MQTT 客户端类
Args:
client_id (int): 客户端 ID
server (str): 服务器地址
port (int): 服务器端口,默认为 0(自动选择默认端口)
user (str): 用户名,默认为 None
password (str): 密码,默认为 None
keepalive (int): 心跳时间,默认为 0
ssl (bool): 是否使用 SSL,默认为 False
ssl_params (dict): SSL 参数,默认为空字典
Returns:
None
'''
# 如果未指定端口,则使用默认端口
if port == 0:
# 如果使用 SSL,则使用端口 8883,否则使用 1883
port = 8883 if ssl else 1883
self.client_id = client_id
# 初始化套接字为 None
self.sock = None
self.server = server
self.port = port
self.ssl = ssl
self.ssl_params = ssl_params
# 初始化报文 ID 为 0
self.pid = 0
# 初始化回调函数为 None
self.cb = None
self.user = user
self.pswd = password
self.keepalive = keepalive
# 初始化遗嘱主题为 None
self.lw_topic = None
# 初始化遗嘱消息为 None
self.lw_msg = None
# 初始化遗嘱 QoS 为 0
self.lw_qos = 0
# 初始化遗嘱消息不保留
self.lw_retain = False
# 发送字符串数据
def _send_str(self, s: str) -> None:
'''
发送字符串数据
Args:
s (str): 待发送的字符串
Returns:
None
'''
# 发送字符串长度
self.sock.write(struct.pack("!H", len(s)))
# 发送字符串内容
self.sock.write(s)
# 接收可变长度整数,用于 MQTT 报文的长度字段
def _recv_len(self) -> int:
'''
接收可变长度整数,用于 MQTT 报文的长度字段
Returns:
int: 接收到的长度
'''
# 初始化长度为 0
n = 0
# 初始化移位量为 0
sh = 0
# 循环接收字节
while True:
# 读取一个字节
b = self.sock.read(1)[0]
# 解析字节的低 7 位
n |= (b & 0x7F) << sh
# 如果最高位为 0,表示结束
if not b & 0x80:
# 返回接收到的长度
return n
# 否则,继续读取下一个字节
sh += 7
# 设置消息回调函数
def set_callback(self, f: callable) -> None:
'''
设置消息回调函数
Args:
f (callable): 回调函数
Returns:
None
'''
# 保存回调函数
self.cb = f
# 设置遗嘱消息
def set_last_will(self, topic: str, msg: str, retain: bool = False, qos: int = 0) -> None:
'''
设置遗嘱消息
Args:
topic (str): 主题
msg (str): 消息
retain (bool): 是否保留,默认为 False
qos (int): QoS 质量,默认为 0
Returns:
None
Raises:
AssertionError: 如果 QoS 不在有效范围内或主题为空
'''
# 验证 QoS 是否在有效范围内
assert 0 <= qos <= 2
# 验证主题是否存在
assert topic
self.lw_topic = topic
self.lw_msg = msg
self.lw_qos = qos
self.lw_retain = retain
# 连接到 MQTT 服务器
def connect(self, clean_session: bool = True) -> int:
'''
连接到 MQTT 服务器
Args:
clean_session (bool): 是否清除会话,默认为 True
Returns:
int: 连接结果
Raises:
MQTTException: 如果连接失败
'''
# 创建套接字
self.sock = socket.socket()
# 获取服务器地址信息
addr = socket.getaddrinfo(self.server, self.port)[0][-1]
# 连接到服务器
self.sock.connect(addr)
# 如果使用 SSL
if self.ssl:
# 导入 SSL 模块
import ussl
# 包装套接字为 SSL
self.sock = ussl.wrap_socket(self.sock, **self.ssl_params)
# 创建固定头的字节数组
premsg = bytearray(b"\x10\0\0\0\0\0")
# 创建可变头和有效载荷的字节数组
msg = bytearray(b"\x04MQTT\x04\x02\0\0")
# 计算消息的总长度
sz = 10 + 2 + len(self.client_id)
# 设置清除会话标志
msg[6] = clean_session << 1
# 如果使用用户名和密码
if self.user is not None:
# 更新消息长度
sz += 2 + len(self.user) + 2 + len(self.pswd)
# 设置用户名和密码标志
msg[6] |= 0xC0
# 如果设置了保活时间
if self.keepalive: # 如果设置了保活时间
# 验证保活时间是否在有效范围内
assert self.keepalive < 65536
# 设置保活时间的高位
msg[7] |= self.keepalive >> 8
# 设置保活时间的低位
msg[8] |= self.keepalive & 0x00FF
# 如果设置了遗嘱消息
if self.lw_topic:
# 更新消息长度
sz += 2 + len(self.lw_topic) + 2 + len(self.lw_msg)
# 设置遗嘱 QoS
msg[6] |= 0x4 | (self.lw_qos & 0x1) << 3 | (self.lw_qos & 0x2) << 3
# 设置遗嘱消息保留标志
msg[6] |= self.lw_retain << 5
# 初始化长度字段的字节数
i = 1
# 如果长度超过 7 位
while sz > 0x7F:
# 继续处理长度字段
premsg[i] = (sz & 0x7F) | 0x80
# 移位处理
sz >>= 7
# 增加字节数
i += 1
# 设置最后一个字节的长度
premsg[i] = sz
# 发送固定头
self.sock.write(premsg, i + 2)
# 发送可变头和有效载荷
self.sock.write(msg)
# 发送客户端 ID
self._send_str(self.client_id)
# 如果设置了遗嘱消息
if self.lw_topic:
# 发送遗嘱主题
self._send_str(self.lw_topic)
# 发送遗嘱消息
self._send_str(self.lw_msg)
# 如果使用用户名和密码
if self.user is not None:
# 发送用户名
self._send_str(self.user)
# 发送密码
self._send_str(self.pswd)
# 读取服务器响应
resp = self.sock.read(4)
# 验证连接确认报文
assert resp[0] == 0x20 and resp[1] == 0x02
# 如果连接失败
if resp[3] != 0:
# 抛出异常
raise MQTTException(resp[3])
# 返回连接结果
return resp[2] & 1
# 断开与 MQTT 服务器的连接
def disconnect(self) -> None:
'''
断开与 MQTT 服务器的连接
Returns:
None
'''
# 发送断开连接报文
self.sock.write(b"\xe0\0")
# 关闭套接字
self.sock.close()
# 发送心跳请求(PINGREQ)
def ping(self) -> None:
'''
发送心跳请求(PINGREQ)
Returns:
None
'''
self.sock.write(b"\xc0\0")
# 发布消息
def publish(self, topic: str, msg: str, retain: bool = False, qos: int = 0) -> None:
'''
发布消息
Args:
topic (str): 主题
msg (str): 消息
retain (bool): 是否保留,默认为 False
qos (int): 服务质量级别 (0, 1, 2),默认为 0
Returns:
None
Raises:
AssertionError: 如果消息大小超过 MQTT 协议限制
'''
# 创建 MQTT 发布数据包的基本结构,默认设置 QoS 为 0,retain 标志为 False
pkt = bytearray(b"\x30\0\0\0")
# 根据 retain 标志和 QoS 设置数据包的标志位
pkt[0] |= qos << 1 | retain
# 计算消息总大小:2 字节用于主题长度,余下的用于消息长度
sz = 2 + len(topic) + len(msg)
# 如果 QoS 大于 0,则增加 2 字节用于 packet identifier (PID)
if qos > 0:
sz += 2
# 断言消息总大小小于 2097152 字节(MQTT 协议的限制)
assert sz < 2097152
# 编码消息大小,采用可变长度编码方案
i = 1
while sz > 0x7F:
pkt[i] = (sz & 0x7F) | 0x80
sz >>= 7
i += 1
pkt[i] = sz
# 将构建好的发布数据包发送给服务器
self.sock.write(pkt, i + 1)
# 发送主题字符串
self._send_str(topic)
# 如果 QoS 大于 0,增加 packet identifier (PID) 并发送
if qos > 0:
self.pid += 1
pid = self.pid
struct.pack_into("!H", pkt, 0, pid)
self.sock.write(pkt, 2)
# 发送消息内容
self.sock.write(msg)
# 如果 QoS 等于 1,等待服务器的 PUBACK 响应
if qos == 1:
while 1:
op = self.wait_msg()
if op == 0x40: # 0x40 表示 PUBACK 报文
sz = self.sock.read(1)
assert sz == b"\x02"
rcv_pid = self.sock.read(2)
rcv_pid = rcv_pid[0] << 8 | rcv_pid[1]
if pid == rcv_pid:
return
# 如果 QoS 等于 2,抛出异常(该代码未实现 QoS 2 的逻辑)
elif qos == 2:
assert 0
def subscribe(self, topic: str, qos: int = 0) -> None:
'''
订阅主题
Args:
topic (str): 主题
qos (int): QoS 质量,默认为 0
Returns:
None
Raises:
AssertionError: 如果订阅回调函数未设置
MQTTException: 如果服务器返回错误代码
'''
# 确保已设置订阅回调函数
assert self.cb is not None, "Subscribe callback is not set"
# 创建 MQTT 订阅数据包的基本结构
pkt = bytearray(b"\x82\0\0\0")
# 增加 packet identifier (PID)
self.pid += 1
struct.pack_into("!BH", pkt, 1, 2 + 2 + len(topic) + 1, self.pid)
# 发送订阅数据包
self.sock.write(pkt)
# 发送主题字符串
self._send_str(topic)
# 发送 QoS 级别
self.sock.write(qos.to_bytes(1, "little"))
# 等待服务器的 SUBACK 响应
while 1:
op = self.wait_msg()
# 0x90 表示 SUBACK 报文
if op == 0x90:
resp = self.sock.read(4)
assert resp[1] == pkt[2] and resp[2] == pkt[3]
if resp[3] == 0x80:
raise MQTTException(resp[3])
return
# 等待单个传入的 MQTT 消息并处理
# 订阅的消息将传递给之前通过 .set_callback() 方法设置的回调函数
# 其他(内部)MQTT 消息由内部处理
def wait_msg(self) -> int:
'''
等待单个传入的 MQTT 消息并处理
Returns:
int: 返回操作码,如果没有收到消息则返回 None
Raises:
OSError: 如果读取到空消息
AssertionError: 如果接收到无效的 PINGRESP 报文
'''
# 读取来自服务器的一个字节
res = self.sock.read(1)
# 如果未收到消息,返回 None
if res is None:
return None
# 如果收到空消息,抛出错误
if res == b"":
raise OSError(-1)
# 如果收到的是 PINGRESP 报文(0xD0),读取其长度(应为 0),然后返回 None
if res == b"\xd0": # PINGRESP
sz = self.sock.read(1)[0]
assert sz == 0
return None
# 解析操作码
op = res[0]
# 如果不是发布消息(0x30 开头),返回操作码
if op & 0xF0 != 0x30:
return op
# 读取消息的剩余长度
sz = self._recv_len()
# 读取主题长度
topic_len = self.sock.read(2)
topic_len = (topic_len[0] << 8) | topic_len[1]
# 读取主题内容
topic = self.sock.read(topic_len)
# 减去已读取的长度
sz -= topic_len + 2
# 如果 QoS 大于 0,读取 packet identifier (PID)
if op & 6:
pid = self.sock.read(2)
pid = pid[0] << 8 | pid[1]
sz -= 2
# 读取消息内容
msg = self.sock.read(sz)
# 调用回调函数处理接收到的消息
self.cb(topic, msg)
# 如果 QoS 为 1,发送 PUBACK 确认
if op & 6 == 2:
pkt = bytearray(b"\x40\x02\0\0")
struct.pack_into("!H", pkt, 2, pid)
self.sock.write(pkt)
# 如果 QoS 为 2,抛出异常(未实现)
elif op & 6 == 4:
assert 0
return op
# 检查是否有来自服务器的挂起消息。
def check_msg(self) -> int:
'''
检查是否有来自服务器的挂起消息
Returns:
int: 返回操作码,如果没有收到消息则返回 None
'''
return self.wait_msg()
# ======================================== 初始化配置 ==========================================
# ======================================== 主程序 ===========================================
micropython-umqtt.simple 文件中定义了两个类:
MQTTException类:自定义的MQTT异常类,用于处理MQTT操作中的错误-
MQTTClient类:实现了MQTT客户端的基本操作,包括连接、断开、发布、订阅等功能
micropython-umqtt.simple 中的 MQTTClient 类主要提供了以下方法来使用 MQTT 协议传输数据:

umqtt.robust 文件中也定义了一个 MQTTClient 类,它继承了 umqttsimple.MQTTClient 的所有功能,并且添加了一个 debug 参数和 log 方法,用于控制调试输出。这使得用户可以控制是否输出调试信息以便于故障排除。它利用 Python 的异常处理机制和无限循环重写了父类的 reconnect 方法、publish 方法、wait_msg 方法和 check_msg 方法,用于解决 umqttsimple 模块在弱网或断网后可能出现死锁或无限递归等问题,使得其在网络不稳定的情况能够正常传输。
这里,我们对原版的 umqtt.robust 文件略加修改,使得更简洁,同时更加符合 Python 面向对象编程的原则,代码如下:
# Python env : MicroPython v1.23.0 on Wiznet W5500
# -*- coding: utf-8 -*-
# @Time : 2024/8/9 下午11:38
# @Author : 李清水
# @File : umqttrobust.py
# @Description : 该模块用于解决umqttsimple模块在弱网或断网后可能出现死锁或无限递归等问题
# ======================================== 导入相关模块 ========================================
# 导入时间相关模块
import time
# 导入umqttsimple模块
import umqttsimple
# ======================================== 全局变量 ============================================
# ======================================== 功能函数 ============================================
# ======================================== 自定义类 ============================================
# 继承自 umqttsimple.MQTTClient 类,用于解决umqttsimple模块在弱网或断网后可能出现死锁或无限递归等问题
class MQTTClient(umqttsimple.MQTTClient):
"""
MQTTClient 类,继承自 umqttsimple.MQTTClient,用于增强 MQTT 客户端功能。
该类在 umqttsimple.MQTTClient 的基础上增加了以下功能:
- 支持调试模式,输出详细的错误日志。
- 在网络不稳定或断网情况下,自动重连 MQTT 服务器。
- 提供有限次数的消息检查和重试机制,避免无限阻塞。
Attributes:
client_id (int): 客户端 ID,用于标识客户端。
server (str): MQTT 服务器地址。
port (int): MQTT 服务器端口,默认为 0(自动选择默认端口)。
user (str): 用户名,默认为 None。
password (str): 密码,默认为 None。
keepalive (int): 心跳时间,默认为 0。
ssl (bool): 是否使用 SSL/TLS 加密连接,默认为 False。
debug (bool): 是否输出调试信息,默认为 False。
ssl_params (dict): SSL/TLS 参数,默认为空字典。
sock (socket): 客户端与服务器通信的套接字。
pid (int): 报文 ID,用于标识 MQTT 报文。
cb (callable): 消息回调函数,用于处理接收到的消息。
lw_topic (str): 遗嘱消息的主题,默认为 None。
lw_msg (str): 遗嘱消息的内容,默认为 None。
lw_qos (int): 遗嘱消息的 QoS 级别,默认为 0。
lw_retain (bool): 遗嘱消息是否保留,默认为 False。
Methods:
__init__(self, client_id, server, port=0, user=None, password=None, keepalive=0, ssl=False, debug=False, ssl_params={}):
初始化 MQTTClient 类实例。
log(self, in_reconnect, e):
用于调试时输出错误信息。
reconnect(self):
在网络不稳定情况下重连 MQTT 服务器。
publish(self, topic, msg, retain=False, qos=0):
发布消息到指定主题,支持自动重连。
wait_msg(self):
等待并处理单个传入的 MQTT 消息,支持自动重连。
check_msg(self, attempts=2):
检查是否有来自服务器的挂起消息,提供有限次数的重试机制。
"""
def __init__(self, client_id: int, server: str, port: int = 0, user: str = None, password: str = None, keepalive: int = 0, ssl: bool = False, debug: bool = False, ssl_params: dict = {}) -> None:
'''
初始化 MQTT 客户端类
Args:
client_id (int): 客户端 ID
server (str): 服务器地址
port (int): 服务器端口,默认为 0(自动选择默认端口)
user (str): 用户名,默认为 None
password (str): 密码,默认为 None
keepalive (int): 心跳时间,默认为 0
ssl (bool): 是否使用 SSL,默认为 False
debug (bool): 是否输出调试信息,默认为 False
ssl_params (dict): SSL 参数,默认为空字典
Returns:
None
'''
# 调用父类的初始化方法
super().__init__(client_id, server, port, user, password, keepalive, ssl, ssl_params, )
# 初始化 debug 属性,用于控制是否输出调试信息
self.debug = debug
def log(self, in_reconnect: bool, e: Exception) -> None:
'''
用于调试时输出错误信息
Args:
in_reconnect (bool): 是否在重连过程中出错
e (Exception): 错误信息
Returns:
None
'''
# 只有在 debug 模式下(debug=True)才会打印日志
if self.debug:
# 判断是否在重连过程中出错,决定输出的日志内容
if in_reconnect:
print("mqtt reconnect: %r" % e)
else:
print("mqtt: %r" % e)
def reconnect(self) -> None:
'''
用于在网络不稳定情况下重连 MQTT 服务器
Returns:
None
'''
# 初始化重试次数计数器 i
i = 0
# 无限循环,直到连接成功
while True:
# 尝试连接到 MQTT 服务器
try:
# 调用父类的 connect 方法进行连接。参数 False 表示不保持之前的会话
return super().connect(False)
# 如果捕获到 OSError 异常,说明连接失败
except OSError as e:
# 调用 log 方法记录重连错误信息
self.log(True, e)
# 增加重试计数器 i,用于控制下一次重连前的等待时间
i += 1
# 根据重试次数 i 进行等待,防止频繁重试
time.sleep(i)
def publish(self, topic: str, msg: str, retain: bool = False, qos: int = 0) -> None:
'''
定义一个发布消息的函数,处理在网络不稳定情况下可能的发布失败
Args:
topic (str): 主题
msg (str): 消息
retain (bool): 是否保留,默认为 False
qos (int): QoS 质量,默认为 0
Returns:
None
'''
# 无限循环,直到成功发布消息
while True:
# 尝试发布消息
try:
# 调用父类的 publish 方法将消息发布到指定主题
return super().publish(topic, msg, retain, qos)
# 捕获发布消息时的 OSError 异常
except OSError as e:
# 调用 log 方法记录发布失败的错误信息
self.log(False, e)
# 如果发布失败,尝试重新连接 MQTT 服务器,并在下一次循环中再次尝试发布
self.reconnect()
def wait_msg(self) -> int:
'''
定义一个等待消息的函数,处理在网络不稳定情况下可能的等待失败
阻塞式运行,直到接收消息才会返回
Returns:
int: 返回操作码
'''
# 无限循环,直到成功接收到消息
while True:
# 尝试接收消息
try:
# 调用父类的 wait_msg 方法等待并接收消息
return super().wait_msg()
# 捕获接收消息时的 OSError 异常
except OSError as e:
# 调用 log 方法记录接收失败的错误信息
self.log(False, e)
# 如果接收消息失败,尝试重新连接 MQTT 服务器,并在下一次循环中再次尝试接收消息
self.reconnect()
def check_msg(self, attempts: int = 2) -> int:
'''
定义一个检查消息的函数,处理在网络不稳定情况下可能的检查失败
提供有限次数的消息检查和重试
Args:
attempts (int): 重试次数,默认为 2
Returns:
int or None: 返回操作码,如果没有收到消息则返回 None
'''
# 循环检查消息,最多尝试 attempts 次
while attempts:
# 将套接字设置为非阻塞模式,确保 wait_msg 方法不会阻塞等待消息
self.sock.setblocking(False)
# 尝试接收消息
try:
# 调用父类的 wait_msg 方法接收消息
return super().wait_msg()
# 捕获接收消息时的 OSError 异常
except OSError as e:
# 调用 log 方法记录接收消息失败的错误信息
self.log(False, e)
# 如果接收消息失败,尝试重新连接 MQTT 服务器
self.reconnect()
# 减少剩余尝试次数,如果尝试次数用尽,则退出循环
attempts -= 1
# ======================================== 初始化配置 ==========================================
# ======================================== 主程序 ===========================================
与原版的 umqtt.robust 文件相比,改动如下:



我们将 micropython-umqtt.simple 和 micropython-umqtt.robust 库分别命名为 umqttsimple.py 文件和 umqttrobust.py 文件保存到同一个文件夹下,并将该文件夹定义为源文件根目录以方便多 Python 文件的烧录:

两个文件和各自文件中 MQTTClient 类关系如下:


这里,我们使用了 `pypi`(Python Package Index)共享 Python 软件包平台上两个 MicroPython 环境中用于实现 `MQTT` 协议的库:`micropython-umqtt.simple` 和 `micropython-umqtt.robust`,它们为 MicroPython 提供了 `MQTT` 协议的客 + 户端功能,但在设计目标和特性上有所不同:

浙公网安备 33010602011771号