Install + Configure NUT & NET-SNMP
Install and Configure NUT
If you're not using the same UPS, check the NUT hardware compatibility list to see if your equipment is supported by the drivers included with NUT. First, run the command below to install NUT
sudo apt install nut
Next, let's configure NUT:
$ sudo vi /etc/ups/ups.conf
Append these lines:
[name_of_your_ups]
driver = usbhid-ups
port = auto
desc = "Description of your UPS"
Change [name_of_your_ups] to any name you'd like. This value becomes the query name for polling the device.
Let's restart the UPS driver:
sudo systemctl reload nut-driver.service
If you receive any error ensure you have sudo privileges—and try restarting the machine if the problem persists. We will also set NUT's mode to standalone.
sudo vi /etc/ups/nut.conf
MODE=standalone
From their documentation:
- standalone: This mode address a local only configuration, with 1 UPS protecting the local system. This implies to start the 3 NUT layer (driver, upsd and upsmon) and the matching configuration files. This mode can also address UPS redundancy.
Configure NUT server and monitor
Once the driver is up and running, we need to set up the user for accessing the NUT daemon. Append the following under upsd.users.
sudo vi /etc/ups/upsd.users
[upsmon]
password = <secretpass>
upsmon master
Change to a secure password of your choosing.
Lastly, we'll edit the NUT monitor configuration with the name of our device, and the access information for the newly created user. Append the following under upsmon.conf
sudo vi /etc/ups/upsmon.conf
MONITOR cyberpower@localhost 1 local_mon <secretpass> master
Of course, change cyberpower to the name you gave your device, and to the password you specified in /etc/ups/upsd.users Enable services
To ensure monitoring ability after planned and unplanned reboots, we need to enable and start the NUT system services.
sudo systemctl enable nut-monitor.service
sudo systemctl enable nut-server.service
sudo systemctl start nut-server.service
sudo systemctl start nut-monitor.service
If you encounter any errors starting the services, restarting may resolve these. Often, running upsdrvctl start as we did earlier hijacks USB communication with the UPS and causes an error when trying to start NUT services. Test UPS querying!
Run (replacing cyberpower with your device name):
upsc name_of_your_ups
And, if all configurations are happy you will see some data returned:
battery.charge: 100
battery.charge.low: 10
battery.charge.warning: 20
battery.mfr.date: CPS
battery.runtime: 2790
battery.runtime.low: 300
battery.type: PbAcid
battery.voltage: 16.0
battery.voltage.nominal: 24
device.mfr: CPS
device.model: CP850PFCLCD
device.serial: 000000000000
device.type: ups
driver.name: usbhid-ups
driver.parameter.pollfreq: 30
driver.parameter.pollinterval: 2
driver.parameter.port: auto
driver.version: 2.7.2
driver.version.data: CyberPower HID 0.3
driver.version.internal: 0.38
input.transfer.high: 139
input.transfer.low: 88
...
Install Net-SNMP
sudo yum install net-snmp
Create the script for MIB formatting of the query data: Note: this script formats MIBs specifically for LibreNMS.
sudo vi /etc/snmp/ups-nut.sh
Past the following, making sure to change UPS_NAME to your device name:
#!/usr/bin/env bash
UPS_NAME='cyberpower'
PATH=$PATH:/usr/bin:/bin
TMP=$(upsc $UPS_NAME 2>/dev/null)
for value in "battery\.charge: [0-9.]+" "battery\.(runtime\.)?low: [0-9]+" "battery\.runtime: [0-9]+" "battery\.voltage: [0-9.]+" "battery\.voltage\.nominal: [0-9]+" "input\.voltage\.nominal: [0-9.]+" "input\.voltage: [0-9.]+" "ups\.load: [0-9.]+"
do
OUT=$(echo $TMP | grep -Eo "$value" | awk '{print $2}' | LANG=C sort | head -n 1)
if [ -n "$OUT" ]; then
echo $OUT
else
echo "Unknown"
fi
done
Make the script executable:
sudo chmod +x /etc/snmp/ups-nut.sh
Now let's extend this script to the SNMP daemon:
sudo vi /etc/snmp/snmpd.conf
Append the following and change to your community name:
rocommunity <community>
extend ups-nut /etc/snmp/ups-nut.sh
Let's enable and start the SNMP daemon:
sudo systemctl enable snmpd
sudo systemctl start snmpd
And finally, make a test query from a another host that can reach the server:
$ snmpwalk -v2c -c <community> <host> 'NET-SNMP-EXTEND-MIB::nsExtendOutLine'
You should see results similar to this:
NET-SNMP-EXTEND-MIB::nsExtendOutLine."ups-nut".1 = STRING: 100
NET-SNMP-EXTEND-MIB::nsExtendOutLine."ups-nut".2 = STRING: 300
NET-SNMP-EXTEND-MIB::nsExtendOutLine."ups-nut".3 = STRING: 2790
NET-SNMP-EXTEND-MIB::nsExtendOutLine."ups-nut".4 = STRING: 16.0
NET-SNMP-EXTEND-MIB::nsExtendOutLine."ups-nut".5 = STRING: 24
NET-SNMP-EXTEND-MIB::nsExtendOutLine."ups-nut".6 = STRING: 120
NET-SNMP-EXTEND-MIB::nsExtendOutLine."ups-nut".7 = STRING: 125.0
NET-SNMP-EXTEND-MIB::nsExtendOutLine."ups-nut".8 = STRING: 14
Your host can now receive an SNMP query, poll your device with NUT, and respond with MIBs formatted for display/graphing on LibreNMS, Observium, or other SNMP-based monitoring platforms.
You could also skip SNMP entirely and use a bash or python script to automate the retrieval of the UPS values via the upsc command.
I hope this helps anyone looking to quantify and monitor the health of their UPS from afar.