I'm currently working on a little MQTT-Projekt where I want to connect a raspberry pi to a windows pc. The connection between those two works perfectly but the problem is that the pc (where the MQTT-Broker is on) starts later than the pi and therefor the connection has to be delayed.
I did a while loop around the client.connect() method so it will try to connect every 2 seconds. But in my case it tries for example 5 times and then stops.
I also implementet a thread that starts a timer that checks if I received a message. The problem with the timer is that it jumps sometimes from 20 seconds to 100 for example.
I guess I misunderstood threads and I made a mistake with it but I don't know where.
My code looks like this:
import threading
import time
import paho.mqtt.client as mqtt
shutdown = 0
def on_connect(client, userdata, flags, rc):
print("Connected with result code "+str(rc))
client.subscribe("CoreElectronics/test")
client.subscribe("CoreElectronics/topic")
def on_message(client, userdata, msg):
global shutdown
shutdown = time.time()
print(msg.topic+" "+str(msg.payload))
def check_connect():
try:
client.connect("192.168.xx.xx", 1883, 60)
return True
except:
print("No connection")
return False
def timer_count():
global shutdown
shutdown = time.time()
elapsed = 0
while elapsed < 10:
elapsed = time.time()-shutdown
print("no Message")
time.sleep(2)
t1 = threading.Thread(target = timer_count)
t1.start()
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
while(True):
if check_connect():
break;
else:
time.sleep(2)
client.loop_forever()
Running this program prints out:
No Message
No Connection
No Message
No Message
No Message
No Message
But in my case it should print out both things simultaneously all the time.
After it doesn't print out No Connection it also doesn't connect to the Broker when it is running...
I made it work by not doing a while loop around the client.connect(xxx). I first checked with the netiface library if the interface was there and then try to connect to it. In this case it waited for the connection and then it worked. Thanks to #JohnAnderson I learned that the client.connect(xxx) is blocking and therefore cause some problems.
Related
I don’t understand why the callback “on_message” is not triggered when a message is published correctly in the same topic that i’m subscribed.
This the code I used:
def on_connect(client, userdata, flags, rc):
""" Callback called when connection/reconnection is detected """
print("Connect %s result is: %s" % (host, rc))
# With Paho, always subscribe at on_connect (if you want to
# subscribe) to ensure you resubscribe if connection is
# lost.
client.subscribe("some/message/to/publish")
if rc == 0:
client.connected_flag = True
print("connected OK")
return
print("Failed to connect to %s, error was, rc=%s" % rc)
# handle error here
sys.exit(-1)
def on_message(client, userdata, msg):
""" Callback called for every PUBLISH received """
print("%s => %s" % (msg.topi, str(msg.payload)))
# Define clientId, host, user and password
client = mqtt.Client(client_id=client_id, clean_session=clean_session)
client.username_pw_set(user_name, password)
client.subscribe("some/message/to/publish")
client.on_connect = on_connect
client.on_message = on_message
# connect using standard unsecure MQTT with keepalive to 60
client.connect(host, port, keepalive=60)
client.connected_flag = False
while not client.connected_flag: # wait in loop
client.loop()
time.sleep(1)
client.subscribe("some/message/to/publish")
# publish message (optionally configuring qos=1, qos=2 and retain=True/False)
ret = client.publish("some/message/to/publish", "{'status' : 'on'}")
client.loop()
print("Publish operation finished with ret=%s" % ret)
client.disconnect()
This the exit code I’ve got:
Connect node02.myqtthub.com result is: 0
connected OK
Publish operation finished with ret=(0, 3)
Process finished with exit code 0
Calling client.loop() only processes a single iteration of the client's network event processor.
The call to client.publish() can take multiple events to complete (depending on the size of the message and the QOS being used) and will be totally separate from handling the message when the broker sends it back to the client.
The call to client.subscribe() will also consume at least one event loop call.
So the single call to client.loop() will not be enough.
Unless you have a really good idea about what you are doing you should probably be using the client.start_loop()/client.stop_loop() functions to run the event processing loop on a separate thread.
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.
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/).
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.
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