NUT & UPS, howto shut down client after 2 min on battery?

Hi!

Some systems I have take some time to shut down, so I would like them to shut down if the UPS have been on battery for 2 minutes. That include my primary ipfire.

Internet has told me that SHUTDOWNCMD “/sbin/shutdown -h +0” in /etc/nut/upsmon.conf will execute when the UPS is both OB (on battery) and LB (Low battery). Like in wiki.ipfire.org - Detailed NUT Configuration where it says

“SHUTDOWNCMD “/sbin/shutdown -h +0” this command will be triggered if UPS sends the BL (Battery Low) flag.”

But I would like to be on the safest side, and not hope “low battery” is enough time to shut down. So 2 minutes sound much more safe for paranoid me.

I do not know much about NUT, but after some Googling, one idea I have is to in /etc/nut/upsmon.conf on client change to this

NOTIFYCMD "/etc/nut/shutdown_script.sh"
NOTIFYFLAG ONBATT EXEC

And then in /etc/nut/shutdown_script.sh have something like this

#!/bin/bash

poll_interval=5
wait_time=120
counter=0
no_wait_time=60
no_counter=0

while true
do
  output=$(upsc qnapups@192.168.222.252 ups.status)
  if echo "$output" | grep -q "OB"
  then
    counter=$((counter + poll_interval))
    no_counter=0
  else
    counter=0
    no_counter=$((no_counter + poll_interval))
  fi
  if [ $counter -ge $wait_time ]
  then
    echo "Still outoput OB = On Battery, after 2 min. I will now shut down"
	# Here I will shutdown the system 
	# "/sbin/shutdown -h +0"
    break
  fi
  if [ $no_counter -ge $no_wait_time ]
  then
    echo "Have not seen OB for 1 min, so quiting the script"
    break
  fi
  sleep $poll_interval
done

But now I am starting to wonder if I am overdoing this. Surely there must already be a ready-made solution for this in NUT somewhere, but I have just searched with wrong words i Google.

Have any of you done something similar with NUT, and what is the right way to do it?

1 Like

I don’t use NUT, I am using APCUPSD which has an ONBATTERYDELAY command where you can define how long on battery before taking some action.

I checked through the NUT manual but was not able to find anything similar.

Did some general checking and found someone on a nut mailing list who was asking, 9 years ago, for how to do the same as you have asked for. Before anyone replied to his post he found a site that had done what he was looking for.

I haven’t looked through it in great detail as I am not that familiar with NUT but it looks like it might do what you are looking for.

The link is
https://srackham.wordpress.com/2013/02/27/configuring-nut-for-the-eaton-3s-ups-on-ubuntu-linux/

Hopefully it will provide you with what you are looking for and is simpler than what you are currently doing. :crossed_fingers:

It does seem peculiar that NUT doesn’t have a command to trigger shutdowns also for time on battery.

1 Like

Looking through the NUT manual a bit more (I have considered changing from APCUPSD to NUT sometime or other, hence I am interested) I did find that there is helper called upssched which takes a status such as ONBAT and then schedules an action at some time after this.

The manual section for this helper is 7.2

1 Like

OK, been reading at 7. Advanced usage and scheduling notes

So I can do as above, and that is called “The simple approach, using your own script

And also with upssched like under, that is called “The advanced approach, using upssched

To use upssched, in upsmon.conf I can have

NOTIFYCMD /usr/sbin/upssched
NOTIFYFLAG ONLINE EXEC
NOTIFYFLAG ONBATT EXEC
NOTIFYFLAG LOWBATT EXEC

And in upssched.conf to shutdown after 2 min

CMDSCRIPT /etc/nut/upssched-cmd
AT ONBATT * START-TIMER onbattwarn 120
AT ONLINE * CANCEL-TIMER onbattwarn
AT ONLINE * EXECUTE ups-back-on-power

And in /etc/nut/upssched-cmd

        #! /bin/sh

        case $1 in
                onbattwarn)
                        shutdown bla bla
                        ;;
                ups-back-on-power)
                        cancel shutdown bla bla
                        ;;
        esac

