Introduction: Build a Better Raspberry Pi Power Button
It's very easy to make a Raspberry power-off or shutdown button. There are lots of such projects on the web and a few here on Instructables, but none of them (that I can see) tell you when your Pi has actually finished shutting down and hence it's safe to pull the power. In fact they don't even acknowledge that the button-press has been seen.
There are projects, too, to restart a Pi that has been shut down, but neither do these give you any visual feedback.
But who needs such a button? If you're a bit of a nerd like me, or even just an aspiring nerd, you can always log in to your Pi locally or over the network and type sudo shutdown -h now. But if you're building a project for non-technical users, that just won't do. True, you can nearly always get away with just pulling the power cord, but note, I said nearly always! Everybody's luck runs out sooner or later. I had an SD card die on me only last week, though I'll never know whether or not it was really due to an abrupt power loss.
In my case I needed to add a power button to a Pi we use as a midi sequencer for recording and playing back hymns and songs in church, for when we don't have a live pianist available. I can always type the shutdown command but I need to de-skill it for when I'm not there.
My intention here is not to give you a finished product, complete with beautifully 3D printed case, like so many other Instructables. Everybody will have a different use for it or want to incorporate in their own project. Rather, I'll set you up with the technology that you can add to your project, whether it be a media centre, an IoT device, or anything else.
(In the video I'm demonstrating it with a Pi Zero v1.2 and a monitor I made from a repurposed laptop screen and a controller from the Far East.)
Step 1: The Design
This is what my power button will do for you:
- When the Pi is running, a LED is lit continuously. If it's shut down manually the LED goes off only when it's safe to unplug the power.
- Whilst running, if you press the button for at least a second a shutdown is initiated and the LED flashes off for a quarter of a second every second until it's safe to unplug the power.
- From a shutdown state (if the power hasn't been removed), pressing the button starts it booting and flashes the LED on for a quarter of a second every second until it's booted up. (It may take a little longer until all services such as ssh and vnc are running.)
The components are very cheap. All you need is:
- ATTiny85 (Arduino-compatible chip)
- 3 resistors: 2 x 330Ω and 1 x 10kΩ
- 1 LED - I suggest green or blue, but it's your choice
- breadboard and jumper wires, or stripboard, or however you want to build it.
Step 2: How It Works
As with all Pi power buttons, this one pulls a GPIO pin to a low state to signal a shutdown request to a helper program running on the Pi. I used GPIO4 (pin 7) but you can use any other pin.
The only way to tell that a Pi has completed shutdown is by watching TxD pin 8, which then goes low. This depends on the serial console being enabled, which it is by default. In fact TxD will regularly go up and down while it's being used as a serial console, but it will never go low for more than around 30mS at a time, even at the slowest common baud rate. It can still be used for a serial console as we just passively watch it.
To reboot, we need to briefly pull SCL1 (pin 5) low. This pin is used by any I2C devices (including my midi interface), but after initiating the boot we leave it alone.
Most of the complexity is in the Arduino sketch which we load into the ATTiny85. This implements a "state machine" - a very useful and powerful way of coding any problem that can be represented by a number of "states". A washing machine works in just the same way. The states represent the stages in the wash cycle, and each one defines what the machine should be doing at that point (motors or pumps to be run, valves to be opened or shut) and what sensor inputs (temperature, water level, timers) determine when to move to the next state and which next state to choose.
The hand sketch is my first draft of a state diagram, showing all the state transitions. This is just to show you how you can initially plan your states and state transitions - it may not be completely accurate as that was before I started debugging.
In our case, we have 6 states which I've called OFF, BOOT REQUEST, BOOTING, RUNNING, SHUTDOWN REQUEST, and SHUTTING DOWN. (After SHUTTING DOWN it moves back to OFF.) These are identified by comments in the sketch, and for each, further comments say what it should be doing and what events will move it to another state.
The helper program running on the Pi is just a little more complicated than for most shutdown buttons. It responds to a long low pulse on the GPIO pin by initiating a shutdown, but it also responds to a short pulse by itself briefly pulling the GPIO pin low. This is how the ATTiny85 can tell that it's running and so can move from the BOOTING to the RUNNING state.
Step 3: Building a Demo Prototype
For demonstration purposes you can prototype it on a solderless breadboard as shown but I've also given you the schematic so you can work out your own layout using stripboard or a custom PCB, perhaps part of a wider project.
Step 4: Programming the ATTiny85
The Arduino sketch and the helper program are attached to this step. In your Arduino sketches folder, create a folder called PiPwr and copy the file PiPwr.ino into it. Launching the Arduino IDE you will now find it in your sketchbook.
There are several ways of programming an ATTiny85. If yours has a bootloader installed you can use an ATTiny85 development board costing only a few pounds. This connects to your PC via a USB port. I used a Hidiot which is essentially the same but with a prototyping area.
In the Arduino IDE under File - Preferences, add
http://digistump.com/package_digistump_index.json
to the Additional boards manager URLs.
Under Tools - Board you should now see a number of Digispark options. Select Digispark (Default - 16.5MHz).
If your ATTiny85 doesn't have a bootloader (or you don't know) then you can get an AVR ISP programmer for a few pounds. Or you can use an Arduino Uno or cheaper Pro Mini or Nano as a programmer. Google for "arduino as isp attiny85" (without the quotes) for instructions.
If you want to modify the sketch you will find it fully commented and hopefully easy to follow. For debugging it's much easier to use an Arduino Pro Mini or Nano. Uncomment the serial.begin() in Setup and the print statements in loop() in order to see the steps it goes through using the serial monitor. There are alternate pin definitions in the source, commented out, for a Uno, Pro Mini or Nano.
On your Raspberry Pi, copy the file shutdown_helper.py to folder /etc/local/bin and set it as executable with the command
sudo chmod +x /usr/local/bin/shutdown_helper.py
Now edit the file /etc/rc.local with your favourite editor. (You will need to do so as root.) Before the last line (exit 0) insert the line
nohup /usr/local/bin/shutdown_helper.py &
Reboot, and the helper program will start automatically.
24 Comments
1 year ago
Well I did what you said (beside using module instead of just attiny85) but its behave strangely. If I give it 3.3V it shutdown but not booting, if I give it 5V from pi gpio it boot but not shutdown (although it reset). Also like Sgifst838cs said it blink 4 short set few times. Not like in your video.
PS: Helper script needs python in rc.local line to be able to load
"nohup python /usr/local/bin/shutdown_helper.py &"
Reply 1 year ago
I normally try and help people as much as I can but I'm somewhat tied up at the moment, and it's a good while since I looked at this. I think different Pis work slightly differently. You need to sit down with the code until you understand it (it's not that hard and fairly well documented) then work out your own diagnostics using print statements and/or LEDs. Do report back with your progress.
2 years ago
I built this and it works fine on a Raspberry Pi 4, but on the Pi3 B+ the LED blinks 4 times and then stops.
Reply 2 years ago
my serial interface was not enabled!
2 years ago
I tried to build this and hook it up to a Pi4. When the Pi4 is booting, the LED will flash. Once booted the LED stays on and the button does not seem to do anything.
I have verified with grep that the helper python script is running.
If the Pi is powered down I can press the button and it will power up. But it does not seem that the button is recognized being pressed while powered on.
I have not changed anything in the code and the unit is hooked up exactly as shown on the PiZero. I even used the same layout on the breadboard as shown.
I have also verified the serial interface is enabled.
Reply 2 years ago
Update. Although the LED stays on and pressing the button for longer than 5 seconds does trigger a shutdown. I would like to reduce the amount of time required to hold the button to get a shutdown.
Reply 2 years ago
Hi -
I'm afraid it's a while since I've looked at this project and it would take a little while for me to get back up to speed with it. First of all, look through other comments. I think the latest Raspbian (or later Raspberry Pis) behave slightly differently, which might affect it. You should at least get an idea from other comments on what to try.
Another aproach would be to implement it on a cheap Arduino Nano (or Uno if you have one lying around) or an even cheaper Pro Mini if you have a FTDI adapter. You can modify the pins it uses by modifying the #define lines near the top of the sketch. If you then uncomment the Serial.begin and all the Serial.print statements and invoke the Arduino serial monitor it'll report the states it goes through.
2 years ago
Very nice instructable :-)
I have (almost) no activity on TX (pin 8) from the RPI during boot. The RPI boots when I pull pin 5 low, but the only thing that happens on the TX is that TX goes high after 9ms and then low again after additional 75ms. It then stays low.
What am I missing? I am using a RPI4 with Raspbian. Please ask if you need more details.
Reply 2 years ago
Have you enabled Serial in raspi-config under Interfacing? It won't detect power-off from the TX pin otherwise.
Reply 2 years ago
Hi Leriche,
Thank you very much for your reply!
I tried to flash the SD-card with a clean Raspbian version (through the Raspberry Pi Imager). I then ran "sudo raspi-config" in the terminal and enabled the Serial, and restarted the RPI. However, I still do not get anything on the TX (the still boots fine when a short the pin 5 and 6.
Do you have any other suggestions?
(Ps. I will try to get another RPI for testing. I will also try to write a small program for the ATTiny to see if it is just my digital analyzer that is broken (it seems to work fine for any other use).)
Reply 2 years ago
There's not much activity expected on TxD. It should be low when the Pi is shut down (even with power still applied) and should be largely high when running, though will oscillate if it generates serial console messages. Double check - correction - triple check you're looking at the right pin and that the Serial interface is enabled. We all make unbelievably dumb mistakes. It might be worth getting a cheap Pi Zero to see if it's any different, or an FTDI serial to USB adapter and seeing if you can detect the console messages. (Make sure it's a 3.3v one or the jumper is in the 3.3v position. Connect TxD to RxD and vice versa, and Gnd to Gnd. On a PC you can use PuTTy or Arduino Monitor to watch the serial port.)
Reply 2 years ago
Hi Leriche,
Thank you so much for your reply! That is very much appreciated.
I found the error, which (of cause) my mistake. I miss understood/read what activity to expect on the TX. I (wrongly) thought that TX was never high or low more than 30 ms, but as you write it is never low more than 30 ms.
By the way, on my setup it takes ~5.5 sec from the SCL pin is pulsed low to the TX goes high. Is that normal? If I understand your state diagram correctly, then the program will go back to OFF (because of the 50 ms timeout) and then first enter BOOTING, when TX goes high.
---
Side note: I am trying to extend your (very nice) setup with a button that contains three leds to show more information, but for that, I need to move to the ATTiny84. I found the button here https://www.aliexpress.com/item/1955136917.html and it is possible to design the specification. I chose: momentary switch, red/green/blue LED, 5V, black body, common anode, and power symbol (it also includes the led resistors). The quality is nice.
Reply 2 years ago
Glad you sorted it! Nice button, but I felt flashing 25% duty cycly for booting and 75% for shutting down was more intuitiv than fdifferent colours.
Does yours now work? Looking back at the code it does seem that it expects TxD to go high within 50mS of signalling a boot request through SCL and that certainly worked for me. But I guess it could be 5 seconds before the kernel enables the TxD/RxD functions on pins 8 and 10 if the firmware hasn't already. In that case, you'd need to change the 50 on line 111 to a minimum of 6000.
2 years ago
Thanks so much for this great tut!
I have tried to rebuild it and encounter some issues, similar to aditya-ranjan above. For your information, I am using GPIO 10 / BCM 15 (Is it an issue that it is the Rx pin?).
Otherwise the behaviour is as follows:
1. when RPI is on, LED is off
2. when button is pressed and RPI is off, RPI boots up, LED blinks until RPI booted
3. when button is pressed and RPI is on, nothing happens.
I have checked and the helper python file is running (using ps -fA | grep python). I have changed the line in /etc/rc.local to 'python /usr/local/bin/shutdown_helper.py &' and I have changed the Pin definition to '15' in the python file.
When running the /etc/rc.local file the output shows 'Starting' but doesn't recognise any button press.
Is there any advice you can give? Is there any way to check if the issue is on the RPI or on the Attiny?
Thanks a lot!
Reply 2 years ago
Hi, :-)
I would love to look into your questions. However, I have a problem with my RPI (no activity on the TX pin) as described above. Maybe you could help me, so I can help you? :-)
Nevertheless, I use my Logic Analyzer a lot for analyzing logic signals:
Analyzer (like this): https://www.aliexpress.com/item/4000146595503.html
Hook (like this): https://www.aliexpress.com/item/1037153617.html
Software (I do not know if the new version is free): https://www.saleae.com/downloads/
Question 3 years ago
Hi, I followed the procedure in your article and got a functional push button. However, it only works in case of switching on the pi. If I press the button to perform shutdown, the led simply goes off for the duration of button press and that is it. The pi does not shutdown.
The button does work incase of trying to boot the pi.
I have done ps -fA | grep python to check if shutdown_helper.py is running or not. It does seem to be running correctly.
If I manually start the shutdown_helper.py like a typical python script on terminal then only "Starting" message shows. Nothing else is displayed or pi does not shutdown on button press.
Answer 3 years ago
Hi. In my case I had to do some modification to work.
changed
nohup /usr/local/bin/shutdown_helper.py &
to
nohup python /usr/local/bin/shutdown_helper.py &
since you seem to have the python script running probably that is not needed.
In some versions of Raspbian, I had to include 'sudo' before the shutdown instruction in the python script, that solved the problem. Hope this helps.
3 years ago
Thanks for the informative article!
You might also be interested in the PowerBlock (https://powerblock.petrockblock.com), which is a ready-to-go power button solution for safe shutdowns and four-stage power status indication via LED.
4 years ago
Great Instructable! You said you are demonstrating on a Raspberry Pi Zero, would this work on a Raspberry Pi 3 B+? I would love to add a safe power off button to my project, but I'm not great with electronics.
Reply 4 years ago
Hi, yes it should work jusy as well with any old Pi.