This is an old revision of the document!
Monitoring an APC UPS via the apcupsd daemon. This plugin will connect to the apcupsd daemon and collect the battery state, AC power state, load percentage, time left and other important data even if the UPS in question isn’t physically connected to your Mac. If you wish to talk to a physically connected UPS please have a look at the original UPS: Uninterruptible Power Supply Plugin plugin. You probably don’t actually want to have a UPS physically plugged into your Mac server anyway believe it or not, see below, but it can be very useful to be able to monitor the UPS anyway. You may have other computers, DVRs, WiFi access points, or other home automation nodes that are on separate UPS’s and it can be very helpful to be able to monitor those and know their approximate runtime and battery health as well. Installing this plugin and apcupsd on a raspberry pi can give you all that.
There is a rather severe problem with connecting a UPS directly to a Mac OS Server. (not MacOSX Server, but any Mac acting as a server) You might wonder why you wouldn’t want to just connect the UPS to the computer? It will shut it down properly then and all will be well. Except that if you have the energy saver preferences set up to properly shut down your computer then it will not restart when the power comes back. There is a setting for most Macs to “restart after a power failure” but this only works if you let the power actually be pulled and NOT do a proper shutdown. The bug in MacOS is that this doesn’t work if you have a UPS connected to the machine! This has been broken for several major OS versions now. If you are running a Mac server and wish to use a UPS then you don’t actually want the UPS connected to the Mac or it will not restart without you there to push the button.
By loading up a Raspberry Pi and installing the apcupsd you can monitor any number of UPS’s without having to have them physically connected to another full sized computer. This is one of my remote nodes and an older Pi, even the oldest Pi’s will work fine for this as no speedy processors are needed. A Pi Zero W is an excellent choice but does require a USB adaptor or a specialty USB cable to get it connected to the UPS since it only has a micro usb port on it. I used these and then a regular usb cable connected to it.
Both the full sized and Pi Zero W’s work great and can be powered from the USB port that is available on most APC devices now. Though the port says it’s limited to 1.5amps it had no trouble running the full sized pi’s for me. I don’t know if they are in some low power mode because the voltage is dropping on them but they appear to be working fine. Powering the Pi Zero’s that way is even less to worry about as they use a fraction of the power. You won’t want to use the Pi Zero without the “w” as it will have no internet connectivity without an adaptor and you already need the usb data port for the UPS connection. You could use a USB hub, but after that you start to lose the benefits of the smaller package with all the wires and external power supplies and such.
I would also recommend putting the Pi in a case just so that it doesn’t short out against anything while rattling around.
You will actually need 2 USB cables, one for the power and one to connect to the USB data port on the APCUPS. You won’t get any data from the charging port nor will you get any power from the data port.
You can setup and configure your Pi in the standard manner. As of this writing I was using Raspian Stretch June 2018 but for a Pi Zero W or running a regular Pi with a much smaller CF card “Stretch Lite” should also be fine.
If you are able to connect the Pi to a monitor and keyboard then the initial configuration is much easier than doing the setup on a blond card. I was not able to get that working with the Pi Zero W as I could not get it to accept it’s wifi parameters that way. YMMV but you’ll need a special HDMI cable to connect the Zero to a monitor and a powered hub to connect both a keyboard and mouse. Most navigation can be done with just a keyboard so I just connected it directly and switched to the mouse when needed which wasn’t much.
You’ll want to enable SSH and VNC just in case you need that. Give your pi a more descriptive host name as well as you can’t have them all showing up on the network as just “raspberry.local”
If you’re connecting over WiFi make sure to properly set the Region when the setup app asks you for that. My Pi’s defaulted to the UK and they have different ranges for WiFi channels. If set to that then some US WiFi channels will not be available to it so it may not be able to connect. Or it may connect fine today but 5 years from now when your WiFi router changes channels automatically to a less crowded area it will just drop off for no apparent reason.
Once you’ve done all this you can be done with the GUI interface. You can also use the raspi-config app or the settings in the GUI to set the pi to boot into a command line instead of the graphic interface. This will save you some memory and CPU cycles as you’re not going to be using that for the most part. You can now ssh from your Mac into the Pi to complete the config. You’ll use the hostname you set above with a command similar to “ssh firstname.lastname@example.org“
This is important so that XTension can connect to the apcupsd program. Yes, you just connected to your Pi via SSH and the hostname but that doesn’t appear to work for other connections. It seems that it only advertises an IPv6 address for the .local hostname and we cannot connect to the apcupsd via IPv6. If someone knows how to configure it to also register it’s IPv4 address then please let me know as that would make the static IP unnecessary.
You can do this in a couple of different ways. You can setup a DHCP reservation in your internet sharing hub, but I never trust those to remember things long term. The best way is to edit the configuration files manually. Since there is now an option to use “predictable” interface names and you must also verify your networks subnet anyway run this command:
ip -4 addr show
this will give you some output like this on the Pi Zero:
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 2: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 inet 192.168.0.90/24 brd 192.168.0.255 scope global wlan0 valid_lft forever preferred_lft forever
and probably something like this on a regular pi. The newer Pi B+ will have at least one wlan and the ethernet options and you’ll want to select whichever your actually using in the next step.
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 inet 192.168.0.90/24 brd 192.168.0.255 scope global eth0 valid_lft forever preferred_lft forever
What you’re looking for here is the name of the hardware interface and the portion after the slash of it’s current ip. So in the first example above the name of the hardware interface is “wlan0” and the subnet portion is “/24” In the second case it’s “eth0” and also “/24” if you are using the 10.0.0.xxx NAT range or have something custom setup for your router then the /24 portion may be different. You have to get that set properly in the next step or it won’t work. Your hardware names may also be something more verbose like et5464754 or something like that. Those are the “predictable” host names which are not turned on by default in the current distribution but may be in the future. Thats the connection type and the MAC address of the hardware. That way if you have multiple interfaces, which the newer pi’s do, you can tell exactly which eth0 and eth1 are without doing a lot of other work.
Now go to edit the dhcp configuration file via:
sudo nano /etc/dhcpcd.conf
If you get an empt file you typed the name wrong. Items you’ll want to change in this file are the “hostname” line, make sure this is set to what you want to call the device on the network. Scroll down till you find the “#Example static IP configuration” There are 5 lines all commented out with a hash at the beginning, uncomment all of them by removing that hash exceptthe “#static ip6_address…” line. If you wish to set a static IPv6 address you certainly may, but that is beyond the scope of these instructions and not needed for this purpose.
for the “static ip_address=“ line enter the address followed by the “/24” or other number that you discovered in the above step. You can probably leave the router and domain_name_servers lines as they are in the default unless you are using a different NAT address range, if so then conform them to the same values as in the same fields in your mac’s network setup panel. My file on a PI Zero W looks like this:
interface wlan0 static ip_address=192.168.0.91/24 static routers=192.168.0.1 status domain_name_server=192.168.0.1 188.8.131.52 fd51:42f8:caae:d92e::1
and the important portion on my ethernet connected pi looks like:
# Example static IP configuration: interface eth0 static ip_address=192.168.0.72/24 #static ip6_address=fd51:42f8:caae:d92e::ff/64 static routers=192.168.0.1 static domain_name_servers=192.168.0.1 184.108.40.206 fd51:42f8:caae:d92e::1
notice that the line for the static ip6 address is not uncommented, there is no need to force a static IPv6 address leave that line commented out.
reboot the pi via “sudo reboot” and then reconnect via ssh when it comes back up with it’s new static IP address.
To install apcupsd run the command:
sudo apt-get install apcupsd
to make sure that it is running at startup edit /etc/default/apcupsd via:
sudo nano /etc/default/apcupsd
and change the single line from “isconfigured=no” to “isconfigured=yet” and save the file.
There are several lines in the configuration file that need to be changed. Most of the options in the file are only needed if you’re trying to use it with older serially connected UPS models. Thats much more complicated because in the past APC purposefully changed pin outs and other requirements to connect so that they could sell you a custom cable. The setup is very model dependent and beyond the scope of this document. If at all possible use a USB connected APC ups. Here’s an excuse to buy a new one.
Change the following lines as described. If the lines are commented out with a hash at the beginning remove that before changing the value to make it live. Note that many of the sections in the configuration file begin with the same command as you must edit, The parameter after it will be named inside of <>’s for example: # UPSNAME <name> that is not the line you wish to edit, scroll past that and the description of the setting in the file to find the real line you must edit at the bottom of each section.
Edit the file via:
sudo nano /etc/apcupsd/apcupsd.conf
uncomment if necessary and edit the following lines:
UPSNAME (give it a short meaningful name, like main or myups or office or attic or something) UPSCABLE usb UPSTYPE usb DEVICE (this is the link to the serial port if it’s a serial device, for the USB version this line must be blank. It is not blank in the default settings and will not work for a USB device unless present, uncommented and blank) POLLTIME 30 (this defaults to 60, I set mine to 30 don’t really know what the effect is as the data seems to change much faster than that anyway) NETSERVER on (this is important it’s how XTension will connect to it) NISIP 0.0.0.0 (this defaults to the 127.0.0.1 address meaning that it will only accept connections from the local host. If you want to be able to connect to it from XTension you must set it to 0.0.0.0) NISPORT 3551 (this is the default, don’t change it, If you have to change it you can enter the port in XTension’s setup for this interface)
Save the file, reboot the Pi and you should be connected to the UPS. After rebooting ssh back into the Pi and issue the command:
and you should get some output like this:
APC : 001,036,0855 DATE : 2018-10-02 06:32:41 -0400 HOSTNAME : upsoffice VERSION : 3.14.14 (31 May 2016) debian UPSNAME : office CABLE : USB Cable DRIVER : USB UPS Driver UPSMODE : Stand Alone STARTTIME: 2018-09-30 14:16:17 -0400 MODEL : Back-UPS NS 675M1 STATUS : ONLINE LINEV : 122.0 Volts LOADPCT : 38.0 Percent BCHARGE : 100.0 Percent TIMELEFT : 5.7 Minutes MBATTCHG : 5 Percent MINTIMEL : 3 Minutes MAXTIME : 0 Seconds SENSE : Medium LOTRANS : 92.0 Volts HITRANS : 139.0 Volts ALARMDEL : No alarm BATTV : 13.6 Volts LASTXFER : Low line voltage NUMXFERS : 0 TONBATT : 0 Seconds CUMONBATT: 0 Seconds XOFFBATT : N/A SELFTEST : NO STATFLAG : 0x05000008 SERIALNO : 4B1616P24555 BATTDATE : 2016-04-22 NOMINV : 120 Volts NOMBATTV : 12.0 Volts NOMPOWER : 360 Watts FIRMWARE : 930.a5 .D USB FW:a5 END APC : 2018-10-02 06:32:43 -0400
If you see that “STATUS:ONLINE” message then your pi is setup properly and your UPS is communicating.
The purpose of installing this script is to keep the apc software from doing a normal shutdown of the pi and also to broadcast power fail and other events to XTension when they happen without waiting for the next poll of apcaccess. If you allow the apc software to operate normally it will shutdown the pi and kill the power from the UPS before the batteries are fully used up. Adding these scripts keeps that from happening in addition to sending powerfail, battery replacement and other events to XTension immediately.
To install these you will download a python script from this site, change it’s properties so that it is executable and run it with the install switch like this:
cd /etc/apcupsd sudo curl -o ./xtevent.py http://machomeautomation.com/files/apc/xtevent # at this point you may view the script so that you understand what it is doing if you wish sudo chmod a+x ./xtevent.py # and finally run the install sudo ./xtevent.py install
The install moves any default scripts to *.orig and creates several sym links to the xtevent.py script so that it will be invoked for every known UPS event. After doing this your raspberry pi install is completely and you can setup the interface in XTension to talk to it and watch for events.
Create a new interface in XTension and select “APC UPS Status” from the Device popup. Enter the static IP address you just gave to your Pi above and then the port. If you didn’t change it in the configuration file then it’s running on port 3551. Give the interface a descriptive name so that you can tell all your UPS’s apart.
Set the polling times. You can set separate polling times for when the power is on and then the power is off. I don’t need to see every single change in load when things are working fine and so the default for AC On Polling time is 30 seconds. Once the power goes off though I want to see updates to the battery charge and time left more often so the default for polling times when the power is off is every 10 seconds. When the interface is running you can manually poll it for new information with the Poll Now button.
The Event Broadcast Port is set by the xtevent.py script you installed above. Immediate events are sent to XTension via a UDP broadcast on this port. If you change this port in XTension then you must edit the xtevent.py script on your raspberry pi to match or you won’t receive any realtime events.
Click the save button, find the new interface in the Interface Status window and check it’s enabled checkbox to start it up.
Once the interface is enabled and running you will be presented with a list of units created automatically by the interface. They will be given a default name that is based on the name you gave the interface and then the function.
AC Power: shows online and is in an on state as long as the AC power is available. This is updated by the realtime user scripts we installed on the pi and also from polling. This way you can catch very short power failures that would not have been caught due to the normal intermittent polling. Note that in order to receive these real time events XTension and your UPS monitor Pi must be on the same subnet. You may wish to change the default colors for this unit so that it displays green when the power is on and red when the power is off as it’s the off state that is the warning state.
Error: sometimes the software will append an error message to the status line. I have seen “LOWBATT” when my ups battery wasn’t going to be able to service the high load. This unit will display either “none” or the message sent. It will be off as long as there is no error and will turn on to alert you that the UPS has sent some error message. Use the On script to notify yourself of an error message from the UPS. Note that this is not the same as a failed battery self test, that message handled separately see the “Self Test Failure” unit below.
Line Voltage: the voltage of the incoming AC power. Will read 0 during a power failure.
Load Percent: how much of the capacity of your UPS are you currently using.
Load Watts: calculated value based on the load percent multiplied by the max load reported by the UPS. This value is approximate.
Battery Charge: The percent of useful charge in the battery pack. Will read 100% when everything is plugged in and normal. You can watch it reduce to 0% while on battery power and return to 100% when recharging afterwards.
Time Left: an estimate of the time the UPS can service the current load.
Battery Voltage: The voltage of the battery pack. For regular SLA batteries that are the standard for these systems it will usually read a couple of volts above the 12v or 24v battery pack voltage. This is normal and is how you properly float charge that kind of battery. This voltage will drop when on battery power and will return to the normal value while recharging.
Self Test Failure: If no self test has been run since the program connected then this unit will be in an off state and show “none”. Once a test has been run while it’s watching the unit label will change to “OK” unless there is a problem. If a self test failure of the battery or the load or whatever happens the label will change to the error message and the unit will turn on. Use the on script to notify yourself of a failed self test.
On Battery: When the power has been out long enough for the UPS to be sure it isn’t a self test this unit will turn on. This is usually 5 or 6 seconds after a power failure. This will not turn on for power failure events shorter than that duration. This could be useful as you might turn off loads that are plugged into the UPS that are not necessary in a long term power failure condition to reduce the load and increase the runtime.
Charging: Once power has returned and the UPS has switched off the On Battery unit this unit will turn on until the batteries are fully charged.
If your device supports these additional readings then units to create them will be setup as well. Most simpler units do not support these.
Output Voltage: The voltage actually being supplied by the UPS to your equipment.
Internal Temperature: The Internal or battery temperature of the device.
Ambient Temperature: The external temperature of the room.
Humidity: The humidity of the room.
If you have installed the user scripts above then you can trap all broadcast events from the UPS inside the Interface Script. In the Edit Interface window click the “Edit” button for the interface script. Then use the “Insert…” toolbar button to insert the “UPS Event Handler” The AppleScript code that is inserted will give you a full list of the known events though depending on your model there may be others that could be sent as well.
Some of the events are also reflected as Unit changes such as the power fail and error messages. Others can only be caught by installing this handler.
(* U P S E V E N T H A N D L E R Called when the UPS sends a broadcast event. This is where you can trap events other than those that have units associated with them. In order to receive these you must have installed the xtevent script on the raspberry pi. EventName will be one of the following: annoyme If we were letting the UPS shutdown our machine this is the alert that it is about to happen. The events scripts stop the shutdown from happening however. changeme The battery needs changing. If we were allowing system shutdown that would happen next. This event also turns on the ERROR unit. commfailure The UPS is no longer responding, possibly unplugged the USB cable? This event also turns on the ERROR unit. commok Only sent after a commfailure event, the UPS is now responding. doshutdown When the config time limits or battery levels have dropped to the point that if it were automatically going to shutdown it would now be doing so. emergency While in the software, nobody knows what would generate an emergency shutdown. failing The batteries are exhausted. The next event will be doshutdown. loadlimit The battery charge is below the low limit set in the config file. The next event will be doshutdown powerout This is sent immediately when the power fails. It can also be generated during a self test of the UPS. onbattery Send 5 or 6 seconds after the powerout event if the power has not returned. This could be used to filter self test events. The timing of this can be set in the config file. offbattery Send when power returns but only if the power has been off long enough to generate the onbattery event. mainsback The power has returned runlimit The Time Left property of the battery has fallen below the configured value. timeout The maximum time on battery value in the configuration has expired. startselftest A self test has been detected. This may not be reliable depending on the onbattery timing endselftest The end of a self test has been detected. battdetatch The batteries have been disconnected battattach The batteries are reconnected *) on UPSEvent( EventName) write log "UPS Event Received: " & EventName end UPSEvent