Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I publish a file using Mosquitto in python?

Tags:

python

mqtt

I am using python-mosquitto to subscribe to my MQTT broker which support file type uploads. I can use it just fine using the -f flag when going from Mosquitto on the command line. However, I can't figure out how to use the client.publish(topic, payload) to specify a file to publish when doing it from within my python script.

Python mosquitto gives me the error TypeError: payload must be a string, bytearray, int, float or None. when I try to throw something weird at it. I have a file stored in local directory already which I want to specify as the payload of the publish.

I'm experienced with MQTT but my python is very rusty, I am assuming I need to do some type of file stream function here, but not sure how to do it.

I want to specify the image here: mqttc.publish("/v3/device/file", NEED_TO_SPECIFY_HERE)

I have tried opening the image by doing:

    f = open("/home/pi/mosq/imagecap/imagefile.jpg", "rb")
    imagebin = f.read()
    mqttc.publish("/v3/device/file", imagebin)

But that didn't work and neither did mqttc.publish("/v3/device/file", bytearray(open('/tmp/test.png', 'r').read()))

The client.publish doesnt throw an error with those, but the file is not received properly by the broker. Any ideas?

Thanks!!

like image 211
calumb Avatar asked Oct 22 '13 00:10

calumb


2 Answers

The publish has to be the whole file at once, so you will need to read the whole file in and publish it in one go.

The following code works

#!/usr/bin/python

import mosquitto

client = mosquitto.Mosquitto("image-send")
client.connect("127.0.0.1")

f = open("data")
imagestring = f.read()
byteArray = bytes(imagestring)
client.publish("photo", byteArray ,0)

And can be received with

#!/usr/bin/python

import time
import mosquitto

def on_message(mosq, obj, msg):
  with open('iris.jpg', 'wb') as fd:
    fd.write(msg.payload)


client = mosquitto.Mosquitto("image-rec")
client.connect("127.0.0.1")
client.subscribe("photo",0)
client.on_message = on_message

while True:
   client.loop(15)
   time.sleep(2)
like image 129
hardillb Avatar answered Oct 25 '22 20:10

hardillb


It's worth noting that this is one of the areas that can have differences between Python 2 and Python 3.

Python 2 file.read() returns a str whereas Python 3 is bytes. mosquitto.publish() handles both types so you should be ok in that case, but it is something to be aware of.

I've added what I consider some minor improvements to @hardillb 's code below. Please don't accept my answer in preference to his because he wrote it originally and got there first! I would have edited his answer, but I think it's useful to see the difference.

#!/usr/bin/python

import mosquitto

def on_publish(mosq, userdata, mid):
  # Disconnect after our message has been sent.
  mosq.disconnect()

# Specifying a client id here could lead to collisions if you have multiple
# clients sending. Either generate a random id, or use:
#client = mosquitto.Mosquitto()
client = mosquitto.Mosquitto("image-send")
client.on_publish = on_publish
client.connect("127.0.0.1")

f = open("data")
imagestring = f.read()
byteArray = bytes(imagestring)
client.publish("photo", byteArray ,0)
# If the image is large, just calling publish() won't guarantee that all 
# of the message is sent. You should call one of the mosquitto.loop*()
# functions to ensure that happens. loop_forever() does this for you in a
# blocking call. It will automatically reconnect if disconnected by accident
# and will return after we call disconnect() above.
client.loop_forever()
like image 45
ralight Avatar answered Oct 25 '22 19:10

ralight