Ahmed.B
Ahmed.B

Reputation: 89

MQTT and time delay

I have a python script which I am trying to work with paho mqtt and time delay. I have looked into similar questions which discuss paho mqtt like Controlling Program with MQTT and Python. My python script is as follows:

Here is my script:

    import paho.mqtt.client as mqttClient
    import time
    import subprocess
    import os
    
    
    global lastprocessed, Connected
    lastprocessed = None
    Connected = False   #global variable for the state of the connection
    
    def on_connect(client, userdata, flags, rc):
        if rc == 0:
            print("Connected to broker")
            global Connected
            Connected = True                #Signal connection
        else:
            print("Connection failed")
    
    
    def on_message(client, userdata, message):
        global lastprocessed
        if message.payload.decode() == "hello":
            lastprocessed = time.time()
    
        if lastprocessed and time.time() - lastprocessed < 20:
            print("good")

broker_address= "192.168.1.111"  #Broker address
port = 1883                         #Broker port
user = "abcde"                    #Connection username
password = "12345"            #Connection password

client = mqttClient.Client("Python")               #create new instance
client.username_pw_set(user, password=password)    #set username and password
client.on_connect= on_connect                      #attach function to callback
client.on_message= on_message                      #attach function to callback
client.connect(broker_address,port,60) #connect
client.subscribe("home/OpenMQTTGateway/433toMQTT") #subscribe
client.loop_forever() #then keep listening forever

What is happening with my code above is that, whenever "hello" is received in the payload it prints "good" but if anything else is received in the payload including "hello" it continues printing "good". It doesn't take into consideration the time of 20 seconds. I am not sure why?

What I am trying to achieve is the following:

  1. When the python script is executed at the beginning, the script should print "bad".
  2. This should stop until "hello" is received in the payload.
  3. Once "hello" is received, "good" should be printed for 20 seconds and during those 20 seconds any other messages received in the topic should be ignored including "hello".
  4. After the 20 seconds, the script should continue printing "bad" but only once and the cycle continues.

Updated question 24/03/2021:

So my new script below keeps printing "Connected to Broker" initially it wasnt and I havent changed anything but now somehow it keeps printing and the if statements are not executed at all.

I know my script worked fine but I just need the if statements to be executed and the continuous loop i.e. continuous printing of "Connected to Broker" to stop.

import paho.mqtt.client as mqttClient
import time
import subprocess
import os
import json


global lastprocessed, Connected
lastprocessed = None
Connected = False   #global variable for the state of the connection

def on_connect(client, userdata, flags, rc):
    if rc == 0:
        print("Connected to broker")
        global Connected
        Connected = True                #Signal connection
    else:
        print("Connection failed")


x = y = 0

def on_message(client, userdata, message):
    global x, y

    global lastprocessed

    a = str(message.payload)

    data = json.loads(a);

    j = data["contact"]
    print(j)

    if j == False:
        x += 1
        print(x)
    if j == True:
        y += 1
        print(y)
    if x == 1 or x == 0 and y == 1:
        os.system("vcgencmd display_power 1")
    if y == 2:
        x = y = 0
        os.system("vcgencmd display_power 0")

broker_address= "192.168.XXX.XXX"  #Broker address
port = 1883                         #Broker port
user = "XXXX"                    #Connection username
password = "XXXX"            #Connection password

client = mqttClient.Client("Python")               #create new instance
client.username_pw_set(user, password=password)    #set username and password
client.on_connect= on_connect                      #attach function to callback
client.on_message= on_message                      #attach function to callback
client.connect(broker_address,port,60) #connect
client.subscribe("zigbee2mqtt/Xiaomi Door Sensor 2") #subscribe
client.loop_forever() #then keep listening forever

Upvotes: 0

Views: 6418

Answers (1)

furas
furas

Reputation: 142651

I use loop_start() and loop_stop() instead of loop_forever() and then between start and stop I can create own loop which can check messages and print text.

I use variable state to control if code is before first hello (state = "start") or it gets hello and now it has to check time and repeate text "good" (state = "hello") or it has 20 seconds after hello and it has print nothing (state = "other")

Inside on_message I only change state to hello when I get message hello and old state is different then hello.

import paho.mqtt.client as mqttClient
import time

# --- functions ---

def on_connect(client, userdata, flags, rc):
    #global state
    global connected

    if rc == 0:
        print("Connected to broker")
        connected = True                
    else:
        print("Connection failed")

def on_message(client, userdata, message):
    global state
    global last_processed
    
    if message.payload.decode() == "hello":
        if state != 'hello':
            state = 'hello'
            last_processed = time.time()

    # OR
    
    #if state != 'hello':
    #    if message.payload.decode() == "hello":
    #        state = 'hello'
    #        last_processed = time.time()

# --- main ---

broker_address = "192.168.1.111"  # broker address
port = 1883                       # broker port
user = "abcde"                    # connection username
password = "12345"                # connection password

# ---

client = mqttClient.Client("Python")               # create new instance
client.username_pw_set(user, password=password)    # set username and password
client.on_connect= on_connect                      # attach function to callback
client.on_message= on_message                      # attach function to callback
client.connect(broker_address, port, 60)           # connect
client.subscribe("home/OpenMQTTGateway/433toMQTT") # subscribe

