How to exit mqtt forever_loop? - python

I created a program to receive data, recently.
And I want to break the loop When I receive a specific data.
For example, if I receive "1" to another machine, then my system will regard it
as an illegal number, then it will break the loop to stop receiving data.
Here is my code in the below, and you can also see client.loop_stop() in my code. But it not works.
I have also tried sys.exit() in my code.
Although it works in this case, it is not suitable to be utilized in other situation.
So I am wondering about how to break the loop of the client, I don't want to close the whole system by sys.exit().
import paho.mqtt.client as mqtt
# This is the Subscriber
a=""
def on_connect(client, userdata, flags, rc):
print("Connected with result code "+str(rc))
client.subscribe("hello")
def on_message(client, userdata, msg):
info=msg.payload.decode()
print info
if str(info)=='1':
print "OK"
client.loop_stop()
client = mqtt.Client()
client.connect("myIp",1883,60)
client.on_connect = on_connect
client.on_message = on_message
client.loop_forever()

In order to stop loop_forever, you must use client.disconnect, not loop_stop.

Related

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 do I continue my program to run even when my MQTT client does not connect?

I'm writing a python program that runs on the raspberry pi and connects to the pic-camera. As I'm using MQTT, when the client does not connect by program freezes. is there any way to continue to run the program even if the client does not connect, i.e. I don't receive any data but the camera still runs.
As an example, how do I print x even if the client does not connect?
import time
import paho.mqtt.client as mqtt
import json
def on_connect(client, userdata, rc):
print ("Connected with rc: " + str(rc))
client.subscribe("demo/test1")
def on_message(client, userdata, msg):
data_json = msg.payload
data = json.loads(data_json)
print(data['ant_plus_power'])
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
x = client.connect("118.138.47.99", 1883, 60)
print(x)
client.loop_forever()
Edit: I ran your code on my end and I get a TimeoutError exception after about 30 seconds: "A connection attempt failed because the connected party did not properly respond after a period of time". You need to handle that exception in your code, so that the program continues running even when it fails to connect:
try:
client.connect("118.138.47.99", 1883, 60)
client.loop_forever()
except:
print("failed to connect, moving on")
print("rest of the code here")
This outputs:
failed to connect, moving on
rest of the code here
However, using connect() and loop_forever() isn't suitable for your needs since they are blocking functions (meaning, they block the execution of your code and prevent it from doing anything else). With the code above, if the client successfully connects, print("rest of the code here") will never be reached due to loop_forever().
Instead, try using connect_async() in conjunction with loop_start() to connect in a non-blocking manner (meaning, your program can continue doing other things while attempting to connect in the background):
client.connect_async("118.138.47.99", 1883, 60)
client.loop_start()
print("rest of the code here")
while True:
time.sleep(1)
This outputs rest of the code here and continues running indefinitely (in the infinite while loop) regardless of whether the connection was successful or not.
Note that your on_connect() definition is missing one argument. It should be:
on_connect(client, userdata, flags, rc)
Also it might be a good idea to check the return code of on_connect, and only subscribe if the connection is successful:
def on_connect(client, userdata, flags, rc):
if rc == 0:
client.connected_flag = True # set flag
print("Connected OK")
client.subscribe("demo/test1")
else:
print("Bad connection, RC = ", rc)
mqtt.Client.bad_connection_flag = True
# create flags so you can check the connection status throughout the script
mqtt.Client.connected_flag = False
mqtt.Client.bad_connection_flag = False
See https://www.eclipse.org/paho/clients/python/docs/ and http://www.steves-internet-guide.com/client-connections-python-mqtt/.
For quickly testing a successful connection, you can connect to test.mosquitto.org (see https://test.mosquitto.org/).

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

Python MQTT Connect only for a limited time

I have a Python script wherein I'm connected to a MQTT server. I'm expecting to get a message through the topic where I'm subscribed to, but should I not receive the message, I want to terminate the script entirely.
The script I'm working with looks as follows:
#!/usr/bin/python
import sys
import json
import paho.mqtt.client as mqtt
def on_message(client, userdata, msg):
if msg.topic == "discovery":
data = json.loads(msg.payload)
serial = data['serial']
print "test successful!"
sys.exit(0)
def on_connect(client, userdata, flags, rc):
client.subscribe([("discovery", 2)])
client = mqtt.Client()
try:
client.connect('localhost', 4444)
except:
print "ERROR: Could not connect to MQTT
client.on_connect = on_connect
client.on_message = on_message
client.loop_forever()
I have tried using a while True statement to loop and figure the time passing in between starting the script and it getting the message, but it seemed to (obviously) not escape the loop even while it gets the message through.
Is there a way that I can say how long it be connected for, and when it exceeds that time, just terminate the script entirely?
Or perhaps, is there a way (as I tried before) to make a loop but also consider the message coming through while in the loop?
Thanks for your suggestions!
Try something like this
It should wait for about 5 seconds for an incoming message then quit. You can adjust the wait time by changing the value waitTime just before the while loop
I have used the version of the mqtt network loop function that only runs for a short time and put it in a while loop. The loop also checks elapsed time and disconnects the client cleanly before bailing out of the loop. I also added a clean client exit for when a message is received.
#!/usr/bin/python
import sys
import json
import paho.mqtt.client as mqtt
import time
def on_message(client, userdata, msg):
if msg.topic == "discovery":
data = json.loads(msg.payload)
serial = data['serial']
print "test successful!"
client.disconnect()
sys.exit(0)
def on_connect(client, userdata, flags, rc):
client.subscribe([("discovery", 2)])
client = mqtt.Client()
try:
client.connect('localhost', 4444)
except:
print "ERROR: Could not connect to MQTT"
client.on_connect = on_connect
client.on_message = on_message
startTime = time.time()
waitTime = 5
while True:
client.loop()
elapsedTime = time.time() - startTime
if elapsedTime > waitTime:
client.disconnect()
break

Categories

Resources