Skip to main content Link Menu Expand (external link) Document Search Copy Copied

创客利器之ESP32(四点五)- 使用MicroPython与MQTT一起控制小灯 - 小插曲

小插曲

上一篇文章我们介绍了如何使用MicroPython连接MQTT Broker。因为我有两个ESP32,都使用了上一篇文章中的main.py。

import time
from umqtt.simple import MQTTClient
from machine import Pin

    # Publish test messages e.g. with:
    # mosquitto_pub -t foo_topic -m hello

    server = "<mqtt_broker_ip>"
    port_num = 9001
    swith_topic = b"home/bedroom/light"
    p5 = Pin(5, Pin.OUT)
    p5.off()

    # 如果值是on,打开小灯;否则关掉小灯
    def sub_cb(topic, msg):
        if msg.decode().lower() == "on":
            p5.on()
        else:
            p5.off()

def main():
    print("main started ...")
    c = MQTTClient("umqtt_client", server, port=port_num)
    c.set_callback(sub_cb)
    c.connect()
    c.subscribe(swith_topic)
    while True:
        try:
            if True:
                # Blocking wait for message
                c.wait_msg()
        except Exception:
            print("wait message fail")
    c.disconnect()

print("will enter main")
if __name__ == "__main__":
    main()

但是我发现只要我打开第二个ESP32时,第一个打开的ESP32就会报错,一直打印 wait message fail 。开始我怀疑是因为MQTT Broker不支持多个客户端订阅同一个地址,但是查了文档发现并没有这样的问题,而且使用mosquitto_sub工具就没有这样的问题。在没有找到原因的情况下,就像很多程序员一样,先修改代码绕过问题。修改后的代码如下。结果两个ESP32每隔一秒钟就报一次错,然后重新连接,不完美还是可以打开关闭小灯。

def main():
    print("main started ...")
    connect = True
    while True:
        try:
            if connect:
                client_id = f"umqtt_client{random.randint(0, 1000)}"
                c = MQTTClient("umqtt_client", server, port=port_num)
                c.set_callback(sub_cb)
                c.connect()
                c.subscribe(switch_topic)
                print("client ", client_id, " connects")
                connect = False
            if True:
                # Blocking wait for message
                c.wait_msg()
        except Exception as e:
             print("wait message fail, ", e)
             c.disconnect()
             time.sleep(1)
             connect = True
    c.disconnect()

由于这个方案并不完美,我还是决定上网找一下是否有人遇到和我一样的问题。还真找到了,有个人遇到了和我一样问题。原来Mosquitto为每个client_id只保留一个连接,而原始的main.py使用了固定的client_id。所以第二个ESP32连接时,第一个ESP32会被断开。再修改main函数如下,给client_id加上一个随机数,这样不同ESP32的client_id大概率就不一样了。

def main():
    print("main started ...")
    connect = True
    while True:
        try:
            if connect:
                client_id = f"umqtt_client{random.randint(0, 1000)}"
                c = MQTTClient(client_id, server, port=port_num)
                c.set_callback(sub_cb)
                c.connect()
                c.subscribe(switch_topic)
                print("client ", client_id, " connects")
                connect = False
            if True:
                # Blocking wait for message
                c.wait_msg()
        except Exception as e:
             print("wait message fail, ", e)
             c.disconnect()
             time.sleep(1)
             connect = True
    c.disconnect()

总结

看来看清楚API文档很重要。