# --- main loop ---

last_processed = None
connected = False      # signal connection
state = 'start' # 'start', 'hello', 'other', 'not connected'   

# ---

client.loop_start()

try:
    while True:
        if not connected:
            print('not connected')
            
        if state == 'start':
            print('bad')
            
        if state == 'hello':
            if last_processed and time.time() - last_processed < 20:
                print("good", time.time() - last_processed, end='\r') # '\r` to write it in the same line.
            else:
                print('bad')
                state = 'other'
                last_processed = None
        
        if state == 'other':
            pass
    
        time.sleep(1.0) # to slow down example
        
except KeyboardInterrupt:
    print('KeyboardInterrupt')
    
client.loop_stop()

EDIT:

If you need bad and hello only once then you can print first bad before loop, and hello when you get message and then time.sleep(20) before you print bad and change steate.

import paho.mqtt.client as mqttClient
import time

# --- functions ---

def on_connect(client, userdata, flags, rc):
    #global state
    global connected

    if rc == 0:
        print("Connected to broker")
        connected = True                
    else:
        print("Connection failed")

def on_message(client, userdata, message):
    global state

    message = message.payload.decode()
    
    if state != 'hello':
        if message == 'hello':
            state = 'hello'
            print('good') # once when start `hello`
        else:
            print('msg:', message)        

# --- main ---

broker_address = "192.168.1.111"  # broker address
port = 1883                       # broker port
user = "abcde"                    # connection username
password = "12345"                # connection password

# ---

client = mqttClient.Client("Python")               # create new instance
client.username_pw_set(user, password=password)    # set username and password
client.on_connect= on_connect                      # attach function to callback
client.on_message= on_message                      # attach function to callback
client.connect(broker_address, port, 60)           # connect
client.subscribe("home/OpenMQTTGateway/433toMQTT") # subscribe

# --- main loop ---

connected = False      # signal connection
state = 'other' # 'hello'

# ---

client.loop_start()

print('bad') # once at start

try:
    while True:
        
        if state == 'hello':
            time.sleep(20)
            print('bad')  # once when end `hello`
            state = 'other'
    
        time.sleep(1.0) # to slow down example
        
except KeyboardInterrupt:
    print('KeyboardInterrupt')
    
client.loop_stop()

It would be useful to use threading.Timer instead of time.sleep() because sleep() blocks loop and it is not so useful if you want to do something more.

import paho.mqtt.client as mqttClient
import threading

# --- functions ---

def on_connect(client, userdata, flags, rc):
    #global state
    global connected

    if rc == 0:
        print("Connected to broker")
        connected = True                
    else:
        print("Connection failed")

def on_message(client, userdata, message):
    global state

    message = message.payload.decode()
    
    if state != 'hello':
        if message == 'hello':
            state = 'hello'
            print('good') # once when start `hello`
            threading.Timer(20, end_hello).start()
        else:
            print('msg:', message)
        
def end_hello():
    global state
    
    print('bad')  # once when end `hello`
    state = 'other'

# --- main ---

broker_address = "192.168.1.111"  # broker address
port = 1883                       # broker port
user = "abcde"                    # connection username
password = "12345"                # connection password

# ---

client = mqttClient.Client("Python")               # create new instance
client.username_pw_set(user, password=password)    # set username and password
client.on_connect= on_connect                      # attach function to callback
client.on_message= on_message                      # attach function to callback
client.connect(broker_address, port, 60)           # connect
client.subscribe("home/OpenMQTTGateway/433toMQTT") # subscribe

# --- main loop ---

connected = False      # signal connection
state = 'other' # 'hello'

# ---

print('bad') # once at start
client.loop_forever()

Eventually you can still check time in loop

import paho.mqtt.client as mqttClient
import time

# --- functions ---

def on_connect(client, userdata, flags, rc):
    #global state
    global connected

    if rc == 0:
        print("Connected to broker")
        connected = True                
    else:
        print("Connection failed")

def on_message(client, userdata, message):
    global state
    global last_processed
    
    message = message.payload.decode()
    
    if state != 'hello':
        if message == 'hello':
            state = 'hello'
            last_processed = time.time()
            print('good') # once when start `hello`
        else:
            print('msg:', message)        

# --- main ---

broker_address = "192.168.1.111"  # broker address
port = 1883                       # broker port
user = "abcde"                    # connection username
password = "12345"                # connection password

# ---

client = mqttClient.Client("Python")               # create new instance
client.username_pw_set(user, password=password)    # set username and password
client.on_connect= on_connect                      # attach function to callback
client.on_message= on_message                      # attach function to callback
client.connect(broker_address, port, 60)           # connect
client.subscribe("home/OpenMQTTGateway/433toMQTT") # subscribe

# --- main loop ---

last_processed = None
connected = False      # signal connection
state = 'other' # 'hello'

# ---

client.loop_start()

print('bad') # once at start

try:
    while True:
        
        if state == 'hello':
            if time.time() >= last_processed + 20:
                print('bad')  # once when end `hello`
                state = 'other'
    
        time.sleep(1.0) # to slow down example
        
except KeyboardInterrupt:
    print('KeyboardInterrupt')
    
client.loop_stop()

Upvotes: 2

Related Questions