How do I print a single data in paho.mqtt instead of a continuous loop in Python?

158 views Asked by At

How do I print a single data in paho.mqtt instead of a continuous loop in Python?

I want to transfer mqtt data to telegram and report it to grafana from there. But the code below returns data in a continuous loop. I want only one data to come out, then the script to be finished. I replaced the client.loop_forever() with client.loop_start() but there was no output.


import random
import json
from paho.mqtt import client as mqtt_client


broker = '192.168.62.24'
port = 1883
topic = "tvekrani"
# generate client ID with pub prefix randomly
client_id = f'python-mqtt-{random.randint(0, 100)}'
username = 'admin'
password = 'admin'


def connect_mqtt() -> mqtt_client:
    def on_connect(client, userdata, flags, rc):
        if rc == 0:
            a=0
        else:
            print("Failed to connect, return code %d\n", rc)

    client = mqtt_client.Client(client_id)
    # client.username_pw_set(username, password)
    client.on_connect = on_connect
    client.connect(broker, port)
    return client


def subscribe(client: mqtt_client):
    def on_message(client, userdata, msg):
        
        #print(msg.payload.decode())
        data=(msg.payload.decode())

        veri = json.loads(data)
        print(veri["speakers"])
    client.subscribe(topic)
    client.on_message = on_message


def run():
    client = connect_mqtt()
    
    subscribe(client)
   
    client.loop_forever()


if __name__ == '__main__':
    run()


1

There are 1 answers

2
noertker On

The reason that client.loop_start() was not showing output is that it starts a daemon thread rather than blocking the whole program in the way that client.loop_forever() does.

In your program, since client.loop_start() would be the last call in the run() method, your program exits immediately after that call, which is why you don't see the output.

To use loop_forever() and block your program, it would be better to stop the loop directly rather than call sys.exit() right after the print line. You should be able to do this with the client.loop_stop() method:

    def on_message(client, userdata, msg):
        
        #print(msg.payload.decode())
        data=(msg.payload.decode())

        veri = json.loads(data)
        print(veri["speakers"])
        client.loop_stop() # <- stops loop here

If you don't want to block your program an the loop_forever() line, you could utilize client.loop_start(), but you would need some other loop to keep your program alive in the run() method. You could simply put a time.sleep() for a few seconds if you knew when you expect to get a MQTT message, or create a loop that runs until some other condition is met.

def run():
    client = connect_mqtt()
    
    subscribe(client)
   
    client.loop_start() # <- Starts daemon client listener

    while True:   # <- blocks the program to do other stuff
        print("Wait for message")
        time.sleep(1)

Using the above code you could add whatever logic you want into a while loop to keep your program running until you want it to exit.

A more optimal solution may be to pass a callback function into on_message to adjust the while condition when you get a message from MQTT. This would enable the MQTT messages to adjust the timing of the loop.