Simple Python MQTT Publish and Subscribe Example Script

This is a very simple example script to publish to a topic, and then receive the published message.

To do that we will need to first subscribe to the topic and then publish messages to the same topic.



We will publish and subscribe using the same client.

The Code


import time
import paho.mqtt.client as paho
broker="broker.hivemq.com"
broker="iot.eclipse.org"
#define callback
def on_message(client, userdata, message):
    time.sleep(1)
    print("received message =",str(message.payload.decode("utf-8")))

client= paho.Client("client-001") #create client object client1.on_publish = on_publish #assign function to callback client1.connect(broker,port) #establish connection client1.publish("house/bulb1","on")
######Bind function to callback
client.on_message=on_message
#####
print("connecting to broker ",broker)
client.connect(broker)#connect
client.loop_start() #start loop to process received messages
print("subscribing ")
client.subscribe("house/bulb1")#subscribe
time.sleep(2)
print("publishing ")
client.publish("house/bulb1","on")#publish
time.sleep(4)
client.disconnect() #disconnect
client.loop_stop() #stop loop

Note: You can copy the code direct from the page, paste it in a file and use.

When we run the script we get

pub-sub-code-output

Code Explanation and Notes

I use the time.sleep() function to insert delays so as to give the client time to connect etc.

We publish and subscribe using the same client.

The client.loop() is important otherwise the callbacks aren’t triggered.

The on message callback function catches the callback and the client.on_message=on_message binds the function to the callback.

There is no error checking i.e. I don’t check for a successful connection before publishing, and subscribing.

I have two free external brokers listed as sometimes the brokers are down and you will need to use the other one.

Just comment out the one you aren’t using.

I’ve used the topic house/bulb1 you can use any topic name you want.

Questions and Things to Try

  1. What would happen if I published before I subscribed?
  2. What would happen if I didn’t start the loop?
  3. What would happen if I didn’t bind the on_message function to the callback?

Answers below

Useful Tutorials and Resources:

Answers

  1. The message would be discarded by the broker.
  2. You wouldn’t see the message.
  3. You wouldn’t see the message.

Save

Save

Save

Save

Save

Save

Facebooktwittergoogle_plusredditpinterestlinkedinmail

