Raspberry Pi UPS monitor (with Nginx web monitoring)

Introduction

With the winter weather, we’ve been having brownouts and power losses more frequently. I wanted to purchase a UPS to protect my equipment from this, but I also wanted to receive alerts when the power goes out, and possibly shutdown equipment. For this, I need an Uninterruptible Power Supply (UPS) and a computer to monitor it with.

Hardware

As you guessed by now, I’m going to be using my Raspberry Pi to monitor the UPS. I covered the setup of my Raspberry Pi in an earlier post, so check that out if you need a place to start. I’m using the Raspberry Pi because it is a low power device, it is always on (hosting a webserver, Unifi controller, and a few other things), and can be run off the UPS it is monitoring.

The UPS I’m using is a CyberPower CP1500PFCLCD, specifically, this one. A crucial factor in choosing a UPS is whether you need Pure Sine Wave or Simulated Sine Wave. This decision is based off of the type of power supply in the equipment you’re protecting. Power supplies that use Active Power Factor Correction (Active PFC) typically require Pure Sine Wave, which is shown on the left. Simulated Sine Wave, shown on the right, mimics Pure Sine Wave and is typically cheaper. However, during a switchover to battery power, Simulated Sine Wave has a momentary gap in power (shown in the red circle). During this time, no power is being sent, and Active PFC power supplies may shutdown (which defeats the purpose of the UPS in the first place). In my case, I was happy to be safe instead of sorry, and went for the Pure Sine Wave UPS.

Disclaimer – I am not an electrical engineer 😉

Software

I need some way to monitor the status of the UPS and act on it if a certain threshold is reached. CyberPower provides software called PowerPanel Personal that runs on Windows, Mac, and Linux. However, it has its limits and cannot be used with anything other than CyberPower devices. Instead, I’m going to be using the Network UPS Tools (NUT) suite. NUT has many advantages over vendor-specific software:

Configuration

The NUT suite consists of three components:

driver – connects to and communicates with the UPS

server – monitors the UPS status

client – sends/receives information from the server

The NUT suite offers a variety of configurations. In my case, I’m using the “simple” configuration, also known as standalone. It consists of one UPS and one computer which runs the driver, server, and client. This is the minimum setup needed.

However, you can setup a more advanced configuration consisting of a “master” computer that runs the driver, server, and client, but also have clients running on one or more separate “slave” computers. With this configuration, the master shuts down last, giving the slaves time to shutdown first.

Driver setup

First, connect your UPS to your Raspberry Pi via the included USB cable. Verify you can see it with lsusb.

Next, we need to install the NUT suite. Just a warning, the systemd service will fail to start until we make a configuration file.

sudo apt-get update && sudo apt-get install nut nut-client nut-server

Over on NUT’s compatibility database, you can see which driver to use for the CP1500PFCLCD (in my case, it was usbhid-ups). Edit the configuration file at /etc/nut/ups.conf and add the following information at the bottom. The friendly name (e.g., cyberpower1) must be one word, no spaces.

Client setup

Since I’m using the standalone setup, I can make all my connections on localhost. Edit the configuration file at /etc/nut/upsmon.conf and add the connection string, using the master user you created earlier.

MONITOR cyberpower1@localhost 1 upsmon_local local1 master

Ensure your ownership and permissions are correct.

