如何阻止JMRI向Pico Wifi重复发送MQTT消息?
问题
我参考教程实现了树莓派Pico W的MQTT订阅功能,使用JMRI(一款用于控制模型铁路轨道、灯光、DCC等的Java程序)作为MQTT消息发布者,发现Pico设备会不断重复收到消息。使用的MQTT服务为broker.hivemq.com,通过HiveMQ WebSocket客户端订阅时无此问题,请问如何让消息仅发送/接收一次?
环境与代码
改编后的Pico W代码如下:
import network import time from machine import Pin from umqtt.simple import MQTTClient wlan = network.WLAN(network.STA_IF) wlan.active(True) wlan.connect("whatever","pwd") time.sleep(5) print(wlan.isconnected()) mqtt_server = 'broker.hivemq.com' client_id = 'bigles' topic_sub = b'/trains/track/turnout/#' def sub_cb(topic, msg): print("New message on topic {}".format(topic.decode('utf-8'))) msg = msg.decode('utf-8') print(msg) def mqtt_connect(): client = MQTTClient(client_id, mqtt_server, keepalive=60) client.set_callback(sub_cb) client.connect() print('Connected to %s MQTT Broker'%(mqtt_server)) return client def reconnect(): print('Failed to connect to MQTT Broker. Reconnecting...') time.sleep(5) machine.reset() try: client = mqtt_connect() except OSError as e: reconnect() while True: client.subscribe(topic_sub) time.sleep(1)
JMRI的MQTT设置路径为:编辑->偏好设置,设置截图如下:
解决方案
1. 修复Pico订阅逻辑(核心问题)
你的代码在主循环中反复执行订阅操作,这会导致客户端不断向Broker发送订阅请求。如果JMRI发送的是保留消息(Retain),Broker会在每次订阅时重新推送这条消息,从而造成重复接收。
修改代码,将订阅操作移到循环外,仅执行一次,循环内改为处理消息:
try: client = mqtt_connect() # 订阅仅执行一次 client.subscribe(topic_sub) except OSError as e: reconnect() while True: # 阻塞等待消息(推荐,节省资源) client.wait_msg() # 若需要非阻塞处理,可替换为: # client.check_msg() # time.sleep(0.1)
2. 检查JMRI的MQTT发布设置
如果修改代码后仍有重复,检查JMRI的MQTT配置:
- 关闭**保留消息(Retain)**选项:若开启该选项,Broker会持久化消息,任何新订阅(包括重复订阅)都会收到这条消息。
- 排查JMRI的事件触发逻辑:确认是否存在重复的状态更新、传感器触发等情况,导致JMRI反复发布相同消息。可通过HiveMQ Web客户端验证:如果Web客户端也收到重复消息,说明问题出在JMRI的发布逻辑上。
3. 额外排查项
- 确认
client_id唯一性:避免多个客户端使用相同ID,导致Broker强制断开旧连接后重新推送消息。 - 检查QoS等级:若JMRI使用QoS 1/2,可能存在重传机制,但Web客户端正常的话,该可能性较低。
内容的提问来源于stack exchange,提问作者user6090578
相关产品推荐
相关产品推荐

