One constant problem I’ve had with my CrashPi in particular is that, since it has no screen or keyboard, when it stops responding, I have no way to tell it to shut down. I watch the activity light, and wait for everything to appear calm, and then pull the power. Then, when I take it over to my desk, hook it up to the monitor, and plug it in to try to figure out what the problem is, I see nothing but a wall of filesystem corruption error messages.
Sometimes, I’ve been able to take the card out, put it in a USB adapter, plug it into another one of my Raspberries, and run fsck on it to recover the filesystem. Not always, though. It could be that the filesystem corruption is what caused it to stop responding in the first place, but there’s not really a good way to know for sure. What I want is a way to shut the Pi down safely, even when it doesn’t have a monitor and keyboard.
There are quite a few articles out there about how to hook a button up to one of the GPIO pins, and use that to trigger a shutdown. Just recently, I saw this article, and liked what I saw. I had not previously known that shorting pin 6 to ground would wake a Pi up from “sleep” when it’s been shut down, but the power is still attached.
I’d seen some other articles with far more complicated scripts such that a momentary press of the button would force a reboot, while holding it longer would cause a full shutdown. The idea is sound, repurposing a single button to perform multiple functions, but this approach seemed much simpler to me. Now, if I want to reboot, all I need to do is wait for the activity light to stop flashing, and push the button again to wake up the Pi.
This is just what I was looking for, but I felt that the scripting portion of it could be reduced to just the Python file rather than requiring a second shell script, so today I decided to see if that was possible.
I’m taking a huge cue from one of the older articles I found, on element14’s site. The author there pulled it off using only a Python script, but the script contained a polling loop in it, and that’s just not good form. The newer articles all use wait_for_edge to trigger the shutdown without burning CPU cycles constantly polling for the button press. This is a cleaner approach in my opinion.
The script provided on the howchoo.com article is fine just the way it is, and I’ll be using it exactly as written in that article with a couple blank lines removed. I’m just interested in ditching the companion shell script.
Create the script using nano:
sudo nano /usr/local/bin/listen-for-shutdown.py
Paste the following into nano.
#!/usr/bin/env python import RPi.GPIO as GPIO import subprocess GPIO.setmode(GPIO.BCM) GPIO.setup(3, GPIO.IN) GPIO.wait_for_edge(3, GPIO.FALLING) subprocess.call(['shutdown', '-h', 'now'], shell=False)
All this script does is listen for GPIO 3 to short to ground before continuing, at which point is shuts down the Pi. It requires importing two libraries, one for interacting with the GPIO pins, and one for interacting with the system.
All I’m going to do is follow the old element14 instructions for running the script automatically at startup with one important difference. The element14 article runs the python script after the section that reports the computer’s IP address. If the problem plaguing your Pi is that the network isn’t working, then the shutdown script supposedly won’t get run. To fix this, I’m going to run the shutdown listener before reporting the IP address.
Edit the rc.local file using nano.
sudo nano /etc/rc.local
Insert the following highlighted section
#!/bin/sh -e # # rc.local # # This script is executed at the end of each multiuser runlevel. # Make sure that the script will "exit 0" on success or any other # value on error. # # In order to enable or disable this script just change the execution # bits. # # By default this script does nothing. # Listen for the shutdown button sudo python /usr/local/bin/listen-for-shutdown.py & # Print the IP address _IP=$(hostname -I) || true if [ "$_IP" ]; then printf "My IP address is %s\n" "$_IP" fi exit 0
The “&” at the end of the call to Python tells the script not to wait around for an answer. It’s “shelling” that command off onto its own thread, essentially. Everything else should continue on as if the call to Python wasn’t even there.
You can start the script manually by typing the call to Python at the command line, but I’m interested in the whole thing working together automatically, so I’m just going to shut the system down, hook up my wires, and then start it back up again.
sudo shutdown -h now
Get a couple of jumper wires and attach them to pins 5 & 6. In my case, pin 6 is already being used for something else, so I used pins 5 & 9 instead. The important thing is that you’re choosing pin 5 and something that’s a ground. Refer to any freely available pinout like the one on this page to choose the ground pin. You could also use a different GPIO pin, but you won’t get the “wake up” functionality unless you use pin 5 (GPIO 3).
Power up the Pi again, wait for everything to settle in, and then touch the free end of the two jumper wires together briefly. The Pi should shut down immediately. Keep an eye on the activity light, and wait for it to stop blinking. The Pi is now “sleeping”. Don’t unplug the power though. Instead, touch the jumper wires together again and the Pi should reboot itself, ready for action again.
Making it permanent
Find a small switch that will fit into your Raspberry Pi’s case without interfering with any of the internal components, and then pick a suitable location for it. You can get as creative as you like with the placement, and different cases will provide different opportunities for where to put it. Just make sure that the switch isn’t going to bump into anything inside the case. Drill a hole in the case (remove the Pi first, obviously) for the switch.
Solder one jumper wire to each pole of the switch, cover the joint with some heat-shrink tubing for good measure, and then mount the switch into the case. Plug the free ends of the jumpers back into the pins from above. Close everything back up and you’re ready to go.
When you need to shut down a headless Pi, you can just hit the button, wait for the activity light to stop blinking, and then pull the power.