When writing code using the Paho Python client you would have had to use the loop() function .
In this tutorial we will look at what it does, and why it is necessary.
When new messages arrive at the Python MQTT client they are placed in a receive buffer.
The messages sit in this receive buffer waiting to be read by the client program.
You could program the client to manually read the receive buffers but this would be tedious.
The loop() function is a built in function that will read the receive and send buffers, and process any messages it finds.
On the receive side it looks at the messages, and depending on the message type, it will trigger the appropriate callback function. See Understanding callbacks.
For example if it sees a CONNACK message it triggers the on_connect() callback.
Now instead of manually reading the receive buffer you just need to process the callbacks.
Outgoing messages and message acknowledgements are placed in the send buffer.
The loop function will read this buffer and send any messages it finds.
Calling the Loop Function
See network loop in docs for function reference.
The Paho Python client provides three methods:
- loop_forever() and
The loop_start() starts a new thread, that calls the loop method at regular intervals for you. It also handles re-connects automatically.
To stop the loop use the loop_stop() method.
The loop_forever() method blocks the program, and is useful when the program must run indefinitely.
The loop_forever() function also handles automatic reconnects.
The loop can be stopped by calling loop.stop().
You should stop the loop before you exit the script.
You can also manually call the loop() method in your program.
If you do this you must remember to call it regularly.
That is it must be in a loop. e.g pseudo code below:
while.. Some code client.loop(.1) #blocks for 100ms some code
Because the loop is a blocking function I call it with a timeout the default timeout is 1 second.
If you call the loop manually then you will need to create code to handle reconnects.
Important! If your client script has more than one client connection then you must call or start a loop for each client connection.
For example, if I create two clients client 1 and client2 in a script, then you would expect to see client1.loop() and client2.loop() in the script.
I have experienced strange behaviour when starting a loop before creating a connection . So
client= mqtt.Client(cname) client.connect(broker,port)) client.loop_start()
Works Ok but
client= mqtt.Client(cname) client.loop_start() client.connect(broker,port))
sometimes gives strange results.
Stopping the loop automatically
If you are using the loop_start() function then you will probably need to stop the loop automatically if the connection fails.
The easiest way of doing this is using the on_disconnect callback.
def on_disconnect(client, userdata,rc=0): logging.debug("DisConnected result code "+str(rc)) client.loop_stop()
However you should only stop the loop if you are completely finished, and are going to exit.
Stopping the loop will stop auto reconnects unless you take steps to call the loop manually.
Loop_start vs Loop_forever
Loop_start starts a loop in another thread and lets the main thread continue if you need to do other things in the main thread then it is important that it doesn’t end.
To accomplish this you need to use your own wait loop.
The loop_forever call blocks the main thread and so it will never terminate.
The loop_forever call must be placed at the very end of the main script code as it doesn’t progress beyond it.
Handling Multiple Clients
If your script connects using multiple clients then each client will need a loop.
Therefore if you are using the loop_start() method then you will need to call it for each client connection.
Therefore if you have 2 client connections you will need two loops which equals two additional threads.
For 2 clients it isn’t really a problem, but what if you have several hundred client connections then you will need several hundred additional threads.
In this situation it is better to manually call the loop for each client and use thread pooling.
I will cover this is another tutorial at a later date.
However for up to around 20 client connections then is is easier to use the inbuilt loop_start and stop functions.
To make it simpler add the clients to a list and loop through the list to start the loops and the same to stop e.g
import paho.mqtt.client as mqtt clients= nclients=20 mqtt.Client.connected_flag=False #create clients for i in range(nclients): cname="Client"+str(i) client= mqtt.Client(cname) clients.append(client) for client in clients: client.connect(broker) client.loop_start()
Common Questions and Answers
Q- My callbacks aren’t being called. Why is that?
A- You need to start a loop or call the loop() function to process callbacks.
Q- My script has ended but the loop still appears to be running?
A- It probably is. You need to stop the loop before exiting the script.
Q- Why call the loop manually when you can use loop_start()?
A-The main reason is when the script has lots of client connections (>20) as if you use loop_start() then you need a loop for each client.
The built in loop functions will process the receive and send buffers to send and receive messages and message acknowledgements.
To make life easier use the loop_start and stop functions unless you have 100’s of client connections.
- Introduction to the Paho Python MQTT Client
- Introduction to the Client Class
- Connecting to a Broker
- Publishing Using The Paho Python MQTT Client
- Subscribing using The Paho Python Client
- Understanding The Loop
- Understanding Callbacks
- Handling Multiple Client Connections