Paho mqtt on internet disconnect not running callback - python

I have this mqtt class
class MQTT():
def __init__(self):
# Observer.__init__(self) # DON'T FORGET THIS
self.mqttClient = paho.Client(client_id=constants.MQTT_CLIENT_ID)
self.mqttClient.username_pw_set(username=constants.MQTT_BROKER_USERNAME, password=constants.MQTT_BROKER_PASSWORD)
# assign mqtt event callbacks
self.mqttClient.on_message = self.on_message
self.mqttClient.on_connect = self.on_connect
self.mqttClient.on_disconnect = self.on_disconnect
self.mqttClient.on_socket_close = self.on_disconnect
self.mqttClient.on_log = self.on_log
def on_disconnect(self,client, userdata, rc):
log("MQTT DISCONNECT:",client, userdata, rc)
and then
mqtt = MQTT()
If i run my code it work perfectly but then i have to run some functions when internet connection is lost. So for that i am using on_disconnect and after running code if turn of network nothing happen. I want some call back to run on Internet connection lost. Do we have any ?

on_disconnect is the right callback for this - the question is when it gets called?
If the network connection is lost your client will only notice it at its next attempt of transmission. So if the client is not about to publish something (or acknowledge a subscription which was received just before the connection dropped) the next transmission will be the PINGREQ
By default keepalive is set to 60 - that means your client will send a PINGREQ every 60 seconds if no other control package was sent within this time interval.
So the on_disconnect callback will be called, it just does not happen as fast as you expected. Try a lower keepalive to improve on this

Related

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.

mqtt_client does not publish immediately [duplicate]

I am implementing a program that listen to a specific topic and react to it when a new message is published by my ESP8266. When a new message is received from ESP8266, my program will trigger the callback and perform a set of tasks. I am publishing two messages in my callback function back to the topic that the Arduino is listening. However, the messages are published only after the function exits.
Thank you for all your time in advance.
I have tried to use loop(1) with a timeout of 1 second inside the callback function. The program will publish the message immediately, but it seems to stuck in the loop. Will someone be able to give me some pointers how can I execute each publish function immediately in my callback function, instead of when the whole callback completes and return to the main loop_forever()?
import paho.mqtt.client as mqtt
import subprocess
import time
# 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("ESP8266")
# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
print(msg.topic+" "+str(msg.payload))
client.publish("cooking", '4')
client.loop(1)
print("Busy status published back to ESP8266")
time.sleep(5)
print("Starting playback.")
client.publish("cooking", '3')
client.loop(1)
print("Free status published published back to ESP8266")
time.sleep(5)
print("End of playback.")
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect("192.168.1.9", 1883, 60)
#client.loop_start()
# 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()
You can't do this, you are already in the message handling loop (that's what called the on_message function) at the point you call publish. This will queue the outgoing messages to be handled by the next iteration of the loop, that's why they are sent once on_message returns.
It hangs when you call the loop method because the loop is already running.
You should not be making blocking (sleep) calls in the on_message callback anyway, if you need to do thing that take time, start up a second thread to do these. By doing this you free up the network loop to handle the outgoing publishes as soon as they are made.

Python Paho MQTT: Unable to publish immediately in a function

I am implementing a program that listen to a specific topic and react to it when a new message is published by my ESP8266. When a new message is received from ESP8266, my program will trigger the callback and perform a set of tasks. I am publishing two messages in my callback function back to the topic that the Arduino is listening. However, the messages are published only after the function exits.
Thank you for all your time in advance.
I have tried to use loop(1) with a timeout of 1 second inside the callback function. The program will publish the message immediately, but it seems to stuck in the loop. Will someone be able to give me some pointers how can I execute each publish function immediately in my callback function, instead of when the whole callback completes and return to the main loop_forever()?
import paho.mqtt.client as mqtt
import subprocess
import time
# 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("ESP8266")
# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
print(msg.topic+" "+str(msg.payload))
client.publish("cooking", '4')
client.loop(1)
print("Busy status published back to ESP8266")
time.sleep(5)
print("Starting playback.")
client.publish("cooking", '3')
client.loop(1)
print("Free status published published back to ESP8266")
time.sleep(5)
print("End of playback.")
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect("192.168.1.9", 1883, 60)
#client.loop_start()
# 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()
You can't do this, you are already in the message handling loop (that's what called the on_message function) at the point you call publish. This will queue the outgoing messages to be handled by the next iteration of the loop, that's why they are sent once on_message returns.
It hangs when you call the loop method because the loop is already running.
You should not be making blocking (sleep) calls in the on_message callback anyway, if you need to do thing that take time, start up a second thread to do these. By doing this you free up the network loop to handle the outgoing publishes as soon as they are made.

The appropriate value of max_packets for MQTT loop function

