paho.mqtt.python
paho.mqtt.python copied to clipboard
Shared Subscription does not match topic using topic_matches_sub()
Using release 1.5.0
I would expect the behavior of this call to return True.
topic_matches_sub("$share/group/+/+/c", "a/b/c")
The MQTTMessage.topic
received from the on_message
callback will be the second part (a/b/c) and is a topic that should fall within the shared subscription topicFilter.
I believe this is causing issues with Client.message_callback_add(). If the subscription is a shared subscription (E.g. Client.message_callback_add("$share/group/+/+/c", callback)
the callback is never executed.
I can confirm the same problem in the latest release 1.5.1.
For now my workaround is delegating the message to the topic-filter-specific callback within the on_message callback that receives the unmatched messages, but it would be great to see this issue addressed in the next release.
Another quick workaround: it seems you can drop the $share/group
portion of the topic filter when adding a message callback.
Quick (runnable) example:
import paho.mqtt.client as mqtt
def handle_yo(client, userdata, msg):
print(f"Yo: {msg.payload}")
def handle_hi(client, userdata, msg):
print(f"Hi: {msg.payload}")
def on_connect(client, userdata, flags, rc):
# The subscription topic is a shared topic
client.subscribe("$share/group/base/#")
print("Subscribed")
c = mqtt.Client()
c.on_connect = on_connect
# Message callbacks drop the `$share/group` portion
c.message_callback_add("base/+/yo", handle_yo)
c.message_callback_add("base/+/hi", handle_hi)
c.connect("localhost", 1883)
c.loop_forever()
Running the script above and publishing the following two messages:
mosquitto_pub -t base/a/yo -m "test"
mosquitto_pub -t base/a/hi -m "test"
gives
Subscribed
Yo: b'test'
Hi: b'test'
A generic way to add these callbacks:
def add_message_callback(client, topic, callback):
"""Add a message callback to a paho MQTT client.
Internally, paho uses a function called `topic_matches_sub` to determine if
a given topic string matches an MQTT topic pattern. Currently, this function
does not match shared topics correctly, e.g.,:
>>> topic_matches_sub("$share/group/+/+/c", "a/b/c") # expected: True
False
Issue link: https://github.com/eclipse/paho.mqtt.python/issues/472
This function handles stripping the `$share/group` portion of a topic
(if required) before calling `client.message_callback_add`.
"""
if topic.startswith("$share"):
# split the topic into at most 3 items: if this is a shared topic
# string, it will be of the form:
# $share/group_id/rest/of/topic/string
# this split gives:
# ["$share", "group_id", "rest/of/topic/string"]
# and we only use the last bit (rest/of/topic/string)
topic = topic.split("/", maxsplit=2)[-1]
client.message_callback_add(topic, callback)
I'm going to flag this as an enhancement. $share
was not part of the v3 spec; as it's included in v5 we should really support it here or, at a minimum, document the fact that its not supported.