MENU

【歪门邪道】使用NUT在Linux上管理UPS

June 2, 2024 • 瞎折腾

之前下雨的时候家里又跳闸了。想来想去,去京东买了个APC的BK650M2-CH的UPS。本文记述如何让NUC在UPS电量低的时候自动关机。

前言

因为Linux在我的印象中一直是很脆弱的那种角色(它很强大,但也很脆弱),尤其是ext4时代经常有人说突然掉电之后会有什么文件系统损毁之类的事情。虽然Btrfs已经不会出现这个问题了,但我对突然掉电还是耿耿于怀。前几天我家又停电了,于是便考虑买个UPS。

我买的型号是APC的BK650M2-CH,特征就不介绍了。我这边测试让NUC跑满s-tui,保持CPU使用率100%,从UPS满电到UPS自动关机,一共能坚持35分钟。我想这35分钟怎么都够我找到新的电源了。就算找不到,我也有时间保存我的工作进度。再不济我直接进入挂起模式,只给内存供电,按照这个功耗那跟定比35分钟要多。

于是问题来了:我睡觉的时候停电了怎么办?得想个办法能够让NUC在最坏情况下保护工作进度。关机是不现实的,因为有些软件并不会自动保存。那么挂起是一个措施,但谁来触发呢?我发现gnome桌面能够自动识别到UPS,但经过我的实际测试,就算是UPS低电量自动关机,就算是在此之前gnome也会提示UPS电量低,但他就是不会自动关机。我猜测可能还是UPS和电池供电不同吧。

最开始我尝试了apcupsd,这个是专门给APC的UPS准备的。但我发现BK650M2-CH和他不兼容,具体表现是acpaccess读取不出来当前UPS的状态。只能作罢,后来看到一个叫做NUT的东西,叫Network UPS Tools,它可以监控UPS的状态,并通过网络将UPS的状态发送出去。这样一来,如果你有10台服务器都接在一个UPS上,那我们只需要将UPS连接到一台服务器上,然后其他服务器通过网络即可查询到UPS的状态,并实现自动关机。

由于我目前的设备比较简单,只有NUC是没有内置电池的,所以本文使用standalone模式。

安装配置

NUT的安装很是方便:

sudo zypper in nut

安装完成后可以查询APC的UPS应该用哪些driver:cat /usr/share/nut/driver.list | grep "APC"

"APC"    "ups"    "3"    "Back-UPS (USB)"    "USB"    "usbhid-ups"

由于我的型号是使用USB进行通讯的,因此driver填写usbhid-ups就可以了。修改配置文件/etc/ups/ups.conf

[apc-bk650m2-ch]
       driver = usbhid-ups
       port = auto
       desc = "APC BK650M2-CH"

然后修改/etc/ups/nut.conf

MODE=standalone

这样我们就无需启动服务器和客户端了。由于我们不需要服务端,因此也无需修改upsd.confupsd.users文件。但我们还需要修改upsmon.conf

MONITOR apc-bk650m2-ch@localhost 1 upsmaster @UPSD_INITIAL_MASTER_PASSWORD@ master
SHUTDOWNCMD "/usr/bin/systemctl suspend"
SHUTDOWNEXIT no

配置文件中默认的名字是myups,我们需要将MONITOR改成我们对应的。后面的数字1表示供电数量,由于这个UPS只提供只向我们系统提供1路供电。

同时我们希望挂起系统而不是关闭系统,所以我们还要修改关机的命令(SHUTDOWNCMD)。同时因为是挂起,所以我们不希望NUT发出关机指令后退出,而是保持运行,所以还要调整SHUTDOWNEXIT

一切调整妥当之后:

systemctl enable nut-driver-enumerator
systemctl enable nut.target --now
upsc apc-bk650m2-ch

第一行用来启动一个叫做nut-driver-enumerator的服务,它的作用是根据ups.conf中定义的设备来拉起对应的driver。第二行用来启动nut服务,第三行用来查询测试nut服务是否和apc连接正常。如果正常的话,第三行会打印出:

