Python paho-mqtt交替连接断开循环仅执行一次问题排查
问题根因
代码仅能运行单轮的核心问题如下:
- 循环结构错误:两个
while块为顺序执行关系,第一个MQTT连接循环跑完一次、将latch置为1后就会永久退出,后续计算逻辑把latch改回0后,没有逻辑能跳转回第一个循环,程序直接终止。 - 回调注册顺序错误:先启动
client.loop_start()网络线程,之后才绑定on_connect、on_message回调,存在事件触发时回调未注册的概率,导致订阅失败、消息丢失。 - 接收逻辑不可靠:固定休眠5秒就断开连接,没有校验三个主题的消息是否全部接收完成,一旦某个节点上报延迟,三边计算会直接触发未定义变量错误。
- 重连逻辑有缺陷:每次循环新建客户端且使用固定Client ID,前一个连接未被broker及时清理时,新连接会被服务端强制踢下线。
修正实现
将MQTT连接、消息接收、业务计算合并到同一个主循环中,增加消息收齐判断,调整回调注册顺序,修正后代码如下:
import paho.mqtt.client as mqtt import time # 全局存储三个锚点的测距值 ESP1 = None ESP2 = None ESP3 = None def on_connect(client, userdata, flags, rc): print(f"Connected with result code {rc}") # 连接成功后订阅目标主题 client.subscribe("trilaterasi/ESP1") client.subscribe("trilaterasi/ESP2") client.subscribe("trilaterasi/ESP3") def on_message(client, userdata, msg): global ESP1, ESP2, ESP3 if msg.topic == 'trilaterasi/ESP1': ESP1 = float(msg.payload) print(f"Msg rcvd {msg.topic} {ESP1}") elif msg.topic == 'trilaterasi/ESP2': ESP2 = float(msg.payload) print(f"Msg rcvd {msg.topic} {ESP2}") elif msg.topic == 'trilaterasi/ESP3': ESP3 = float(msg.payload) print(f"Msg rcvd {msg.topic} {ESP3}") # 三个主题消息全部收齐后主动断开,进入计算环节 if None not in (ESP1, ESP2, ESP3): client.disconnect() if __name__ == "__main__": broker = "ipaddress" # 锚点固定坐标 ESP1x, ESP1y = 300, 0 ESP2x, ESP2y = 0, 130 ESP3x, ESP3y = 150, 260 while True: # 每轮开始重置测距值,避免旧数据干扰 ESP1 = ESP2 = ESP3 = None # 先注册回调再连接,Client ID拼接时间戳避免重连冲突 client = mqtt.Client(f"Python_{int(time.time())}") client.on_connect = on_connect client.on_message = on_message client.connect(broker, keepalive=10) # 阻塞运行网络循环,断开连接后自动往下执行 client.loop_forever() # 执行三边测量计算 a = 2 * (-ESP1x + ESP2x) b = 2 * (-ESP1y + ESP2y) c = ESP1**2 - ESP2**2 - ESP1x**2 + ESP2x**2 - ESP1y**2 + ESP2y**2 d = 2 * (-ESP2x + ESP3x) e = 2 * (-ESP2y + ESP3y) f = ESP2**2 - ESP3**2 - ESP2x**2 + ESP3x**2 - ESP2y**2 + ESP3y**2 x = (c*e - f*b) / (e*a - b*d) y = (c*d - a*f) / (b*d - a*e) print(f"定位结果 x: {x:.2f}, y: {y:.2f}") # 计算完成后加短延时,避免重连过于频繁 time.sleep(0.5)
补充说明
- 用
loop_forever()替代原有的loop_start()+固定休眠逻辑,阻塞等待消息收齐后再断开,不需要冗余等待时间,响应更快。 - 每轮重置测距值为
None,确保不会用上一轮的旧数据计算。 - 如果需要增加超时机制(比如某路ESP离线时避免永久卡住),可以加定时器判断超时后主动断开连接,进入下一轮重连。
内容的提问来源于stack exchange,提问作者Natriz Kiandral
相关产品推荐
相关产品推荐

