简体   繁体   中英

Newbie: Yet another non-blocking delay: delay LED turn-on without sleep()

I have a Raspberry Pi running the Flask framework to make a very application-specific http server. Doing an HTTP GET of a particular page on the Pi server triggers a GPIO action (eg: check if button is pressed, LED on, LED off and so on). Because I will poll the /status page to see if the button is pressed at 250ms intervals, I do not want the polling of the /unlock page to use timer.sleep(0.25) to close a relay for 250ms.

I want to set up an action that when called, will wait 250ms, turn the LED off then quietly go away. I tried both threading and sched. Threading works ONCE and throws an error when I pass through the code a second time ( raise RuntimeError("threads can only be started once") ).

#
# lots of other defines and includes
#
import threading
# set up function to turn de-energize relay (and Green LED)
def LED_Off_Wait():
    GPIO.output(GREEN, False)

# set up timed thread
LED_Off = threading.Timer(0.25, LED_Off_Wait)

#
# flask framework page definitions go here
#

# unlock page where we energize and de-energize a lock
@app.route('/unlock')
def thing_unlock():
    GPIO.output(GREEN, True) # energize the relay (and green LED)
#    time.sleep(0.25) # don't want to do this
#    GPIO.output(GREEN, False) #don't want to do this
    LED_Off.start() # trigger the non-blocking thread to turn off 
                    #  the GPIO pin in 0.25s
# more flask stuff...
    response = make_response(render_template('body.html', response='unlocked'))
    response.headers['Access-Control-Allow-Origin'] = '*'
    return response

I tried sched as well and it does not work for me, although it may be because I'm programming from the inside-out, learning by doing:

import sched

def LED_Off():
    GPIO.output(GREEN, False)

# set up scheduled action, as nearly as I can determine from my reading
LED_ON_Delay = sched.scheduler(time.time, time.sleep) # set up scheduler (no sleep!)
LED_ON_Delay.enter( 1, 1, LED_Off,()) # schedule LED_Off for 0.25s in the future

#
# again, more Flask stuff here
#

@app.route('/unlock')
def thing_unlock():
    GPIO.output(GREEN, True)
#    time.sleep(0.25) # don't want to do this
#    GPIO.output(GREEN, False) # don't want to do this
    LED_ON_Delay.run()  #trigger "non-blocking sleep"
    response = make_response(render_template('body.html', response='unlocked'))
    response.headers['Access-Control-Allow-Origin'] = '*'
    return response

# more Flask stuff...

Bottom Line: how do I spin off a task that will turn the GPIO off after a certain time (or do anything else for that matter) without an error if I try to do it twice?

With the help of a friend, the answer was simpler than I expected: Lambda functions. First, import threading then declare the function that will do what you want (turn off the LED) after a time interval using threading.Timer() :

def LED_Off_Wait( wait_time,IO_port ):
    threading.Timer(wait_time, lambda: GPIO.output(IO_port, False)).start()

In this case, I need to use it in more than one place so I pass it the delay time and the GPIO pin it needs to act on.

When I need to turn the LED off after a delay inside another function, I call it like this:

@app.route('/unlock')
def prop_unlock():
    GPIO.output(GREEN, True)
    LED_Off_Wait( 0.5, GREEN )
    response = make_response(render_template('body.html', response='unlocked'))
    response.headers['Access-Control-Allow-Origin'] = '*'
    return response

For completeness, GREEN has been previously defined like this:

GREEN = 24
# Use GPIO pin numbers
GPIO.setmode(GPIO.BCM)
GPIO.setup(GREEN, GPIO.OUT)

Works like a charm.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM