Using Paho Python: Why the callback “on_message” is not triggered? - python

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.

Related

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.

Mqtt broker is disconnecting frequently even though it has a unique client id

Hi I have a mqtt broker up and running. I am connecting to it from python using paho-mqtt.
Code
def on_connect(client, userdata, flags, rc):
if rc==0:
print("connected OK Returned code=",rc)
else:
print("Bad connection Returned code=",rc)
print("Subscribing to topic","data/#")
client.subscribe("data/#")
def on_disconnect(client, userdata, rc):
print("Client Got Disconnected")
if rc != 0:
print('Unexpected MQTT disconnection. Will auto-reconnect')
else:
print('rc value:' + str(rc))
broker_address="ip"
port = 'port'
print("creating new instance")
client = mqtt.Client(clean_session=True) #create new instance
client.on_connect = on_connect
client.on_message = on_message #attach function to callback
client.on_disconnect = on_disconnect
print("connecting to broker")
client.connect(broker_address, port=port,) #connect to broker
client.loop_forever() #stop the loop
I am using the same code in multiple scripts ,connecting to broker and subscribing to a topic. The frequency of disconnection was less when there were 5-6 scripts. I have around 12-13 scripts connecting to the broker and frequency of disconnects has increased significantly. Is there some thing wrong with the connection in the scripts or its about the broker. Can someone help me with this?
My guess though is your broker does not like the fact that the Python client defaults to a null clientid. As per the spec it should treat this as an indication it must assign a unique id to your client, but it may be implementing the spec improperly?
Please try passing a randomly generated / unique client id in your connect(), as this will guarantee your clients are all unique, rather than all having the same id which for your broker means it's kicking out any connected client when a new one with the same id tries to connect.

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/).

Thread is blocking the console

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.

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