Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python "shutdown / reboot raspberry pi" script, using a single button

I got a piece of code in Python from here: http://www.raspberry-pi-geek.com/Archive/2013/01/Adding-an-On-Off-switch-to-your-Raspberry-Pi

And I wanted to improve on it.

Since this is the first time I work with Python, I got stuck on understanding what actually happens.

Here is the code:

# Import the modules to send commands to the system and access GPIO pins
from subprocess import call
import RPi.GPIO as gpio
from time import sleep

gpio.setmode(gpio.BCM) # Set pin numbering to board numbering
gpio.setup(22, gpio.IN) # Set up pin 22 as an input

rebootBool = 0

# Define a function to keep script running
def main(pin):
    while True:
        #gpio.remove_event_detect(pin)
        gpio.add_event_detect(22, gpio.RISING, callback=confirmation, bouncetime=200) # Set up an interrupt to look for button presses
        sleep(5000000)

def confirmation(pin):
    gpio.remove_event_detect(pin)
    gpio.add_event_detect(22, gpio.RISING, callback=shutdown, bouncetime=200)
    sleep(3) # if button has been pressed again within 3 seconds, shut down will happen
    main(22)

def reboot(pin):
    rebootBool = 1
    call('reboot', shell=False)
    exit(0)

# Define a function to run when an interrupt is called
def shutdown(pin):
    gpio.remove_event_detect(pin)
    gpio.add_event_detect(22, gpio.RISING, callback=reboot, bouncetime=200)
    sleep(3) # if the button has been pressed for a third time, within 3 seconds, Pi will reboot
    if rebootBool == 0: # Just to make sure a halt is not called after the 3 seconds have passed, if reboot is called
        call('halt', shell=False)
    exit(0)

main(22) # Run the loop function to keep script running

What I want to do is this:

  • If button is pressed once, a confirmation function is executed, in which it resets the button to call the shutdown function, if it's pressed within 3 seconds.
    • Else, resume with the main loop
  • In the shutdown function, if it's pressed again (within 3 seconds), it resets to call the reboot function.
    • Else go on, and shut down

What happens is this:

If I press the button twice or three times, it tells me that gpio.add_event_detect is already defined, when it tries to define it in main(). So it doesn't change it, and if I press it one more time, it calls the shutdown function.

What I don't understand is:

Why does it want to define the gpio event in main, when the actual function is either reboot or shutdown (and it should call either reboot or shutdown)?

like image 611
Wilhelm Sorban Avatar asked Jun 21 '26 04:06

Wilhelm Sorban


1 Answers

Because a callback function is running in a separate thread. This means, for example, when you call any callback function in the main loop it still works(main loop), and thus it happens when you call a function gpio.add_event_detect from a callback function(thread #1) and from the main loop(thread #2) at the same time. It's typical race condition. You can check it by running this code:

#!/usr/bin/python
# Import the modules to send commands to the system and access GPIO pins
from subprocess import call
import RPi.GPIO as gpio
from time import sleep

gpio.setmode(gpio.BCM) # Set pin numbering to board numbering
gpio.setup(22, gpio.IN, pull_up_down=gpio.PUD_DOWN) # Set up pin 22 as an input

rebootBool = 0

# Define a function to keep script running
def main(pin):
    while True:
        print "main loop"
        gpio.remove_event_detect(22)
        gpio.add_event_detect(22, gpio.RISING, callback=confirmation, bouncetime=200) # Set up an interrupt to look for button presses
        sleep(1)
        #raw_input()

def confirmation(pin):
    print "confirmation1"
    sleep(5)
    print "confirmation2"
    gpio.remove_event_detect(22)
    gpio.add_event_detect(22, gpio.RISING, callback=shutdown, bouncetime=200)
    sleep(5) # if button has been pressed again within 3 seconds, shut down will happen
    gpio.remove_event_detect(22)
    main(22)

def reboot(pin):
    rebootBool = 1
    print "reboot"
    #call('reboot', shell=False)
    exit(0)

# Define a function to run when an interrupt is called
def shutdown(pin):
    print "shutdown"
    gpio.remove_event_detect(pin)
    gpio.add_event_detect(22, gpio.RISING, callback=reboot, bouncetime=200)
    sleep(3) # if the button has been pressed for a third time, within 3 seconds, Pi will reboot
    if rebootBool == 0: # Just to make sure a halt is not called after the 3 seconds have passed, if reboot is called
        #call('halt', shell=False)
        print "halt"
    exit(0)

main(22) # Run the loop function to keep script running
like image 178
Anton Glukhov Avatar answered Jun 22 '26 19:06

Anton Glukhov



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!