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.