The original reason for my interest in the Raspberry Pi was for a mini computer to monitor a UPS and alert us if there was a power loss. The following is how I setup the Raspberry Pi to monitor the UPS and send an email to our cell phones in the event of a localized power loss.
|
CyberPower LCD "Smart" UPS |
Short Story of Education the Hard Way
(
note to reader: If you are just interested just in the UPS monitoring details, skip ahead...)
What are we monitoring with the UPS? Well, we have a small chest style deep freezer in our garage. We store steaks and other expensive meats in it. Anytime there is an excellent sale, my wife stocks up on meats. A few months ago, something caused the GFCI to trip, and we didn't notice until a few days latter when the rancid smell reached us. We estimated over $500 worth of meat lost in one fell swoop. So the wife tasked me with coming up with a solution to avoid a repeat in the future.
So my solution was to use a "smart" UPS, one that I could actively read the metrics from, and send a email notification in the event of a power failure. The second benefit, or so I had thought, is the UPS could keep the fridge powered for short term power loss. I already have a CyberPower UPS connected to my file server, and it works great for battery backed power outages, monitoring battery reserves, and shutting down the server if the reserves deplete.
A bit of painful education. I wanted to make sure I purchased the "right" size of UPS, so I pulled out my Kill A Watt power meter and connected it to the refrigerator. During the occasional freeze cycle it appeared to pull about 460-490 Watts, and lasted less than a minute. At idle, it rated closer to 10 Watts. I rationalized that the UPS should be able to handle a few of these cycles before failing out.
When I looked online for consumer UPS, a majority measured in VA. So how does one get VA from Watts? Well, I cheated. The Kill A Watt also has a VA meter, so I selected that, and it showed around 560-580 VA. I then found a 600 VA CyberPower UPS. I admit that I realized 580 to 600 is not a lot of wiggle room, but the next battery size up jumped quite a bit in price. I crossed my fingers and ordered it. I should have done a bit more research.
The UPS arrived and I connected it to the freezer. The freezer's motor kicked on and the UPS went offline. Clearly I was wrong.
When I actually searched for VA to Watt conversion calculations online, I found that a good estimate is closer to 50% - 60%. I would have needed almost 800 VA to be on the safe side. Even this may not have been sufficient, as I learned that the initial motor spike can be quite high.
Lesson learned: You would probably need an industrial sized UPS to battery back a simple freezer.
Well, the battery protection was a bust, but at least I could still use the UPS to monitor for a power failure. Unfortunately, had I known this, I could have saved a few bucks, and just purchased the cheaper smaller "smart" UPS. The Raspberry Pi could run for days off even the smallest one.
So onto the technical stuff...
The setup. The Raspberry Pi lives out in the garage, on top of the deep freezer. I have a USB powered hub connected to the UPS, in one of the battery backed up slots. The USB hub then powers the Raspberry Pi (to avoid having to waste two power adapters). To talk to the USB hub I have a second USB cable connected to the data side of the Pi. To connect to the network, I have a WiFi dongle connected to the USB powered hub. To try and keep it as clean as possible, I have Raspberry Pi inside a plastic container, with holes for air flow. Finally, to get as much use of the Raspberry Pi, it also serves double duty and controls/monitors the garage door.
There are numerous "UPS" monitoring packages available, but the one I have had the most success with, is the one from APC called "
apcupsd - APC UPS Power Management (daemon)". Although it was designed for APC branded UPS, it works quite well with numerous other UPS.
I tend to purchase the CyperPower UPS line with the LCD display. I am a sucker for the LCD that provides quick visual metrics, of the UPS. The CyperPower UPS connects to a PC through USB and works well with the
apcupsd daemon.
Luckily the package is already included in the Raspbian repositories, so installation is this simple:
# apcupsd installation
apt-get update
apt-get install apcupsd
The next step is to modify the configuration scripts, so
apcupsd can find the UPS. Use your editor and modify
/etc/apcupsd/apcupsd.conf with the following changes.
# vim /etc/apcupsd/apcupsd.conf
#UPSCABLE smart
UPSCABLE usb
#UPSTYPE apcsmart
UPSTYPE usb
#DEVICE /dev/ttyS0
DEVICE
These changes tell
apcupsd that the UPS is connected via USB.
Next we want to test our connection to the UPS. This can be achieved with the '
acptest' program.
# apctest
2013-09-14 14:49:10 apctest 3.14.10 (13 September 2011) debian
Checking configuration ...
Attached to driver: usb
sharenet.type = Network & ShareUPS Disabled
cable.type = USB Cable
mode.type = USB UPS Driver
Setting up the port ...
Doing prep_device() ...
You are using a USB cable type, so I'm entering USB test mode
Hello, this is the apcupsd Cable Test program.
This part of apctest is for testing USB UPSes.
Getting UPS capabilities...SUCCESS
If you see the "SUCCESS", everything is great. There isn't much here that you will want to change, so let's quit this program and start the apcupsd daemon.
First, enable the service:
# vim /etc/default/apcupsd
ISCONFIGURED=yes
Next, restart the service:
# service apcupsd restart
Starting UPS power management: apcupsd.
To have apcupsd auto start at boot:
# update-rc.d apcupsd defaults
Next, we can query the UPS to see the various metrics available to us using the '
apcaccess' application. The properties that apcupsd supports is quite large, and each UPS uses different properties, so your results may vary.
# apcaccess
APC : 001,032,0781
DATE : 2013-09-14 14:54:31 -0600
HOSTNAME : pi-ups
VERSION : 3.14.10 (13 September 2011) debian
UPSNAME : pi-ups
CABLE : USB Cable
DRIVER : USB UPS Driver
UPSMODE : Stand Alone
STARTTIME: 2013-09-14 14:54:30 -0600
MODEL : UPS CP600
STATUS : ONLINE
LINEV : 120.0 Volts
LOADPCT : 0.0 Percent Load Capacity
BCHARGE : 100.0 Percent
TIMELEFT : 82.0 Minutes
MBATTCHG : 5 Percent
MINTIMEL : 3 Minutes
MAXTIME : 0 Seconds
OUTPUTV : 120.0 Volts
DWAKE : 000 Seconds
LOTRANS : 100.0 Volts
HITRANS : 140.0 Volts
ALARMDEL : 30 seconds
NUMXFERS : 0
TONBATT : 0 seconds
CUMONBATT: 0 seconds
XOFFBATT : N/A
SELFTEST : OK
STATFLAG : 0x07000008 Status Flag
SERIALNO : AEC7101.251
NOMINV : 120 Volts
NOMPOWER : 340 Watts
END APC : 2013-09-14 14:55:02 -0600
Now that we can query the UPS, let's work with the apcupsd "event" scripts. This is how we will get an email sent when a power failure occurs. The event scripts can all be found in the
/etc/apcupsd/ folder. All events are controlled by the
/etc/apcupsd/apccontrol master script, so take a quick peak there if you want to know what else can be modified.
The two scripts we are interested in are the "
onbattery" and "
offbattery" scripts. The "onbattery" is triggered during a power failure, and "offbattery" is triggered when power returns.
By default these scripts are just simple bash scripts that send a message to the PC's console and send a local email. Instead of using local mail, we will use Gmail to send our notification, and write the script in Python. One other side benefit of having these scripts written in Python, is I can also
integrate Xively and then update Xively with the
various data points of my UPS.
Let's backup the current scripts, before modifying them:
cp /etc/apcupsd/onbattery /etc/apcupsd/onbattery.original
cp /etc/apcupsd/offbattery /etc/apcupsd/offbattery.original
This is the powery failure script I use:
onbattery:
#!/usr/bin/env python
import smtplib
import email.mime.text
import syslog
syslog.openlog('[UPS]')
def log(msg):
syslog.syslog(str(msg))
GMAIL_ADDRESS = 'xxx@gmail.com'
GMAIL_PASSWORD = 'xxx'
from_email = GMAIL_ADDRESS
to_emails = ["xxxxxxxxxx@tmomail.net"] # cell phone address
msg_subject = "ALERT: UPS Power Failure"
msg_text = "Auto Notification"
log(msg_subject)
msg = email.mime.text.MIMEText(msg_text)
msg['Subject'] = msg_subject
msg['From'] = from_email
msg['To'] = ", ".join(to_emails)
s = smtplib.SMTP_SSL('smtp.gmail.com', '465')
s.login(GMAIL_ADDRESS, GMAIL_PASSWORD)
s.sendmail(from_email, to_emails, msg.as_string())
s.quit()
And for when power returns:
offbattery:
#!/usr/bin/env python
import smtplib
import email.mime.text
import syslog
syslog.openlog('[UPS]')
def log(msg):
syslog.syslog(str(msg))
GMAIL_ADDRESS = 'xxx@gmail.com'
GMAIL_PASSWORD = 'xxx'
from_email = GMAIL_ADDRESS
to_emails = ["xxxxxxxxxx@tmomail.net"] # cell phone address
msg_subject = "OK: UPS Power Recovered"
msg_text = "Auto Notification"
log(msg_subject)
msg = email.mime.text.MIMEText(msg_text)
msg['Subject'] = msg_subject
msg['From'] = from_email
msg['To'] = ", ".join(to_emails)
s = smtplib.SMTP_SSL('smtp.gmail.com', '465')
s.login(GMAIL_ADDRESS, GMAIL_PASSWORD)
s.sendmail(from_email, to_emails, msg.as_string())
s.quit()
Finally, we test the scripts locally to make sure the email notification is sent. If everything looks good, test a power failure by disconnecting the UPS from the wall. Within a few seconds, the apcupsd daemon should trigger the onbattery event and our email should be sent. Now we will immediately know the next time the UPS looses wall power.
So, what if the power loss is not local to just the UPS? An external
monitoring service could be used. Something like Nagios running from
the cloud works great for this, but I will save that for another time.