Thursday, February 27, 2020

Raspberry Pi Power Switch (Open Source!)

Introduction

This project will describe how to create a power switch for your Raspberry Pi (any version) that safely shuts your R-Pi down with the press of a button and then cut power to the R-Pi. Then, to start the R-Pi back up again, press another button right next to it. Pretty cool, right?

It should be stated that this is not my original idea or design, and I would like to attribute the original creator of the circuit but sadly I can not find their blog anymore. However, I do have a picture that I saved from the blog, which I'll display below. Whoever you are, thank you for creating the original design! You are awesome!

The original circuit diagram.

The purpose of recreating the circuit and blog post is that I've made some improvements to the project overall. In light of the fact that this idea was not my own, I will be open sourcing everything, including all circuit diagrams and PCB designs. Feel free to download them, edit them, and make them your own!

A quick warning about this project is that I have tested this circuit with my own R-Pi with a prototype board I threw together myself and it works perfectly fine, but I have not actually tested the finalized PCB produced by EasyEDA yet, so I have no idea whether it works for sure or not (I'm fairly certain it will work, but I can't guarantee that it will work, so use at your own risk!). Once I order the PCB and test it myself, I will come back and update this post.

The Circuit

Another reason for recreating the circuit diagram was that the original image was very small and a little pixelated, so I have provided a much larger image for download that is easier to see.

The new circuit diagram.

As you can see, I have used the software called EasyEDA to design this diagram (and the PCB as well). The files will be available in EasyEDA source code, as a PNG image, and a PDF file. The Gerber file and other files will be available as well, but I'll get into that later.

Now, I am certainly no expert at laying out a circuit diagram (or PCB layout, as you'll see later), so I apologize if it's a little strange looking. It's a fairly simple circuit; one tactile switch, when pressed, turns on the relay that supplies the 5 volts for the R-Pi and simultaneously starts charging up the capacitor that keeps the relay engaged. When the second tactile switch is pressed, it begins discharging the capacitor as well as sending a 3.3 volt logic level signal to the R-Pi that lets the Pi know it should begin shutting down. The capacitor stays charged for long enough that the R-Pi is able to shut down safely before the cap runs out of charge and switches the relay off. This is an oversimplification of exactly how the circuit works (I really didn't mention the role the transistors play), but it's enough to get a basic understanding.

From here, you can certainly solder everything together on a prototype board and begin using it with your R-Pi, however if you are interested in the PCB, continue reading to the next section. If not, skip ahead to "The Code" section.

Downloads


The Board

The PCB design was not really planned out in any specific way, and I kind of just laid it out how I thought it looked good to me. You can see a 3D preview of it below.

The old 3D preview of the unpopulated PCB with no screw holes.

As I forgot to include screw holes for mounting (Doh!) I'll be coming back and updating this image and everything else later. I've decided to leave up the original design without screw holes is case anybody wants it, however the new design is shown below with screw holes. I don't really like the way it looks with the screw holes, especially because of all the negative space on the top and bottom of the board, but oh well. Both versions of all files are available.

The new 3D preview, with the screw holes.

The board is designed to take 5 volt power in from a micro-B USB socket, which both powers the circuit and the R-Pi. The output is a standard female USB connector that the R-Pi plugs into. To interface with the R-Pi, there is a 1x2 header pin that can be used to connect to the Pi with jumper wires or something similar. When you build this yourself, you can choose to leave out the header altogether and solder wires directly to the board.

The PCB layout in EasyEDA showing the front traces (red), the rear traces (blue), the pads (gray), and the silk screen (yellow).

Above is an image of the PCB being laid out in EasyEDA, which I'm not sure if you'll find useful, but I decided to include it anyways. One reason I included this image is to mention that I did not route these traces myself, I used the autorouter. I know, I know!! Blasphemy! However, it appears to have done the job well enough for this PCB. If something looks incorrect or janky to you, don't blame me, blame EasyEDA's autorouter! (I would like to hear about how the traces could be better routed in the comments, this is my first PCB ever!)

