Python2 vs Python3 - parsing JSON - python

I try to read MQTT messages using Python. For debugging purposes, I reduced the program at the minimum.
import paho.mqtt.client as mqtt
import json
def on_connect(client, userdata, flags, rc):
print("Connected with code " + str(rc))
client.subscribe("temperature")
def on_message(client, userdata, message):
if message.topic == "temperature":
print("New message received")
dhtreadings_json = json.loads(message.payload)
temperature = dhtreadings_json['temperature']
print(temperature)
mqttc = mqtt.Client()
mqttc.username_pw_set("user","password")
mqttc.on_connect = on_connect
mqttc.on_message = on_message
mqttc.connect("192.168.1.133",1883,60)
mqttc.loop_forever()
Under Python 2, everything works fine:
Under Python3, I got the connection established message and I am informed that a new message was received and this is all. More than this no other output after:
Environment: Latest version of Raspbian on Raspberry Pi 3B+
As suggested, I replaced to print ("New message received", message.payload).
The message.payload is the same in Python2 and Python3.
Python2:
Python3:
Thank you!

This will be because with Python3 the message.payload is a byte array and with Python2 it's a string. (this can be seen in the images you posted because the Python3 strings are proceeded with b'...)
The change is to move closer to the MQTT spec which treats all MQTT payloads as just a collection bytes and also not making any assumptions about what character set should be used to covert the payload to a string.
The following should work with Python3 (assuming the initial json is utf-8 encoded)
dhtreadings_json = json.loads(message.payload.decode("utf-8"))

Related

mqtt paho library running test with docker

