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 配置
图 1 施奈德后备式UPS电源APC BK650M2。
虽然施奈德官方提供的 PowerChute 软件只支持 Windows 系统,但 Linux 下亦有 apcupsd
可以使用。该软件以守护进程的方式运行,通过串行数据通信的方式(串口或 USB )实时获取 UPS 电源信息,包括当前外部输入电压、负载功率、电池电量等。当电池电量低于指定值时,会自动运行脚本程序 /etc/apcupsd/apccontrol
,以实现电脑系统的自动关闭或任何用户指定的操作。
把 UPS 电源与电脑连好后,根据 apcupsd
的说明文档 ,我们首先使用 lsusb
命令检查 Linux 系统是否能检测到已连接的 UPS 电源。
$ lsusb | grep Uninterruptible
Bus 002 Device 004 : ID 051d : 0002 American Power Conversion Uninterruptible Power Supply
确认能够找到设备后。
安装:
$ sudo apt install apcupsd
编辑 apcupsd
的配置文件 /etc/apcupsd/apcupsd.conf
,将其中 UPSCABLE
与 UPSTYPE
两项均设为 usb
。
因为台式机与 UPS 电源之间是通过 USB 通讯的,所以需要注释掉配置文件中的串口设置部分:
将 NISIP
值设为 0.0.0.0
或你想绑定的指定主机 IP
其余保持默认即可。
至此,可以启动 apcupsd
系统服务了。
$ 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
客户端配置:
安装:
$ sudo apt install apcupsd
打开 apcupsd 配置文件 /etc/apcupsd/apcupsd.conf
将 UPSCABLE
值设为 ether
将 UPSTYPE
值设为 net
将 DEVICE
值设为你的 apcupsd 服务端地址和端口(也就是和 UPS 以 USB 相连接的主机)
与 NIS 相关的设置保持默认(也就是保持 NETSERVER
为 on
)
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配置。
安装
apt update && apt install - y nut
通过 USB 连接 UPS
在将 UPS 通过 USB 连接到树莓派后,可以通过查看 USB 设备进行检查
其中的 Device 003 就是 UPS,说明 USB 连接正常
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
正确识别到连接的 UPS 设备,驱动为 usbhid-ups
,产品为 SANTAK TG-BOX
[ nutdev1 ]
driver = "usbhid-ups"
port = "auto"
vendorid = "0463"
productid = "FFFF"
product = "SANTAK TG-BOX"
serial = "Blank"
vendor = "EATON"
bus = "001"
或者如下:
[ 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设备建立连接,并获取有关电源状态、电池状态和其他参数的信息
使用 nut-scanner
将连接的 UPS 信息追加到 /etc/nut/ups.conf
配置中,其中的 nutdev1
是设备的名称,可以自定义
sudo nut - scanner - q | sudo tee - a / etc / nut / ups .conf
使用 upsdrvctl
命令启动 NUT
配置 UPS 守护进程
upsd 负责与UPS设备通信,并将UPS状态信息提供给其他NUT组件和客户端
# 配置NUT为UPS服务器模式
sudo sed - i "s/^MODE=.*/MODE=netserver/g" / etc / nut / nut .conf
sudo upsd
查看 UPS 状态
使用 upsc
命令查看 UPS 设备的状态;其中的 nutdev1
是 /etc/nut/ups.conf
中配置的名称
sudo upsc nutdev1 @ localhost
该命令会返回 UPS 设备的所有信息
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 状态
sudo upsc nutdev1 @ localhost ups .status
Init SSL without certificate database
OL
配置关机策略
配置 upsd 用户
upsd 用户对应的配置文件是 /etc/nut/upsd.users
,配置用户用于读取 UPS的信息;在以下配置中,用户名是 upsmon
,密码是 123456
,运行模式是 master
,即该设备为主节点(如果有同时使用其他 UPS则可以是 slave
)
[ upsmon ]
password = "123456"
upsmon master
配置关机策略
关机策略使用的是 upsmon,upsmon 监控守护进程用于监视UPS状态,并在检测到电力问题时执行操作,它可以配置为执行自定义脚本、关闭计算机或发送警报通知
修改 /etc/nut/upsmon.conf
,添加如下配置,使用的是刚才创建的用户信息,这样,当设备监听到 UPS 发出的 LOWBATT
命令后,就会执行关闭系统
MONITOR ups @ localhost 1 monuser 123456 master
这个命令告诉NUT要监控名为 “ups” 的UPS设备,该设备位于本地主机上。监控用户 “monuser”,可以使用密码 “123456” 连接到NUT,并具有 “master” 角色的权限。这允许用户通过NUT连接来监视和管理UPS设备
执行自定义动作
NUT 通过 upssched
支持监听 UPS 事件并执行指定脚本,因此可以用于执行一些自定义的动作,如发送通知等
配置 upsmon
修改 /etc/nut/upsmon.conf
文件,添加如下配置
该配置用于在发生事件时运行 /sbin/upssched
服务
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
中
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
事件,则取消计时器
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 日志
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
指定了日志输出格式
输出日志参考:
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 的状态;如果不需要监听则不需要配置
配置 upsd
修改 upsd 对应的配置文件 /etc/nut/upsd.conf
,添加监听的地址和端口;添加局域网 IP 是用于局域网内其他设备进行监控,否则可能会拒绝连接
LISTEN 127.0.0.1 3493
LISTEN :: 1 3493
LISTEN 0.0.0.0 3493
sudo upsd - c reload
sudo reboot
配置 NUT Exporter
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"
Server 的地址即为树莓派局域网的IP地址,用户名和密码是 upsd 的用户和密码;NUT_EXPORTER_VARIABLES
是需要抓取的监控指标类型,不同的设备可能指标不一样;可以通过 upsc ups@localhost
获取所有的指标名称进行替换
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
- 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
导入 https://github.com/helloworlde/nut_exporter/blob/master/dashboard/dashboard.json 即可
参考链接