Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Making Your Own RPi Power Button

DZone's Guide to

Making Your Own RPi Power Button

While not a true power button, you can hook up a button to your Raspberry Pi that puts your device to sleep so you can save energy while not losing data.

· IoT Zone ·
Free Resource

This post describes an easy way to add a power button to a raspberryp pi that:

  • Only needs a button and wires, no other hardware components.
  • Allows graceful shutdown and powerup.
  • Only needs modification of config files and does not need a dedicated daemon to read GPIO pins.

There are two caveats:

  • This shuts down in the same way as shutdown -h now or halt does. It does not completely cut the power (like some hardware add-ons do).
  • To allow powerup, the I²C SCL pin (aka GPIO3) must be used, conflicting with externally added I²C devices.

If you use Raspbian stretch 2017.08.16 or newer, all that is required is to add a line to /boot/config.txt:

dtoverlay=gpio-shutdown

Make sure to reboot after adding this line. If you need to use a different gpio, or different settings, lookup gpio-shutdown in the docs.

Then, if you connect a pushbutton between GPIO3 and GND (pin 5 and 6 on the 40-pin header), you can let your raspberry shutdown and startup using this button.

All this was tested on a Rpi Zero W, Rpi B and a Rpi B+.

If you have an older Raspbian version, or want to know how this works, read on below.

Powering down your pi

To gracefully power down a Raspberry Pi (or any Linux system), it has to be shut down before cutting power. On the rpi, which has no power button, this means using SSH to log in and running a shutdown command. Or, as everybody usually does, cutting the power and accepting the risk of data corruption.

Googling around shows a ton of solutions to this problem, where a button is connected to a GPIO pin. The GPIO pin is monitored and when it changes, a shutdown command is given. However, all of these seem to involve a custom daemon, usually written in Python, to monitor the GPIO pin. A separate daemon just for handling the powerbutton does not sound great, and if it is not apt-get installable, it seems too fragile for my tastes. Ideally, this should be handled by standard system components only.

Another thing is that a lot of these tutorials recommend wiring a pullup or pulldown resistor along with the button, while the raspberry pi has builtin pullups and pulldowns on all of its I/O pins which can just as easily be used.

It turns out a combination of systemd power key handling, combined with the kernel gpio-keys driver and devicetree overlay can be used to handle graceful shutdown completely with existing system components.

Shutdown using systemd-logind

Having a shutdown button connected to a GPIO pin is probably not so uncommon, so I Googled some more. I came across the 70-power-switch.rules udev file from systemd-logind, which adds the "power-switch" tag to some kernel event sources representing dedicated power buttons. Since v225 does this for selected gpio sources as well (commit). A bit of digging shows that:

  • The udev rules add the "power-switch" tag to selected devices. Udev does not use these tags itself, but other programs can.
  • The "power-switch" udev tag causes systemd-logind to open the event source as a possible source of power events.
  • When a KEY_POWER keypress is received, systemd-logind initiates a shutdown. It also handles some suspend-related keys.
  • Since last week, 70-power-switch.rules tags all event sources as "power-switch" (commit) and lets systemd-logind figure out which could potentially fire KEY_POWER events (commit) and monitor only those (though this change does not really change things for this usecase).

Linux gpio-keys driver

So, how to let a GPIO pin generate a KEY_POWER event? The first logind commit linked above has an example device tree snippet that sets up the kernel gpio-keys driver which does exactly that: Generate key events based on gpio changes.

Normally, the devicetree is fixed when compiling the kernel, but using a devicetree overlay (see the Rpi device tree docs) we can insert extra configuration at boot time. I found an example that ties multiple buttons to GPIO pins and configures them as a tiny keyboard. Then I found an example in the the gpio-button package that does the same with a single button and also shows how to configure a pulldown on the pin.

I've created a devicetree overlay based on that example, that sets up the gpio-keys driver with a single GPIO to trigger a KEY_POWER event. The overlay is just a text file and I added elaborate comments, so look inside if you are curious.

This overlay was merged into the official kernel repository and is shipped in Rasbpian images from 2017.08.16 and onwards. See below for instructions on manually compiling and installing this overlay on older images.

Waking up

With the above, you get a shutdown button: Press it to initiate a clean shutdown procedure, after which the raspberry pi will turn off (note that it does not completely cut power, that would require additional hardware. Instead, the system goes into a very deep sleep configuration while still drawing some current).

After shutdown, starting the system back up means removing and reinserting the USB cable to momentarily cut power. This begs the question: Can you not start the system again through one of the GPIO pins?

I found one post that pointed out the RUN pin, present on Rpi 2 and up, which can be shorted to GND to reset the CPU (without clean shutdown!), but can also power the system up. However, having two buttons, along with the risk of accidentally pressing reset instead of shutdown did not seem appealing to me.

After more digging I found a forum post saying that shorting GPIO3 to GND wakes up the Rpi after shutdown. It also says GPIO1 should work, but I do not think any Rpi makes that pin available, so I haven't tested that. Official docs on this feature seem to be lacking, I found one note on the elinux.org wiki saying bootcode.bin (version 12/04/2012 and later) puts the system in sleep mode, and starts the system when GPIO3 goes low.

Since GPIO3 is also a normal IO pin, this is perfect: By configuring the shutdown handling on GPIO3, the same button can be used to shutdown and wake up. Note that GPIO3 is also an I²C pin, so if you need to also connect I²C-devices, another pin must be used for shutdown and you cannot use the wakeup feature. Also note that GPIO3 (and GPIO2) have external pullups at least on the Rpi Zero.

Setting this up on older Rasbpian versions

On Rasbpian versions older than 2018.08.16, two additional steps need to be taken:

  1. Older images do not include the overlay yet. You will need to get and build the DT overlay yourself. Download the devicetree overlay file. The easiest is to run wget on the raspberry pi itself:
    $ wget http://www.stderr.nl/static/files/Hardware/RaspberryPi/gpio-shutdown-overlay.dts
    Then compile the devicetreefile:
    $ dtc -@ -I dts -O dtb -o gpio-shutdown.dtbo gpio-shutdown-overlay.dts
    Ignore any "Warning (unit_address_vs_reg): Node /fragment@0 has a unit name,
    but no reg property
    " messages you might get. Copy the compiled file to /boot/overlay where the loader can find it:
    $ sudo cp gpio-shutdown.dtbo /boot/overlays/
  2. Older images run a systemd version older than v225 (check with systemd --version), which only handles KEY_POWER events from specific devices. To make it work with gpio-keys as well, create a file called /etc/udev/rules.d/99-gpio-power.rules containing these lines:
    ACTION!="REMOVE", SUBSYSTEM=="input", KERNEL=="event*", SUBSYSTEMS=="platform", \
        DRIVERS=="gpio-keys", ATTRS{keys}=="116", TAG+="power-switch"

Update 2018-04: I restructured this post to reflect that Rasbpian has merged the needed changes and make the instructions focus on making things work with a recent Rasbpian image (while keeping the extended instructions for older images at the bottom).

Topics:
raspberry pi ,power ,gpio ,tutorial

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}