Paho Python - MQTT Client Library Encyclopedia

Written by Roger Light

Category: MQTT MQTT Client Library

Published: September 28, 2015




Short info

Arduino PubSubClient
Language Python
License EDL / EPL
API-Style Asynchronous Callbacks, Blocking
Website http://eclipse.org/paho/clients/python/

Description

The Paho Python library came about because there were no Python libraries for MQTT at the time and this was a big deficiency. It was started out in 2010 as a wrapper around the mosquito C client library, but has long since been pure Python, supporting Python 2.7 and 3.x.

The library implements a client class that can be used to add MQTT support to your Python program either by creating instances of the client or through inheriting with your own class. It also provides some helper functions to make publishing one shot messages extremely easy.

Features

Feature
MQTT 3.1 ok
MQTT 3.1.1 ok
LWT ok
SSL/TLS ok
Automatic Reconnect ok
Feature
QoS 0 ok
QoS 1 ok
QoS 2 ok
Authentication ok
Throttling nok


Usage

Installation

Use the standard “pip” tool for installation, either

pip install paho-mqtt

Or

pip3 install paho-mqtt

depending on whether you are installing on Python 2 or Python 3.

Connect

This section shows the API usage how to connect with the library to a MQTT broker.

There are a number of ways to connect to a broker, a simple but incomplete example is given below:

1
2
3
4
5
6
7
8
import paho.mqtt.client as paho

def on_connect(client, userdata, flags, rc):
    print(CONNACK received with code %d. % (rc))

client = paho.Client()
client.on_connect = on_connect
client.connect(broker.mqttdashboard.com, 1883)

This creates a client instance using the default parameters, assigns a callback to be called once a successful connection has occurred, and starts the connection.

The Client() constructor has some optional parameters:

1
paho.Client(client_id=””, clean_session=True, userdata=None, protocol=paho.MQTTv31)

If you do not specify a client_id, a random id will be generated for you (and clean_session must be set to True). The userdata parameter can be any value or datatype that you wish and the data will be passed to all callbacks as the userdata variable.

The connect() function has some optional parameters as well:

1
client.connect(host=localhost, port=1883, keepalive=60, bind_address=””)

Hopefully these are all obvious with the exception of bind_address, which allows the socket to be bound to a specific address at the local side of the connection, useful if you have more than one outgoing interface.

The connect() call blocks until the socket connection is made with the broker, but is asynchronous afterwards, so once it returns you cannot be sure that the broker has accepted the connection – the on_connect() callback should be used for this purpose. A successful connection will result in the rc variable being set to 0, as in the MQTT protocol specification.

The other functions for connecting are:

1
2
connect_async(host, port=1883, keepalive=60, bind_address="")
connect__srv(self, domain=None, keepalive=60, bind_address="")

connect_async() does not block when connecting. connect_srv() attempts to use DNS SRV records for a domain to determine the broker address to connect to.

Connect with MQTT 3.1 or MQTT 3.1.1

To choose which protocol version to connect with, use the protocol parameter to connect():

1
2
client.connect(, protocol=paho.MQTTv31)
client.connect(, protocol=paho.MQTTv311)

MQTT v3.1 will be used by default, but this will change at some point in the future.

Connect with LWT

To connect with a will, you must call will_set() before connecting to the broker:

1
2
3
client = paho.Client()
client.will_set(topic, payload=None, qos=0, retain=False)
client.connect(broker.mqttdashboard.com)

The payload here can be a str or bytearray.

Connect with Username / Password

To connect with a username and password, call username_pw_set() before connecting:

1
2
3
client = paho.Client()
client.username_pw_set(username, password)
client.connect(broker.mqttdashboard.com)

The password is optional.

Staying connected

Once the client is connected, the network traffic between the client and the broker must be processed. This can be done in one of two ways, either a blocking method or with a background thread.

client.loop_forever() will block, processing the network traffic and reconnecting automatically as necessary. This function is most useful if you are only subscribing to the broker and acting on the messages you receive.

client.loop_start() starts a background thread to handle the network traffic and will return immediately. This is better suited to the situation where you wish to do other tasks in your program. It is complemented by the client.loop_stop() function, which stops the background thread.

Finally, you may also use the raw client.loop() function to process the network traffic manually. If you do this you will need to handle reconnecting yourself, it is recommended to use one of the previous two methods instead.

Publish

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import paho.mqtt.client as paho
import time

def on_publish(client, userdata, mid):
    print("mid: "+str(mid))
 
client = paho.Client()
client.on_publish = on_publish
client.connect(broker.mqttdashboard.com, 1883)
client.loop_start()

while True:
    temperature = read_from_imaginary_thermometer()
    (rc, mid) = client.publish(encyclopedia/temperature, str(temperature), qos=1)
    time.sleep(30)

This example shows how you might interface to a sensor and publish the data. The client is created, it sets a publish callback, connects to the broker and starts the background network thread. It then sits in a loop reading from an imaginary thermometer every 30 seconds and publishing the value to the “encyclopedia/temperature” topic. The QoS of the message can be controlled with the qos parameter. The payload in this example is “str(temperature)”, but is entirely optional. If not given, a zero length payload will be sent.

The publish() call returns a tuple of the function return code and the message id of the message being published. The message id can be used with the on_publish callback to determine when a particular message has been published. The client assigns a message id to all messages internally, even if they are QoS 0.

The version of the client currently in development offers a different (but still backwards compatible) return value from publish() which provides a better means of determining if a message has been published, as well as a way of blocking until the message has been published:

1
2
3
4
5
6
7
msg_info = client.publish()

