How to make a response on the web using MQTT and Flask? - python

I have an issue with MQTT lib ( https://pypi.python.org/pypi/paho-mqtt/1.1 ).
I want to have async and sync tasks for multiple requests, but it seems I cannot get around an issue to make a response on web, for requested url /mqtt when actual subscribed message is received, because on_message is a callback function.
#app.route('/mqtt', methods=['POST', 'GET'])
def main():
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
test = on_message
client.username_pw_set('x', 'x')
client.connect("x", 1883, 60)
client.subscribe("/message/1")
client.loop_forever()
# how do I get the message from callback function on_message and then stop loop_forever?
#I thought about: return msg but it doesn't work.
def on_connect(client, userdata, flags, rc):
print("Connected with result code " + str(rc))
# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
#how to pass this msg to the main function?
print(msg.topic + " " + str(msg.payload))

To stop loop_forever when get message, you can use client.disconnect
Sample code:
def on_message(client, userdata, msg):
print(msg.topic + " " + str(msg.payload))
client.disconnect() # disconnect when get message
To pass message to main function, you can simply use global variable. But my suggestion is to start another process for mqtt client, pass variables via shared memory. It's a lot of overhead for connecting to mqtt broker every time got a GET or POST .

Related

doesn't publish data strings that i subscribed

In the following script i can subscribe from a topic but it wont publish my data strings and i don't get an error message. Are some functions out of order?
import paho.mqtt.client as mqtt
broker = "broker" #Broker address
port = 1883 #Broker port
user = "user" #Connection username
psw = "psw" #Connection password
client = mqtt.Client("Python")
client.username_pw_set(user, psw)
client.connect(broker, port, 60)
pubtopic = 'pubtopic'
def on_publish(client, pubtopic, msg):
print("publish data")
client.publish(pubtopic, msg.payload)
on_publish(client, msg.payload)
subtopic = 'subtopic'
def on_connect(client, userdata, flags, rc):
print("received: " + str(rc))
client.subscribe(subtopic)
def on_message(client, userdata, msg):
print(msg.topic+" "+str(msg.payload))
client.on_publish = on_publish
client.on_connect = on_connect
client.on_message = on_message
client.loop_forever()
Remove the on_publish callback it's not doing anything useful here, as #Brits mentioned, it is only called when this particular client publishes a message (which you are not doing in your current code) and the 3rd argument is not a full message object, it is just a message id field.
Please send some time and read the Python Paho doc section on callbacks.
It clearly lays out under what conditions each callback will be triggered.
If you want to react to a message you have subscribed to then you need an on_message callback. It is within this function that you need do any actions as a result of receiving that message.
e.g.
def on_message(client, userdata, msg):
print(msg.topic+" "+str(msg.payload))
client.publish(pubtopic, msg.payload)

Python/paho MQTT - not receiving messages

I am new to using MQTT and I would like to run two Python programs simultaneously: one to publish messages to a topic and the other to print out the messages as they are published to the topic. However, the callback function to print out the message isn't working for me.
These are the two programs I have:
Publish messages:
import paho.mqtt.client as mqtt
def on_connect(client, userdata, flags, rc):
print("Connected! Result code: " + str(rc))
client = mqtt.Client(client_id="clientID")
client.on_connect = on_connect
client.username_pw_set(username="username", password="password")
client.loop_start()
client.connect("node02.myqtthub.com", 1883)
while True:
client.publish("my/topic", "test")
Subscribe to and print messages:
import paho.mqtt.client as mqtt
def on_message(client, userdata, msg):
print(msg.payload.decode())
def on_connect(client, userdata, flags, rc):
print("Connected! Result code: " + str(rc))
client.subscribe("my/topic")
client = mqtt.Client(client_id="clientID")
client.on_connect = on_connect
client.on_message = on_message
client.username_pw_set(username="username", password="password")
client.connect("node02.myqtthub.com", 1883)
client.loop_forever()
Could someone help me fix this issue?
Both programs are using client_id="clientID"; the mqtt spec states
If the ClientId represents a Client already connected to the Server then the Server MUST disconnect the existing Client [MQTT-3.1.4-2].
So whichever app connects second will cause the first to be disconnected. To fix this change the client id in one of the apps.
Note: This is a comment on something obviously wrong. When asking a question please state what you see happening (any output, errors, what you have tried etc) because there may be another problem.

MQTT : Not able to send and receive messages at the same time and in the same file

I have written a code that can do both publishing and subscribing in the same python file. My aim is to be able to send endlessly color temperature to a lamp and receive back its state (ON/OFF or online/offline).
However, when I run the code, I can send messages to the lamp but I don't receive anything (note that publisher and subscriber worked well separately)
import paho.mqtt.client as mqtt
import sys
import time
topic = "testtopic/3"
topic_casa = "testtopic/1"
def on_connect(client, userdata, flags, rc):
print("Connection to the broker. Result : "+str(rc))
client.subscribe(topic_casa, qos=1)
client.publish(topic, light.circadianLight())
def on_message(client, userdata, msg):
Message = str(msg.payload)
print("[MSG RECEBIDA] Topico: "+msg.topic+" / Mensagem: "+Message)
def on_publish(client,userdata,result):
client.publish(topic, light.circadianLight())
time.sleep(10)
def on_disconnect(client, userdata, rc):
if rc != 0:
print("Unexpected disconnection.")
try:
print("[STATUS] Inicializando MQTT...")
#inicializa MQTT:
client = mqtt.Client()
client.username_pw_set(username, password)
client.on_connect = on_connect
client.on_message = on_message
client.on_disconnect = on_disconnect
client.on_publish = on_publish #with this callback we won't be able to
#receive messages
client.connect(Broker, PortaBroker, KeepAliveBroker)
client.loop_forever()
except KeyboardInterrupt:
print ("\nCtrl+C pressionado, encerrando aplicacao e saindo...")
sys.exit(0)
The problem is two fold, first that you are calling time.sleep(10) in the on_publish() callback.
This is blocking the MQTT client network loop so it will not send/receive any messages for 10 seconds every time you publish a message.
You should not be doing any blocking or long running tasks in any of the MQTT client callbacks.
The other problem is that without the sleep the client will spend all it's time publishing messages (because everytime it finishes publishing a message it trigger the on_publish() callback which kicks off another publish. It will never get round to handing the incoming messages.
If you want to publish messages at a regular interval then you need to start a separate thread to do it, not try to do it in the callbacks.

How can I send a image by using mosquitto?

I'm trying to send a jpg image using MQTT mosquitto broker(pub and sub) in Raspberry Pi2.
This is my python code pub.py(modified)
import paho.mqtt.client as mqtt
def on_publish(mosq, userdata, mid):
mosq.disconnect()
client = mqtt.Client()
client.connect("test.mosquitto.org", 1883, 60)
client.on_publish = on_publish
f=open("b.jpg", "rb") #3.7kiB in same folder
fileContent = f.read()
byteArr = bytearray(fileContent)
client.publish("image",byteArr,0)
client.loop_forever()
and it's sub.py(modified)
import paho.mqtt.client as mqtt
def on_connect(client, userdata, rc):
print("Connect" + str(rc))
client.subscribe("image")
def on_message(client, userdata, msg):
print "Topic : ", msg.topic
f = open("/tmp/output.jpg", "w") #there is a output.jpg which is different
f.write(msg.payload)
f.close()
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect("test.mosquitto.org", 1883, 60)
client.loop_forever()
My python verson is 2.7.9.
After I solved some error, It seems to work but It doesn't.
When I implement the sub.py, It connects successfully so I implement the pub.py in other terminal.
However, There isn't any reaction without connect message which is "Connect with result code 0"
There is no error message so I don't know what my mistake is.
Tested Code:
Requirements:
Install Mosquitto Broker
Install paho.mqtt package.
pub.py
import paho.mqtt.publish as publish
MQTT_SERVER = "xxx.xxx.xxx.xxx" #Write Server IP Address
MQTT_PATH = "Image"
f=open("image_test.jpg", "rb") #3.7kiB in same folder
fileContent = f.read()
byteArr = bytearray(fileContent)
publish.single(MQTT_PATH, byteArr, hostname=MQTT_SERVER)
One small modification, file permission is write byte instead of write mode.
sub.py
import paho.mqtt.client as mqtt
MQTT_SERVER = "localhost"
MQTT_PATH = "Image"
# The callback for when the client receives a CONNACK response from the server.
def on_connect(client, userdata, flags, 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(MQTT_PATH)
# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
# more callbacks, etc
# Create a file with write byte permission
f = open('output.jpg', "wb")
f.write(msg.payload)
print("Image Received")
f.close()
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect(MQTT_SERVER, 1883, 60)
# 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()
Expected Output:
Able to transfer the Image from Raspberry Pi to server machine.
In sub.py you have 2 on_public functions which should be renamed on_connect and on_publish respectively.
In pub.py you need to actually set the on_publish method on the client so it will be called once the publish has been completed.
...
client.connect("test.mosquitto.org", 1883, 60)
client.on_publish = on_public
...
Also as #ralight pointed out in his answer to your previous question, you should change client.loop(5) to client.loop_forever() it will still exit once the message has been sent because of the mosq.disconnect()
In your sub.py you need a callback which handles incoming messages for your subscription. The standard callback for that is on_message.
Just rename in your sub.y on_publish(client, userdata, msg) to on_message(client, userdata, msg)and assign client.on_message = on_message.

Paho Python MQTT client connects successfully but on_connect callback is not invoked

I have a simple script on a Raspberry Pi that publishes a sample message every 3 seconds. I have declared the callbacks on_connect, on_publish and on_disconnect. This client connects successfully but on_connect is not called, publishes and on_publish is called, disconnects and on_disconnect is called.
This is my script
import paho.mqtt.client as mqtt
import time
def on_connect(mqttc, userdata, rc):
print("Connected with result code "+str(rc))
if rc!=0 :
mqttc.reconnect()
def on_publish(mqttc, userdata, mid):
print "Published"
def on_disconnect(mqttc, userdata, rc):
if rc != 0:
print("Unexpected disconnection. Reconnecting...")
mqttc.reconnect()
else :
print "Disconnected successfully"
# Setup MQTT
# broker='test.mosquitto.org'
broker = 'iot.eclipse.org'
broker_port=1883
# Create a client instance
mqttc=mqtt.Client(client_id="MyClient")
mqttc.on_connect = on_connect
mqttc.on_publish = on_publish
mqttc.on_disconnect = on_disconnect
while 1:
mqttc.connect(broker, broker_port, 60)
# print "Connected." # I don't want this message.
# Why isn't the on_connect callback invoked?
try:
topic = "this/is/a/test/topic"
payload = "test_message"
print "Publishing " + payload + " to topic: " + topic + " ..."
mqttc.publish(topic, payload, 0)
except Exception as e:
print "exception"
log_file=open("log.txt","w")
log_file.write(str(time.time())+" "+e.__str__())
log_file.close()
mqttc.disconnect()
print ""
time.sleep(3)
Although this minor "bug" doesn't affect the message publishing, which is mainly what I want to achieve, why does it happen and how can I resolve it?
The reason this isn't working is that you aren't calling any of the loop*() functions. These process network traffic. If you don't use one, there is no guarantee your outgoing messages will be sent and absolutely no incoming messages will be processed.
loop_forever() is a blocking call that processes the network loop - probably not what you want.
loop_start() starts a thread to process the network loop and so returns straight away.
I would do this:
mqttc.connect(broker, broker_port, 60) # Don't forget to handle errors
mqttc.loop_start()
while 1:
try:
topic = "this/is/a/test/topic"
payload = "test_message"
print "Publishing " + payload + " to topic: " + topic + " ..."
mqttc.publish(topic, payload, 0)
except Exception as e:
print "exception"
log_file=open("log.txt","w")
log_file.write(str(time.time())+" "+e.__str__())
log_file.close()
print ""
time.sleep(3)
You do still need to fix your on_connect callback as #Kiran says.
There is no need to disconnect each time - and in fact there is no guarantee your message will have been sent when you do disconnect. You should use the on_publish callback to know when the message is sent.
If you want to do a simple connect-publish-disconnect, then maybe use the paho.mqtt.publish helper module:
import paho.mqtt.publish as publish
while 1:
try:
topic = "this/is/a/test/topic"
payload = "test_message"
print "Publishing " + payload + " to topic: " + topic + " ..."
publish.single(topic, payload, 0, host=broker, port=broker_port)
except Exception as e:
print "exception"
log_file=open("log.txt","w")
log_file.write(str(time.time())+" "+e.__str__())
log_file.close()
print ""
time.sleep(3)
Your on_connect() method declaration is missing the flags(1) parameter. So it is not getting invoked. Flags parameter contained the response sent by broker. It had to be
def on_connect(mqttc, userdata, flags, rc):
Also, why are you connecting and disconnecting in loop ? Try using the loop_start() and loop_stop() methods which handles auto-reconnections on a connection drop(example).

Categories

Resources