Search code examples
pythondjangovisual-studio-codemqttmosquitto

Django Python MQTT Subscribe onMessage got executed two times


I've my Mosquitto MQTT broker and I've created a simple Django APP that subscribes to the topic $SYS/broker/uptime like below

from django.apps import AppConfig
from threading import Thread
import paho.mqtt.client as mqtt


class MqttClient(Thread):
    def __init__(self, broker, port, timeout, topics):
        super(MqttClient, self).__init__()
        self.client = mqtt.Client()
        self.broker = broker
        self.port = port
        self.timeout = timeout
        self.topics = topics
        self.total_messages = 0

    #  run method override from Thread class

    def run(self):
        self.connect_to_broker()

    def connect_to_broker(self):
        self.client.on_connect = self.on_connect
        self.client.on_message = self.on_message
        self.client.connect(self.broker, self.port, self.timeout)
        self.client.loop_forever()

    # The callback for when a PUBLISH message is received from the server.

    def on_message(self, client, userdata, msg):
        self.total_messages = self.total_messages + 1
        print(str(msg.payload) + "Total: {}".format(self.total_messages))


    # The callback for when the client receives a CONNACK response from the server.

    def on_connect(self, client, userdata, flags, rc):
        #  Subscribe to a list of topics using a lock to guarantee that a topic is only subscribed once
        for topic in self.topics:
            client.subscribe(topic)


class AppMqtteConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'app_mqtt'

    def ready(self):
        MqttClient("localhost", 1883, 60, ["$SYS/broker/uptime"]).start()

For some reason, the print statement on the on_message callback got executed two times, at least from what I'm seeing from the console. See screenshot. I can't understand why

enter image description here


Solution

  • It turned out that in some instances, particularly in tests, the ready method could be called multiple times as suggested in the Documentation.

    As explained on this answer the issue is resolved with an if os.environ.get('RUN_MAIN'): before the ready method