• Build logs, Tutorials and Hacks

    Friday, October 18, 2013

    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.




    [caption id="attachment_734" align="aligncenter" width="300"]RPi GPIO Header RPi GPIO Header[/caption]

    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.




    [caption id="attachment_735" align="aligncenter" width="300"]GPIO Connector P5 GPIO Connector P5[/caption]

    [caption id="attachment_736" align="alignright" width="236"]RPI Connector P5 RPI Connector P5[/caption]

    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;

    [code]
    # 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)

    [/code]

    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

    [code] sudo python /home/pi/scripts/shutdown.py [/code]

    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.




    [code]
    #!/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

    [/code]

    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:




    [code] sudo chmod 755 /home/pi/scripts/shutdown.sh
    sudo sh /home/pi/scripts/shutdown.sh
    [/code]

    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.

    [code] sudo nano /etc/rc.local [/code]

    [caption id="attachment_741" align="aligncenter" width="300"]Screenshot: rc.local in nano Screenshot: rc.local in nano[/caption]

    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.

    30 comments:

    1. A big Thank you! This is working perfectly! I am just using GPIO 25 ;)

      ReplyDelete
    2. 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.

      ReplyDelete
    3. 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!

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

      ReplyDelete
    5. 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.

      ReplyDelete
    6. Thanks for the clarification Inderpreet!

      ReplyDelete
    7. 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

      ReplyDelete
    8. Thanks for the input. I will try and use if and revert back.
      Thanks.

      ReplyDelete
    9. 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?

      ReplyDelete
    10. 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.

      ReplyDelete
    11. I think I am going to do a video on the subject...

      ReplyDelete
    12. 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.

      ReplyDelete
    13. […] Adding a Shutdown Button to the Raspberry Pi | The Embedded Code. […]

      ReplyDelete
    14. 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.

      ReplyDelete
    15. 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.

      ReplyDelete
    16. Perhaps a stupid question, but can I "install" the Python script to the SD via Windows and a cardreader?

      ReplyDelete
    17. 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

      ReplyDelete
    18. 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? :)

      ReplyDelete
    19. 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 :)

      ReplyDelete
    20. Good to know and thanks for posting the info. It will be useful.

      ReplyDelete
    21. 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.

      ReplyDelete
    22. try adding a sudo before the command. I really recommend just using python for beginners.
      Hope this helps.
      Cheers

      ReplyDelete
    23. 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

      ReplyDelete
    24. The & at the end makes the command run in the background. You are correct.

      ReplyDelete
    25. I didn't have any problems without the & mark in the rc.local file.

      ReplyDelete
    26. Thanks for this, it was just what I was looking for and worked first time with a push button from my box of bits

      ReplyDelete
    27. 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.

      ReplyDelete
    28. The shutdown function is defined there and thats it. It just shells a command to shutdown. The event call makes it possible to call the function.

      ReplyDelete