I bought an “Eaton 3S” uninterruptible power supply (UPS) some time ago. It is supposed to support my servers with power in case of a power loss. I also wanted to get notified about those “power down” events, so I looked for an open-source software to monitor the UPS hardware. I found the “Network UPS Tools” (NUT). In this article, I describe some of the pitfalls I came across.
The UPS can be connected via USB cable (see Fig. 1) to the computer to be monitored by NUT. With the NUT-daemons installed and configured, you can handle UPS-events like “ON BATTERY” and “ONLINE”. This requires functioning detection of the UPS by the NUT-drivers. Unfortunately, I was unable to build a working setup on my “Alpine Linux” servers with the existing software packages, while an older “Debian” server had no problems at all. The NUT-drivers on my “Alpine Server” could not detect the UPS. This was the beginning of a series of some longer nights to fix the problem.
There are several software components (see Fig. 2) relevant for this article. The description below is based on information from the “NUT user manuals”.
UPS drivers provide a common interface between the physical UPS and the
upsd-server. The driver translates the native protocol of the UPS to a common format.
upsdconnects to each UPS driver to serve data from the drivers to the clients.
Requisites for readers
This article is written for people with a basic understanding in “Linux” operating systems and containers. Writing this article, I assume the reader does not have “Alpine Linux” (Alpine) running on her/his workstation. The instructions given here should work for most Linux distributions. In this article, I also assume you’ve got an Alpine diskless setup.
I added tags to clarify which commands have to be executed on which of your systems (see Fig. 3):
- Workstation: Your local desktop computer or laptop which you use to run the container.
- Server: The server where NUT will be set up.
To make this article easier to read, I do not prefix commands run as
sudo. Instead, I use the following syntax for the commands in this
article. But for your daily business, I definitively recommend using the
$ command: Running the command as a normal or admin user
# command: Running the command as
Reasons for my problems
mdev instead of
(e)udev by default to set up
mdev is unable to set up permissions correctly for NUT. Additionally, the NUT-package was missing some required package dependencies — see this
merge request for the required changes to the
nut-package. It was merged on 05/09/2021.
Install monitoring software
Server Connect the UPS to the server
Please connect your UPS via USB cable to your server.
Workstation Connect to your server via SSH from your local computer
Please start a new shell on your local system and run the following command.
$ ssh root@<IP address of your server>
Server Add repository
To make your UPS device work with Alpine, you need to set up
nut. First, you need to make the
edge/testing-repository available to your system.
Server Install packages
After that, you can install the required packages.
# apk update # apk add nut@edge-testing
Server Attach the UPS via USB cable to your computer
Server Verify setup
As of the time writing this article, this failed for no obvious reason.
# upsdrvctl start Network UPS Tools - UPS driver controller 20210212-471-g17c662d69e Network UPS Tools - Generic HID driver 0.41 (20210212-471-g17c662d69e) USB communication driver 0.33 No matching HID UPS found
Server Monitor the kernel ring buffer
You need to install and use
dmesgto get some more information.
# dmesg -w
Server Re-attach the UPS to your computer
Server Monitor the kernel ring buffer
Upon having the UPS connected to my computer, I saw the following logs. Everything looked fine. The device was detected by the kernel.
# dmesg -w 2021-07-07T06:25:44.679088+02:00 host-xy kernel: [ 4.420351] usb 1-1: New USB device found, idVendor=0463, idProduct= ffff, bcdDevice= 1.00 2021-07-07T06:25:44.679089+02:00 host-xy kernel: [ 4.420360] usb 1-1: New USB device strings: Mfr=1, Product=2, Seria lNumber=4 2021-07-07T06:25:44.679090+02:00 host-xy kernel: [ 4.420365] usb 1-1: Product: Eaton 3S 2021-07-07T06:25:44.679091+02:00 host-xy kernel: [ 4.420369] usb 1-1: Manufacturer: EATON 2021-07-07T06:25:44.679092+02:00 host-xy kernel: [ 4.420373] usb 1-1: SerialNumber: 000000000
Server Check the visibility of the device with
I was disappointed to see, that there’s no UPS-device when I ran
# lsusb Bus 001 Device 003: ID 0781:5583 SanDisk Corp. Ultra Fit Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
If you run
lsusb -t, it will print the whole USB device tree. With this parameter given,
lsusbprints out an entry for the UPS-device.
# lsusb -t : Bus 02.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/7p, 5000M : Bus 01.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/9p, 480M |__ Port 1: Dev 2, If 0, Class=Human Interface Device, Driver=usbhid, 1.5M |__ Port 4: Dev 3, If 0, Class=Mass Storage, Driver=usb-storage, 480M
Server Install the
Making USB devices available in Alpine requires some extra software. Without the required package, you won’t see your device with
# apk add hidapi
After installing the
hidapi-package, I could see the UPS in the output of
# lsusb Bus 001 Device 002: ID 0463:ffff MGE UPS Systems UPS
Please install all required packages. For Alpine, the
eudev-package provides a similar functionality as the normal
udev-package provided by
# apk add eudev udev-init-scripts-openrc
Next, disable the
mdev- and enable the
# rc-update rm mdev sysinit # rc-update add udev sysinit
# rc-service udev start
We need to fix the wrong file path for the
udev-rule file –
/lib/udev/rules.d-directory would the correct place for the new rules. Unfortunately, this directory is not part of the default
lbu-configuration of an Alpine diskless setup. Instead, move the file to
# mv /usr/lib/udev/rules.d/rules.d/* /etc/udev/rules.d/
Reload and apply
udev-rules before starting the NUT-drivers. Please add the following line, right after
MODE=xxx. This is just a hack to work around the missing integration of
initramfs. There’s a merge request to fix this permanently.
# /etc/nut/nut.conf # MODE=xxx udevadm control --reload-rules && udevadm trigger
Reload and apply
Reload and apply
udev-rules to check if the USB device nodes were correctly created. Check if the correct group for the device node is set. The group needs to be
# udevadm control --reload-rules && udevadm trigger
$ ls -al /dev/bus/usb/*/* crw-rw-r-- 1 root nut 189, 1 Jul 13 23:44 /dev/bus/usb/001/002
Server Start NUT-driver
Please start the NUT-driver again.
# upsdrvctl start Network UPS Tools - UPS driver controller 20210212-471-g17c662d69e Network UPS Tools - Generic HID driver 0.41 (20210212-471-g17c662d69e) USB communication driver 0.33 Using subdriver: MGE HID 1.39
Server Add services to default runlevel
To make the services start on each but, activate the following NUT-services.
# rc-update add nut-upsd # rc-update add nut-upsmon
Server Commit changes with
This step is required for diskless setups – otherwise all configuration files are lost with the next reboot.
# lbu commit
# rc-service nut-upsd start
In the logfile
/var/log/messagesyou should see something similar to the following output.
2021-07-14T00:20:07.997234+02:00 host1 usbhid-ups: Startup successful 2021-07-14T00:20:08.004792+02:00 host1 upsd: listening on 127.0.0.1 port 3493 2021-07-14T00:20:08.005220+02:00 host1 upsd: Connected to UPS [myups]: usbhid-ups-myups 2021-07-14T00:20:08.007036+02:00 host1 upsd: allowfrom in upsd.users is no longer used 2021-07-14T00:20:08.007441+02:00 host1 upsd: Startup successful 2021-07-14T00:20:08.084491+02:00 host1 upsmon: Startup successful 2021-07-14T00:20:08.085015+02:00 host1 upsmon: Init SSL without certificate database
Find some more documentation
Some more information can be found in the libusb FAQs and in the hidapi README.
Now I have got a UPS device, which can be monitored with NUT.