In this document, I will explain how to setup nut
(Network UPS Tools) on Ubuntu 18.04 and 20.04.
It is basically the next chapter of my previous gist, Upgrade nut on Ubuntu 18.04.
I'll only document USB
connected UPS and not the other supported connection modes.
sudo apt install nut -y
# bash <(curl -Ss https://my-netdata.io/kickstart.sh) all --dont-wait --disable-telemetry
wget -O /tmp/netdata-kickstart.sh https://my-netdata.io/kickstart.sh && sh /tmp/netdata-kickstart.sh --no-updates --stable-channel --disable-telemetry
I'd seriously recommend you to take the time to explore this book written by Roger Price that contains tons of useful information about how to implement and configure nut.
Here is how you can detect your connected UPS. I'll mainly focus on the USB
connection and not the other connection modes.
# Scan all available devices (default)
$ nut-scanner
# Scan USB devices only
$ nut-scanner -U
# Scan USB devices only but print in ups.conf format
$ nut-scanner -UN
Use the following commands to add the details about the connected UPS in the /etc/nut/ups.conf
file:
# Add some spacing and UPS details
echo -e "\n# Detected UPS from USB" | sudo tee -a /etc/nut/ups.conf
# Add detected UPS details
nut-scanner -UNq 2>/dev/null | sudo tee -a /etc/nut/ups.conf
# Check the result
sudo cat /etc/nut/ups.conf
You should get something similar:
# Detected UPS from USB
[nutdev1]
driver = "usbhid-ups"
port = "auto"
vendorid = "0764"
productid = "0501"
bus = "001"
You can now change [nutdev1]
by something more representative to your UPS and also add the desc
field. You'll need sudo
to edit the config files.
# Edit the config file
sudo nano /etc/nut/ups.conf
Then change the previously generated config that way:
# Detected UPS from USB
[CP1500PFCLCD]
driver = "usbhid-ups"
port = "auto"
vendorid = "0764"
productid = "0501"
product = "CP1500PFCLCD"
serial = "000000000000"
vendor = "CPS"
desc = "CyberPower PFC Sinewave 1500 PFCLCD"
bus = "001"
Once the UPS defined in the /etc/nut/ups.conf
file, we must define the monitoring user that will used to read the data from the UPS and define the actions according to them.
The created user is not related to the standard UNIX users, it will only exist in the nut
context.
Here is how to create it:
# Install password generator
sudo apt install pwgen -y
# Generate strong password (but avoid using special chars)
export NUT_RAND_PW=$(pwgen -snc -B 128 | awk '{ print $1 }')
# Create monitoring user dynamicaly
echo -e "\n[monitor]\n\tpassword = ${NUT_RAND_PW}\n\tupsmon master\n" | sudo tee -a /etc/nut/upsd.users
# Generate connection string
# You will have to copy it in the 'upsmon.conf' file later
echo -e "\nMONITOR CP1500PFCLCD@localhost 1 monitor $NUT_RAND_PW master\n"
# Remove generated password from environment
unset NUT_RAND_PW
You should get something similar:
$ export NUT_RAND_PW=$(pwgen -snc -B 128 | awk '{ print $1 }')
$ echo -e "\n[monitor]\n\tpassword = ${NUT_RAND_PW}\n\tupsmon master\n" | sudo tee -a /etc/nut/upsd.users
[monitor]
password = [REDACTED]
upsmon master
$ echo -e "\nMONITOR CP1500PFCLCD@localhost 1 monitor $NUT_RAND_PW master\n"
MONITOR CP1500PFCLCD@localhost 1 monitor [REDACTED] master
$ unset NUT_RAND_PW
Now we have to add the generated connection string into the /etc/nut/upsmon.conf
file:
sudo nano /etc/nut/upsmon.conf
after the examples of the MONITOR section:
# Examples:
#
# MONITOR myups@bigserver 1 monmaster blah master
# MONITOR [email protected] 1 upsmon secretpass slave
# MONITOR myups@localhost 1 upsmon pass master (or slave)
MONITOR CP1500PFCLCD@localhost 1 monitor [REDACTED] master
# --------------------------------------------------------------------------
By default the /bin/upssched-cmd
script is pretty basic and does not contains enough commands:
#! /bin/sh
#
# This script should be called by upssched via the CMDSCRIPT directive.
#
# Here is a quick example to show how to handle a bunch of possible
# timer names with the help of the case structure.
#
# This script may be replaced with another program without harm.
#
# The first argument passed to your CMDSCRIPT is the name of the timer
# from your AT lines.
case $1 in
upsgone)
logger -t upssched-cmd "The UPS has been gone for awhile"
;;
*)
logger -t upssched-cmd "Unrecognized command: $1"
;;
esac
Now, create a copy of the original script:
# Create a copy
sudo cp -v /bin/upssched-cmd /bin/upssched-cmd.bak
# Edit the current version
sudo nano /bin/upssched-cmd
And change the script to that:
#! /bin/sh
#
# This script should be called by upssched via the CMDSCRIPT directive.
#
# Here is a quick example to show how to handle a bunch of possible
# timer names with the help of the case structure.
#
# This script may be replaced with another program without harm.
#
# The first argument passed to your CMDSCRIPT is the name of the timer
# from your AT lines.
# Dynamic name assignment
UPS=$( upsc -l 2>/dev/null )
# Or manual name assignement
# UPS="YOUR-UPS-DEFINED-NAME-IN-UPS.CONF"
STATUS=$( upsc $UPS ups.status )
CHARGE=$( upsc $UPS battery.charge )
CHMSG="[$STATUS]:$CHARGE%"
case $1 in
online) MSG="$UPS, $CHMSG - power supply has been restored." ;;
onbatt) MSG="$UPS, $CHMSG - power failure - save your work!" ;;
lowbatt) MSG="$UPS, $CHMSG - shutdown now!" ;;
upsgone) MSG="The UPS $UPS has been gone for awhile" ;;
*) MSG="$UPS, $CHMSG - Unrecognized command: $1" ;;
esac
logger -i -t upssched-cmd $MSG
# Comment out the line below for workstations
# notify-send-all "$MSG"
Now that we have improved the existing commands scheduling scripts, we have to edit the /etc/nut/upssched.conf
file and change or set some values:
# Define PIPE file
sudo sed -e 's|# PIPEFN /run/|PIPEFN /run/|' -i /etc/nut/upssched.conf
# Define Lock file
sudo sed -e 's|# LOCKFN /run/|LOCKFN /run/|' -i /etc/nut/upssched.conf
# Add commands defined in the scripts
echo -e "\n# Custom commands" | sudo tee -a /etc/nut/upssched.conf
echo -e "AT ONLINE $(upsc -l 2>/dev/null)@localhost EXECUTE online\nAT ONBATT $(upsc -l 2>/dev/null)@localhost EXECUTE onbatt\nAT LOWBATT $(upsc -l 2>/dev/null)@localhost EXECUTE lowbatt" | sudo tee -a /etc/nut/upssched.conf
# Comment out this line if it didn't worked with the 'upsc' command above
# echo -e "AT ONLINE CP1500PFCLCD@localhost EXECUTE online\nAT ONBATT CP1500PFCLCD@localhost EXECUTE onbatt\nAT LOWBATT CP1500PFCLCD@localhost EXECUTE lowbatt" | sudo tee -a /etc/nut/upssched.conf
# Check the result
sudo nano /etc/nut/upssched.conf
Now that we have defined the UPS in the /etc/nut/ups.conf
file and the monitoring user in the /etc/nut/upsd.users
then finally set the monitoring connection in /etc/nut/upsmon.conf
, we must now change the running mode which is by default set to none
and would not let systemd
services to run correctly. We'll set it to the standalone
mode for now.
# Change the running mode
sudo sed -e 's/MODE=none/MODE=standalone/' -i /etc/nut/nut.conf
# Check the result
sudo nano /etc/nut/nut.conf
You can now restart all the nut
related systemd
services:
for S in nut-client.service nut-driver.service nut-monitor.service nut-server.service ; do sudo systemctl restart $S ; done
Wait few seconds to let them start then check their status:
for S in nut-client.service nut-driver.service nut-monitor.service nut-server.service ; do systemctl status $S -l ; done
You should see something similar:
$ for S in nut-client.service nut-driver.service nut-monitor.service nut-server.service ; do systemctl status $S -l ; done
● nut-monitor.service - Network UPS Tools - power device monitor and shutdown controller
Loaded: loaded (/lib/systemd/system/nut-monitor.service; enabled; vendor preset: enabled)
Active: active (running) since Fri 2021-07-02 07:49:48 CEST; 1min 8s ago
Process: 8731 ExecStart=/sbin/upsmon (code=exited, status=0/SUCCESS)
Main PID: 8733 (upsmon)
Tasks: 2 (limit: 4915)
Memory: 3.0M
CGroup: /system.slice/nut-monitor.service
├─8732 /lib/nut/upsmon
└─8733 /lib/nut/upsmon
jui 02 07:49:48 [REDACTED] upsmon[8731]: Using power down flag file /etc/killpower
jui 02 07:49:48 [REDACTED] systemd[1]: nut-monitor.service: Can't open PID file /run/nut/upsmon.pid (yet?)
jui 02 07:49:48 [REDACTED] upsmon[8732]: Startup successful
jui 02 07:49:48 [REDACTED] systemd[1]: nut-monitor.service: Supervising process 8733 which is not our child
jui 02 07:49:48 [REDACTED] systemd[1]: Started Network UPS Tools - power device monitor and shutdown contro
jui 02 07:49:48 [REDACTED] upsmon[8733]: Login on UPS [APCBU1400@localhost] failed - got [ERR ACCESS-DENIED
jui 02 07:49:53 [REDACTED] upsmon[8733]: Poll UPS [APCBU1400@localhost] failed - Write error: Broken pipe
jui 02 07:49:53 [REDACTED] upsmon[8733]: Communications with UPS APCBU1400@localhost lost
jui 02 07:49:58 [REDACTED] upsmon[8733]: Communications with UPS APCBU1400@localhost established
jui 02 07:49:58 [REDACTED] upsmon[8733]: UPS APCBU1400@localhost on line power
● nut-driver.service - Network UPS Tools - power device driver controller
Loaded: loaded (/lib/systemd/system/nut-driver.service; static; vendor preset: enabled)
Active: active (running) since Fri 2021-07-02 07:49:48 CEST; 1min 16s ago
Process: 8704 ExecStart=/sbin/upsdrvctl start (code=exited, status=0/SUCCESS)
Main PID: 8725 (usbhid-ups)
Tasks: 1 (limit: 4915)
Memory: 1.1M
CGroup: /system.slice/nut-driver.service
└─8725 /lib/nut/usbhid-ups -a APCBU1400
jui 02 07:49:48 [REDACTED] systemd[1]: Starting Network UPS Tools - power device driver controller...
jui 02 07:49:48 [REDACTED] upsdrvctl[8704]: Using subdriver: APC HID 0.96
jui 02 07:49:48 [REDACTED] upsdrvctl[8704]: Network UPS Tools - Generic HID driver 0.41 (2.7.4)
jui 02 07:49:48 [REDACTED] upsdrvctl[8704]: USB communication driver 0.33
jui 02 07:49:48 [REDACTED] upsdrvctl[8704]: Network UPS Tools - UPS driver controller 2.7.4
jui 02 07:49:48 [REDACTED] usbhid-ups[8725]: Startup successful
jui 02 07:49:48 [REDACTED] systemd[1]: Started Network UPS Tools - power device driver controller.
● nut-monitor.service - Network UPS Tools - power device monitor and shutdown controller
Loaded: loaded (/lib/systemd/system/nut-monitor.service; enabled; vendor preset: enabled)
Active: active (running) since Fri 2021-07-02 07:49:48 CEST; 1min 16s ago
Process: 8731 ExecStart=/sbin/upsmon (code=exited, status=0/SUCCESS)
Main PID: 8733 (upsmon)
Tasks: 2 (limit: 4915)
Memory: 3.0M
CGroup: /system.slice/nut-monitor.service
├─8732 /lib/nut/upsmon
└─8733 /lib/nut/upsmon
jui 02 07:49:48 [REDACTED] upsmon[8731]: Using power down flag file /etc/killpower
jui 02 07:49:48 [REDACTED] systemd[1]: nut-monitor.service: Can't open PID file /run/nut/upsmon.pid (yet?)
jui 02 07:49:48 [REDACTED] upsmon[8732]: Startup successful
jui 02 07:49:48 [REDACTED] systemd[1]: nut-monitor.service: Supervising process 8733 which is not our child
jui 02 07:49:48 [REDACTED] systemd[1]: Started Network UPS Tools - power device monitor and shutdown contro
jui 02 07:49:48 [REDACTED] upsmon[8733]: Login on UPS [APCBU1400@localhost] failed - got [ERR ACCESS-DENIED
jui 02 07:49:53 [REDACTED] upsmon[8733]: Poll UPS [APCBU1400@localhost] failed - Write error: Broken pipe
jui 02 07:49:53 [REDACTED] upsmon[8733]: Communications with UPS APCBU1400@localhost lost
jui 02 07:49:58 [REDACTED] upsmon[8733]: Communications with UPS APCBU1400@localhost established
jui 02 07:49:58 [REDACTED] upsmon[8733]: UPS APCBU1400@localhost on line power
● nut-server.service - Network UPS Tools - power devices information server
Loaded: loaded (/lib/systemd/system/nut-server.service; enabled; vendor preset: enabled)
Active: active (running) since Fri 2021-07-02 07:49:52 CEST; 1min 16s ago
Process: 8787 ExecStart=/sbin/upsd (code=exited, status=0/SUCCESS)
Main PID: 8800 (upsd)
Tasks: 1 (limit: 4915)
Memory: 1.1M
CGroup: /system.slice/nut-server.service
└─8800 /lib/nut/upsd
jui 02 07:49:52 [REDACTED] upsd[8787]: fopen /run/nut/upsd.pid: No such file or directory
jui 02 07:49:52 [REDACTED] upsd[8787]: listening on 127.0.0.1 port 3493
jui 02 07:49:52 [REDACTED] upsd[8787]: listening on ::1 port 3493
jui 02 07:49:52 [REDACTED] upsd[8787]: listening on 127.0.0.1 port 3493
jui 02 07:49:52 [REDACTED] upsd[8787]: listening on ::1 port 3493
jui 02 07:49:52 [REDACTED] upsd[8787]: Connected to UPS [APCBU1400]: usbhid-ups-APCBU1400
jui 02 07:49:52 [REDACTED] upsd[8787]: Connected to UPS [APCBU1400]: usbhid-ups-APCBU1400
jui 02 07:49:52 [REDACTED] upsd[8800]: Startup successful
jui 02 07:49:52 [REDACTED] systemd[1]: Started Network UPS Tools - power devices information server.
jui 02 07:49:58 [REDACTED] upsd[8800]: User monitor@::1 logged into UPS [APCBU1400]
If yes, then you can read the data available from your UPS that way:
# Use 'upsc -l' to get the name of the UPS
# Then pass it as self argument to read the UPS data
upsc $(upsc -l 2>/dev/null) 2>/dev/null
It should output something similar but with different values according to your UPS:
upsc $(upsc -l 2>/dev/null) 2>/dev/null
battery.charge: 100
battery.charge.low: 10
battery.charge.warning: 20
battery.mfr.date: CPS
battery.runtime: 3438
battery.runtime.low: 300
battery.type: PbAcid
battery.voltage: 24.0
battery.voltage.nominal: 24
device.mfr: CPS
device.model: CP1500PFCLCD
device.serial: 000000000000
device.type: ups
driver.name: usbhid-ups
driver.parameter.bus: 001
driver.parameter.pollfreq: 30
driver.parameter.pollinterval: 2
driver.parameter.port: auto
driver.parameter.product: CP1500PFCLCD
driver.parameter.productid: 0501
driver.parameter.serial: 000000000000
driver.parameter.synchronous: no
driver.parameter.vendor: CPS
driver.parameter.vendorid: 0764
driver.version: 2.7.4
driver.version.data: CyberPower HID 0.4
driver.version.internal: 0.41
input.transfer.high: 139
input.transfer.low: 88
input.voltage: 0.0
input.voltage.nominal: 120
output.voltage: 136.0
ups.beeper.status: enabled
ups.delay.shutdown: 20
ups.delay.start: 30
ups.load: 13
ups.mfr: CPS
ups.model: CP1500PFCLCD
ups.productid: 0501
ups.realpower.nominal: 900
ups.serial: 000000000000
ups.status: OB DISCHRG
ups.test.result: No test initiated
ups.timer.shutdown: -60
ups.timer.start: -60
ups.vendorid: 0764
Broadcast message from nut@chromebox (somewhere) (Thu Sep 15 03:47:08 2022):
UPS CP1500PFCLCD@localhost on line power
cloudgenius@chromebox:~$ upsc $(upsc -l 2>/dev/null) 2>/dev/null
battery.charge: 100
battery.charge.low: 10
battery.charge.warning: 20
battery.mfr.date: CPS
battery.runtime: 3172
battery.runtime.low: 300
battery.type: PbAcid
battery.voltage: 24.0
battery.voltage.nominal: 24
device.mfr: CPS
device.model: CP1500PFCLCD
device.serial: 000000000000
device.type: ups
driver.name: usbhid-ups
driver.parameter.bus: 001
driver.parameter.pollfreq: 30
driver.parameter.pollinterval: 2
driver.parameter.port: auto
driver.parameter.product: CP1500PFCLCD
driver.parameter.productid: 0501
driver.parameter.serial: 000000000000
driver.parameter.synchronous: no
driver.parameter.vendor: CPS
driver.parameter.vendorid: 0764
driver.version: 2.7.4
driver.version.data: CyberPower HID 0.4
driver.version.internal: 0.41
input.transfer.high: 139
input.transfer.low: 88
input.voltage: 122.0
input.voltage.nominal: 120
output.voltage: 138.0
ups.beeper.status: enabled
ups.delay.shutdown: 20
ups.delay.start: 30
ups.load: 13
ups.mfr: CPS
ups.model: CP1500PFCLCD
ups.productid: 0501
ups.realpower.nominal: 900
ups.serial: 000000000000
ups.status: OL
ups.test.result: No test initiated
ups.timer.shutdown: -60
ups.timer.start: -60
ups.vendorid: 0764
You can now configure Netdata and add the name of your UPS in the configuration file:
# Go to the netdata config folder
cd /etc/netdata
# Run the editing script
sudo ./edit-config charts.d/nut.conf
You don't really need to change anything as normally the defaults are good enough to simply having to restart the service and nothing more:
sudo systemctl restart netdata ; systemctl status netdata -l
Now you can navigate to http://localhost:19999 and search for the UPS section on the right, you should see something like that:
- https://github.com/networkupstools/nut
- https://wiki.archlinux.org/title/Network_UPS_Tools
- https://manpages.ubuntu.com/manpages/focal/en/man8/nut-scanner.8.html
- http://rogerprice.org/NUT/
- http://rogerprice.org/NUT/ConfigExamples.A5.pdf
- https://learn.netdata.cloud/docs/agent/collectors/charts.d.plugin/nut