My Pi is headless and running a program 24X7. In some cases, I want to reset the application, and on others do a controlled shutdown instead of yanking the power cord.
Here is what I came up with, feel free to comment or make suggestions:
The code and comments should explain it well enough to make any changes to fit your application.
Code: Select all
#!/usr/bin/env python2.7 from time import sleep import subprocess import RPi.GPIO as GPIO CHANNEL = 23 # GPIO channel 23 is on pin 16 of connector P1 # it will work on any GPIO channel GPIO.setmode(GPIO.BCM) GPIO.setup(CHANNEL, GPIO.IN, pull_up_down=GPIO.PUD_UP) # setup the channel as input with a 50K Ohm pull up. A push button will ground the pin, # creating a falling edge. def system_action(CHANNEL): print('Button press = negative edge detected on channel %s'%CHANNEL) button_press_timer = 0 while True: if (GPIO.input(CHANNEL) == False) : # while button is still pressed down button_press_timer += 1 # keep counting until button is released else: # button is released, figure out for how long if (button_press_timer > 7) : # pressed for > 7 seconds print "long press > 7 : ", button_press_timer # do what you need to do before halting subprocess.call(['shutdown -h now "System halted by GPIO action" &'], shell=True) elif (button_press_timer > 2) : # press for > 2 < 7 seconds print "short press > 2 < 7 : ", button_press_timer # do what you need to do before a reboot subprocess.call(['sudo reboot &'], shell=True) button_press_timer = 0 sleep(1) GPIO.add_event_detect(CHANNEL, GPIO.FALLING, callback=system_action, bouncetime=200) # setup the thread, detect a falling edge on channel 23 and debounce it with 200mSec # assume this is the main code... try: while True: # do whatever # while "waiting" for falling edge on port 23 sleep (2) except KeyboardInterrupt: GPIO.cleanup() # clean up GPIO on CTRL+C exit GPIO.cleanup() # clean up GPIO on normal exit
If your Pi is in a "noisy" environment, you may want to add a "real" pull-up to the 3V3 rail with a 10K resistor. The internal 50K worked well enough for me.
Just in case the application and/or Debian crashed, you need another method to restart everything. This I did with a hardware solution using P6, to drive the Run/Reset input of the SOC.
Here is the circuit in LTspice: Note that I added the components that are either on the circuit board of the Pi (R3, C1, D1 and D2), or internal in the SOC (R1).
The circuit works as follows. The same reset button as above is used to create a low for this circuit as well. The button is simulated with V1. When the button is pushed, M2 is released and C2 is charging through R2, providing a time constant. When the voltage over C2 increases, M1 conducts, resulting in a short for the P6 jumper, which is connected to the Run pin of the SOC. When the push button is released, the cycle ends, M1 releases the Run line again which (re)starts the SOC chip.
In this simulation, R2 and C2 have been selected to create a ramp-up of 12 seconds.
If you build this circuit, you may have to tune the value of R2, because there are a number of components that will have an effect on the time constant. Especially the VGS parameters of the MOSFETS, and the toleration of R2 and C2 of course. There is enough of a margin built-in, but it makes sense to stick to the 2, 7 and 12 second intervals with 5 second margins.
So, in the complete setup, pressing the push button anything less than 2 seconds does nothing (to prevent accidental pushes), anything between 2 seconds and less than 7, produces a software reboot. Pressing the button anywhere from 7 seconds to less than 12 produces a system Halt (for a safe power down), and pressing the push button longer than 12 seconds produces a hardware reset.
Below is the simulation: The Green trace is at the Gate of M1, Blue is at P6-1, the Run signal.
One unfortunate by-product of this circuit is that there is always a current flowing through R2 and M2. Because of the value of R2, it is in the uA range, so we don't steal too much away from the 50mA limit on the 3V3 supply.
Here is one nice side-effect of this circuit. If you halted the Pi with the 7 second option, you can later restart it again by pressing the button for 12+ seconds again. Toggling the Run pin will wake the Pi up from it's beauty sleep.
One final word of caution, Although the software portion has been implemented and tested, I have not built the actual hardware circuit yet, and thus have not tested it. I did test the waking-up from a Halt though, that works fine.