sudo chown root:nut /etc/nut/*
sudo chmod 640 /etc/nut/*

Then, start the client service (this is the same as running upsmon) and check the status.

sudo systemctl start nut-monitor
sudo systemctl status nut-monitor

You can test the connection via localhost (replace cyberpower1 with the friendly name of your UPS).

sudo upsc cyberpower1@localhost

Web monitoring (Nginx)

Assuming you have Nginx installed, you can monitor NUT from the master client via a browser. It’s easier to do this with Apache, but I prefer Nginx. However, unlike Apache, Nginx doesn’t have built in support for executing CGI scripts, so a helper application is needed to handle dynamic content. In this case, that package is fcgiwrap.

sudo apt-get update && sudo apt-get install nut-cgi fcgiwrap

Edit the configuration file at /etc/nut/hosts.conf and add the following line (replace cyberpower1 with the friendly name of your UPS).

If you want to visit the settings/admin page, you will need to edit the configuration file at /etc/nut/upsset.conf and uncomment the line below. You can then login with the admin username/password we set earlier.

###I_HAVE_SECURED_MY_CGI_DIRECTORY

Email alerting

Email setup

Because most ISPs block port 25 (SMTP), we need an external STMP server that we can use to route messages through. Luckily, Google provides one for free if you have a Gmail account. Google’s SMTP settings are here, we’ll need them later. A few protips for this:

Obviously, I would advise against using your primary Gmail account for this. Setting up a dedicated Gmail account just for this application only takes a few minutes and is worth it, in my opinion.

Testing

Test your email alerts by unplugging the USB cable from the Raspberry Pi and plugging it back in. This action will trigger the COMMBAD and COMMOK flags, which we’ve set to write to the syslog, wall, and execute our script.

You can check the syslog, as shown below.

grep ups /var/log/syslog

You should get a message on any SSH sessions you have open, since we specified to use a wall message.

Caveat

The main caveat with this setup is that you may get a notification storm. If the weather is bad and the power goes in and out repeatedly, you’ll get a notification for each event. To mitigate this, NUT has another program called upssched that can call our script, after a specific interval has passed.

Using upssched, we can call our script after the UPS has been on battery for 30 seconds, instead of right away. Then, if the power goes back on in 20 seconds, you can cancel the timer. I haven’t set this up yet, but I’m working on it.

Tweaks

After a few days, I noticed I was receiving constant storms of COMMBAD/NOCOMM/COMMOK, even though the power wasn’t going out. After some Google-ing, I stumbled across this article with a solution (copied out below).

Edit the configuration file at /etc/nut/ups.conf and add a poll interval.

30 thoughts on “Raspberry Pi UPS monitor (with Nginx web monitoring)”

Logan, this is awesome. And though I know you’re not tech support, I can’t get it to work completely. The test emails work, sudo upsc works and shows me what I need, and I get the wall messages. However, the system won’t email me the alerts.

One issue thought that I can’t seem to get around, is that emails are sent correctly, and are being received, however I cannot get a meaningful from name. All the emails come up as from “derived from envelope by postmaster@***.

Sorry, I was assuming a familiarity with Nginx. The configuration files for Nginx are generally located in /etc/nginx/sites-available and you’ll need to use some sort of text editor (e.g., emacs, vi, nano, etc…) to edit the files.

Hi Logan,
Thanks for posting this guide. I just purchased a CyberPower CP1500PFCLCD UPS for my home ESXi server and originally wanted to use use the CyberPower PowerPanel Business Edition for Virtual Machines, but my ESXi server does not support DirectPath IO so I searched for another solution. I came across your guide and was able to set up the NUT suite on an old Raspberry PI B+ and get it working, however is seems that after a few hours of running the pi starts reporting “Broadcast message from nut@rp1 (somewhere) (Sat Nov 18 01:38:54 2017): UPS cyberpower1@localhost is unavailable” and upsc reports “Error: Data stale”. Rebooting the pi solves it for a bit but then it starts failing again. I am thinking that setting this up on a new pi3 might be the answer but wonder if you have any thoughts on this and appreciate any input you may have.

Hi Logan,
Thanks for the reply. I noticed that sometimes when I get this, the nut-driver is reporting correctly and restarting the nut-server works, yet other times I need to restart both. I will try the tweaks section and a new cable too.

HI Logan,
Your tweaks did the trick and this is now working great for me including the web page and alerting. Thanks again for posting this guide; not only do I have alerting now for my new UPS but I learned a lot in the process!

Hello Logan, I recently set this up and it is working perfect, but I ran into an issue. When rebooting the pi the UPS reboots as well… This is not optimal as the UPS is running a server and my entire network..

I have the exact same UPS model as you and was wondering if you had a fix for this.

This is a great guide, I have it all working on my pi/ups combo. But one thing I cannot figure out is how to get NUT to start automatically when the pi restarts. I read all kinds of conflicting tips on this. Any advice?

Thank you for your reply, I have this setup in my Pi with Octopi and Octoprint, I will have to check up on the Nginx server I had seen there might be a conflict with the new ver of Octoprint and Nginx…..

Thank you for the tutorial, I have gotten everything to function properly except the Nginx server. I’m new to Nginx and not sure if I have set it up properly. I am able to start the server and get the Nginx welcome page when I visit the ip address, but I cant get to the ip address/nut I get a 404.

Here is my .conf for the server does any stick out as improperly written?

First thing, the nginx.conf and your website configs should be two separate files, not mixed into one file like here.

If you run sudo nginx -t, what happens?

Second, does /var/log/nginx/error.log show anything? What about /var/log/nginx/access.log?

Also, I would change server_name localhost; to server_name XX.XX.XX.XX; (where XX.XX.XX.XX is the IP of your RPi). Unless you’re visiting the webpage directly from the RPi, localhost won’t work anywhere on your network.

One more thing, are you using PHP5 or PHP7? This line is different for PHP7, Google it for the syntax.fastcgi_pass unix:/var/run/php5-fpm.sock;