When you subscribe to an MQTT topic there is always a change that the subscription will fail.
Therefore it is important that your code checks that the subscription succeeded.
MQTT provides message Ids for this purpose.
The subscribe function returns a tuple to indicate success, and also a message id which is used as a tracking code.
Therefore the subscribe call need to check this.
This is what to docs say:
So in pseudo code we have
- Try to subscribe and raise an error if it failed
- check result for 0 and if not zero fail
- If result =0 then store mid value so we can check it is acknowledged.
This is the python code I use:
def subscribe_topics(client,topics,qos=0): print("topic ",topics," ",qos) if type(topics) is not list: #topics should be list of tuples if type(topics) is not tuple: #topics isn't tuple? topic_list=[(topics,qos)] else: topic_list=[topics] else: topic_list=topics try: r=client.subscribe(topic_list) if r==0: logging.info("subscribed to topic "+str(topic_list)+" return code" +str(r)) client.topic_ack.append([topic_list,r,0]) #keep track of subscription else: logging.info("error on subscribing "+str(r)) print("error on subscribing "+str(r)) return -1 except Exception as e: logging.info("error on subscribe"+str(e)) return -1 return r
Notes: when subscribing the topic and mid value are stored in a list. This list is updated by the on_subscribe callback function as shown below:
def on_subscribe(client,userdata,mid,granted_qos): """removes mid valuse from subscribe list""" logging.debug("in on subscribe callback result "+str(mid)) if len(client.topic_ack)==0: #print("All subs acknowledged") return for index,t in enumerate(client.topic_ack): if t==mid: client.topic_ack.pop(index)#remove it #print("removed from list")
Now all we need to do is wait for all subscriptions to be complete. I use a check_subs function that checks the subscribe acknowledgements. Here is the code:
def check_subs(client): wcount=0 while wcount<10: #wait loop if len(client.topic_ack)==0: return True time.sleep(1) wcount+=1 if not client.running_loop: client.loop(.01) #check for messages manually return False
The code waits about 10 seconds before it gives up.
Flags and variable used that need to be assigned
client.running_loop #set False if running manual loop otherwise set true
client.topic_ack= #list for subscribe topics and mids.
To use the above code we do this:
- wait for all subscriptions
The code looks like this:
subscribe(client,"sensors/#") if not check_subs(client): print("missing subscribe acknowledgements")
Subscribing to multiple topics
When you subscribe to multiple topics using a topic list then you only get a single acknowledgement for all topics. The screen shot below shows the mid values when subscribing to single topics, tuple and topic list
- The Paho MQTT Python Client-Beginners Guide
- Understanding Callbacks -Using The Python MQTT Client
- MQTT Subscribe Using Python With Examples
- Client Objects-Working with The Python MQTT Client
- Working with Client Connections- Python MQTT
- MQTT Publish-Python MQTT Client Examples