An Uninterruptible Power Supply (UPS) is a peripheral which provides emergency battery power to servers when the input power source or mains power fails. While most UPS devices are quite large and heavy, smaller devices used to protect individual PCs. These smaller devices are more affordable with prices around £100, however, they are overkill for a Raspberry Pi. In this DIY project, we will use a mobile phone power block to provide a battery backup for the Raspberry Pi which is both low cost and small in size. If you have a spare power bank lying around not being used, this project may not even cost a penny.
A mobile phone power bank is ideal as it already has USB charger in and typically a micro USB out so in the most basic form all that is required is to plug the mains adaptor into the power bank and the power bank into the Raspberry Pi. Depending on the capacity of the power bank you may get a few minutes to several hours use from the battery. Some of the newer ultra high battery may even last days, but I'd recommend anything over 4,000 mA.
In order to be fully protected, you need to have the Raspberry Pi automatically shutdown when the power is cut. For this, we need to have the Raspberry Pi connected to an ethernet hub which is not on the protected circuit. The plan is that when the power is cut, the hub loses power. We can then detect this from the Raspberry Pi and have a shutdown command issued. Of course, this will also cause the Raspberry Pi to shut down should the cable be disconnected as well, but for most home server applications, this isn't an issue.
We will be using a small bash script which will allow us to shut down the Raspberry Pi on a power outage and log the events to the system log.
sudo mkdir /opt/check_lan sudo pico /opt/check_lan.sh
Copy in these lines for the script
#!/bin/sh # cron script for checking lan connectivity # change 192.168.1.1 to whatever IP you want to check. IP_FOR_TEST="192.168.1.1" PING_COUNT=1 PING="/bin/ping" IFUP="/sbin/ifup" IFDOWN="/sbin/ifdown --force" INTERFACE="eth0" FFLAG="/opt/check_lan/stuck.fflg" # ping test $PING -c $PING_COUNT $IP_FOR_TEST > /dev/null 2> /dev/null if [ $? -ge 1 ] then logger "$INTERFACE seems to be down, trying to bring it up..." if [ -e $FFLAG ] then logger "$INTERFACE is still down, shutting down..." rm -f $FFLAG 2>/dev/null sudo shutdown -h -t 0 else touch $FFLAG logger $(sudo $IFDOWN $INTERFACE) sleep 10 logger $(sudo $IFUP $INTERFACE) fi else # logger "$INTERFACE is up" rm -f $FFLAG 2>/dev/null fi
Next we need to make this script executable:
sudo chmod 700 /opt/check_lan.sh
Now we need to edit the crontab:
sudo pico /etc/crontab
And add this line so that our script runs every two minutes
*/2 * * * * root /opt/check_lan.sh >/dev/null
That should be all good to go.
What this is going to do is create a scheduled task which runs every two minutes. This task will call a bash script to check the LAN connection. It will first ping the IP address defined at the start of the script, in this case, my router. If the ping is unsuccessful it will write a temp file
stuck.fflg, drop the ethernet connection and restart it. The script then ends. Two minutes after, it checks the ping. If it still doesn't work it removes the temp file and shuts down the Raspberry Pi. If the ping does work, it removes the temp file and carries on as normal.
The total time between first checking the connection and the shutdown is 4 minutes. You can change this value to anything you want, just make sure that your battery lasts at least this long because if the battery runs out before the script runs you will risk damaging the Raspberry Pi.