20 comments

  1. Hi Steve,
    Wondering if you tried to log a MQTT message to a SQL database (MySQL for instance)? I’m working on a small python script that keeps status of a MQTT message before logging data into MySQL database. The very odd thing is that the MySQL piece of code block never get executed (within a try … except trap). Any experience in that direction?
    Thanks,
    Yanick

  2. Hi, I tried your script with a broker (an other pi) on my lan and I get the result expected. Therefore, for me is still missing a piece of the story (I admit, non only from you tutorial!): how can I publish from a client and read from an other client? How can I keep running two pi’s and transmit infos with mqtt from one pi to the other? Should I launch a script like this one for the publisher and a second script for the subscriber? The web if full of examples using third party apps for the cloud but I would leave all my stuff on the lan.
    Thanks

    1. To get a publish script and subscribe script then just copy the pub-sub script.
      You then need to change the client name as each client needs to use its own name.
      You can then remove the subscribe code from the publish script and the publish code from the subscribe script.

      To move info between two pi’s then you need to publish from pi 1 and subscribe using pi 2 and vice versa. This you can do using the original pub-sub script.you will need to assign topic names e.g
      pi 1 would publish on topic pi-1 and pi 2 would subscribe to topic pi-1 and vice versa.
      The broker could be located on one of the pi’s or in the cloud.
      Does it make sense?

      1. Hi Steve, thank you for the suggestion. I created two separate scripts, one for the publisher (also broker) and one on a second machine for the subscriber. Both scripts have a while cicle. I launch together and I get message appearing on subscriber at regular intervals.
        Thank you again

  3. Hi Steve,
    Thanks for nice explanation,I want to explore on MQTT from scratch .
    Could you please suggest any link/documentation with few hands on examples.
    Thanks in advance!!!

  4. I get this error please suggest solution for this

    Traceback (most recent call last):
    File “/home/pi/RPi/mqtt1.py”, line 29, in
    client.loop_forever()
    File “/usr/local/lib/python3.5/dist-packages/paho/mqtt/client.py”, line 1481, in loop_forever
    rc = self.loop(timeout, max_packets)
    File “/usr/local/lib/python3.5/dist-packages/paho/mqtt/client.py”, line 1003, in loop
    rc = self.loop_read(max_packets)
    File “/usr/local/lib/python3.5/dist-packages/paho/mqtt/client.py”, line 1284, in loop_read
    rc = self._packet_read()
    File “/usr/local/lib/python3.5/dist-packages/paho/mqtt/client.py”, line 1849, in _packet_read
    rc = self._packet_handle()
    File “/usr/local/lib/python3.5/dist-packages/paho/mqtt/client.py”, line 2311, in _packet_handle
    return self._handle_connack()
    File “/usr/local/lib/python3.5/dist-packages/paho/mqtt/client.py”, line 2372, in _handle_connack
    self.on_connect(self, self._userdata, flags_dict, result)
    File “/home/pi/RPi/mqtt1.py”, line 12, in on_connect
    client.subscribe(“/esp/pot”,0) # remember this topic to put inside ESP code later
    AttributeError: ‘NoneType’ object has no attribute ‘subscribe’

    1. my script file running in raspberry pi

      # Main template for our paho.mqtt.client code
      # lets obtain potentiometer reading from ESP8266
      # listen to topic “/esp/pot”
      import paho.mqtt.client as mqtt

      # The callback for when the client receives a CONNACK response from the server.
      def on_connect(self,client, userdata, rc):
      print(“Connected with result code “+str(rc))
      # Subscribing in on_connect() means that if we lose the connection and
      # reconnect then subscriptions will be renewed.
      client.subscribe(“/esp/pot”) # remember this topic to put inside ESP code later

      # The callback for when a PUBLISH message is received from the server.
      def on_message(client, userdata, msg):
      print(“on msg”)
      print(msg.topic+” “+str(msg.payload))

      client = mqtt.Client()
      client.on_connect = on_connect
      client.on_message = on_message

      client.connect(“localhost”, 1883) # localhost is the Raspberry Pi itself

      # Blocking call that processes network traffic, dispatches callbacks and
      # handles reconnecting.
      # Other loop*() functions are available that give a threaded interface and a
      # manual interface.
      client.loop_forever()

  5. Thank you for the explanation on how to use MQTT under Python. I have managed to successfully write a script to control my house heating using a Raspberry Pi with Mosquitto and Python3. It is running flawlessly as far as I can tell.

    I have tried to make it start at boot in case the Pi goes down and starts when power is restored but I can’t get it to work when called via a cron job. It seems it can’t find the client and publish libraries presumably because it is being run by root at this stage.

    Is it possible to give the full path to the import function and, what is more to the point, what would that path be?

    1. John
      I’ve haven’t done what you are trying but I would try running the cron job as your normal user I found these instructions.
      https://stackoverflow.com/questions/8475694/how-to-specify-in-crontab-by-what-user-to-run-script

      On my Linux box the mqtt client is under
      /home/steve/.local/lib/site-packages
      On some of my scripts I use my own classes which I don’t put in site packages the command at the top of the python script to set the path is this.(windows system)
      sys.path.append(“c:/python34/steve/network/”)
      Hope that helps.
      Rgds
      Steve

      1. Hi Steve,

        Many thanks for your reply. I really thought that you had cracked it when you suggested using cron as a local user but, unfortunately, not.

        I also tried adding the two lines:
        import sys
        sys.path.append(“/home/pi/.local/lib/python3.5/site-packages/paho/mqtt”)
        at the top of my script (having checked with FileZilla that that was where the packages where kept) but again, no luck.

        It’s interesting that Python did not balk at the’ import sys’ so it must be something to do with Python not being able to find the Paho library. It says, “No module named ‘paho'”

        Anyway, I shall have to shelve this for now; it has taken up far too much of my time (and yours). The program works just fine; I just have to start it manually in the event of a system reboot.

        Thanks again,

        John.

        1. John
          Try import the paho client using the full path in a normal script (not cron) or a python shell. That way you can be sure it is were you think it is.
          If it is finding SYS Ok then it is a path problem.

          1. Once again, so close but not quite there.

            I added the full path but Python balked at the forward slashes. Then it dawned on me that the path uses dots and not forward slashes. BUT the .local directory has a dot in the name and I haven’t figured out how to escape it in that situation.

            Despite the fact that I said I was going to shelve the problem, I did try putting ‘sleep 100’ in the shell file so that the system had time to settle before attempting to import any Paho libraries but again, no joy.

            Thanks for your help. If I ever sort it, I shall get back to you and let you know what the solution is.

            John.

          2. I finally got back to this problem and I have now found a solution.
            I created a script file called ‘ch_boot.sh’ in my python directory. It contains 2 lines:
            sleep 10
            python3 /home/pi/jb_python/Heating_RPi.py &
            In my cron file, opened using crontab -e (not sudo), I added the following:
            @reboot /home/pi/jb_python/ch_boot.sh
            And it works!
            I think that allowing the 10 seconds before starting the script allows Raspbian time to set up set up MQTT properly and load the references to the Paho library.
            Anyway I thought you would be interested in the solution and many thanks for you help.

Leave a Reply

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