UPS (Uninterruptible Power Supply),是一种含有储能装置的不间断电源。主要用于给部分对电源稳定性要求较高的设备,提供不间断的电源。
一般的 UPS 都支持通过 USB 连接到电脑或者 NAS 等设备上,Linux/Mac/Windows 均支持使用 UPS。
因为电路不稳定,存在偶尔断电的情况,因此希望通过 UPS 保护树莓派、路由器、光猫、硬盘录像机等设备;将 UPS 通过 USB 接口连接到树莓派,由树莓派控制其他设备在断电时关机。
当前主要有两个方案,一个是 NUT(Network UPS Tools) 另一个是使用 apcupsd (Apcupsd UPS control software),两者二选一即可。
如果是群晖,可能只有使用 NUT(Network UPS Tools) ,如果使用 U-NAS 可能只能使用 apcupsd (Apcupsd UPS control software)。
从配置简便性上,推荐 apcupsd (Apcupsd UPS control software)。
apcupsd 配置
虽然施奈德官方提供的 PowerChute 软件只支持 Windows 系统,但 Linux 下亦有 apcupsd
可以使用。该软件以守护进程的方式运行,通过串行数据通信的方式(串口或 USB )实时获取 UPS 电源信息,包括当前外部输入电压、负载功率、电池电量等。当电池电量低于指定值时,会自动运行脚本程序 /etc/apcupsd/apccontrol
,以实现电脑系统的自动关闭或任何用户指定的操作。
把 UPS 电源与电脑连好后,根据 apcupsd
的说明文档,我们首先使用 lsusb
命令检查 Linux 系统是否能检测到已连接的 UPS 电源。
1 2 |
$ lsusb | grep Uninterruptible Bus 002 Device 004: ID 051d:0002 American Power Conversion Uninterruptible Power Supply |
确认能够找到设备后。
安装:
1 |
$ sudo apt install apcupsd |
编辑 apcupsd
的配置文件 /etc/apcupsd/apcupsd.conf
,将其中 UPSCABLE
与 UPSTYPE
两项均设为 usb
。
1 2 |
UPSCABLE usb UPSTYPE usb |
因为台式机与 UPS 电源之间是通过 USB 通讯的,所以需要注释掉配置文件中的串口设置部分:
1 |
DEVICE /dev/ttyS0 |
将 NISIP
值设为 0.0.0.0
或你想绑定的指定主机 IP
1 |
NISIP 0.0.0.0 |
其余保持默认即可。
至此,可以启动 apcupsd
系统服务了。
1 |
$ sudo systemctl restart apcupsd |
该服务启动后,除了正常的 UPS 电源实时监测外,还会在本机的端口上开启一个服务器。我们可以在命令行终端使用apcaccess
命令来获得电源的运行状态。其中的主要参数为:
-
LINEV
:线电压 -
LOADPCT
:负载占比 -
TIMELEFT
:电池剩余维持时间 -
LOTRANS
:最低容许输入电压 -
HITRANS
:最高容许输入电压 -
BATTV
:电池输出电压 -
NOMPOWER
:额定功率
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
$ sudo apcaccess status APC : 001,036,0870 DATE : 2021-09-03 13:09:29 +0800 HOSTNAME : [YOUR-HOST-NAME] VERSION : 3.14.14 (31 May 2016) debian UPSNAME : [YOUR-UPS-NAME] CABLE : USB Cable DRIVER : USB UPS Driver UPSMODE : Stand Alone STARTTIME: 2021-09-03 13:03:24 +0800 MODEL : Back-UPS BK650M2-CH STATUS : ONLINE LINEV : 226.0 Volts LOADPCT : 20.0 Percent BCHARGE : 100.0 Percent TIMELEFT : 29.9 Minutes MBATTCHG : 5 Percent MINTIMEL : 3 Minutes MAXTIME : 0 Seconds SENSE : Low LOTRANS : 160.0 Volts HITRANS : 278.0 Volts ALARMDEL : 30 Seconds BATTV : 13.5 Volts LASTXFER : No transfers since turnon NUMXFERS : 0 TONBATT : 0 Seconds CUMONBATT: 0 Seconds XOFFBATT : N/A SELFTEST : OK STATFLAG : 0x05000008 SERIALNO : 000000000000 BATTDATE : 2001-01-01 NOMINV : 220 Volts NOMBATTV : 12.0 Volts NOMPOWER : 390 Watts FIRMWARE : 294803G -292804G END APC : 2021-09-03 13:09:39 +0800 |
客户端配置:
安装:
1 |
$ sudo apt install apcupsd |
打开 apcupsd 配置文件 /etc/apcupsd/apcupsd.conf
- 将
UPSCABLE
值设为ether
- 将
UPSTYPE
值设为net
- 将
DEVICE
值设为你的 apcupsd 服务端地址和端口(也就是和 UPS 以 USB 相连接的主机)
与 NIS 相关的设置保持默认(也就是保持 NETSERVER
为 on
)
1 2 3 4 |
# 示例配置 UPSCABLE ether UPSTYPE net DEVICE 10.10.10.125:3551 |
启动 apcupsd 服务,输入 apcaccess
命令,你应该能看到 apcupsd 输出电源信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
$ sudo systemctl restart apcupsd $ sudo apcaccess status APC : 001,035,0891 DATE : 2024-10-01 12:45:29 +0800 HOSTNAME : hpgen8 VERSION : 3.14.14 (31 May 2016) debian UPSNAME : raspberrypi CABLE : Ethernet Link DRIVER : NETWORK UPS Driver UPSMODE : Stand Alone STARTTIME: 2024-10-01 12:45:29 +0800 MASTERUPD: 2024-10-01 12:45:29 +0800 MASTER : 10.10.10.125:3551 MODEL : Back-UPS 650 STATUS : ONLINE SLAVE LINEV : 224.0 Volts LOADPCT : 36.0 Percent BCHARGE : 100.0 Percent TIMELEFT : 3.4 Minutes MBATTCHG : 5 Percent MINTIMEL : 3 Minutes MAXTIME : 0 Seconds SENSE : Low LOTRANS : 165.0 Volts HITRANS : 266.0 Volts BATTV : 13.6 Volts LASTXFER : Unacceptable line voltage changes NUMXFERS : 0 TONBATT : 0 Seconds CUMONBATT: 0 Seconds XOFFBATT : N/A STATFLAG : 0x05000408 SERIALNO : ********** BATTDATE : 2018-11-04 NOMINV : 220 Volts NOMBATTV : 12.0 Volts FIRMWARE : 822.A3.I USB FW:A3 END APC : 2024-10-01 12:45:31 +0800 |
NUT 配置
安装 NUT
NUT (Network UPS Tools) 是一种开源软件工具,其主要功能特点是实时监控与管理不间断电源(UPS)设备,支持多种通信协议,自动执行操作以应对电力故障,适用于多平台,并允许集中管理多个UPS设备,以确保与这些设备连接的计算机和设备在电力问题发生时能够继续正常运行或安全关闭。
NUT中的主要软件组件和功能:
-
Driver(驱动程序):NUT包括各种不同制造商的UPS设备的驱动程序,使NUT能够与多种型号的UPS设备通信。这些驱动程序负责与UPS设备建立连接,并获取有关电源状态、电池状态和其他参数的信息。
-
upsd(UPS守护进程):upsd是NUT的核心守护进程,负责与UPS设备通信,并将UPS状态信息提供给其他NUT组件和客户端。它可以通过网络协议(如SNMP、HTTP、XML-RPC等)向其他计算机提供UPS状态信息。
-
upsmon(UPS监控守护进程):upsmon监控守护进程用于监视UPS状态,并在检测到电力问题时执行操作。它可以配置为执行自定义脚本、关闭计算机或发送警报通知,以确保系统的连续性和数据完整性。
-
upslog(UPS事件记录器):upslog用于记录UPS事件和状态信息,以便后续分析和故障排除。它可以生成日志文件,其中包含UPS的运行历史和电力事件。
-
nutclient(NUT客户端工具):NUT提供了一些用于监控和管理UPS的命令行工具,例如upsc用于查询UPS状态,upscmd用于发送命令到UPS,以及upsrw用于修改UPS配置。
-
安装
1 |
apt update && apt install -y nut |
通过 USB 连接 UPS
在将 UPS 通过 USB 连接到树莓派后,可以通过查看 USB 设备进行检查
- 检查 USB 连接
1 |
sudo lsusb |
其中的 Device 003 就是 UPS,说明 USB 连接正常
1 2 3 4 5 6 7 |
Bus 001 Device 004: ID 051d:0002 American Power Conversion Uninterruptible Power Supply Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 002 Device 002: ID 174c:55aa ASMedia Technology Inc. ASM1051E SATA 6Gb/s bridge, ASM1053E SATA 6Gb/s bridge, ASM1153 SATA 3Gb/s bridge, ASM1153E SATA 6Gb/s bridge Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub Bus 001 Device 003: ID 0463:ffff MGE UPS Systems UPS Bus 001 Device 002: ID 2109:3431 VIA Labs, Inc. Hub Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub |
- 通过
nut-scanner
检查 UPS 设备
1 |
sudo nut-scanner -q |
正确识别到连接的 UPS 设备,驱动为 usbhid-ups
,产品为 SANTAK TG-BOX
1 2 3 4 5 6 7 8 9 |
[nutdev1] driver = "usbhid-ups" port = "auto" vendorid = "0463" productid = "FFFF" product = "SANTAK TG-BOX" serial = "Blank" vendor = "EATON" bus = "001" |
或者如下:
1 2 3 4 5 6 7 8 9 |
[nutdev1] driver = "usbhid-ups" port = "auto" vendorid = "051D" productid = "0002" product = "Back-UPS 650 FW:822.A3.I USB FW:A3" serial = "**********" vendor = "APC" bus = "001" |
配置 UPS
###配置 UPS 驱动
驱动程序负责与UPS设备建立连接,并获取有关电源状态、电池状态和其他参数的信息
- 将 UPS 设备添加到 NUT
使用 nut-scanner
将连接的 UPS 信息追加到 /etc/nut/ups.conf
配置中,其中的 nutdev1
是设备的名称,可以自定义
1 |
sudo nut-scanner -q | sudo tee -a /etc/nut/ups.conf |
- 启动 NUT
使用 upsdrvctl
命令启动 NUT
1 |
sudo upsdrvctl start |
配置 UPS 守护进程
upsd 负责与UPS设备通信,并将UPS状态信息提供给其他NUT组件和客户端
- 启动 upsd
1 2 3 4 |
# 配置NUT为UPS服务器模式 sudo sed -i "s/^MODE=.*/MODE=netserver/g" /etc/nut/nut.conf sudo upsd |
查看 UPS 状态
使用 upsc
命令查看 UPS 设备的状态;其中的 nutdev1
是 /etc/nut/ups.conf
中配置的名称
1 |
sudo upsc nutdev1@localhost |
该命令会返回 UPS 设备的所有信息
1 2 3 4 5 6 7 8 9 |
Init SSL without certificate database battery.charge: 98 battery.charge.low: 20 battery.runtime: 2744 battery.type: PbAc device.mfr: EATON device.model: SANTAK TG-BOX 600 device.serial: Blank ... |
也可以指定名称查看 UPS 状态
1 |
sudo upsc nutdev1@localhost ups.status |
1 2 |
Init SSL without certificate database OL |
配置关机策略
配置 upsd 用户
upsd 用户对应的配置文件是 /etc/nut/upsd.users
,配置用户用于读取 UPS的信息;在以下配置中,用户名是 upsmon
,密码是 123456
,运行模式是 master
,即该设备为主节点(如果有同时使用其他 UPS则可以是 slave
)
1 2 3 |
[upsmon] password = "123456" upsmon master |
- 重启 upsd
1 |
sudo upsd -c reload |
配置关机策略
关机策略使用的是 upsmon,upsmon 监控守护进程用于监视UPS状态,并在检测到电力问题时执行操作,它可以配置为执行自定义脚本、关闭计算机或发送警报通知
- 配置关机策略
修改 /etc/nut/upsmon.conf
,添加如下配置,使用的是刚才创建的用户信息,这样,当设备监听到 UPS 发出的 LOWBATT
命令后,就会执行关闭系统
1 |
MONITOR ups@localhost 1 monuser 123456 master |
这个命令告诉NUT要监控名为 “ups” 的UPS设备,该设备位于本地主机上。监控用户 “monuser”,可以使用密码 “123456” 连接到NUT,并具有 “master” 角色的权限。这允许用户通过NUT连接来监视和管理UPS设备
- 启动 upsmon
1 |
sudo upsmon |
执行自定义动作
NUT 通过 upssched
支持监听 UPS 事件并执行指定脚本,因此可以用于执行一些自定义的动作,如发送通知等
配置 upsmon
修改 /etc/nut/upsmon.conf
文件,添加如下配置
- 指定运行命令
该配置用于在发生事件时运行 /sbin/upssched
服务
1 |
NOTIFYCMD /sbin/upssched |
- 配置触发条件
1 2 3 |
NOTIFYFLAG ONLINE SYSLOG+WALL+EXEC NOTIFYFLAG ONBATT SYSLOG+WALL+EXEC NOTIFYFLAG LOWBATT SYSLOG+WALL+EXEC |
这里监听了 ONLINE
, ONBATT
, 和 LOWBATT
三个事件,分别是电源供电、电池供电和低电量事件;SYSLOG
声明记录事件日志到系统中,WALL
声明通知所有在线用户,EXEC
声明需要执行命令
配置 upssched
配置好 upsmon 后,还需要配置 upssched 执行相关的命令,需要将以下内容添加到 /etc/nut/upssched.conf
中
- 配置 upsmon
1 2 3 4 5 6 7 8 9 10 |
CMDSCRIPT /usr/local/bin/upssched-script.sh PIPEFN /run/nut/upssched/upssched.pipe LOCKFN /run/nut/upssched/upssched.lock AT ONBATT * EXECUTE battery_on # 发送断电的消息 AT ONLINE * EXECUTE power_online # 发送来电的消息 AT ONBATT * START-TIMER watch_battery 60 # 60 秒后执行监控电池状态 AT ONLINE * CANCEL-TIMER watch_battery # 取消 监控电池状态 AT LOWBATT * EXECUTE low_battery # 低电量 |
CMDSCRIPT
指定了监听到事件后需要执行的脚本 PIPEFN
和LOCKFN
指定了监听事件的管道并加锁,避免被修改 AT
和 EXECUTE
指定了监听的事件并执行相关的脚本;当监听到 ONBATT
, ONLINE
和 LOWBATT
时执行 CMDSCRIPT
指定的脚本,并将 battery_on
, power_online
和 low_battery
作为参数 AT
和 START-TIMER
启动了一个计时器,在 60s 后执行 AT
和 CANCEL-TIMER
指定如果在启动计时器60s 内发生了 ONLINE
事件,则取消计时器
- 配置 upssched-script.sh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
#!/bin/bash BARK_URL=${BARK_URL:-"https://api.day.app/xxxxxx"} function send_message() { message="$1" echo "发送通知:${message}" curl -X "POST" "$BARK_URL" \ -H 'Content-Type: application/json; charset=utf-8' \ -d "{ \"title\": \"UPS 状态发生变化\", \"body\": \"${message}\", \"group\": \"UPS\" }" } case $1 in battery_on) battery_charge=$(upsc ups@localhost battery.charge) send_message "UPS 电池已启用,目前电量: ${battery_charge}" ;; power_online) battery_charge=$(upsc ups@localhost battery.charge) send_message "UPS 已恢复供电,目前电量: ${battery_charge}" ;; watch_battery) battery_charge=$(upsc ups@localhost battery.charge) send_message "UPS 目前电量: ${battery_charge}" ;; low_battery) battery_charge=$(upsc ups@localhost battery.charge) send_message "UPS 低电量: ${battery_charge},开始关机" ;; *) logger -t upssched-cmd "其他未知指令: $1" ;; esac |
这段脚本用于接收事件,并执行动作;这里通过 Bark 发送了通知
记录 UPS 日志
ups 支持通过 upslog
记录 UPS 日志
1 |
sudo upslog -l /var/log/ups.log -i 1 -s ups@localhost -f "%TIME @Y-@m-@d @H:@M:@S%, battery.charge:%VAR battery.charge%, input.voltage:%VAR input.voltage%, ups.load:%VAR ups.load%, ups.status:[%VAR ups.status%], ups.temperature:%VAR ups.temperature%, input.frequency:%VAR input.frequency%" |
这段命令中,通过 -l
指定了输出文件为 /var/log/ups.log
,-i 1
表示1s输出一次,-s ups@localhost
指定了 UPS 位置,-f
指定了日志输出格式
输出日志参考:
1 |
2023-10-06 19:58:38, battery.charge:78, input.voltage:NA, ups.load:8, ups.status:[OL], ups.temperature:NA, input.frequency:NA |
配置 UPS 监控
NUT 支持通过 HTTP 接口对外提供 UPS 的信息,因此可以用于监控 UPS; https://github.com/helloworlde/nut_exporter 提供了 Prometheus Exporter,可以使用 Prometheus 和 Grafana 对 UPS 进行监控
修改 NUT 运行模式
配置文件是 /etc/nut/nut.conf
;将模式修改为 netserver
的目的是允许通过局域网访问 UPS 的设备信息,用于其他设备监控、监听 UPS 的状态;如果不需要监听则不需要配置
1 |
MODE=netserver |
配置 upsd
修改 upsd 对应的配置文件 /etc/nut/upsd.conf
,添加监听的地址和端口;添加局域网 IP 是用于局域网内其他设备进行监控,否则可能会拒绝连接
1 2 3 |
LISTEN 127.0.0.1 3493 LISTEN ::1 3493 LISTEN 0.0.0.0 3493 |
- 重启 upsd
1 2 3 |
sudo upsd -c reload sudo reboot |
配置 NUT Exporter
- 配置
docker-compose.yaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
version: "3" services: nut-exporter: image: hellowoodes/nut-exporter container_name: nut-exporter hostname: nut-exporter restart: unless-stopped command: --log.level=debug ports: - "9199:9199" environment: - NUT_EXPORTER_SERVER=${NUT_EXPORTER_SERVER} - NUT_EXPORTER_USERNAME=${NUT_EXPORTER_USERNAME} - NUT_EXPORTER_PASSWORD=${NUT_EXPORTER_PASSWORD} - NUT_EXPORTER_VARIABLES=${NUT_EXPORTER_VARIABLES} volumes: - "/etc/localtime:/etc/localtime:ro" |
- 配置
.env
Server 的地址即为树莓派局域网的IP地址,用户名和密码是 upsd 的用户和密码;NUT_EXPORTER_VARIABLES
是需要抓取的监控指标类型,不同的设备可能指标不一样;可以通过 upsc ups@localhost
获取所有的指标名称进行替换
1 2 3 4 |
NUT_EXPORTER_SERVER=192.168.31.11 NUT_EXPORTER_USERNAME=monuser NUT_EXPORTER_PASSWORD=123456 NUT_EXPORTER_VARIABLES=battery.charge,battery.charge.low,battery.runtime,battery.type,device.mfr,device.model,device.serial,device.type,driver.name,driver.parameter.pollfreq,driver.parameter.pollinterval,driver.parameter.port,driver.parameter.product,driver.parameter.productid,driver.parameter.serial,driver.parameter.synchronous,driver.parameter.vendor,driver.parameter.vendorid,driver.version,driver.version.data,driver.version.internal,input.transfer.high,input.transfer.low,outlet.1.desc,outlet.1.id,outlet.1.status,outlet.1.switchable,outlet.desc,outlet.id,outlet.switchable,output.frequency.nominal,output.voltage,output.voltage.nominal,ups.beeper.status,ups.delay.shutdown,ups.delay.start,ups.firmware,ups.load,ups.mfr,ups.model,ups.power.nominal,ups.productid,ups.serial,ups.status,ups.timer.shutdown,ups.timer.start,ups.type,ups.vendorid |
- 配置 Prometheus
1 2 3 4 5 6 7 8 9 |
- job_name: ups-exporter honor_timestamps: true scrape_interval: 15s scrape_timeout: 10s metrics_path: /ups_metrics scheme: http static_configs: - targets: - 192.168.31.11:9199 |
- 配置 Grafana 面板
导入 https://github.com/helloworlde/nut_exporter/blob/master/dashboard/dashboard.json 即可