pythonraspberry-pigpiozero

GPIOZero Pi Alarm system: Need alternative for time delay


I require help with my alarm system code that I am building with GPIOZero library (my boss really likes the library). The system is meant for a laptop cart so people do not forget to close the door as there is a buzzer that rings if people leave it open for too long. So what I want it to do is really simple but it always waits for the function to finish before going to the next:

If door opens: Log time, Time Delay ,Buzzer turns on

If door is closed/closes: Buzzer is off, Log Time

Is there a way to not wait for the function to finish in the GPIOZero library. Please let me know!

from gpiozero import Button
from signal import pause
from gpiozero import Buzzer
from gpiozero import LED
from time import sleep

##### VARIABLES DEF #######
button = Button(21, pull_up=True)
buzzer = Buzzer(4)

def door_opened():
    f = open("log" + '.txt', 'a')               
    f.write("Opened " + time.strftime("%m-%d-%Y %X"))
    f.close()
    print("Door Open")
    sleep(100)
    print("door held, alarm on")
    buzzer.on

def door_closed():
    f = open("log" + '.txt', 'a')               
    f.write(" " + time.strftime("%X"))
    f.write('\n')
    f.close()
    print("Door Closed")
    buzzer.off()
    print("Buzzer off")


button.when_pressed = door_closed
button.when_released = door_opened


pause()

Solution

  • You will have to restructure things a little to get this done.

    The idea here is that you have a pair of global variables that are updated by the GPIOZero event handlers:

    There's also an infinite main loop that ticks once per second which reads the door_is_open variable and increments the open counter... and finally, if the open counter reaches the threshold desired (5 seconds here because we're impatient people), it turns the buzzer on.

    The door_closed handler takes care of resetting the buzzer, but that could also be done in the main loop.

    I also took the liberty of refactoring the logging into a function of its own that handily also prints the same thing to the console. (As an aside, I'd suggest using ISO 8601 date formatting, but I didn't want to impose that here.)

    A further refactoring might wrap this all in a neat class to avoid global variables.

    (This all is dry-coded, so your mileage may vary, but the idea should work. :) )

    import time
    from gpiozero import Button, Buzzer
    
    
    button = Button(21, pull_up=True)
    buzzer = Buzzer(4)
    door_is_open = False
    door_open_counter = 0
    
    
    def log_event(text):
        print(log_line)
        with open("log.txt", "a") as log_file:
            log_line = "%s | %s" % (time.strftime("%m-%d-%Y %X"), text)
            log_file.write(log_line + "\n")
    
    
    
    def door_opened():
        global door_is_open
        global door_open_counter
        log_event("Opened")
        door_is_open = True
        door_open_counter = 0
    
    
    def door_closed():
        global door_is_open
        global door_open_counter
        log_event("Closed")
        buzzer.off()
        door_is_open = False
        door_open_counter = 0
    
    
    button.when_pressed = door_closed
    button.when_released = door_opened
    
    while True:
        time.sleep(1)
        if door_is_open:
            door_open_counter += 1
            if door_open_counter >= 5:
                buzzer.on()