Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save lvnilesh/0600934ab9a7f6a47ea572bdae31be12 to your computer and use it in GitHub Desktop.
Save lvnilesh/0600934ab9a7f6a47ea572bdae31be12 to your computer and use it in GitHub Desktop.
Setup nut and netdata on Ubuntu

Setup nut and netdata on Ubuntu

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.

Install required dependencies

Nut

sudo apt install nut -y

Netdata

# 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

Must read

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.

Detect connected UPS

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"

Create monitoring connection

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

# --------------------------------------------------------------------------

Improve UPS commands scheduling script

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"

Configure commands scheduling

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

Start nut services

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

Configure Netdata

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:

image

References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment