If you need to be notified of a power outage at your equipment location, this is a quick and cheap way of doing just that. This method will allow you to use a Raspberry Pi, connected to both an Uninterruptible Power Supply (UPS) and a commercial power outlet, to monitor and send email/text alerts with power changes.
Assumptions:
- You have a Raspberry Pi already set up which is networked
- You have an SMTP service installed and setup on the Pi like sSMTP
- You have the ability to execute Python (or can install it if your distro does not have it)
Parts:
- Raspberry Pi (any model, even Zeros as long as you can network)
- Relay (this is the one I used)
- A UPS power source to run the Pi
- A non-UPS power source to monitor
- Jumpers
- Soldering Iron and Solder
Here is the relay I used. It takes 5v from a standard USB so it is quite universal but it does require one quick modification to simplify the power need. Remember the USB power goes to a commercial power outlet not serviced by a UPS system.
The modification is this: you probably don’t want to plug in a USB power and input power to control the relay. Just using one is fine and the USB power can act as both. If the unit is powered by the USB, you can trigger the relay by pushing the “Button Trigger”. Well, just keep it on if there is power and it will disconnect when there is no power. Simple. How do you keep the button pressed? Jumper it always on.
You can remove the button if you like, but I just jumper-ed over it (yellow wire). Power at USB now always turns on the relay (at the Normally Open terminal).
The relay has three screw terminals. Common (COMM), Normally Open (NO), and Normally Closed (NC). Technically you can write the code anyway you want to as long as the logic is the same or inverse. I wrote it such that COMM is 3.3V and the NO terminal went to GPIO 26 (BCM). That is, if input BCM 26 is HIGH (3.3V) there is power. If input BCM 26 is 0V, there is no power.
Here is the Pi header wiring diagram from Raspberry Pi Pinout:
Connect the COMM wire (RED) to any 3.3V pin (in the pic here I used physical pin number 17) and the NO terminal wire (YELLOW) to BCM GPIO 26 (physical pin number 37). You can vary this depending on your code, if you prefer. For clarification the other pins used at the top are for a room temperature and humidity sensor and not part of this project.
Below is the code. Because it may be hard to read on WordPress, here is a link to the file. Remember to change it from .txt to .py to run.
import RPi.GPIO as GPIO # import GPIO library
import subprocess # needed for subprocess call
from time import sleep # this lets us have a time delay
GPIO.setmode(GPIO.BCM) # set up BCM GPIO numbering
GPIO.setup(26, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) # set up pin 26 for input detection of 3.3V
init = 1 # set inital state for boot message
try:
while True: # this will carry on until you hit CTRL+C
if GPIO.input(26): # if port 26 == 1 (there is power)
if init == 1: # we must have cold booted on purpose or from a failure on UPS dead battery extended outage
email = 'echo "REBOOT from extended power failure or device reset. Power is ON." | mail email1@email.com, email2@email.com'
subprocess.call(email, shell=True) # send email command
else:
email = 'echo "Power restored at site. Commercial power is ON." | mail email1@email.com, email2@email.com'
subprocess.call(email, shell=True) # send email command
while GPIO.input(26): # do nothing if the power state stays on
sleep(0.1)
else: # there is no power detected at pin 26
init = 0 # why bother checking every time it happens only once
email = 'echo "Power failure at site. Commercial power is OFF." | mail email1@email.com, email2@email.com'
subprocess.call(email, shell=True) # send email command
while GPIO.input(26) == 0: # do nothing if the power state stays off
sleep(0.1)
finally: # this block will run no matter how the try block exits
GPIO.cleanup() # clean up on exit
A couple notes on the code. You can add as many email addresses as you want separated by commas. The sleep is very short, you can adjust if too much CPU is used. Don’t use “shell=True” in a subprocess.call if you don’t control what is going into it. If you use that based on user input, they could execute. Here, there is no user input requested.
Also, DO NOT use the 5v pins. The header cannot tolerate that much voltage and you will burn it out. Only use 3.3V.
You probably want this to start automatically each time the RPi is booted. You can add a line in /etc/rc.local to do this (modified for your file location):
/usr/bin/python /home/pi/Code/PowerCheck.py
That should be it. Happy monitoring.