if msg_info.is_published() == False:
    print(Message is not yet published.)

# This call will block until the message is published.
msg_info.wait_for_publish()

The next version of the client will also have the ability to specify per-message callbacks that will be called once that individual message is published, with a function call of the form:

1
client.publish(, callback=on_publish_msg)

Publish a retained message

To publish a retained message, simply set retain=True in the call to publish:

1
client.publish(, retain=True)

Publish using the utility functions

1
2
3
4
5
import paho.mqtt.publish as publish

publish.single(topic, payload=None, qos=0, retain=False, hostname="localhost",
           port=1883, client_id="", keepalive=60, will=None, auth=None,
           tls=None, protocol=mqtt.MQTTv31)

This function creates an MQTT client, connects to a broker and publishes a single message. Once the message has been delivered, it disconnects cleanly from the broker. It exposes all of the connection options present in the client, but most of them are not needed. A simple example would be:

1
publish.single(encyclopedia/temperature, payload=hot)

There is a full description of the the will, auth and tls parameters in the client documentation.

1
2
publish.multiple(msgs, hostname="localhost", port=1883, client_id="", keepalive=60,
             will=None, auth=None, tls=None, protocol=mqtt.MQTTv31)

This function is identical to publish.single, except that multiple messages can be published at once. The “msgs” parameter is a list of messages to publish. Each message should be a dict of the format

1
msg = {'topic':"<topic>", 'payload':"<payload>", 'qos':<qos>, 'retain':<retain>}

Subscribe

To subscribe to a topic use something like the example below:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import paho.mqtt.client as paho

def on_subscribe(client, userdata, mid, granted_qos):
    print("Subscribed: "+str(mid)+" "+str(granted_qos))

def on_message(client, userdata, msg):
    print(msg.topic+" "+str(msg.qos)+" "+str(msg.payload))    

client = paho.Client()
client.on_subscribe = on_subscribe
client.on_message = on_message
client.connect(broker.mqttdashboard.com, 1883)
client.subscribe(encyclopedia/#”, qos=1)

client.loop_forever()

In this example the on_subscribe and on_message callbacks are demonstrated. on_subscribe is called once the broker has responded to a subscription request. The granted_qos parameter contains a list of the granted QoS (or failure) codes sent by the broker. The on_message callback is called for each message received and the msg variable is an MQTTMessage class, which has members topic, payload, qos, retain and mid. The call to loop_forever() is blocking, which means the client will continue to print out incoming message information until the program is killed.

In this example, the call to client.subscribe() comes immediately after the call to client.connect(). Whilst this is valid, with a non-durable client the subscription will not be renewed if the connection to the broker drops and is renewed. It is suggested that for simple programs like this, putting the call to subscribe() in the on_connect callback will ensure that the subscription is renewed for each reconnection.

The subscribe function may be called in one of three ways:

Simple string and integer

1
subscribe("my/topic", qos=2)

topic: A string specifying the subscription topic to subscribe to. qos: The desired quality of service level for the subscription. Defaults to 0.

String and integer tuple

1
subscribe(("my/topic", 1))

topic: A tuple of (topic, qos). Both topic and qos must be present in the tuple.

List of string and integer tuples

1
subscribe([("my/topic", 0), ("another/topic", 2)])

This allows multiple topic subscriptions in a single SUBSCRIPTION command, which is more efficient than using multiple calls to subscribe().

topic: A list of tuple of format (topic, qos). Both topic and qos must be present in all of the tuples.

Per topic message callbacks

It is possible to add callbacks that respond only to messages published within a particular topic pattern. For example, you could subscribe to the topic “encyclopedia/#”, but have a message callback that would fire only for messages on the topic “encyclopedia/+/value”. This would be achieved with the following code:

1
2
client.subscribe(encyclopedia/#”)
client.message_callback_add(encyclopedia/+/value, on_message_value)

where on_message_value has the same format as the message callbacks already mentioned.

Unsubscribe

To unsubscribe, call:

1
client.unsubscribe(topic)

Topic is a single string, or list of strings that are the subscription topics to unsubscribe from.

The on_unsubscribe callback looks like:

1
on_unsubscribe(client, userdata, mid)

Disconnect

To unsubscribe, call:

1
client.unsubscribe(topic)

Topic is a single string, or list of strings that are the subscription topics to unsubscribe from.

The on_unsubscribe callback looks like:

1
on_unsubscribe(client, userdata, mid)

Disconnect

To disconnect:

1
client.disconnect()

The on_disconnect callback looks like:

1
on_disconnect(client, userdata, rc)

The rc parameter indicates whether this disconnection was intentional (rc=0, after a call disconnect()) or for some other reason (rc=1).

Using SSL / TLS

The client supports certificate based TLS. You should call the tls_set() function to enable TLS mode and to specify the CA certificates that you trust.

1
client.tls_set(/path/to/ca.crt)

It is also possible to set a client certificate, the certificate verification requirements, the version of TLS to use and the allowable ciphers: tls_set(self, ca_certs, certfile=None, keyfile=None, cert_reqs=cert_reqs, tls_version=tls_version, ciphers=None)

Full details of these parameters is given in the client documentation.

Full example application

A complete example demonstrating both publish and subscribe, is available in the project git repository.

This example is a utility that can clear retained messages from a broker based on a subscription pattern.

About Roger Light

Roger is a lecturer in the Electrical and Electronic Engineering Department at the University of Nottingham, UK. As well as developing the Paho Python client, he is also the lead and main developer of the mosquitto MQTT broker.

Website

<  HiveMQ 3.0 is now available!   |   MQTT.DART - MQTT Client Library Encyclopedia   >