Python "shutdown / reboot raspberry pi" script using one button
I got some of the 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 it.
Since this is the first time I am working with Python, I am stuck in understanding what is actually going on.
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
I want to do the following:
- If the button is pressed once, a confirmation function is executed in which it resets the button to invoke the shutdown function if pressed for 3 seconds.
- Continue, resume work with the main loop
- In shutdown function, if it is pressed again (within 3 seconds), it is reset to call the restart function.
- Go on and off
What's happening:
If I click the button two 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 again it calls the shutdown function.
I dont understand what:
Why does he want to define a gpio event in the main when the actual function reloads or exits (and it should cause reloads or exits)?
So, after Anton Glukhov explained to me what to look for, I learned how to solve each problem and now it works flawlessly.
This is a link that better explains what I did: http://sourceforge.net/p/raspberry-gpio-python/wiki/Inputs/
Unfortunately, I was unable to do this other than using a while loop in the main function. But since nothing is critical, 1 second sleep is added to each cycle, which ensures minimal CPU usage.
I am sharing the final code here, in the hopes that it might help others:
# 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
from os import system
gpio.setmode(gpio.BCM) # Set pin numbering to BCM numbering
gpio.setup(22, gpio.IN) # Set up pin 22 as an input
def confirmation(pin):
#print "Confirmation Function on pin %d" % pin
system('echo Press again to confirm Shut down menu! | wall -n') # let all logged in users know
gpio.remove_event_detect(pin)
gpio.add_event_detect(pin, gpio.RISING, bouncetime=200)
sleep(2) # if button has been pressed again within 2 seconds, shut down function is called
if gpio.event_detected(pin):
shutdown(pin)
else:
#print "canceled"
system('echo Shut down canceled! | wall -n') # let all logged in users know
main()
def resetPin(pin):
#print "Pin %d has been reset" % pin
gpio.remove_event_detect(pin)
gpio.add_event_detect(pin, gpio.RISING, bouncetime=200)
def reboot(pin):
#print "Reboot Function on pin %d" % pin
call('reboot', shell=False)
exit(0)
# Define a function to run when an interrupt is called
def shutdown(pin):
#print "ShutDown function on pin %d" % pin
system('echo Press again if you want to reboot instead of shut down! | wall -n') # let all logged in users know
gpio.remove_event_detect(pin)
gpio.add_event_detect(pin, gpio.RISING, bouncetime=200)
sleep(2) # if the button has been pressed for a third time, within 2 seconds, Pi will reboot
if gpio.event_detected(pin):
reboot(pin)
else:
call('halt', shell=False)
exit(0)
# Define a function to keep script running
def main():
#print "Main Function"
resetPin(22)
while True:
sleep(1)
if gpio.event_detected(22):
confirmation(22)
main() # Run the main function to keep script running
Because the callback function runs on a separate thread. This means, for example, when you call any callback function in the main loop, it still runs (main loop), and this happens when you call the gpio.add_event_detect function from the callback function (thread # 1) and from the main loop (thread # 2) at the same time. This is a 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