skyblond@crescent-rose:~> upsc apc-bk650m2-ch
battery.charge: 100
battery.charge.low: 93
battery.mfr.date: 2001/01/01
battery.runtime: 3011
battery.runtime.low: 120
battery.type: PbAc
battery.voltage: 13.6
battery.voltage.nominal: 12.0
device.mfr: American Power Conversion
device.model: Back-UPS BK650M2-CH
device.serial: 【数据删除】
device.type: ups
driver.debug: 0
driver.flag.allow_killpower: 0
driver.name: usbhid-ups
driver.parameter.pollfreq: 30
driver.parameter.pollinterval: 2
driver.parameter.port: auto
driver.parameter.synchronous: auto
driver.state: quiet
driver.version: 2.8.2
driver.version.data: APC HID 0.100
driver.version.internal: 0.53
driver.version.usb: libusb-1.0.27 (API: 0x100010a)
input.sensitivity: low
input.transfer.high: 278
input.transfer.low: 160
input.voltage: 232.0
input.voltage.nominal: 220
ups.beeper.status: enabled
ups.delay.shutdown: 20
ups.firmware: 294803G -292804G 
ups.load: 9
ups.mfr: American Power Conversion
ups.mfr.date: 2024/03/24
ups.model: Back-UPS BK650M2-CH
ups.productid: 0002
ups.realpower.nominal: 390
ups.serial: 【数据删除】
ups.status: OL
ups.test.result: No test initiated
ups.timer.reboot: 0
ups.timer.shutdown: -1
ups.vendorid: 051d

测试

现在我们拔掉UPS的电源,通过watch -n 5 upsc apc-bk650m2-ch来观测电量低时是否会自动挂起。

第一次测试发现我这个ups很容易就发起Low Battery状态。尽管nut认为电池还有70%的余量,但只要ups发出Low Battery它就会发出关机指令。为了改进这个问题,我们让nut在battery.charge低于battery.charge.low的时候触发挂起。但默认情况下battery.charge.low是93,有点太高了。在ups.conf中修改:

[apc-bk650m2-ch]
       ...
       ignorelb
       override.battery.charge.low = 75

追加一个忽略UPS的低电量通知,然后追加一行override即可把低阈值改为75%,随后重启服务:

sudo service nut restart

拔掉电源,再做测试,发现这次确实是在UPS电量低于75%的时候触发的挂起。

最后我们再来计算一下找到不到设备的时候会发生什么:假如我要带着NUC去别的地方,那肯定不会带UPS。这样一来就会出现NUT在运行,但一直联系不上UPS的状况。经过测试,这种连不上的情况并不会导致异常挂起,但nut-monitor确实会一直尝试刷新。而每次刷新失败都会导致打印一些日志。

解决方法嘛,也很简单:关掉服务就好了。如果不关的话其实也问题不大,无外乎就是打出一大堆日志。但openSUSE对日志大小有限制,不必担心日志写满磁盘。

后记

购入了UPS之后家里有过几次停电。最开始进入了挂起状态却还是没电了,恢复之后发现竟然是UPS没电了,我左思右想,最终发现:虽然笔记本电脑的充电器并没有连着UPS,但是磁带机使用雷电接口接入笔记本,雷电接口是可以提供PD协议快冲的。所以就算是停电了,磁带机本身待机功耗不大,可是它开始用UPS的电给笔记本充电,最终导致UPS电池耗尽。由于磁带机也不常用,现在基本上就是每两周备份的时候使用,因此平时不用的时候都拔掉电源,同时我还把进入挂起的电源电量从25%提高到了75%(之前文章里写的是25,后来改成75了),这样尽最大可能保证进入挂起状态后能够坚持到供电恢复,从而保证不丢数据。

至此,停电再也不是我的心头大患了。

-全文完-


知识共享许可协议
【歪门邪道】使用NUT在Linux上管理UPS天空 Blond 采用 知识共享 署名 - 非商业性使用 - 相同方式共享 4.0 国际 许可协议进行许可。
本许可协议授权之外的使用权限可以从 https://skyblond.info/about.html 处获得。

Archives QR Code
QR Code for this page
Tipping QR Code