Adding a Shutdown Button to the Raspberry Pi

I’ve been using the raspberry pi for some time and since I use it as s headless device, I have missed the shutdown button. After some experimentation, I have come up with a simple solution. There are many ways to implement a shutdown script, but I am going to walk through the two simplest ones.

The Hardware

We need a physical button which we can press to shutdown the RPi and I really did not want to waste the GPIO Connector P6 that we typically use.

RPi GPIO Header
RPi GPIO Header

Shown above is the connector which I am talking about. While going through the RPi documentation, I found another GPIO connector which can be used.

GPIO Connector P5
GPIO Connector P5
RPI Connector P5
RPI Connector P5

So naturally I soldered a connector to it and additionally I soldered a simple push button to a relimate connector. The result is shown below.

Its that simple!. Now we have the physical button. No additional hardware is required! Beauty!

The Software

There are two parts to the software..

  1. The script that will execute the shutdown and
  2. Adding the script to be executed automatically when the system is started. 

The Python Way

We can use a simple python script to shutdown the RPi. This script simply waits for the button to be pressed and when that happens, a command is sent to the kernel to safely shutdown the RPi. The code is as follows;

# Simple script for shutting down the raspberry Pi at the press of a button.
# by Inderpreet Singh

import RPi.GPIO as GPIO
import time
import os

# Use the Broadcom SOC Pin numbers
# Setup the Pin with Internal pullups enabled and PIN in reading mode.
GPIO.setmode(GPIO.BCM)
GPIO.setup(31, GPIO.IN, pull_up_down = GPIO.PUD_UP)

# Our function on what to do when the button is pressed
def Shutdown(channel):
 os.system("sudo shutdown -h now")

# Add our function to execute when the button pressed event happens
GPIO.add_event_detect(31, GPIO.FALLING, callback = Shutdown, bouncetime = 2000)

# Now wait!
while 1:
 time.sleep(1)

Copy the script code and create a file using nano and save it in a known location as shutdown.py. I created a folder in my home folder called scripts and saved them there. In order to test the script run the following command

 sudo python /home/pi/scripts/shutdown.py  

Pressing the button should shutdown the RPi

Bourne Again Shell

The working of the bash script is quite simple and the comments explain the working of the script. It is basically monitoring the button for a press. I have not done any load testing to see which one will load the cpu more and if there is anyone who can suggest testing results I would be more than happy to append it here.

#!/bin/bash

# monitor GPIO pin 31 (wiringPi pin 1) for shutdown signal

# export GPIO pin 31 and set to input with pull-up
echo "31" > /sys/class/gpio/export
echo "in" > /sys/class/gpio/gpio31/direction
echo "high" > /sys/class/gpio/gpio31/direction

# wait for pin to go low
while [ true ]
do
if [ "$(cat /sys/class/gpio/gpio31/value)" == '0' ]
then
 echo "Raspberry Pi Shutting Down!"
 halt &
 exit 0
fi
sleep 1
done

Copy the script code and create a file using nano and save it in a known location. I created a folder in my home folder called scripts and saved them there.
Test the bash script by running the following commands:

 sudo chmod 755 /home/pi/scripts/shutdown.sh
sudo sh /home/pi/scripts/shutdown.sh

Press the button and the system should shutdown.
Starting the script at startup

Now that we have the scripts we need to set up the RPi to run them at startup. This is as simple as adding the commands to the /etc/rc.local file. Be sure to add an & so that the script runs in the background and does not wait there forever.

 sudo nano /etc/rc.local 
Screenshot: rc.local in nano
Screenshot: rc.local in nano

It should look like the above screenshot. In case you opt for the python option, simply replace the corresponding command.

That’s it!

I have tried to explain the simple process as much as possible. Please leave a comment below for queries etc.

Advertisements

