繁体   English   中英

Paho MQTT 动态订阅新主题

[英]Paho MQTT dynamically subscribe to new topic

我还在学习如何使用 MQTT 发布和订阅。

如果用户添加新主题,是否可以动态订阅主题?

例如,现在的代码是这样的:

import anotherModule

topic = anotherModule.topic #the output is similar to this -> [('Test1', 0), ('Test2', 0)]
...

def connect_mqtt() -> mqtt_client:
    def on_connect(client, userdata, flags, rc):
        if rc == 0:
            print("Connected to MQTT Broker!")
        else:
            print("Failed to connect, return code %d\n", rc)

    client = mqtt_client.Client(client_id)
    client.username_pw_set(username, password)
    client.on_connect = on_connect
    client.connect(broker, port)
    return client


def subscribe(client: mqtt_client):
    def on_message(client, userdata, msg):
        new_msg = json.loads(msg.payload.decode())
        print(new_msg)
    
    def check_topic():
        while True:
            client.subscribe(anotherModule.topic) #subscribe to the new topic if there are any
            time.sleep(1)

    t3 = threading.Thread(target=check_topic)
    t3.start()
    #  client.subscribe(topic)
    client.on_message = on_message

client = connect_mqtt()
subscribe(client)
t1 = threading.Thread(target=periodic_check_connection) #this function is irrelvant to the question
t1.start()
t2 = threading.Thread(target=client.loop_forever)
t2.start()

现在,我正在使用线程在 while 循环中的另一个线程上运行订阅。 这样,如果用户要添加,它将始终订阅任何新主题。

有没有更好的方法来做到这一点? 如果用户要订阅“Test3”,则 ('Test3', 0) 将附加在 anotherModule.topic 中。 但是,mqtt 无法动态订阅这个新主题,因此引入了 while 循环。

任何帮助表示赞赏。 谢谢!

编辑1:

def connect_mqtt() -> mqtt_client:
    def on_connect(client, userdata, flags, rc):
        if rc == 0:
            print("Connected to MQTT Broker!")
        else:
            print("Failed to connect, return code %d\n", rc)

    client = mqtt_client.Client(client_id)
    client.username_pw_set(username, password)
    client.on_connect = on_connect
    client.connect(broker, port)
    client.subscribe(anotherModule.topic) # I tried putting here but wont work
    return client

def update_topic(new_topic):
    client.subscribe(new_topic) # How to run client.subscribe here?

def run():
    global client
    client = connect_mqtt()
    subscribe(client)
    t1 = threading.Thread(target=periodic_check_connection)
    t1.start()
    t2 = threading.Thread(target=client.loop_forever)
    t2.start()

我尝试在客户端上添加全局,但它似乎不起作用。 它说没有为 client.subscribe(new_topic) 定义名称客户端

是的,

建立连接后,您可以随时调用client.subscribe() ,这将告诉代理将匹配模式的消息发送到该客户端。

您还可以调用client.unsubscribe()来停止接收给定主题模式的消息。

在循环中调用client.subscribe()没有任何用处,每个主题只需要调用一次,订阅详细信息由代理而不是客户端维护。

“其他模块”应该只调用此模块上的 function 传递它感兴趣的主题(以及可选的 QOS),然后调用client.subscribe(topic)

但值得指出的是,只有 1 个client.on_message回调,如果您尝试多次设置此回调(例如每次调用 subscribe),您只会覆盖最后一个。

我认为最优雅的方法是使用订阅通配符并正确设计已发布的主题路径。 因此,您可能有一些顶级主题Test例如和未知数量的子主题,如下所示:

Tests/Test1
Tests/Test2
Tests/Test3
...

订阅客户端只需订阅Tests/+ ,将自动获取所有子主题,无需重新订阅。

您在特殊主题的有效负载中提供新主题的方法也应该有效,但不需要进行一些无限循环订阅。 为此,您可能有一个列表来管理您当前订阅的主题,如果您的主题名称尚不存在于此列表中,则只需调用client.subscribe即可。

我设法通过将 anotherModule 设为 class 来解决这个问题。 我已经实例化了 anotherModule 并从当前模块传入客户端,这样我就可以从 anotherModule 调用 client.subscribe 而不是调用 function。 谢谢您的帮助!

# current module
def run():
    client = connect_mqtt()
    anotherModule.ModuleClass(client) #client is pass to another module
    subscribe(client)
    t1 = threading.Thread(target=periodic_check_connection)
    t1.start()
    t2 = threading.Thread(target=client.loop_forever)
    t2.start()
# anotherModule
class ModuleClass:
    def __init__(self, client):
        self.client = client
        ....

    def updateTopic(new_topic):
        self.client.subscribe(new_topic)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM