前言
由于家里时不时停电,导致群晖里面机械硬盘出现莫名其妙的问题,回家之后整了一个UPS(施耐德APC BK650M2-CH 390W),到货后就开始着手配置,最终实现:UPS电量不足时,ESXI中所有虚拟机安全关机,最后关闭ESXI,即软路由关机.
本文设备: J4125 软路由 4 CPUs x Intel(R) Celeron(R) J4125 CPU @ 2.00GHz
ESXI系统版本: 7.0 Update 3
群晖版本: DSM 7.1-42661 Update 4
USB信息: Celeron/Pentium Silver Processor USB 3.0 xHCI Controller
供应商名称: Intel Corporation
ID: 0000:00:15.0 设备 ID: 0x31a8 供应商 ID: 0x8086 功能: 0x0 总线: 0x0
类 ID: 0xc03 子设备 ID: 0x7270 子供应商 ID: 0x8086 插槽: 0x15

上面照片是我强制直通之后的,因为我这个版本ESXI不兼容这个USB控制器(没驱动).
若你的信息与本文不符,可参考本文内容.
直通USB控制器
注: 若你的ESXI设备能正常识别USB控制器,即插上UPS数据线,你的ESXI能识别出UPS设备(可在添加USB设备界面查看)
获取USB控制器相关信息.
上图可知.供应商ID、设备ID以及类ID分别为 0x8086 0x31a8 0xc03
开启ESXI的SSH功能
开启Secure Shell (SSH)

添加直通代码
1 | ssh root@xxx |
按G,即”shift+g”,跳到文本的最后一个字符,然后按i进入编辑模式,按回车键来换行,然后输入下面内容
1 |
|
其中8086是供应商ID 31a8是设备ID d3d0和default固定值
然后保存退出(esc :wq),并重启启动ESXI(reboot)
配置USB控制器
去管理,硬件,PCI设备中将usb控制器切换为直通.
然后在群晖虚拟机中添加PCI设备.

注意: cpu这3项需要关闭
内存需设置为 全部锁定
配置好后,重启ESXI,然后启动群晖.就能在群晖中配置UPS了!

在常规里面

配置NutClient-ESXi
NutClient-ESXi 可以获取群晖所连接UPS的信息.
首先,将 ESXi 的 IP 添加到允许的 DiskStation 设备中(可参考上图).
接下来开始配置NutClient-ESXi.
下载代码并安装
下面代码运行环境为ESXI中的SHELL
1 | esxcli software acceptance set --level=CommunitySupported |
下面分3种情况
①ESXI不能科学上网
访问此人博客https://rene.margar.fr/2012/05/client-nut-pour-esxi-5-0/
下载NutClient-ESXi (binaires)并解压
将解压后的文件通过SFTP传输到ESXI主机/tmp目录下
然后运行命令sh upsmon-install.sh && /etc/init.d/hostd restart
注: 若你安装过,且安装版本低于即将安装的,~~~~请用命令先卸载sh upsmon-update.sh,否则sh upsmon-remove.sh再安装.
②ESXI能够科学上网
1 | wget 'https://rene.margar.fr/download/1483/?tmstv=1690200590' \ |
③自编译并提供邮件发送支持
请参阅本博客中 自编译 NutClient-ESXI, 更改邮件逻辑 文章
本文不再赘述.
配置服务
通过 GUI 登录 ESXi,然后转到 管理 -> 系统 -> 高级设置,然后查找UserVars.nut并更新等待设置的值

UserVars.NutUpsName:ups@IP地址(此IP地址填群晖的地址)
UserVars.NutUser:monuser
UserVars.NutPassword:secret
1 | UserVars.NutFinalDelay NUT 在发生低电量事件后等待几秒钟才关闭 |
配置完成后,转到 服务 并查找nutclient,找到列出的服务.启动它并设置它与主机一起启动/停止
注: 每次修改UserVars参数后都要重启NutClient服务才能生效
配置防火墙
如图所示,启动并设置自启动.

