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

evgi9 picture evgi9 · Apr 5, 2016 · Viewed 12.7k times · Source

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?

Answer

ralight picture ralight · Apr 6, 2016

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)