..

Making APC BX700 UPS actually work on debian

There are two things I want from UPS:

  • to shut down my server when power is out
  • to bring it back up when power is back

Pretty simple? Well, it was not working out of the box and I had to do googling to make it work. Plus I’ve noticed a lot of confusion in the internet about this topic, so I decided to write this post.

Fortunately there is software providing controlling daemon apcupsd for model I’ve chosen: APC BX750MI. There was no need to install any drivers (at least on debian 11). I’ve just plugged it in and it worked.

The problem

Unfortunately whatever I’ve set in the config file my machine stayed off when power came back. Finally, setting WAKEUP directive in /etc/apcupsd/apcupsd.conf helped, but then I realized that my machine was not shutting down cleanly every time. It looked like from time to time it was just cut off from power - not exactly what I wanted. I realized this was due KILLDELAY directive in /etc/apcupsd/apcupsd.conf which was set to non-zero value.

# If KILLDELAY is non-zero, apcupsd will continue running after a
# shutdown has been requested, and after the specified time in
# seconds attempt to kill the power. This is for use on systems
# where apcupsd cannot regain control after a shutdown.
# KILLDELAY <seconds>  0 disables

So it seems that apcupsd was not able to shut down the system within KILLDELAY and apcupsd shut off the power. The right solution here seems to be to disable KILLDELAY and let systemd handle the shutdown based on powerfail signal from apcupsd.

The solution

Here is my current /etc/apcupsd/ configuration which solves this problem:

UPSCABLE usb
UPSTYPE usb
DEVICE
POLLTIME 60
LOCKFILE /var/lock
SCRIPTDIR /etc/apcupsd
PWRFAILDIR /etc/apcupsd
NOLOGINDIR /etc
ONBATTERYDELAY 6
BATTERYLEVEL 15
MINUTES 3
TIMEOUT 0
ANNOY 300
ANNOYDELAY 60
NOLOGON disable
KILLDELAY 0
NETSERVER on
NISIP 127.0.0.1
NISPORT 3551
EVENTSFILE /var/log/apcupsd.events
EVENTSFILEMAX 10
UPSCLASS standalone
UPSMODE disable
STATTIME 0
STATFILE /var/log/apcupsd.status
LOGSTATS off
DATATIME 0

but it needs to be complemented with systemd service which will trigger shutdown based on power outage detected by apcupsd:

$ sudo systemctl edit --force --full apcupsd-killpower.service
[Unit]
# refer to: PWRFAILDIR /etc/apcupsd in apcupsd.conf
Description=APC UPS killpower
ConditionPathExists=/etc/apcupsd/powerfail
DefaultDependencies=no
After=shutdown.target
Before=final.target

[Service]
Type=oneshot
ExecStart=/sbin/apcupsd --killpower
TimeoutSec=0
StandardOutput=tty
RemainAfterExit=yes

[Install]
WantedBy=shutdown.target
$ sudo systemctl enable apcupsd-killpower.service

Extra steps to extend battery life

apcupsd detects multiple events which are defined in /etc/apcupsd/apccontrol script. One of them is ONBATTERY which is triggered when UPS switches to battery power. This event is handled by /etc/apcupsd/onbattery script which by default does nothing. I’ve decided to switch machine into low power state in order to prolong backup power. I’m doing this by leveraging tune-adm:

#!/bin/sh

HOSTNAME=`hostname`
MSG="$HOSTNAME UPS $1 Power Failure !!!"
#
(
   echo "$MSG"
   echo " "
   /sbin/apcaccess status
) | $APCUPSD_MAIL -s "$MSG" $SYSADMIN

/usr/sbin/tuned-adm proile server-powersave
exit 0

Additionally, I’ve added /etc/apcupsd/offbattery script which switches machine back to performance mode which in my case is virtual-host profile - you probably should adjust this to your needs:

#!/bin/sh

HOSTNAME=`hostname`
MSG="$HOSTNAME UPS $1 Power has returned"
#
(
   echo "$MSG"
   echo " "
   /sbin/apcaccess status
) | $APCUPSD_MAIL -s "$MSG" $SYSADMIN
/usr/sbin/tuned-adm profile virtual-host
exit 0

Summary

Let’s summarize:

  1. Motherboard BIOS setting related to power should be set to always on.
  2. apcupsd monitors power supply and creates /etc/apcupsd/powerfail file if any of the following conditions: BATTERYLEVEL, MINUTES, and TIMEOUT are satisfied.
  3. apcupsd-killpower systemd service is triggered by presence of /etc/apcupsd/powerfail file and triggers UPS to cut off power at the end of shutdown target so that operating system can shut down cleanly.
  4. WAKEUP directive in apcupsd.conf is responsible for bringing up UPS power output after power is back.
  5. apcupsd/onbattery script is responsible for switching machine into low power state when power is out.

Problem I’ve encountered relates to discussion in this thread: Lost USB comms after a killpower - BX700U - Communities

Changelog

fixes: typos leading to table in Making APC BX700 UPS actually work on debian
fixes: minor editorial stuff in UPS
adds: section on low/high power state controlled by apcupsd
adds: Making APC UPS BX700 actually work on debian