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.
- 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)
- 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
- 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 email@example.com, firstname.lastname@example.org' subprocess.call(email, shell=True) # send email command else: email = 'echo "Power restored at site. Commercial power is ON." | mail email@example.com, firstname.lastname@example.org' 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 email@example.com, firstname.lastname@example.org' 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):
That should be it. Happy monitoring.