A word about the parts I based this design on: I used generic parts suggested by EasyEDA. That means that the materials listed in the BOM (bill of materials) can be substituted with any compatible parts from any supplier. For example, the transistor listed in the BOM is the 2N3904 PNP transistor, but you could just as well use a 2222A PNP transistor in its place. Just make sure that the substitute part is compatible!

Anyways, everything you might need for this board is below, including the Gerber file.

Downloads


The Code

The code has also been adapted and rewritten from the original, but I don't have the original code unfortunately. This code was written in Node.js (of course, what else would I write it in?), but if you have the skills you can adapt this code to any language that can interface with the R-Pi's GPIO pins. Without further ado, here's the code below.

var Gpio = require('pigpio').Gpio;
var exec = require("child_process").exec;

var input = new Gpio(4, {
 mode: Gpio.INPUT,
 pullUpDown: Gpio.PUD_DOWN,
 edge: Gpio.FALLING_EDGE
});

var output = new Gpio(2, {mode: Gpio.OUTPUT});
output.digitalWrite(1);

input.on('interrupt', (level) => {
 exec('sudo shutdown -h now', (error, stdout, stderr) => {
  if (error) {
   console.error(`exec error: ${error}`);
   return;
  }
  console.log('Shutting down now!');
 });
});

You'll notice that my implementation runs on Wiring-Pi, which sadly is no longer supported. I will definitely be updating the code soon to work with pigpio as it's more or less just as capable as Wiring-Pi, and it's still supported. The code above has been updated and works with pigpio! A link for instructions for installing pigpio are here. Another thing to mention is that this code only works with the R-Pi 2, 3, and 4. For the R-Pi 1, Zero, and Zero W you'll need to change the shorthand function notation inside of the exec() function to the regular function syntax (the reason for this is the older and smaller R-Pi's processor only allows them to run an older version of Node.js that does not support shorthand function notation).

You may need to edit the code if you decide to use different pins than I chose to use, which are pin 11 GPIO04 for the input on the R-Pi and pin 13 GPIO02 for the output on the R-Pi.

Once you have downloaded the code and its dependencies (Wiring-Pi) to your R-Pi, all you need to do is make the script run at startup, by adding the following line to a new line in your rc.local file:

sudo node /path/to/softshut.js &

Next up, it's time to put it all together.

Downloads


Putting it All Together

Once you have your board soldered and put together, it is time to hook it up to your Raspberry Pi. Plug in the micro-B USB cable from your power adapter to the input on the board, then plug in another USB cable from the output to your R-Pi power input. Next, connect the pin on the board labeled "Input" to the R-Pi GPIO pin that will be acting as the output in the script, and then connect the pin labeled "Output" to the R-Pi's pin that will be accepting an input.

Now, press the "On" button and see if it boots up! You will hear the relay click the instant you press the on button. Wait for the R-Pi to fully boot, then try pressing the "Off" button. If the Pi does not immediately start its shutdown sequence, then you've got a problem! If this is the case, enter the shutdown command to your R-Pi as quickly as you can, as the capacitor will have started draining and the relay will switch off the power to your R-Pi soon. Something is wrong with either your script not starting up correctly, or maybe the pins are assigned incorrectly, or something along those lines. You'll need to do some troubleshooting to figure out exactly what went wrong!

Conclusion

All in all this is a very useful addition to just about any Raspberry Pi project, especially with projects that are battery powered! I really wish something like this was built into the R-Pi already, but it makes sense why it wasn't included when you consider the fact that the Raspberry Pi was engineered to be as cheap as possible.

Like I said, I will be coming back and updating/refining this post as I go, but I wanted to publish it as soon as possible, just to get it out into people's hands.

This project will also be available on GitHub once it is finalized, so stayed tuned!