1 | esxcli network firewall ruleset list | grep NutServer |
验证连接
命令:
1 | /opt/nut/bin/upsc ups@IP地址 |
得到:
1 | /opt/nut/bin/upsc ups@IP地址 |
已知BUG: 部分信息不准确.以及部分信息存在错误.
其中最不能接受的是: battery.charge.low.故建议重写notify.sh文件,参考博客文章 自编译 NutClient-ESXI, 更改邮件逻辑 或者我fork项目 NutClient-ESXi
测试
建议:直接看结论,下面内容又丑又长
实测用群晖NAS能够关闭ups,首先达到battery.charge.low的低电量会发FSD信号,
群晖NAS会进入待机模式,大约等待180秒左右(3分钟)关闭UPS电源(关机逻辑很迷.).故我们可根据这个时间为基准来通过不断实测调整NutFinalDelay值,从而达到在ups关机之前,esxi能安全关机,而不是直接断电.为了达到这个目标,下面是测试记录,测试应进行多次,数据应多次记录,并取平均值,如果出现某些数据差异过大,可采用加权之类操作(默认都会概率论.)
① 在ups电量🔋处于设定的低电量🪫之下时,给ups断开市电⚡️的同时,开始计时⌛️,得到数据📊:xxx..等
② 通过等待⌛️ups电量🔋低于设定的低电量🪫之下时,开始计时⌛️,得到数据📊:xxx..等
综合数据,并不断调整.下面是举例
NutFinalDelay值为170
91->89 耗时85s 群晖不可访问
结束00:01:28总耗时213秒 -> 开始计时(即UPS断电)时间23:57:55 耗时85秒 -> 群晖不可访问模式开始时间23:59:22 耗时128秒 -> UPS断电时间 00:01:28
ESXI在23:58:27同时收到SHUTDOWN和FSD信号 在23:58:22时收到LOWBATT信号 在23:56:00时收到ONBATT信号
测试结果: UPS关机,ESXI未预期关机,NutFinalDelay应小于181,但实际已小于,故该实验数据标记为?
NutFinalDelay值为160 2分40秒
00:32:33 电量为91 00:35:10 丢失群晖ups连接 00:37:21 发生未预期断电,即ESXI未安全关机. 第一阶段2分37秒 第二阶段2分11秒
00:35:? 收到群晖GMAIL邮件 (推测,貌似发这个邮件,代表已向UPS发送关机信号.)
00:52:19 丢失群晖ups连接 00:53:27 UPS关机 耗时1分8秒 NutFinalDelay值调整为100,再次实验.
00:54:31 UPS电量达到91触发低电量 00:55:13 收到群晖邮件 00:55:57 丢失群晖ups连接
结果: esxi达到预期关机效果,ups也关机. 但缺陷是:esxi关机后,ups等待较长时间才会关机,故当esxi关机后,ups在未关机之前,市电恢复供应,那么ups将不会关机,由于ups电源未断过,软路由主板并不会自动开机,这种情况只能改进,无法完善解决(除非你是正版群晖,而不是软路由),因为我们设备并不支持ups,我的建议是调整NutFinalDelay值,直到能将时间差缩短至30秒内(增加时间,减少误差,因为轮训需要时间,而每时每刻这个时机都不一样)
继续实验,NutFinalDelay值调整为120,结果发生非预期事件,esxi安全关机,但ups未关机.但已收到群晖邮件提示,根据观察,ESXI貌似比上一次更快地关机,初步判断为群晖未来得及向ups发送关机指令而被esxi关闭.NutFinalDelay值调整为155并重启NutClient服务,再次实验.
结果: 发生非预期事件,esxi未安全关机,ups关机,NutFinalDelay值调整为140并重启NutClient服务,再次实验.
结果: esxi达到预期安全关机效果,ups也关机.时间差约为8秒符合预期,因未对数据进行更详细记录,再次进行更准确实验.
软路由完全关机到ups断电时间间隔约为10秒.esxi发出关机指令到软路由完全关机用时约23秒,从群晖ups连接断开到esxi发出关机指令用时约95秒.
结果: esxi达到预期安全关机效果,ups也关机.
时间差符合预期,故将NutFinalDelay值调整为148并重启NutClient服务,进行最后一次准确实验,若符合预期则采用该值.
从esxi发出关机指令到ups断电用时约33秒,软路由在关机过程中,ups断电导致未完全关机.
结果: 发生非预期事件,esxi未安全关机,ups关机,NutFinalDelay值调整为143并重启NutClient服务,再次实验.
实验: 在ups电量在低于91的情况下,切断市电并开始计时,用命令行每秒时刻监控群晖ups连接情况,用网页监控esxi发生关机
看计时器可以知道经过2分57秒软路由完全关机 esxi发送关机指令, 翻命令日志开始计算: 06:11:38 UTC丢失群晖ups连接.
06:11:54 UTC对应计时为02:23.76 ESXI发送关机指令时间为 14:12:04 CST.我们可以得到:
断开ups电源到丢失群晖ups连接用时约为127秒 丢失群晖ups连接到ESXI发送关机指令用时约为26秒
易得 断开ups电源到ESXI发送关机指令用时约为153秒,根据我们NutFinalDelay值143可得10秒差.
结果: 发生非预期事件,esxi安全关机,ups未关机,但恢复市电也会重启电源,故软路由也会启动.尝试将NutFinalDelay值调整为145并重启NutClient服务,再次实验.但本次实验采用冷测试,不采用命令监控,网页监控等,模拟真实情况,仅仅做软路由断电时间与ups断电时间记录.由于ups电量未恢复到安全电量之上,故将等待ups电量恢复,当恢复到91以上时,进行断开市电操作.
结果: 应该没问题,误差1秒,故决定将NutFinalDelay值设置为144秒
经过实际测试,发现即使ups恢复市电,esxi和ups也会关机,但ups会重启供电(又测试了一次,不会),故上面提到的缺陷可能不存在.
当NutFinalDelay值设置好后,存在的缺陷是若在esxi未关机之前恢复供电,群晖会重启,但esxi延迟关机缺不会中止,甚至群晖还没来得及启动成功,esxi就关机了.解决办法: 在执行关机命令之前判断群晖的CPU使用是否大于300MHZ,如果大于则代表已恢复供电不进行关机,并启动已关机的虚拟机.
发现,即使ups未关机,恢复市电也会重启电源,故软路由也会重启,所以我上面哪些测试貌似多余的?👉🤡小丑竟是我自己?!(应该是我搞错了?难道是ups里面有定时关机,但还没到时间,然后恢复市电,会重启供电?不清楚,反正现在没大问题了.)
若发现某些数据与数据结果之间产生冲突,通过排查分析,原因可能有 曾安装过旧版程序未使用旧版程的vib序进行卸载,而是直接采用新版程序的vib进行升级,导致某些错误,ESXI未正常关机不会保存设置的NutFinalDelay值数据,修改数值后未能成功重启服务等. 解决并验证,使用旧版程的vib序进行卸载并重启,拉取最新版仓库代码然后编译出文件进行安装,安装后根据本文内容进行设置,设置好后,esxi进行安全关机操作,然后开机看看设置是否生效,修改文件是否成功等.如果修改NutFinalDelay值,建议刷新网页看看修改是否成功,如果重启服务,建议先关闭,再刷新网页看看关闭是否成功再启动 没问题再进行测试.
综上所示,经过多次类似记录与分析,得到基于我的设备的较为稳定且安全的数值结果:
结论
NutFinalDelay值: 144
如果你参阅了本博客中 自编译 NutClient-ESXI, 更改邮件逻辑 文章并使用了自编译的方式,那么在询问你是否(y/n)需要ESXI关机前查询群晖CPU使用情况?的时候,请输入y然后回车即可.
能够达到下面👇的效果
① 市电⚡️一直不恢复↩️
ups🔋到低电量🪫时,群晖会进入待机模式(大概过会就会发送ups延迟关机信号),esxi会(通过ssh调用命令)关闭一些不支持安全关机的设备,等待NutFinalDelay值的时间(实际上不准确,要比这个值大).然后安全关闭esxi和软路由.大概过10秒左右,ups自动关机
② 市电⚡️在群晖待机模式中恢复供电,且群晖还未向ups发送延迟关机信号
这种情况,群晖会重启,那么群晖cpu使用绝对会高于100MHz,而自编译程序中在关机前会对群晖cpu使用情况进行判断,所以将不会关机(你还可以写一些命令来启动一些被关闭的虚拟机).待群晖启动后,能给esxi upsmon提供ups信息.
③ 市电⚡️在群晖待机模式中恢复供电,且群晖已向ups发送延迟关机信号
这种情况,群晖不会重启,因为ups将会延迟关机,我们只需等待esxi和软路由安全关闭后,再等待大概10秒左右,ups将重启电源.如果你在软路由主板中设置了来电启动,那么将成功自启动.
效果预览
没有实际预览,贴几张邮件图吧(注:来自自编译的方式).

可能用到的垃圾代码:
1 | while true; do sleep 1; echo $(date);/opt/nut/bin/upsc ups@IP地址 battery.charge ;done |