54 Comments

  1. You don’t say which pins you use or if there is any special requirements for the switch, like a resistor. Or that an LED could be linked in to confirm the shutdown process has started.

    1. Oops! I seem to have missed that in the text… Actually I left that to you. I used the gpio pin 31 as you can see in the code, but you are free to use any gpio pin. No there are no resistors needed and you can link up an LED but I have not done that yet. I might do that though. Cheers!

      1. I still don’t get it. What does your button connect? Pin 31 and ground? Why should this work without a resistor to 5V?

      2. Well the Pi’s GPIOs have in built pull up resistors and hence you don’t need an external pull up. This means that without any external connections, the GPIO will be read as a ‘1’ or high. As soon as you connect the GPIO pin to ground by pressing the button between the pins, it reads it as a ‘0’ or LOW. This status is read by the script and issues the shutdown command and viola!
        Hope that helps.

      3. Hello Inderpreet, I was very happy to find your thread on the raspberry shutdown button but it’s not working for me at all. The python script is shuting down the unit immediately after running the script. What’s wrong? I check everything 1000 times. I am running a rasperry pi B with the newest weezy firmware and everything is updated. Any recommendation or solution? If this thread is outdated it would be fine to make a remark “obsolete”.

      4. This is what I used to do a reboot which works great.

        __author__ = ‘Inderpreet Singh’
        # Simple script for shutting down the raspberry Pi at the press of a button.
        # by Inderpreet Singh

        import RPi.GPIO as GPIO
        import time
        import os

        # Use the Broadcom SOC Pin numbers
        # Setup the Pin with Internal pullups enabled and PIN in reading mode.
        GPIO.setmode(GPIO.BCM)
        GPIO.setup(26, GPIO.IN, pull_up_down = GPIO.PUD_UP)

        # Our function on what to do when the button is pressed
        def reBoot(channel):
        os.system(“sudo reboot”)

        # Add our function to execute when the button pressed event happens
        GPIO.add_event_detect(26, GPIO.FALLING, callback = reBoot, bouncetime = 2000)

        # Now wait!
        while 1:
        time.sleep(1)

  2. Thank you, exactly what I was looking for..

    I have little modified your shell script. I thing it’s less strain on the CPU.
    I removed IF command and changed a sleep time for 5 seconds

    #!/bin/bash
    echo “23” > /sys/class/gpio/export
    echo “in” > /sys/class/gpio/gpio23/direction
    echo “high” > /sys/class/gpio/gpio23/direction
    while [ “$(cat /sys/class/gpio/gpio23/value)” != ‘0’ ]
    do
    sleep 5
    done
    poweroff &
    exit 0

  3. So by connecting a momentary switch to pin 31 and ground and running the same code from above the script will work?
    doesn’t this script need to be started when the pi boots?

    1. By above i assume you mean the one in the article.That is exactly how it will work. In order to start the script at boot, add it to the RC.local file.
      If you mean the script in the comment, then it works using the gpio23 pin instead of the gpio31. The rest is the same.
      Hope that helps.

      1. import RPi.GPIO as GPIO
        import os
        GPIO.setmode(GPIO.BOARD)
        GPIO.setup(11, GPIO.IN, pull_up_down=GPIO.PUD_UP)
        GPIO.wait_for_edge(11, GPIO.FALLING)
        os.system(“sudo shutdown -h now”)
        GPIO.cleanup(11)

        save the above as shutdown.py and use with the latest GPIO.
        GPIO hardware prerequisites: ●~$ sudo aptget install pythondev y ●~$ wget http://pypi.python.org/packages/source/R/RPi.GPIO/RPi.GPIO0.5.4.tar.gz ●~$ tar zxvf RPi.GPIO0.5.4.tar.gz ●~$ mv RPi.GPIO0.5.4 GPIO ●~$ cd GPIO ●~/GPIO$ sudo python setup.py install

        GPIO python ●In terminal or SSH session: ●~$ mkdir scripts ●This completes the path /home/pi/scripts/
        ●~$ cd scripts ●~/scripts$ nano shutdown.py ●Paste the script text in from the bottom of the page
        ●Ctrl+o to write out
        ●Ctrl+x to exit ●~/scripts$ ls    (this will list the files) ●~/scripts$ shutdown.py   (this is the output you should see as well as any other files in the same directory) ●~/scripts$ cd ●TEST your python script ●~$ sudo python /home/pi/scripts/shutdown.py
        ●Ctrl+c to stop the script or push the button to shutdown!
        Launch at boot: ●~$ sudo nano /etc/rc.local ●Insert this line above the last line ●sudo python /home/pi/scripts/shutdown.py & ●Ctrl+o to write out ●Ctrl+x to exit The & makes the script run in the background

    1. Inderpreet,
      What I did one RPi was use the shell version which worked. Then I tried it with another RPi running nginx, php5 and Mysql with WordPress and what I found in the rc.local was what looked to be a command for wordpress and adding the sudo …/shutdown.sh I get an error message on line 14 which repeats.

      1. Sorry for the late reply. I suggest trying the python script. I myself have had problems with the shell script like many others. I will look into writing a program in C for the functionality but seems like an overkill.

    1. Thanks for the input. I did not share the CPP version of the above code for a number of reasons. The bash or python scripts are simpler and most people interested in RPi are working with python hence I thought it would be just less painful to have a scripting approach to a simple problem such as adding a shutdown button.

      I will be doing a followup post with various versions and a mmore “current” approach to doing the same.
      Cheers.

    1. First off, there is no such thing as a stupid question. Second, well you just need to copy it to your RPi. You can do that by means of a program called WinSCP. Google it and download it. Once you connect the RPi to a network via Ethernet cable or Wifi Dongle, you will need it’s IP address. For home routers with default configuration, the IP addressed start from 192.168.1.1(the router itself) and then in the sequence in which devices are connected, 192.168.1.2, 192.168.1.3…. and so on. I guess you can enter these addresses in turn and depending upon the number of devices you have, you should get connected pretty soon.
      The username is pi and password is raspberry.
      You should be able to just copy it to the running Pi.

      Next you need a program called putty which will connect to the same IP address and get a terminal where you can do the rest of the configuration. I have a tutorial on setting up an RPi at https://embeddedcode.wordpress.com/2013/07/10/the-geek-getting-started-guide-to-the-raspberry-pi/

      Hope this helps,
      Cheers

      1. Thanks, this helps! Only “problem” now is that the pi is mounted in my car allready without wifi (havn’t installed it yet)

        I did manage to mount the linux partition with read/write permissions and I can edit / make the required files in Windows 7 with notepad, but either the script doesn’t work or the psu sends the wrong signal because it doesn’t work.

        I first will try a switch and then your solution and report back.

        Probably also need to google it, but any chance you can tell me how to open a terminal with raspbmc? 🙂

  4. well, I have an SSH connection to my pi, I now have Openelec and I found out it differs from the tutorial. There’s no ETC or HOME folder. I want to use the RPi as a CarPC and i’m experimenting with different images, so far no luck.

    I do like the OpenElec more then the RaspBMC, but is there a good alternative?
    I’m also struggling with the sound and S-Video quality and I can’t even get a copied script to work 😦
    Maybe I’m going way to fast, but I have no audio in the car right now, at least the Pi should safely turn off on ignition off.

    Can you give me some advice on what OS to use?
    Most forums don’t even reply on my topics, this is the fastest responce I got 🙂

  5. Sorry for all the comments, but I got it working on RaspBMC!

    For the noobs like me:
    The folders “home”, “pi” or “etc” arn’t visible but you can edit the files using nano. I used ls -al to display the files and folders and “sudo nano /etc/rc.local” to edit the file, and “mkdir Scripts” to create the folder and “sudo nano Shutdown.py” to create and edit the shutdown script.

    Had to install Python and some other stuff (updates?)..

    I used these commands, don’t know if they are all required but it did fix it for me!

    General update:
    apt-get update –fix-missing
    apt-get upgrade –fix-missing
    apt-get dist-upgrade –fix-missing

    apt-get update
    apt-get upgrade
    apt-get dist-upgrade

    Install Certs (otherwise I got and error of none trusted supplier):
    sudo apt-get install ca-certificates
    sudo apt-get install git-core

    python package:
    $sudo apt-get update
    $sudo apt-get install python-dev
    $sudo apt-get install python-rpi.gpio (common on the internet but didn’t work for me)

    sudo pip install –upgrade RPi.GPIO (DID work)

    Also in the rc.local file in the above screenshot I had to change the command to include “python” or else it didn’t run.

    so: “sudo python /home/pi/scripts/Shutdown.py”

    Flawless now, thank you!

      1. Hello Inderpreet,

        I have successfully executed the python script, but I am receiving an error when I use the bash script. My terminal tells me that it:

        a) cannot create the directories
        b) & that there is a syntax error, and that the script is ending unexpectedly.

        I am not sure what the syntax error would be, and am fairly stumped right now.

        any help here would be appreciated.

        Thanks again.

  6. Hello, this is a great script for me as I am just starting out. I came across a problem when doing this using python, the script would run when the Pi started but then I could not control the Pi unless I SSH in. It seemed that it would run the script but then not carry on. I had “sudo python /home/pi/scripts/Shutdown.py” in the rc.local file. I then changed this to “sudo python /home/pi/scripts/Shutdown.py &” the & would let the script continue. Is this correct?
    Thanks

    1. I did. My Pi booted up and was stuck waiting for me to press the shutdown button… I couldnt bypass to get to emulationstation so I had to reimaged my SD card. It is super important to use the “&”!!!!!

      By the way, I added this information to petrockblock, and gave you huge credit for your simple solution to this issue! Thank you so much Inderpreet!!!!!!

  7. Does the def Shutdown(channel): function use the shell script as input to check if the button is pressed? Also i was wondering where to find information about how to use this function. I checked on the python website but was unable to find it.

  8. Hello Inderpreet,
    thankyou for your guide.
    Python script and rc.local worked fine in a system running on my RPi with the button connected on P5 pin 6(GPIO 31) and 8.
    Today I rebuilded the system, again with Raspbian but now the same hw + sw solution produces a message “Kernel [ 412.476900] Disabling IRQ #50 and the system does not halt.
    Any idea on the issue ?

    Regards
    Barth

    1. You are right and in recent times a lot Of people have complained about this. If you are using a python script executing it as sudo does the job. There are many ways to do that and I will edit the original post to reflect that.
      Thanks again.

      1. Thank you for your prompt reply!
        My rc.local is 777 and the line refferring the python script is as follow:
        sudo python /home/pi/Scripts/RPi_Stop.py &
        placed just the line before exit 0 .

        Even lauching the same line manually does not produces the expected result but Disabling IRQ #50.

        Hoping you can suggest a solution!

        Regards
        Barth

  9. Hello Inderpreet,
    after some investigation I ended up with a partial solution.
    When I rebuild my RPi I performed also an rpi-update it resulted in a firmware and kernel update that was related to the release available in mid of January 2015. Looking at the RPi site I found a page where it is stated that some changes are in place in the newest especially a configuration change to enable Device Tree support by default.
    I do not found anithing related to the GPIO PYTHON library by Ben Croston but I have done a test downgrading my RPI with
    sudo rpi-update 5ea0f44b673eaa52c578fcd6480495f19cd53d97 (example)
    to the rpi-firmware released on 22 November 2014 and now the halt button is working fine !!

    As said, this is a partial solution because it seems clear to me that there is some kind of incompatibility between GPIO.RPI and the newest firmware and up to the moment when Ben Croston or someone like PhilE from Raspberry Pi Org will fix the situation, we will have to use an old firmware in order to use the halt button python script.

    Best regards
    Barth

    1. Thanks for the input Barth. I have been getting similar reports and I am in the process of making a new post around the subject. I have tested some options and I am waiting for the Pi2 to be delivered to test the solution on that as well. I will be presenting a unified way to add the shutdown button very soon. Thanks again and stay tuned.;)

  10. I am looking forward to see an updated process. I’ve used your python method on my Pi2 using pin 21. I would suggest adding a loop to make it require a long press of the button, 5 seconds, to avoid accidental shutdowns.

  11. I’ve been working with your python script, out of laziness as I’m not fully fluent with python yet.

    when triggered, this script gets stuck in a loop – re-executing the commands after every sleep interval.

    I’d like it to execute the commands once, and then resume waiting for button press events – any suggestions?

    here’s my code, with a few commented out lines from previous experiments:

    # Simple script for shutting down the raspberry Pi at the press of a button.
    # by Inderpreet Singh

    import RPi.GPIO as GPIO
    import time
    import os

    # Use the Broadcom SOC Pin numbers
    # Setup the Pin with Internal pullups enabled and PIN in reading mode.
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(13, GPIO.IN, pull_up_down = GPIO.PUD_UP)

    # Our function on what to do when the button is pressed
    def Shutdown(channel):
    os.system(“mpg321 -g 50 /home/pi/p51approaching.mp3”)
    os.system(“mpg321 -g 90 /home/pi/p51flyby.mp3”)

    # os.system(“sudo shutdown -h now”)
    # os.system(“reboot”)
    # os.system(“mpg321 -g 50 /home/pi/chimeup.mp3”)

    # Add our function to execute when the button pressed event happens
    GPIO.add_event_detect(13, GPIO.FALLING, callback = Shutdown, bouncetime = 2000)

    # Now wait!
    while 1:
    time.sleep(1)

    In case you are wondering about the p51 part, it’s for a light and sound show for a military museum I volunteer for – and will be using lightshowpi to run relays from the mp3 output

    1. I’ve since found it’s probably a debouncing issue.
      the script appears to be triggered twice.

      I’ve tried increasing the bouncetime to 5000ms
      and also trigger on rising, falling and both.

      the bouncetime increase improved the trigger from 5-6 times, down to two. I’ll keep playing while I await advice.

      I don’t have a resistor on my switches, they are very old school, and removed from a 1950’s radar installation – they use incandescent globes (12v) so I can’t rule out interference from the adjacent contacts.

      1. FYI – I found I had to add a small ceramic capacitor across the switch contacts. The big mechanical switches I am using were causing a spike, as they also switch 12v on the other side of the contact.

        no more bouncing issues.

  12. Hi Inderpreet
    Thanks for the tutorial
    Im having problems with one bit.
    Iv done lots of Arduino but just started today with RPi. Ive done zero Linux, bash etc.
    Ive got it all going down to the bit where you say
    “Copy the script code and create a file using nano and save it in a known location. I created a folder in my home folder called scripts and saved them there.
    Test the bash script by running the following commands:

    sudo chmod 755 /home/pi/scripts/shutdown.sh
    sudo sh /home/pi/scripts/shutdown.sh

    Press the button and the system should shutdown.”
    Do I have to use nano?
    what extension do I save file as?
    Testing the bash script-do I just enter both those scripts seperately and push enter?
    When I do the second one-sudo sh /home/pi/scripts/shutdown.sh- I get an error
    /home/pi/scripts/shutdown.sh: 13: [: 1: unexpected operator
    which keeps repeating.
    Just stuck around this area of the tutorial due to my lack of RPi, bash knowledge. Note I changed GPIO to 23 and changed 31 to 23 in the shutdown.sh file.
    Thanks John D

    1. Hi John.
      Since you are beginning with RPi, I suggest you try out the python code instead. Create a new shutdown.py file and add it to the /etc/rc.local
      That does it on the newer versions of the Linux OS and works on the RPi 2 as well.
      Lemme know if that works.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s