NUT UPS monitor on OpenBSD


NUT is the "Network UPS Tools" one can use to monitor an uninterpretable power supply. In this exercise we will use NUT to monitor an APC ups unit on OpenBSD through the USB port.

Install NUT

The first task is to install NUT and the supporting USB libraries. Both are available from OpenBSB packages. When you install nut the supporting library package , libusb may be installed automatically.

pkg_add -i nut-2.2.1p0
pkg_add -i libusb-0.1.12

Config files are in /etc/nut/

Notice that all of the config files and support script for NUT will be in /etc/nut/ . We will continue with this pattern for this example NUT setup.

Verify the USB ports are enabled in your BIOS

Reboot your box and make sure that the usb ports are enabled. You can enable them all or just a few. Each BIOS is slightly different so you will need to check the motherboard manual if you have questions. We choose to enable 2 of the 8 usb ports on our box. The manual told us which USB ports were considered number 1 and 2.

Connect the UPS to the USB port on the computer

Connect the UPS to the computer with the vendor supplied USB cable. Check /var/log/massages to make sure the computer sees that a new device has been attached. For example, this is the output when our OpenBSD box saw our APC 1300.

Jan 10 10:11:12 calomel /bsd: ugen0 at uhub1
Jan 10 10:11:12 calomel /bsd:  port 1 "American Power Conversion Back-UPS XS 1300 LCD FW:888.88 .D USB FW:88" rev 1.88/1.89 addr 2

Verify the OpenBSD box can see the UPS through the USB port

Use usbdevs -vd to list out all USB devices you box can see. You should see your UPS unit listed.

root@calomel: usbdevs -vd
addr 1: EHCI root hub, VIA
addr 1: UHCI root hub, VIA
 addr 2: Back-UPS XS 1300 LCD FW:888.88 .D USB FW:88, American Power Conversion

Notice that our UPS is using the device "ugen0". The first device listed on OpenBSD is /dev/ugen0.00 and that is what out UPS unit will be using.

Allow the USB device to be read/write by the _ups user

Make sure that the user "_ups" that was added by the package "NUT" can read and write to the device /dev/ugen0.00 .

First, add the NUT group, "_nut" to the deamon group.

root@calomel: cat /etc/group | grep nut

Second, change the permissions on the usb device so the daemon group, which now includes the _nut group, can write to the device.

root@calomel: ls -al /dev/ugen0.00
crw-rw----  1 root  wheel   63,   0 Jan  10 10:11 /dev/ugen0.00
root@calomel: chown root:daemon /dev/ugen0.00
root@calomel: ls -al /dev/ugen0.00
crw-rw----  1 root  daemon  63,   0 Jan  10 10:11 /dev/ugen0.00

Create the "/etc/nut/ups.conf" config file

The ups.conf is the device driver config file. It specifies what usb device to use (/dev/ugen0.00) and what usb driver. We are using the driver "usbhid-ups" because our ups, the Back-UPS XS 1300 LCD, is fully supported.

###   ups.conf
user = _ups
  driver = usbhid-ups
  port = /dev/ugen0.00
  desc = "Back-UPS XS 1300 LCD_USB"

Start the NUT USB driver

Now that the config file is in place lets start the ups driver "usbhid-ups". You should see output like the following. If you see an error like the driver can not find the device then make sure you changed the permissions on the usb device "/dev/ugen0.00".

root@calomel: /usr/local/bin/upsdrvctl start
Network UPS Tools - UPS driver controller
Starting UPS: apc
exec: /usr/local/bin/usbhid-ups -a apc
Network UPS Tools: 0.29 USB communication driver - core 0.32 ()

Using subdriver: APC HID 0.92

Create the "/etc/nut/upsd.conf" config file