I have this code that should run indefinitely, however, it doesn't. It keeps on stopping every few hours from the client's side (stop publishing, the loop keeps on running, but nothing is received at the broker), and the only thing that can be done is to rerun it again.
I was advised here to increase the number of max_packets for the loop function, but it's not working and the client stops publishing randomly without continuing. What should be done? I tried the values of 1, 3, 5, 50 and a 1000 but no use.
Code:
client = mqtt.Client()
client.connect(address, 1883, 60)
while True:
data = getdata()
client.publish("$ahmed/",data,0)
client.loop(timeout=1.0, max_packets = 1) # what should be the parameters here so it doesn't stop publishing?
time.sleep(0.2)
In addition to applications messages which are published/subscribed, MQTT also have internal keepalive to avoid problem of half open TCP connections(1). And it is the responsibility of client to make sure keepalives are sent. As per specification, the broker will disconnect clients which doesn't send keepalives in one and half times of keepalive time interval( in absence of other messages).
In addition to sending messages, the loop()* functions also maintains this keepalive traffic flow between broker and client.
A random try: Try using loop_start() once instead of calling loop() in while loop. E.g.
client = mqtt.Client()
client.connect(address)
#runs a thread in background to call loop function internally.
#In addition, this also reconnects to broker on a lost connection.
client.loop_start()
while True:
data = getdata()
client.publish("$ahmed",data)
client.loop_stop()
Just a random guess... has the client disconnected?
In your code you are not handling any callback like on_disconnect(client, userdata, rc) which is called when the client disconnects from the broker.
def on_disconnect_handler(client, userdata, rc):
if rc != 0:
print("Unexpected disconnection.")
client.on_disconnect = on_disconnect_handler
You are also not checking loop() return value:
Returns MQTT_ERR_SUCCESS on success.
Returns >0 on error.
You should do something like
while True:
rc = client.loop(timeout=1.0)
if rc:
# handle loop error here
Just make the client connect every time the loops is through. I have tested it and connecting to the brokers doesn't any significant extra latency on the flow. Since I have to rerun the program to make work it again, I may as well reconnect the client in the loop, so I don't have to do it myself. This is the rawest idea I could come up with that seems to be working without any problems.
client = mqtt.Client()
client.connect(address, 1883, 60)
while True:
client.connect(address, 1883, 60) # just let it reconnect every time it loops ;)!
data = getdata()
client.publish("$ahmed/",data,0)
client.loop(timeout=1.0, max_packets = 1)
time.sleep(0.2)

Unable to receive more than 20 MQTT messages using Mosquitto/Paho for Python

I'm using the Mosquitto (now Paho) python MQTT client to connect to a HiveMQ broker. The code is very basic, as taken from their documentation here - https://pypi.python.org/pypi/paho-mqtt
#SUBSCRIBER
import paho.mqtt.client as mqtt
# The callback for when the client receives a CONNACK response from the server.
def on_connect(client, userdata, rc):
client.subscribe("GB/node0/", 2)
# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
print "Topic: ", msg.topic+'\nMessage: '+str(msg.payload)
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect("192.168.15.4", 1883, 60)
# Blocking call that processes network traffic, dispatches callbacks and
# handles reconnecting.
client.loop_forever()
As you notice in client.subscribe(), the QoS is 2. This is the only modification to the official documentation's code.
The publishing client's code is-
#PUBLISHER
import paho.mqtt.client as mqtt
mqttc = mqtt.Client("python_pub")
mqttc.connect("192.168.15.4", 1883, 60)
mqttc.publish("GB/node0/", "Hello, World baby!",2)
Here also, the QoS is 2.
This modification of QoS results in only 20 messages being received by the subscriber. Upon further probing, I realized the problem is probably due to max_inflight_messages_set(), which is an option function which sets the maximum number of messages with QoS>0 that can be part way through their network flow at once. The default is 20.
However, changing it to any other value does not work. Also, why does the client think these messages are still inflight when they've been received? How do I resolve the problem? How do I ensure that the client understands these messages are not "inflight" and have been delivered?
Try calling mqttc.loop(2,10) after the mqttc.publish() in the publisher so the publisher can handle the QOS2 acknowledgement from the broker that it has received the publish.
The 2 second timeout and the 10 packets is probably more than is needed but it should work
#hardillb is right, you need some form of loop*() call. To be more certain, do this:
import paho.mqtt.client as mqtt
def on_publish(client, userdata, mid):
client.disconnect()
mqttc = mqtt.Client() # There's normally no need to set a client id.
mqttc.on_publish = on_publish
mqttc.connect("192.168.15.4", 1883, 60)
mqttc.publish("GB/node0/", "Hello, World baby!",2)
mqttc.loop_forever()
Or:
import paho.mqtt.publish as paho
paho.single("GB/node0/", "Hello, World baby!", qos=2, hostname="192.168.15.4")

Categories

Resources