• No results found

A controlled shutdown button

The Raspberry Pi should always be shut down correctly to avoid the SD card being corrupted (by losing power when writing to the card). This can pose a problem if you don't have a keyboard or screen connected (if you are running an automated program or controlling it remotely over a network and forget to turn it off) as you can't type the command or see what you are doing. By adding our own buttons and LED indicator, we can easily command a shutdown, reset, and start up again to indicate when the system is active.

Getting ready

You will need the following equipment:

f 3x Dupont female to male patch wires

f Mini breadboard (170 tie points) or a larger one f Push button

f Standard LED (for example, a red one) f 2x 470 ohm resistors

The entire layout of the shutdown circuit will look as shown in the following figure:

The controlled shutdown circuit layout

How to do it…

Create the shtdwn.py script as follows: #!/usr/bin/python3

#shtdown.py import time

import RPi.GPIO as GPIO import os

# Shutdown Script

DEBUG=True #Simulate Only SNDON=True

#HARDWARE SETUP # P1

SHTDWN_BTN = 7 #1 LED = 12 #L def gpio_setup(): #Setup the wiring GPIO.setmode(GPIO_MODE) #Setup Ports GPIO.setup(SHTDWN_BTN,GPIO.IN,pull_up_down=GPIO.PUD_UP) GPIO.setup(LED,GPIO.OUT) def doShutdown(): if(DEBUG):print("Press detected") time.sleep(3) if GPIO.input(SHTDWN_BTN):

if(DEBUG):print("Ignore the shutdown (<3sec)") else:

if(DEBUG):print ("Would shutdown the RPi Now") GPIO.output(LED,0)

time.sleep(0.5) GPIO.output(LED,1)

if(SNDON):os.system("flite -t 'Warning commencing power down'") if(DEBUG==False):os.system("sudo shutdown -h now")

if(DEBUG):GPIO.cleanup() if(DEBUG):exit() def main(): gpio_setup() GPIO.output(LED,1) while True:

if(DEBUG):print("Waiting for >3sec button press") if GPIO.input(SHTDWN_BTN)==False: doShutdown() time.sleep(1) try: main() finally: GPIO.cleanup()

print("Closed Everything. END") #End

To get this script to run automatically (once we have tested it), we can place the script in ~/bin (we can use cp instead of mv if we just want to copy it) and add it to crontab with the following code:

mkdir ~/bin

mv shtdwn.py ~/bin/shtdwn.py crontab –e

At the end of the file, we add the following code:

@reboot sudo python3 ~/bin/shtdwn.py

How it works…

This time when we set up the GPIO pin, we define the pin connected to the shutdown button as an input and the pin connected to the LED as an output. We turn the LED on to indicate that the system is running.

By setting the DEBUG flag to True, we can test the functionality of our script without causing an actual shutdown (by reading the terminal messages); we just need to ensure to set DEBUG to False when using the script for real.

We enter a while loop and check every second to see if the GPIO pin is set to LOW (the switch has been pressed); if so, we enter the doShutdown() function.

The program will wait for 3 seconds and then test again to see if the button is still being pressed. If the button is no longer being pressed, we return to the previous while loop. However, if it is still being pressed after 3 seconds, the program will flash the LED and trigger the shutdown (also providing an audio warning using flite).

When we are happy with how the script is operating, we can disable the DEBUG flag (by setting it to False) and add the script to crontab. Crontab is a special program that runs in the background that allows us to schedule (at specific times, dates, or periodically) programs and actions when the system is started (@reboot). This allows the script to be started automatically every time the Raspberry Pi is powered up. When we press and hold the shutdown button for more than 3 seconds, it safely shuts down the system and enters a low power state (the LED switches off just before this, indicating it is safe to remove the power shortly after). To restart the Raspberry Pi, we briefly remove the power; this will restart the system, and the LED will light up when the Raspberry Pi has loaded.

There's more…

Resetting and rebooting Raspberry Pi

The Model B Rev 2 Raspberry Pi (and all of Model A) has holes for mounting a reset header (marked P6 on the unit), which allow the device to be reset using a switch rather than by removing the micro USB connector each time to cycle the power.

