IoT-For-Beginners 的 MQTT 消息发布后订阅端收不到,如何排查 Topic 与 QoS 配置
【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners
在 IoT-For-Beginners 课程的第 4 课(Connect your device to the Internet)中,夜灯示例会把 Wio Terminal 或 Raspberry Pi(也可以是用 CounterFit 搭建的虚拟设备)接入公共 MQTT 测试 brokertest.mosquitto.org:设备把光敏读数发布到<ID>/telemetry主题,本地运行的 Python 服务端代码订阅该主题,再向<ID>/commands主题发布 LED 开关命令,设备订阅这个命令主题。如果你看到设备端已经打印出 "Sending telemetry"、服务端却一条 "Message received" 都没有(或者反向:命令发出去设备没反应),问题通常出在 Topic 或 QoS 配置上。本文按项目 TROUBLESHOOTING.md 中 "MQTT messages not received" 一节的排查项,结合 第 4 课主文档 给出的示例代码与验证输出,给出一条可核对的排查路径。
先确认两端真的连上了 broker
排查 Topic 和 QoS 之前,先确认发布方和订阅方都已经和 broker 建立连接,否则消息根本没有进入 broker。
Wio Terminal:上传代码后打开 PlatformIO 的 Serial Monitor,确认出现以下输出(文档示例):
Connecting to WiFi.. Connected! Attempting MQTT connection...connectedRaspberry Pi / 虚拟设备:运行
app.py后终端应打印MQTT connected!(文档示例)。
如果连接这一步就失败,按 TROUBLESHOOTING.md "MQTT connection fails" 一节逐项检查:broker 地址是否正确、端口(1883 为未加密,8883 为 TLS)、需要用户名/密码时凭据是否正确、TLS 证书是否有效可信、防火墙是否放行了端口。课程示例中 Wio Terminal 用client.setServer(BROKER.c_str(), 1883)连接test.mosquitto.org的 1883 端口,服务端app.py用mqtt_client.connect('test.mosquitto.org')连接。
检查一:发布方与订阅方的 Topic 是否完全一致
TROUBLESHOOTING.md 对该问题的第一条建议是:Verify subscriber topic matches publisher topic exactly——订阅方订阅的 Topic 必须与发布方发布的 Topic 逐字符一致。
课程代码里两端的 Topic 都基于同一个唯一 ID 拼出来:
Wio Terminal 的config.h(见 wio-terminal-mqtt.md 与 wio-terminal-telemetry.md):
const string CLIENT_TELEMETRY_TOPIC = ID + "/telemetry"; const string SERVER_COMMAND_TOPIC = ID + "/commands";服务端app.py(见 README.md "Write the server code" 一节):
id = '<ID>' client_telemetry_topic = id + '/telemetry' server_command_topic = id + '/commands'<ID>是读者必须提供的值:课程要求替换成一个唯一 ID,并明确警告服务端代码里的id必须与设备端使用的 ID 相同,"or the server code won't subscribe or publish to the right topic"。因为test.mosquitto.org是公共 broker,被许多使用者(包括其他正在上这门课的人)共用,使用唯一 ID 和唯一 Topic 是为了避免与别人冲突。Pi / 虚拟设备端的代码同样是client_telemetry_topic = id + '/telemetry'和server_command_topic = id + '/commands'(见 single-board-computer-telemetry.md 与 single-board-computer-commands.md),两端写法必须一致。
对照方法:把设备端config.h中的ID与服务端app.py中的id逐字符比对,再核对拼出来的 Topic 是否为<ID>/telemetry和<ID>/commands。任何一边多一个前导斜杠、大小写不同或 ID 不同,消息都会发到另一个 Topic 上,订阅方自然收不到。
检查二:Topic 通配符写法是否正确
TROUBLESHOOTING.md 建议检查通配符是否用对:+匹配单级,#匹配多级(Check topic wildcards are used correctly (+for single level,#for multi-level))。
第 4 课主文档用一个例子说明 Topic 层级:温度消息发到/telemetry/temperature,湿度消息发到/telemetry/humidity,云端应用订阅上一层级就能同时收到两种消息。如果你的订阅端依赖通配符而不是完整 Topic 名,按上述+/#的定义核对层级数:订阅层数写错,broker 就不会把消息路由到这个客户端。
检查三:QoS 级别
第 4 课主文档定义了 QoS(quality of service,决定消息被接收的保证程度)的三级语义:
- At most once:消息只发一次,客户端和 broker 不做额外的确认(fire and forget);
- At least once:发送方多次重发,直到收到确认(acknowledged delivery);
- Exactly once:发送方与接收方通过两级握手确保只收到一份(assured delivery)。
TROUBLESHOOTING.md 对 "消息发布后收不到" 给出的第二条建议是:Try QoS 1 or 2 instead of 0——当前级别下消息丢失时,改用 QoS 1 或 2 再试。注意课程的示例代码(Wio 端client.publish(...)、Pi 端mqtt_client.publish(client_telemetry_topic, telemetry)、订阅端mqtt_client.subscribe(...))都没有显式传 QoS 参数,所以调整 QoS 时需要在你自己代码的 publish/subscribe 调用里改,改完重新运行并重复下文的验证步骤。
检查四:连接时序与 retained 消息
剩下两个与 Topic、QoS 相关的常见原因是时序和消息保留,TROUBLESHOOTING.md 分别给出对应建议:
- Connection timing:Ensure subscriber connects before messages are published——先让订阅方连上 broker 并订阅,再让发布方发消息。课程文档也明确:服务端
app.py必须先处于运行状态,设备端发来的消息才能被收到;并且 MQTT 虽然名字里有 "Queueing",但实际并不支持消息队列——客户端断开期间发布的消息,在重连后不会补投(除已通过 QoS 流程开始处理的消息外)。所以验证顺序应是:先启动服务端订阅者,再启动设备端发布者。 - Retained messages:发布方可以设置 retain 标志让 broker 保留该主题的最后一条消息(Check retained messages: Publisher can set retain flag to keep last message)。broker 会把这条消息发给之后才订阅该主题的客户端。如果你期望的是"后订阅的客户端也能拿到最近一次的值",检查发布端有没有按预期设置 retained 标志。
验证:怎样确认已经修好
按 README.md 中的验证方式,在激活的虚拟环境里运行服务端:
python app.py然后调整物理设备或 CounterFit 虚拟设备检测到的光强。服务端终端应打印收到的遥测消息,文档示例输出如下(数值为示例,实际读数会不同):
(.venv) ➜ nightlight-server python app.py Message received: {'light': 0} Message received: {'light': 400}反向链路(命令下行)的验证:调整光强后,设备端 Serial Monitor 会打印Message received:及命令 JSON 内容,LED 随命令点亮或熄灭,即说明<ID>/commands主题上的订阅正常。
TROUBLESHOOTING.md 还给出一个独立于课程代码的验证工具:用 MQTT Explorer 或mosquitto_pub/mosquitto_sub直接向 broker 发布/订阅,用来区分"broker 与网络没问题、问题出在自己代码的 Topic/QoS 上"的情况。
限制说明
- test.mosquitto.org是公共测试 broker,课程文档明确提示它不安全:任何人可能正在监听你发布的内容,不要用它传输需要保密的数据。
- 由于 broker 公共且多人共用,设备端与服务端的
<ID>必须使用同一个唯一值;ID 不一致时两端会落在不同的 Topic 上,这正是本场景最常见的一类收不到消息的原因。
【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考