MQTT Client Library Encyclopedia – Paho Python

Guest post by Roger Light

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

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

MQTT 3.1 ok
MQTT 3.1.1 ok
LWT ok
SSL/TLS ok
Automatic Reconnect ok
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:

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:

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:

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:

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():

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:

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:

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

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:

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:

client.publish(…, callback=on_publish_msg)

Publish a retained message

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

client.publish(…, retain=True)

Publish using the utility functions

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:

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

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

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

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

Subscribe

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

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

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

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

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:

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:

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:

on_unsubscribe(client, userdata, mid)

Disconnect

To unsubscribe, call:

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:

on_unsubscribe(client, userdata, mid)

Disconnect

To disconnect:

client.disconnect()

The `on_disconnect callback` looks like:

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.

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:

https://github.com/eclipse/paho.mqtt.python/blob/master/examples/mqtt_clear_retain.py

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

Author Information

rogerlight
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

18 comments

  1. Ferry Boender says:

    The examples for Python have unicode double-quotes in them, instead of normal (“) quotes.

  2. I am attempting to use client.connect to a IPv6 broker. The topic is never posted to the broker. Works fine if I change the hostname in /etc/hosts to the IPv4 address of the broker. I have tried with both python 2 and 3. The broker itself works fine with IPv6 when I test it with mosquitto client from the CLI. Any advice ?

    mqttc.connect(“hhmqttbroker”, 1883)

  3. Prathamesh says:

    How can we find the number of connections made to the broker ?
    The broker doesn’t reflect anything in itself. Also what do we do if we need to find out number of subscribers to a certain topic ?

    1. Hallo there,

      you can find a list of all the metrics supported by HiveMQ here.
      Additionally our Plug In System allows for custom metrics.

      Hope that was helpful,
      Florian of the HiveMQ Team.

    2. Prathamesh says:

      Thanks Florian. I would check that out.

  4. Jagu.ar says:

    i’m looking for mqtt client that can connect to tls broker without providing .crt file. so the client will verify the broker with trusted sites (x.509).
    Does paho python support that?
    Does hivemq online broker support that?

    1. Hallo Jaguar,

      HiveMQ does support x.509 Client Certificate Authentication. See this chapter in the HiveMQ user guide.
      According to the MQTT Client Library Encyclopedia entry on Paho Python, which has been written by its developer:

      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)

      PS: If by “online broker” you are referring to the public HiveMQ broker. That does not have tls enabled.
      I hope this answers your question.

      Kind regards,
      Florian, form The HiveMQ Team.

  5. nit says:

    this repositary for the full code is not working

    1. thank you for noticing, seems paho moved their repositories.
      We updated the link in the article.

  6. R.G says:

    Thanks for the useful article!
    I just have a question about how to create more than one broker?

    1. Hallo R.G,

      We are glad you find the article useful.
      I am not certain I understand your query correctly. Paho is an MQTT client implementation, not a broker.
      Please specify your question in a more detailed way and I will gladly help you find an answer for your question.

      Kind regards,
      Florian from The HiveMQ Team.

    2. R.G says:

      I mean:
      How to create a broker cluster for HIVEMQ?
      Then connect the paho clients to this cluster.

    3. Hi R.G,

      The HiveMQ User Guide clustering chapter has all the information you need to build a HiveMQ cluster.
      Once you’re cluster is up and running you can connect the paho clients to either of the nodes.

      Kind regards,
      Florian from The HiveMQ Team.

    4. R.G. says:

      Thanks !
      If you do not mind, I have another question. Is there any possibility to reconnect the clients to another node in the cluster in case one of the broker nodes left the cluster?
      I do not want to change manually the IP of the broker that the clients connected to. Suppose I have have large number of clients connected to that broker node, changing the Ip manually in each client will not be practical.

    5. Hi there,

      You’re welcome. What you are describing is a scenario that happens a lot in real life deployments and is a concern for any clustered system.
      In order to have a single IP-ADDRESS to connect to as well as a functionality to distribute computing load equally amongst nodes of a system, there is functionality called
      load balancing

      Kind regards,
      Florian from The HiveMQ Team.

  7. sangar says:

    Hello thanks for your great tutorial. I’m a beginner to mqtt. i tried with the code that you provided, and I try to publish the message to the specific website address (this website was connected with hivemq ) from my raspberry pi but the message didn’t published. could you please tell the mistake in my code.
    I have installed paho python and mosquitto client on rpi.

    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(“xx.xx.xxx.xxx”, 1883)
    client.loop_start()
    while True:
    (rc, mid) = client.publish(“topic/hello”, “Hi”, qos=0)
    time.sleep(30)

    thanks in advance

  8. sangar says:

    hello at first thank you for your great tutorial. i want to publish message to specific ip address (my server ip=52.22.122.165 ), i replaced thehostname by ipaddress, but it didn’t work could you please suggest me a way to solve my problem please.

    1. Hallo Sangar,

      Glad you like the tutorial and are taking an interest in MQTT.
      In order to use a HiveMQ running on a server via the internet, you have to make sure, that the port, you opened the tcp-listener on, is reachable from the internet.

      Kind regards,
      Florian from The HiveMQ Team.

Leave a Reply

Your email address will not be published. Required fields are marked *