To make use of it, you will need to solder a wire or pin header to the Raspberry Pi and connect a switch/button to it (or briefly touch a wire between the two holes of P6 each time). Alternatively, we can extend our previous circuit as shown in the following diagram:

The controlled shutdown circuit layout and reset button

We can add this extra button to our circuit, which can be connected to connection 1 of the P6 reset header (the hole closest to the edge). This pin, when pulled low by connecting to ground (such as the hole next to it or another ground point such as Pin 6 of the P1 header), will reset the Raspberry Pi and allow it to boot up again following a shutdown.

Adding extra functions

Since we now have the script monitoring the shutdown button all the time, we can add extra buttons/switches/jumpers to be monitored at the same time. This will allow us to trigger specific programs or set up particular states just by changing the inputs. The following example allows us to easily switch between automatic DHCP networking (the default networking setup) and using a direct IP address, as used in the Networking directly to a laptop or computer recipe of Chapter 1, Getting Started with a Raspberry Pi Computer, for direct LAN connections.

Add the following components to the previous circuit:

f A 470 ohm resistor

After adding the previous components, our controlled shutdown circuit now looks as follows:

The controlled shutdown circuit layout, reset button, and jumper pins

In the previous script, we add an additional input to detect the status of the LAN_SWA pin (the jumper pins we added to the circuit) using the following code:

LAN_SWA = 11 #2

Ensure that it is set up as an input (with a pull-up resistor) in the gpio_setup() function using the following code:

GPIO.setup(LAN_SWA,GPIO.IN,pull_up_down=GPIO.PUD_UP)

Add a new function to switch between the LAN modes, and read out the new IP address. The doChangeLAN() function checks if the status of the LAN_SWA pin has changed since the last call, and if so, it sets the network adaptor to DHCP or sets the direct LAN settings accordingly (and uses flite to speak the new IP setting if available). Finally, the LAN being set for direct connection causes the LED to flash slowly while that mode is active. Use the following code to do so:

def doChangeLAN(direct):

if(DEBUG):print("Direct LAN: %s" % direct) if GPIO.input(LAN_SWA) and direct==True: if(DEBUG):print("LAN Switch OFF") cmd="sudo dhclient eth0"

cmd="sudo ifconfig eth0 169.254.69.69" direct=True else: return direct if(DEBUG==False):os.system(cmd) if(SNDON):os.system("hostname -I | flite") return direct

Add another function, flashled(), which will just toggle the state of the LED each time it is called. The code for this function is as follows:

def flashled(ledon): if ledon: ledon=False else: ledon=True GPIO.output(LED,ledon) return ledon

Finally, we adjust the main loop to also call doChangeLAN() and use the result, to decide if we call flashled() using ledon to keep track of the LED's previous state each time. The main() function should now be updated as follows:

def main(): gpio_setup() GPIO.output(LED,1) directlan=False ledon=True while True:

if(DEBUG):print("Waiting for >3sec button press") if GPIO.input(SHTDWN_BTN)==False: doShutdown() directlan= doChangeLAN(directlan) if directlan: flashled(ledon) time.sleep(1)

Relocating to the P5 header

The previous circuit can be very useful if permanently fitted to the Raspberry Pi, but it would get in the way if you intend to connect other components to the main GPIO header (P1). Fortunately, you can use the GPIO pins available on the P5 connections of the board and adjust the code to suit. You will either need to solder an extra pin header in place (it is recommended that this be done at a slight angle to still allow space for a ribbon connector

A P5 header is shown in the following image:

An extra P5 header added

The RPi.GPIO library does not have numbering allocated for the P5 header using the GPIO.BOARD references, so we have to use the GPIO.BCM references (the GPIO reference of the Broadcom processor pins) as shown in the following diagram:

P5 GPIO pins (Board Revision 2 only)

Change the pin references in the code to reference the P5 pins as follows, and then relocate all the wiring from the P1 header to the P5 header:

#HARDWARE SETUP # P5

# 1[==Lx]7 # 2[=21x]8

#BTN CONFIG - Set GPIO Ports GPIO_MODE=GPIO.BCM