i've been trying to make this example running for many hours. I was building an example so my friend can learn some python but i've end up frustrated on my own.
My python knowledge is quite limited. Something is causing the program thread to finish no matter how much I try delaying the execution with time.sleep (i've removed that part of the code).
Expect result: sender container should be started after the receiver one. So the receiver is subscribed to the broker and waiting for messages.
Given result: receiver container starts and then dies.
Thanks in advance.
I have a docker compose as follows:
services:
mqtt_broker:
image: eclipse-mosquitto
volumes:
- "./mosquitto.conf:/mosquitto/config/mosquitto.conf"
client_send:
build:
context: ./client_send/
environment:
BROKER_HOST: mqtt_broker
depends_on:
- client_receive
client_receive:
build:
context: ./client_receive/
environment:
BROKER_HOST: mqtt_broker
depends_on:
- mqtt_broker
Then I have client code for each of these clients:
Receiver:
import os
import paho.mqtt.client as mqtt
def on_connect(client, userdata, flags, rc):
print("[receiver] Connected with result code " + str(rc))
client.subscribe("sample_topic")
def on_message(client, userdata, msg):
print("[receiver] got a message: " + str(msg.payload.decode()))
client.loop_stop()
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect(os.environ["BROKER_HOST"], 1883, 60)
client.loop_start()
Sender:
import os
import paho.mqtt.client as mqtt
def run():
print("[sender] will send a message")
client.publish("sample_topic", "message from sender")
client.loop_stop()
def on_connect(client, userdata, flags, rc):
print("[sender] Connected with result code " + str(rc))
run()
client = mqtt.Client()
client.on_connect = on_connect
client.connect(os.environ["BROKER_HOST"], 1883, 60)
client.loop_start()
I was using loop_forever without too much success bcoz print() calls were not logging anything since the main thread was blocked so I couldn't see if my code was working.
EDIT: previous paragraph is just not correct. loop_forever will work taking this into account: Python app does not print anything when running detached in docker
Finally got it working as suggested by #Brits (see comments) just by running exit or disconnecting the client (works using exit too)
I also keep the depends_on so the docker-compose.yml was not changed
This is the receiver:
import os
import paho.mqtt.client as mqtt
def on_connect(client, userdata, flags, rc):
print("[receiver] Connected with result code " + str(rc))
client.subscribe("sample_topic")
def on_message(client, userdata, msg):
print("[receiver] got a message: " + str(msg.payload.decode()))
client.disconnect()
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect(os.environ["BROKER_HOST"], 1883, 60)
client.loop_forever()
As a side note, if the main thread is blocked you will never be able to see the output of the program even if you got the message back from the sender. If you don't disconnect the client it might actually work if your application does not rely on console output. Soo freeing the main thread allows for the system to release the output logs to docker.

MQTT msg.payload funny characters

I have a temperature sensor connected to raspberry via MQTT on ESP32 controller, it display correctly temperature in Arduino IDE serial monitor also in Home Assistant webpage.
I am trying to get it display on Raspberry Pi console with a python 3 script. it display the value but add charachteres --> b' 22.71'
I tried to strip characters or display values from specific position without success. I need to have only temperature value for export it.
the script is
import paho.mqtt.client as mqtt
def on_connect(client, userdata, rc, *extra_params):
client.subscribe("ha/temperature")
def on_message(client, userdata, msg):
if msg.topic == 'ha/temperature':
print(msg.payload)
client = mqtt.Client("test")
client.on_connect = on_connect
client.on_message = on_message
client.username_pw_set(username="username",password="password")
client.connect("192.168.0.100", 1883, 60)
client.loop_forever()
the result is:
pi#raspberrypi:~ $ sudo python3 BasicMQTT.py
b' 22.71'
b' 22.71'
b' 22.71'
b' 22.71'
how it can be strip "b" "'" and space characters from output?
thanks in advance
This is because with python3 the paho library is returning a byte array not the string representation of the byte array for the payload.
You can fix changing the on_message callback as follows:
def on_message(client, userdata, msg):
if msg.topic == 'ha/temperature':
print(msg.payload.decode("utf-8") )

Paho mqtt client not working properly

I'm new to MQTT and raspberry pi! I'm running a client script and I simply publish a message using another script. I'm using my own Mosquitto broker.
Client:
import paho.mqtt.client as mqtt
def on_connect(client, userdata, flags, rc):
print("Connected with result code "+str(rc))
client.subscribe("Example/test")
client.subscribe("Example/topic")
def on_message(client, userdata, msg):
print(msg.topic+" "+str(msg.payload))
if msg.payload == "Hello":
print("Received message #1, do something")
if msg.payload == "World":
print("Received message #2, do something else")
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect("192.168.1.4", 1883)
client.loop_forever()
Publisher:
import paho.mqtt.publish as publish
publish.single("Example/test", "Hello", hostname="192.168.1.4")
publish.single("Example/topic", "World", hostname="192.168.1.4")
print("OK")
That's where things seem weird and those things happen.
1.When I run both the client and the publisher using the python3 command the if statements are skipped and only topic + payload are printed
2.When I run the client using python command and publisher using both python3 and python command everything works fine!
3.When I do all the above, while running the client on virtualenv again the if statements are ignored, in all occasions!
I would like to know if there is a compatibility reason for this to happen, or anything wrong in the code as I must run something more complicated like that on virtualenv!
UPDATE: I found a solution that works fine !
In the client code in the if statement I used
if msg.payload == b"Hello":
and
if msg.payload == b"World":
As far as I know it must have been due to a variable type thing and they didn't match.
I found a solution that works fine !
In the client code in the if statement I used
if msg.payload == b"Hello":
and
if msg.payload == b"World":
As far as I know it must have been due to a variable type thing and they didn't match.
stumbled upon this post while trying Paho mqtt client -
It may be good to note how characters & bytes are treated in Python, as explained in detail in this post.
So, above snippet could also be written as,
if (msg.payload.decode() == 'Hello'):

OpenCV (in C++) to MQTT broker

My goal is to publish from OpenCV (C++) a JSON stream of (x, y) coordinates to an MQTT broker. I'm confused as to a good way to transmit the JSON data to MQTT from OpenCV.
I currently have an MQTT broker that manages a JSON message queue between a Python publisher script on Computer 1 and a Javascript client script on Computer 2. I have Computer 3 running OpenCV and need to send many small JSON blobs of (x, y) coordinates in near real-time to the MQTT broker.
I initially considered continuously writing coordinates from OpenCV to a local text file, which is then continuously read by a Python MQTT publisher script that runs in parallel. However, there are issues around file locking and it seems that writing to disk is unnecessary.
Ideally, I'm hoping for the stream of coordinates to stay in memory and published to the MQTT broker often, say every 10ms. I'm struggling to find a way to use stdin/stdout to work between the OpenCV code and a Python publisher script.
Your guidance is appreciated. Thank you.
Not certain what parts you are missing, but you basically want:
#include "mqtt.h"
...
// Start up
mqtt_broker_handle_t *broker = mqtt_connect(client_name, ip_addr, port);
...
...
// Update broker
mqtt_publish(broker, topic, msg, QoS1);
You mentioned a python script for a publisher.
Here is the publisher:
#!/usr/bin/env python3
import paho.mqtt.client as mqtt
# This is the Publisher
client = mqtt.Client()
client.connect("localhost",1883,60)
client.publish("topic/test", "Hello world!", qos=0, retain=False)
client.disconnect()
Here is a subscriber:
#!/usr/bin/env python3
import paho.mqtt.client as mqtt
# This is the Subscriber
def on_connect(client, userdata, flags, rc):
print("Connected with result code "+str(rc))
client.subscribe("topic/test")
def on_message(client, userdata, msg):
if msg.payload.decode() == "Hello world!":
print("Yes!")
client.disconnect()
client = mqtt.Client()
client.connect("localhost",1883,60)
client.on_connect = on_connect
client.on_message = on_message
client.loop_forever()

How can i fix "UnicodeDecodeError:'ascii' code can't decode byte oxff in psition" error

I've been trying to pub and sub a image using mosquitto in R-pi.
This is pub.py
import paho.mqtt.client as mqtt
def on_publish(mosq, userdata, mid):
mosq.disconnect()
client = mqtt.Client()
client.connect("test.mosquitto.org", 1883, 60) #error?
f = open("1.jpg", "rb")
fileContent = f.read()
byteArr = bytes(fileContent)
client.publish("image", byteArr, 0)
client.loop(5)
However, there is a error which is "UnicodeDecodeError:'ascii' code can't decode byte oxff in psition" when I run it.
I've thought this error is caused by "test.mosquitto.org" Line 8.
So, I was trying to change it other ways but It didn't work.
The most wired thing is that it worked when I'd tried open a text file and extract some char and pub/sub like this source.
#It does work
import paho.mqtt.client as mqtt
def on_public(mosq, userdata, mid):
mosq.disconnect()
client = mqtt.Client()
client.connect("test.mosquitto.org", 1883, 60)
f=open("text.txt")
con=f.read(3)
client.publish("image",con)
client.loop(5)
I can't find any difference and solve.
It looks like you're running Python 2.7.
Try replacing
byteArr = bytes(fileContent)
with
byteArr = bytearray(fileContent)
The former still looks like a string, which is then passed through upayload = payload.encode('utf-8') by the library. If you've got binary data that won't work.
Other things you should do are to replace client.loop(5) with client.loop_forever(), otherwise the file may not get sent.
You don't assign your callback function either.

Categories

Resources