Here are more examples on stuff in upssched.conf [TUTORIAL] Networked NUT for Cyberpower UPS - Plugins and Apps - Unraid

# Command pipe and lock-file
PIPEFN /var/run/nut/upssched.pipe
LOCKFN /var/run/nut/upssched.lock

# Send alerts immediately on change in line power
AT ONBATT * EXECUTE onbatt
AT ONLINE * EXECUTE onpower

# (Optional) Silence the beeper after 2 minutes
AT ONBATT * START-TIMER mute_beeper 120
AT ONLINE * CANCEL-TIMER mute_beeper

# Shutdown after 20 minutes on battery (20 * 60 = 1200)
AT ONBATT * START-TIMER onbatt_shutdown 1200

# Cancel timer if power's restored
AT ONLINE * CANCEL-TIMER onbatt_shutdown

# Battery replacement indicated by cron'd quick test
AT REPLBATT * EXECUTE replace_batt

And in upssched-cmd

# START: User-specific settings                            
#
UPS_USERNAME="admin"
UPS_PASSWORD="<pwd>"
UPS_LINK="cyberpower@localhost"
# END  

case $1 in
    onbatt)
        # make sure beeper is enabled
        upscmd -u ${UPS_USERNAME} -p ${UPS_PASSWORD} ${UPS_LINK} beeper.enable
        # alert
        message="Power outage, on battery"
        logger -t upssched-cmd "$message"
        ;;
    onpower)
        message="Power restored"
        logger -t upssched-cmd "$message"
        ;;
    mute_beeper)
         message="(2) minute limit exceeded, muting beeper"
         upscmd -u ${UPS_USERNAME} -p ${UPS_PASSWORD} ${UPS_LINK} beeper.mute
         ;;
    onbatt_shutdown)
        message="Triggering shutdown after (20) minutes on battery"
        logger -t upssched-cmd "$message"
        /sbin/upsmon -c fsd
        ;;
    replace_batt)
        message="Quick self-test indicates battery requires replacement"
        logger -t upssched-cmd "$message"
        ;;
    *)
        logger -t upssched-cmd "Unrecognized command: $1"
        ;;
esac

chat.openai.com also told me I can use this in upssched.conf to check every 5 sek, and after 2 min shutdown
onbattery.duration >= 2 -i 5 shutdown
But I have not seen this info anywere else :wink:

Hmm… OK, I have to think about this. But using upssched seems to give more options…

1 Like

(I got this answer from the NUT user mailing list, and add it here for future reference)

From: Nut-upsuser nut-upsuser-bounces@alioth-lists.debian.net on behalf of Matt via Nut-upsuser nut-upsuser@alioth-lists.debian.netSent: Saturday, December 31, 2022 05:51To: nut-upsuser@alioth-lists.debian.net nut-upsuser@alioth-lists.debian.netSubject: Re: [Nut-upsuser] NUT & UPS, how to shut down client after 2 min on battery?

On 2022-12-22 05:47, raffe via Nut-upsuser wrote:

I do not know much about NUT, but after some Googling, one idea I have
is to in /etc/nut/upsmon.conf on client change to this

|NOTIFYCMD “/etc/nut/shutdown_script.sh” NOTIFYFLAG ONBATT EXEC |

And then in /etc/nut/shutdown_script.sh have something like this

Hi Raffe, I had a very similar setup to this for a long time until I
recently changed it; I will describe what I used to do and why I don’t
set a timer like this anymore.

In /etc/ups/upsmon.conf (my system is Fedora) I captured three events:
NOTIFYFLAG ONLINE SYSLOG+EXEC
NOTIFYFLAG ONBATT SYSLOG+EXEC
NOTIFYFLAG LOWBATT SYSLOG+EXEC
NOTIFYCMD /usr/sbin/upssched

The key thing here is I am not calling a bash script directly with
NOTIFYCMD, but delegating it to the built in upssched process which has
timer functionality (and is packaged with nut in Fedora).

In /etc/ups/upssched.conf, the key options are:
CMDSCRIPT /usr/local/bin/upsmon-execscript.sh
AT ONBATT * START-TIMER shutdown_onbatt 600
AT ONLINE * CANCEL-TIMER shutdown_onbatt

As you can see it starts a 10 minute timer, and cancels the timer if
mains power is restored. The bash script is similar to yours, but
benefits from not having to do any time management of its own or count
how long it has been running. upssched does that for you, and simply
calls your script when the listed events occur and with the timer of
your choosing.

Here is the problem with this approach in general:

  • what happens if I boot my server while already on battery, and
    the battery is low? My script won’t do anything for 10 minutes
  • what happens if the power repeatedly cycles on/off/on/off?
    10 more minutes are granted every time, which again leaves you
    in a dangerous situation

My current approach is to have my server turn off when the UPS hits 40%
battery. I have redefined the “lowbatt” signal to a very comfortable
40%, so there is plenty of time to shutdown and still plenty of battery
left for charging other things like my cellphone etc.

The way to accomplish this is in /etc/ups/ups.conf, under your ups
configuration put:
ignorelb
override.battery.charge.low=40

This seems safer to me because it’s based on the actual capacity
remaining, and not an arbitrary timer.

Hope this helps, and happy new years!
Matt


Nut-upsuser mailing list
Nut-upsuser@alioth-lists.debian.net
Nut-upsuser Info Page

3 Likes

Now I have this in /etc/nut/upsmon.conf (my QNAP NAS wants admin and 123456 or not working)

RUN_AS_USER root
MONITOR qnapups@localhost 1 admin 123456 master
# MONITOR qnapups@192.168.222.252 1 admin 123456 slave
MINSUPPLIES 1
SHUTDOWNCMD "/sbin/shutdown -h +0"
POLLFREQ 5
POLLFREQALERT 5
HOSTSYNC 15
DEADTIME 15
POWERDOWNFLAG /etc/killpower

NOTIFYFLAG ONLINE SYSLOG+EXEC
NOTIFYFLAG ONBATT SYSLOG+EXEC
NOTIFYFLAG LOWBATT SYSLOG+EXEC
NOTIFYFLAG REPLBATT SYSLOG+EXEC
NOTIFYCMD /usr/sbin/upssched

RBWARNTIME 43200
NOCOMMWARNTIME 300
FINALDELAY 5

And in /etc/nut/upssched.conf

CMDSCRIPT /etc/nut/upssched-execscript.sh

PIPEFN /etc/nut/upssched.pipe
LOCKFN /etc/nut/upssched.lock

AT ONBATT * START-TIMER shutdown_onbatt 240
AT ONBATT * EXECUTE info_onbatt

AT ONLINE * CANCEL-TIMER shutdown_onbatt
AT ONLINE * EXECUTE ups-back-on-power

AT LOWBATT * EXECUTE shutdown_lowbatt

AT REPLBATT * EXECUTE replace_batt

And in /etc/nut/upssched-execscript.sh

#! /bin/sh
case $1 in
    shutdown_onbatt)
        logger -t upsmon[upssched] "shutdown_onbatt): Triggering shutdown after 4 minutes on battery"
        /sbin/shutdown -h +0
        ;;

    shutdown_lowbatt)
        logger -t upsmon[upssched] "shutdown_lowbatt): Triggering shutdown when battery.charge.low is under 50%"
        /sbin/shutdown -h +0
        ;;

    info_onbatt)
        logger -t upsmon[upssched] "info_onbatt): Now on battery"
        ;;

    ups-back-on-power)
        logger -t upsmon[upssched] "ups-back-on-power): UPS back on power"
        ;;

    replace_batt)
        message="Quick self-test indicates battery requires replacement"
        logger -t upsmon[upssched] "replace_batt): $message"
        ;;

    *)
        logger -t upsmon[upssched] "*) = Unrecognized command: $1"
        ;;
esac

And in /etc/nut/ups.conf

[qnapups]
    driver = usbhid-ups
    port = auto
    desc = "UPS"
    ignorelb
    override.battery.charge.low=50

And in /etc/nut/upsd.users

[admin]
                password = 123456
                actions = SET
                instcmds = ALL
                upsmon master           # or upsmon slave

So I have these files

[root@ipfire2 nut]# pwd
/etc/nut
[root@ipfire2 nut]# ls -la
total 104
drwxr-xr-x  2 root root  4096 Jan 10 09:23 .
drwxr-xr-x 50 root root  4096 Jan 10 10:33 ..
-rw-r--r--  1 root root  1542 Jan 10 09:05 nut.conf
-rw-r--r--  1 root root  1538 Dec 18  2020 nut.conf.sample
-rw-r--r--  1 root root  4734 Jan 10 09:10 ups.conf
-rw-r--r--  1 root root  4618 Dec 18  2020 ups.conf.sample
-rw-r-----  1 root root  4606 Dec 22 08:44 upsd.conf
-rw-r--r--  1 root root  4578 Dec 18  2020 upsd.conf.sample
-rw-r-----  1 root root  2292 Dec 22 07:11 upsd.users
-rw-r--r--  1 root root  2131 Dec 18  2020 upsd.users.sample
-rw-r--r--  1 root root 15569 Jan 10 10:20 upsmon.conf
-rw-r--r--  1 root root 15313 Dec 18  2020 upsmon.conf.sample
-rw-r--r--  1 root root  4173 Jan 10 10:22 upssched.conf
-rw-r--r--  1 root root  3895 Dec 18  2020 upssched.conf.sample
-rwxr-xr-x  1 root root   810 Jan 10 10:29 upssched-execscript.sh

Do that seem right to you?

EDIT: I added:

PIPEFN /etc/nut/upssched.pipe
LOCKFN /etc/nut/upssched.lock

EDIT 2
After info in the post under this post, I in this post above changed from this
MONITOR qnapups@192.168.222.252 3493 admin 123456 slave
to this:
# MONITOR qnapups@192.168.222.252 1 admin 123456 slave

And I also added /etc/nut/upsd.users above

1 Like

(I got this answer from the NUT user mailing list, and add it here for future reference)

Cc: nut-upsuser@alioth-lists.debian.net nut-upsuser@alioth-lists.debian.net
Subject: Re: [Nut-upsuser] NUT & UPS, how to shut down client after 2 min on battery?

Cheers,

At least a few things that DO NOT seem right upon quick reading are:

  • upsmon.conf:
RUN_AS_USER root

Should not normally be required: when started as root, upsmon splits into unprivileged process for most of the work and leaves the shutdown handler running as root; with this setting you get it all running as root which is potentially unsafe.

  • upsmon.conf:

MONITOR qnapups@localhost 1 admin 123456 master
MONITOR qnapups@192.168.222.252 3493 admin 123456 slave
MINSUPPLIES 1

Do you have two UPSes powering this system, or are you trying to monitor the same one by localhost and LAN IP addresses? Note that the number (“1” in the first line) is how many power sources of the current system that UPS powers (e.g. you may monitor remote UPSes in some branch office without critically reacting to their state by setting 0 here).

So the second line has the other UPS feed 3494 power sources of this system while you only require one to be powered reliably and stay calm :wink:

I suppose here you meant the port - it should be a colon-separated suffix after the IP address (IIRC), and 3493 is the IANA registered default for NUT so not needed at all here.

The master/slave regards direct connection to the UPS (does this system control it, including a power-cut command, or a remote one does?)

  • I did not use upssched much myself so do not feel qualified to comment; however pipe and lock files may better belong in /var/state/ups, /var/run/nut, /tmp or /dev/shm - preferably in a tmpfs to avoid hitting real storage with I/O that should not persist across reboots:
PIPEFN /etc/nut/upssched.pipe
LOCKFN /etc/nut/upssched.lock

While it should not be “fatal” to have them under /etc/nut as long as the processes involved have access there (in your case, ones already running as root), generally the daemon process should only have read-only access to its configuration files and their directory - to avoid having it exploited to overwrite the configs to something more sinister.

  • FWIW upsmon.conf should not be world-readable as it has a copy of the passwords. Generally ups.conf also - it may be sensitive depending on protocols involved (snmp communities, netxml/ipmi/… logins…)

  • admin/123456 - this should be set in upsd.users so not sure how much QNAP intervenes into the content of that config file to be “not working” otherwise. These are NUT accounts, not OS ones.

Hope this helps,

Jim

3 Likes