Linux + APC Smart UPS 750 notes (apcupsd and other stuff)

This post was written by eli on October 31, 2018
Posted Under: Linux,systemd

Introduction

These are my somewhat messy jots while setting up an APC Smart UPS 750 (SMT750I) with a Linux Mint 19 machine, for a clean shutdown on power failure. Failures and mistakes shown as well.

Even though I had issues with receiving a broken UPS at first, and waiting two months for a replacement (ridiculous support by Israeli Serv Pro support company), the bottom line is that it seems like a good choice: The UPS and its apcupsd driver handles the events in a sensible way, in particular when power returns after the shutdown process has begun (this is where UPSes tend to mess up).

As for battery replacement, two standard 12V / 7 AH batteries can be used, as shown in this video. Otherwise, good luck finding vendor-specific parts ten years from now in Israel.

Turning off the UPS manually (and losing power to computer): Press and hold the power button until the second beep. The first beep confirms pressing the button, the second says releasing the button will shut down the UPS.

Turning off beeping when the UPS is on battery: Press the ESC button for a second or so.

Basic installation

Driver for UPS:

# apt-get install apcupsd

Settings

Edit /etc/apcupsd/apcupsd.conf, and remove the line saying

DEVICE /dev/ttyS0

Change TIMEOUT, so the system is shut down after 10 minutes of not having power. Don’t empty the batteries — I may want to fetch a file from the computer with the network power down. This timeout applies also if the computer was started in an on-battery state.

TIMEOUT 600

Don’t annoy anyone to log off. There is nobody to annoy except myself:

ANNOY 0

No need for a net info server. A security hole at best in my case.

NETSERVER off

Wrong. Keep the server, or apcaccess won’t work.

Stop “wall” messages

This is really unnecessary on a single-user computer (is it ever a good idea?). If power goes out, it’s dark and the UPS beeps. No need to get all shell consoles cluttered. The events are logged in /var/log/apcupsd.events as well as the syslog, so there’s no need to store them anywhere.

Edit /etc/apcupsd/apccontrol, changing

WALL=wall

to

WALL=cat

The bad news is that an apt-get upgrade on apcupsd is likely to revert this change.

Hello, world

Possibly as non-root:

$ apcaccess status
APC      : 001,027,0656
DATE     : 2018-10-28 21:36:29 +0200
HOSTNAME : preruhe
VERSION  : 3.14.14 (31 May 2016) debian
UPSNAME  : preruhe
CABLE    : USB Cable
DRIVER   : USB UPS Driver
UPSMODE  : Stand Alone
STARTTIME: 2018-10-28 21:36:27 +0200
MODEL    : Smart-UPS 750
STATUS   : ONLINE
BCHARGE  : 100.0 Percent
TIMELEFT : 48.0 Minutes
MBATTCHG : 5 Percent
MINTIMEL : 3 Minutes
MAXTIME  : 0 Seconds
ALARMDEL : 30 Seconds
BATTV    : 27.0 Volts
NUMXFERS : 0
TONBATT  : 0 Seconds
CUMONBATT: 0 Seconds
XOFFBATT : N/A
STATFLAG : 0x05000008
MANDATE  : 2018-05-22
SERIALNO : AS182158746
NOMBATTV : 24.0 Volts
FIRMWARE : UPS 09.3 / ID=18
END APC  : 2018-10-28 21:36:47 +0200

Shutting down UPS on computer shutdown

By default, the computer puts the UPS in “hibernation” mode at a late stage of its own shutdown. This turns the power down (saving battery), and resumes power when the network power returns. The trick is that apcupsd creates a /etc/apcupsd/powerfail file before shutting down the computer due to a power failure, and /lib/systemd/system-shutdown/apcupsd_shutdown handles the rest:

#!/bin/sh
# apcupsd: kill power via UPS (if powerfail situation)
# (Originally from Fedora.)

# See if this is a powerfail situation.
faildir=$(grep -e^PWRFAILDIR /etc/apcupsd/apcupsd.conf)
faildir="${faildir#PWRFAILDIR }"

if [ -f "${faildir:=/etc/apcupsd}/powerfail" ]; then
  echo
  echo "APCUPSD will now power off the UPS"
  echo
  /etc/apcupsd/apccontrol killpower
fi

Note that the powerfail file is created before the shutdown, not when the UPS goes on battery.

So for the fun, try

# touch /etc/apcupsd/powerfail

and then shutdown the computer normally. This shows the behavior of a shutdown forced by the UPS daemon. As expected, this file is deleted after booting the system (most likely by apcusbd itself).

What happens on shutdown

The UPS powers down after 90 seconds (after displaying a countdown on its small screen), regardless of whether power has returned or not. This is followed by a “stayoff” of 60 seconds, after which it will power on again when power returns. During the UPS hibernation, the four LEDs are doing a disco pattern.

I want the USB to stay off until I turn it on manually. The nature of power failures is that they can go on and off, and I don’t want the UPS to go on, and then empty the battery on these.

To make a full poweroff instead of a hibernation, edit (or create) /etc/apcupsd/killpower, so it says:

#!/bin/bash
#

APCUPSD=/sbin/apcupsd

echo "Apccontrol doing: ${APCUPSD} --power-off on UPS ${2}"
sleep 10
${APCUPSD} --power-off
echo "Apccontrol has done: ${APCUPSD} --power-off on UPS ${2}"

exit 99

This is more or less a replica of /etc/apcupsd/apccontrol’s handler for “killpower” command, only with apcupsd called with the –power-off flag instead of –killpower. The latter “hibernates” the UPS, so it wakes up when power returns. That’s the thing I didn’t want.

The “exit 99″ at the end inhibits apccontrol’s original handler.

So now there’s a “UPS TurnOff” countdown of 60 seconds, after which the UPS is shut down until power on manually.

Manual fixes

Set menus to advanced, if they’re not already. Then:

  • Configuration > Auto Self Test, set to Startup Only: I tried to yank the battery’s plug on the UPS’ rear during a self test, and the computer’s power went down. So I presume that a failing self test will drop the power to the computer. Not clear what the point is.
  • Configuration > Config Main Group Outlets > Turn Off Delay set to 10 seconds, to prevent an attempt to reboot the computer when the USB is about to power down. Surprisingly enough, this works when hibernating the UPS, but when enabling the power-off script above, the delay is 60 seconds, despite this change. I haven’t figured out how to change this.

Maybe the source code tells something

I dug in the sources for the reason that the UPS shuts down after 60 seconds, despite me setting the “Turn Off Delay” to 10 seconds directly on the UPS’ control buttons.

The relevant files in the acpupsd tarball:

  • src/apcupsd.c: The actual daemon and main executable. Surprisingly readable.
  • src/drivers/apcsmart/smartoper.c: The actual handlers of the operations (shutdown and power kill, with functions with obvious names). Written quite well, in terms of the persistence to carry out sensible operations when things go unexpected. Also see drivers/apcsmart/apcsmart.h.

So looking at smartoper.c, it turns out that the kill_power() method (which is used for “hibernation” of the UPS) sends a “soft” shutdown with an “S” command to the UPS, and doesn’t tell it the delay time. Hence the UPS decides the delay by itself (which is what I selected with the buttons).

The shutdown() method, on the other hand, calls apcsmart_ups_get_shutdown_delay(), which accepts an argument saying what the delay is. The name of this function is however misleading, as it just sends a shutdown command to the UPS, without telling it the delay. The figure in the delay is used only in the log messages. The UPS gets a “K” command, and doesn’t tell the UPS anything else. Basically, it works the same as kill_power(), only with a different command.

Trying NUT (actually, don’t)

What tempted me into trying out NUT was this page which implied that it has something related with shutdown.stayoff. And it’s keeping the UPS off that I wanted. But it seems like apcupsd is a much better choice.

Note my older post on NUT.

Since I went through the rubbish, here’s a quick runthrough. First install nut (which automatically ditches apcuspd (uninstalls it totally, it seems):

# apt-get install nut

The relevant part in /etc/nut/ups.conf for the ups named “smarter”:

[smarter]
        driver = usbhid-ups
        port = auto
        vendorid = 051d

I’m under the impression that the “port” assignment is ignored altogether. Don’t try it with other drivers — you’ll get “no such file”, for good reasons. Possibly usbhid-ups is the only way to utilize a USB connection.

And then in /etc/nut/upsmon.conf, added the line

MONITOR smarter@localhost 1 upsmon pass master

The truth is that I messed around a bit without too much notice of what I did, so I might have missed something. Anyhow, a reboot was required, after which the UPS was visible:

# upsc smarter
Init SSL without certificate database
battery.charge: 100
battery.charge.low: 10
battery.charge.warning: 50
battery.runtime: 3000
battery.runtime.low: 120
battery.type: PbAc
battery.voltage: 26.8
battery.voltage.nominal: 24.0
device.mfr: American Power Conversion
device.model: Smart-UPS 750
device.serial: AS1821351109
device.type: ups
driver.name: usbhid-ups
driver.parameter.pollfreq: 30
driver.parameter.pollinterval: 2
driver.parameter.port: auto
driver.parameter.synchronous: no
driver.parameter.vendorid: 051d
driver.version: 2.7.4
driver.version.data: APC HID 0.96
driver.version.internal: 0.41
ups.beeper.status: enabled
ups.delay.shutdown: 20
ups.firmware: UPS 09.3 / ID=18
ups.mfr: American Power Conversion
ups.mfr.date: 2018/05/22
ups.model: Smart-UPS 750
ups.productid: 0003
ups.serial: AS1821351109
ups.status: OL
ups.timer.reboot: -1
ups.timer.shutdown: -1
ups.vendorid: 051d

and getting the list of commands:

# upscmd -l smarter
Instant commands supported on UPS [smarter]:

beeper.disable - Disable the UPS beeper
beeper.enable - Enable the UPS beeper
beeper.mute - Temporarily mute the UPS beeper
beeper.off - Obsolete (use beeper.disable or beeper.mute)
beeper.on - Obsolete (use beeper.enable)
load.off - Turn off the load immediately
load.off.delay - Turn off the load with a delay (seconds)
shutdown.reboot - Shut down the load briefly while rebooting the UPS
shutdown.stop - Stop a shutdown in progress

So it didn’t really help.

Add a Comment

required, use real name
required, will not be published
optional, your blog address