The upsd.conf file is for the upsd daemon that will poll the USB communication driver (upsdrvctl). The upsd daemon will also allow the upsmon program to monitor the data output from the ups. Notice that we have setup an access control list to only allow localhost ( to access the daemon. We will also be listening on localhost port 3493.

##  upsd.conf
ACL all
ACL localhost
ACCEPT localhost

Create the "/etc/nut/upsd.user" config file

The upsd.users file specifies which users and passwords are allowed to access the upsd daemon. The admin account is for modifying setting on the ups and the monuser is used for polling the ups data.

##  upsd.users
        password = passwd1
        allowfrom = localhost
        actions = SET
        instcmds = ALL

        password = passwd2
        allowfrom = localhost
        upsmon master

Start the UPSD daemon

Now that the upsd.conf and upsd.users files are in place we can start the upsd daemon.

root@calomel: /usr/local/sbin/upsd
Network UPS Tools upsd
listening on port 3493
Connected to UPS [apc]: usbhid-ups-apc

Verify the OpenBSD box can read the UPS data

With the usb driver (usbhid-ups) and upsd daemon started you can verify client access to the apc unit. Simple use the command upsc apc@localhost to poll the upsd daemon. This is an example from our APC unit.

root@calomel: upsc apc@localhost
battery.charge: 100
battery.charge.low: 10
battery.charge.warning: 50 2008/01/01 2008/08/20
battery.runtime: 1564
battery.runtime.low: 120
battery.type: PbAc
battery.voltage: 26.9
battery.voltage.nominal: 24.0 usbhid-ups
driver.parameter.pollfreq: 30
driver.parameter.pollinterval: 2
driver.parameter.port: /dev/ugen0.00
driver.version: APC HID 0.92
driver.version.internal: 0.32
input.transfer.high: 139
input.transfer.low: 88
input.voltage: 121.0
input.voltage.nominal: 120
ups.beeper.status: enabled
ups.delay.shutdown: -1
ups.firmware: 836.H5 .D
ups.firmware.aux: H5
ups.load: 23
ups.mfr: American Power Conversion 2008/08/20
ups.model: Back-UPS XS 1300 LCD
ups.productid: 0002
ups.serial: 8B0123R01234
ups.status: OL
ups.test.result: No test initiated
ups.vendorid: 012e

Create the "/etc/nut/upsmon.conf" config file

The upsmon.conf file will allow us to monitor the output of upsd without manually executing upsc. This config is setup to monitor the upsd daemon and if this is problem it will log the error to syslog and execute the script "/etc/nut/" which will send email with the same error.

##  upsmon.conf
MONITOR apc@localhost 1 monuser passwd2 master
NOTIFYCMD /etc/nut/
POWERDOWNFLAG /etc/nut/killpower
SHUTDOWNCMD "/sbin/shutdown -p -h +0"

## Notify message format
NOTIFYMSG ONLINE   "UPS %s on line power"
NOTIFYMSG ONBATT   "UPS %s on battery"
NOTIFYMSG LOWBATT  "UPS %s battery is low"
NOTIFYMSG FSD      "UPS %s: forced shutdown in progress"
NOTIFYMSG COMMOK   "Communications with UPS %s established"
NOTIFYMSG COMMBAD  "Communications with UPS %s lost"
NOTIFYMSG SHUTDOWN "Auto logout and shutdown proceeding"
NOTIFYMSG REPLBATT "UPS %s battery needs to be replaced"
NOTIFYMSG NOCOMM   "UPS %s is unavailable"
NOTIFYMSG NOPARENT "upsmon parent process died - shutdown impossible"

## Notify conditions

Create the script "/etc/nut/" used by the "upsmon.conf"

The /etc/nut/ simple takes the argument sent by the upsmon daemon and sends an email to root. The argument upsmon sends is the error message.

echo $1 | mail -s "NUT $1" root

Start the "upsmon" daemon


Allow NUT to start on reboot

Add the following to you /etc/rc.conf . It will start all three daemons on the next reboot.

# Start NUT
if [ -x /usr/local/bin/upsdrvctl ]; then
    echo -n ' nut'
    /usr/local/bin/upsdrvctl start > /dev/null 2>&1
    /usr/local/sbin/upsd > /dev/null 2>&1
    /usr/local/sbin/upsmon > /dev/null 2>&1

All done - Finished

Congratulations! All three NUT daemons are started and you now receive notifications if any events are triggered on the UPS unit. The status messages will be sent to the system in /var/log/messages and an email will be sent to root. You can verify the status of the daemons using "ps -aux | grep ups".

root@calomel: ps -aux | grep ups
_ups     12345  Ss  12:00AM  0:00.71 /usr/local/bin/usbhid-ups -a apc
_ups     67890  Ss  12:00AM  0:00.09 /usr/local/sbin/upsd
_ups      2345  S   12:00AM  0:00.06 /usr/local/sbin/upsmon
root     23456  Is  12:00AM  0:00.00 /usr/local/sbin/upsmon

Questions ?

Why are there two copies of upsmon running?

It's not really two complete copies if your OS forks efficiently. By default, upsmon runs the majority of the work as an unprivileged user and keeps a stub process around with root powers that can only shut down the system when necessary. This should make it much harder to gain root in the event a hole is ever discovered in upsmon.

If this really bothers you and you like running lots of code as root, start upsmon with -p and it will go back to being one big process. This is not recommended, so don't blame me if something bad happens in this mode.

The ups driver works as root, but not when run as _nut. Why?

This is most likely a permissions problem denying a user to the usb device. Try using systrace. Tedb of suggested the following line which is handy in tracking down permission problems once you confirmed the Nut driver works running as root.

systrace -A -d /tmp/st usbhid-ups -a UPS	

Questions, comments, or suggestions? Contact