☰
基于SNMP与开源组件的UPS实时监测系统搭建指南
2026/10/22 2:50:19 网站建设 项目流程

1. 为什么手术室停电不是小事,UPS监测到底在防什么

先说个真实的场景。我去年配合某地医院的机电科室做能源管理改造,当时在手术室做负荷侧调研,麻醉科主任的一句话让我印象很深:“我们最怕的不是术中出血,而是术中停电。”他说的是灯灭了可以忍几秒,但麻醉机停转、监护仪黑屏、电刀停摆,这几秒就是生命危险。医院配电通常有双回路,但双回路切换有动作时间,UPS是那个“无缝续命”的角色。可问题在这里:UPS有没有电,电池还能撑多久,是不是已经悄悄挂掉了一块,很多医院其实是不知道的。

这也是我为什么想把这个项目写出来。手术室所在的关键区域,常规做法是配备大容量UPS(不间断电源,Uninterruptible Power Supply)给生命支持类设备供电。但UPS本身是一个“被动待命”的装置,平时电力正常时它看起来一切安好,一旦真正断电,它能否撑住、能撑多久、负载在什么水平,这些完全取决于它内部电池的健康状态和实时剩余电量。而这两个参数,恰恰是日常巡检中最容易被忽略、也最难靠人工及时掌握的。

我做的是一个完全基于开源组件的能源监测方案,核心就想干一件事:把手术室这边UPS的实时数据——包括输入输出电压、负载率、电池剩余容量、电池温度、预估后备时间——全部采集上来,汇聚到一个监测面板上,按阈值触发告警。它不是要替代现有的配电监控,而是把UPS从“失控的黑盒”变成“可视、可判、可预警”的白盒。实测下来,这套东西从安装到跑通,一个熟悉Linux的工程师一两天就够。

适合谁来参考?医院后勤/机电信息科的工程师、做医疗行业物联网集成的朋友、以及那些机房里有大量UPS但一直靠脚去巡检的IT运维。这篇文章我会把架构选型、数据采集配置、告警规则设计、以及我在现场踩过的坑,全部拆开讲透。代码、参数都给齐,你照着搭就能用。

2. 整体设计思路:先想清楚要采什么、怎么采、给谁看

2.1 医院环境下UPS监测的三种常规路子,我为什么选了开源

在确定方案之前,我先把市面上常见的三类做法理了一遍。

第一种是用UPS原厂自带的监控管理卡。绝大多数中高端UPS都支持加装SNMP卡或Modbus卡,原厂也有一套自己的监控软件。这套路子的优点是即插即用,读取的协议和参数都是原厂做过适配的,准确性有保障。但缺点是致命的:每台UPS要单独买卡,贵的品牌一块卡上万块很常见;而且不同品牌、不同型号的UPS,管理软件不互通。在一家三甲医院的手术中心,UPS可能有十台以上,来自三四个品牌,你等于要维护三四套孤岛系统,告警阈值、账号体系、展示界面五花八门。后勤的老师最怕这种局面,一个故障要开三个软件才能确认。

第二种是走智能配电柜/动环监控的集成方案。就是找做动环的集成商,把UPS的RS485/RS232口接进采集器,汇总到一套商业动环平台里。这个方案的好处是集中,整个配电间的温湿度、漏水、烟感、UPS全在一张图里。但动环平台的项目制味道很浓,按点位收费,一个点位一年几百到上千,十几个点位算下来是个不小的运营开支;而且手术室因为洁净分区和电磁屏蔽要求,很多弱电点位不一定允许你放开去铺线。

第三种,也就是我最终采用的思路:基于SNMP协议,用开源采集器把UPS数据拉出来,存进时序数据库,用开源可视化面板出图,再用开源告警组件做阈值推送。这套组合在IT机房监控领域几乎算标配,但把它搬到医院手术室场景,并且拿来做“供电保障”而不是“网络设备监控”,价值就被重新发现了。

需要说明的是,有一些UPS由于型号偏老,走不了SNMP,只能提供RS485的Modbus RTU接口。这种情况我后面会讲兼容方案,项目里我也做了处理。这里先把最典型的SNMP方案讲透。

2.2 系统分层和核心数据流:从UPS到手机告警短信一共经过几道关

整个系统我拆成了四层,每一层的职责边界都很清晰。

第一层是数据采集层。医院手术室里的UPS通过随机附带的SNMP网卡或者单独的SNMP管理卡,接到医院的弱电交换机上。这边我统一让工程同事把UPS的网线划到设备网VLAN里,不给它暴露到办公网,安全性是第一位的。采集器用snmp_exporter,按预设的OID去抓UPS的MIB库数据。绝大多数UPS都支持标准的UPS MIB(RFC 1628),品牌型号不同OID可能略有差异,但核心几项——输入电压、输出电压、电池容量、电池电压、负载率、预估后备时间——都在这套MIB里,非常通用。

第二层是存储与计算层。抓回来的指标别直接扔数据库,因为我这里是按秒级去抓的,长期跑下去数据量会膨胀得很快。我用的方案是Prometheus搭配Mimir做长期存储后端,但如果你只是想跑个最小可用版本,单机Prometheus配好保留策略就够。时序模型的好处在于,电压、容量这些指标天然带时间维度,出趋势图、做阈值判断都非常顺手。

第三层是可视化层,用Grafana。这块没什么神秘感,但有一个设计原则我想单拎出来说:视图一定要按角色分。电工师傅想看的是“电池还有多少电、还能撑多久”;护士长关心的是“今天有没有异常报警”;科室主任关心的是“过去一个月断电了几次、UPS介入了几次”。如果全堆在一个大屏上,谁都找不到重点。我在项目里就做了三个Dashboard:实时总览、电池健康趋势、告警事件回顾。

第四层是告警通知层。这里我用Alertmanager统一管理,把告警路由到企业微信机器人、短信网关和邮件三个渠道。优先级不一样,通知方式也不一样:电池容量低于30%这种严重告警,必须走短信+电话语音;充电异常这种次严重告警,走企业微信就够。

数据流大概是这样的:UPS网卡每30秒被snmp_exporter拉一次指标,Prometheus每1分钟做一次规则评估,命中阈值就推给Alertmanager,由它按路由规则把人找出来提醒。从UPS数据变化到人收到告警,全链路延迟不超过两分钟。

3. 核心细节拆解:UPS的哪些参数值得盯、阈值怎么定才不狼来了

3.1 必采参数清单:不是OID越多越好,关键是盯准六个指标

医院手术室UPS的参数,MIB库里能拉出来的有几十项,但我实际配置下来,真正值得建告警的,也就六项。我把它们的英文标识、含义、以及我使用的阈值策略对照列一下。

指标名含义我用的阈值策略
upsInputVoltage输入电压低于198V或高于242V触发“输入异常”提示,连续3次采样才告警
upsOutputVoltage输出电压低于215V或高于230V需要关注,逆变状态异常立即告警
upsBatteryCapacity电池剩余容量低于50%预警告警,低于30%严重告警
upsBatteryVoltage电池组端电压偏离标称电压15%以上判定异常
upsLoadPercent负载率持续15分钟超过70%触发告警,因为带载过高会缩短后备时间
upsEstimatedMinutesRemaining预估后备时间低于10分钟触发紧急告警,低于5分钟连发三次

你以为电池容量是最该盯的?其实后两项——负载率和预估后备时间——才是手术室场景下最容易出幺蛾子的地方。我见过一个案例:某手术间同时开了四五台高功耗设备,UPS负载跑到90%以上,电池看着还有80%,但真断电了可能三分钟就顶不住。容量百分比高会给你一种安全的错觉,但负载率一高,放电曲线断崖式下跌。所以我在Dashboard上把这两个指标并排展示,并且专门加了一个“安全供电余量”的计算:用预估后备时间乘负载率系数,数值低于15分钟就标红。

3.2 阈值怎么设?连续N次采样才告警,避免单次抖动误报

告警阈值设计这件事,我吃了不少亏。

一开始我把容量低于50%的告警规则设成单次命中就触发,结果隔三差五半夜两三点响一次。排查下来,发现是UPS在自检或电池浮充切换的瞬间,容量采样值会有一个短暂的“抖动”,比如87%瞬间掉到49%又弹回88%。这种抖动如果不做滤波,就是告警轰炸,狼来了喊多了,真正出事反而没人当回事。

解决办法是给告警加时间维度:连续3次采样(也就是90秒)都低于阈值才触发。对电压这类变化快的量,我用连续2次;对容量这种变化慢的量,我用连续3到4次。Prometheus的规则配置里,可以这样写:

groups: - name: ups_alerts rules: - alert: UpsBatteryCapacityLow expr: | ups_battery_capacity_percent < 50 and (changes(ups_battery_capacity_percent[3m]) < 3) for: 3m labels: severity: warning annotations: summary: "UPS电池容量偏低" description: "{{ $labels.instance }} 电池容量低于50%"

for: 3m这个关键字才是防抖的功臣,它要求告警条件持续满足3分钟才算触发,临时抖动直接跳过。

关于阈值本身,不同品牌的UPS放电特性有差异,我给的是一组比较稳妥的初值。你落地的时候,建议先跑两周看基线数据,再回头调阈值。比如某台UPS长期带载只有20%,那它的容量低于50%可能意味着电池真的老化了;但如果这台UPS本来就在重载场景下运行,容量跌得快,阈值就得相应放宽,不然容易误报。

3.3 为什么我坚持要把预估后备时间也纳入告警?讲讲我亲历的一次“虚惊”

有一次现场培训,我把模拟断电测试做给后勤的老师看——直接断掉UPS的输入电,让它切到电池逆变。这时候UPS的实时曲线里,输入电压瞬间变0,输出电压稳定在220V左右,负载率跳到60%,预估后备时间显示57分钟。看着好像一切尽在掌握,但第二分钟的时候,预估后备时间从57分钟掉到23分钟,第三分钟掉到11分钟。

原因不复杂:这组电池已经有老化迹象,内阻升高,负载一上去放电曲线陡降。如果不看这个指标,单看容量百分比,前几分钟它可能还显示85%呢,会给人一种“撑得住”的感觉。可实际后备时间已经崩得很快了。

所以我把“预估后备时间小于10分钟”设成P1级的紧急告警,直接会触发短信和电话语音。这个指标含有UPS自己根据放电曲线做的估算,虽然各家算法不同,不一定精确,但趋势变化非常有参考意义。你不需要完全依赖它的绝对值,只要它出现“非线性的快速下跌”,基本能说明电池或负载有一方出了问题。

4. 实操过程:从零部署一套手术室UPS监测系统

4.1 一个小主机加一个网段:整套系统的硬件要求其实很低

这套系统对硬件的要求低到你可能不相信。我用的是一台退役下来的工控机,4核CPU、8G内存、一块256G的SSD,装了Debian系统,跑docker-compose拉起四个容器:Prometheus、snmp_exporter、Grafana、Alertmanager。整机功耗满载不到30瓦,放配电间角落完全不占地。

因为要放在医院环境里,我给这台主机做了一点加固:系统装在加密LVM卷上,BIOS设了上电自启(断电恢复后能自动起来),网口只绑定一个管理IP,并且用iptables做了白名单,只允许监控网段的几个固定IP访问。

UPS端需要确认两件事:一是UPS有没有网卡或管理卡,二是这个网卡分配到的IP你知不知道。很多医院早年装UPS的时候,原厂工程师把网卡配好就收工了,IP地址写在配电柜的标签纸上,年头一久标签纸早就糊了。我的建议是,在机房里用IP扫描工具跑一下整个设备网段,把开放的161端口(SNMP默认端口)摸出来,基本就是UPS网卡的地址。对了,千万别用Search All那种扫全网段的工具跑办公网,守住设备网就好,医院网络安全合规不是闹着玩的。

4.2 通过docker-compose把四件套搭起来

整个搭建过程,核心是写好docker-compose文件。我用的版本大概是这样的:

version: "3.8" services: prometheus: image: prom/prometheus:v2.47.0 volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml - ./rules/:/etc/prometheus/rules/ - prom_data:/prometheus command: - "--config.file=/etc/prometheus/prometheus.yml" - "--storage.tsdb.retention.time=180d" restart: always networks: - monitor snmp-exporter: image: prom/snmp-exporter:v0.24.1 volumes: - ./snmp.yml:/etc/snmp_exporter/snmp.yml restart: always networks: - monitor grafana: image: grafana/grafana:10.2.3 ports: - "3000:3000" environment: - GF_SECURITY_ADMIN_PASSWORD=change_me_please volumes: - grafana_data:/var/lib/grafana restart: always networks: - monitor alertmanager: image: prom/alertmanager:v0.26.0 volumes: - ./alertmanager.yml:/etc/alertmanager/alertmanager.yml restart: always networks: - monitor volumes: prom_data: grafana_data: networks: monitor: driver: bridge

这里最有讲究的是snmp.yml。它定义了SNMP采集器如何把OID映射到Prometheus指标名。项目里我直接基于标准UPS MIB做的映射,核心几段的写法是:

auths: public_v2: community: public version: 2 security_level: noAuthNoPriv modules: ups_mib: walk: - 1.3.6.1.2.1.33.1.1 # upsIdent - 1.3.6.1.2.1.33.1.2 # upsBattery - 1.3.6.1.2.1.33.1.3 # upsInput - 1.3.6.1.2.1.33.1.4 # upsOutput metrics: - name: ups_battery_capacity_percent oid: 1.3.6.1.2.1.33.1.2.4.0 type: gauge help: "Battery capacity remaining percent"

如果你家的UPS走的是Modbus而不是SNMP,一种做法是用Modbus TCP转SNMP的网关设备,另一种是用开源的modbus_exporter直接把Modbus寄存器值转成Prometheus指标。我在另一个项目里用过后者,思路完全一样,只是多了个寄存器地址对照表的活。市面上主流几个品牌的UPS,寄存器地址在说明书里都可以找到,工程量不大。

4.3 把UPS接入Prometheus:静态发现不够优雅,但最省心

在Prometheus配置文件里添加抓取目标,这里有个选择:用静态配置还是自动发现。医院手术室环境里的UPS数量不多(通常5到15台),而且IP相对固定,我选择用静态配置,写清楚每一台的位置标签,方便告警信息直接带上“几号楼几层几手术间”这种信息。例如:

scrape_configs: - job_name: "ups" static_configs: - targets: - "192.168.20.11" # 手术一室UPS - "192.168.20.12" # 手术二室UPS - "192.168.20.13" # 手术三室UPS labels: location: "住院楼3层手术中心" metrics_path: /snmp params: module: [ups_mib] relabel_configs: - source_labels: [__address__] target_label: instance - source_labels: [__address__] regex: "(.*)" target_label: ups_ip replacement: "${1}"

我给每台机器都加了location标签。别小看这一步,后面告警文案里直接就用{{ $labels.location }}来定位设备,省去人工翻IP查位置的麻烦。医院里士气和效率都是靠这些细节堆出来的。

4.4 Grafana仪表盘设计:给电工师傅看的图,切忌花哨

Grafana仪表盘设计,我坚持三个原则:大数字、颜色分区、趋势线不堆叠。

实时总览页最上面一排,是四块醒目的Stat面板:当前UPS数量、在线UPS数量、电池容量低于50%的数量、最近一条告警时间。中间是每台UPS的“容量+负载+后备时间”组合条形图,用红黄绿三色来表示健康程度。最下面才是电压曲线和负载曲线,方便有需要的人去深挖。

要特别注意一个细节:Grafana面板要设置好刷新时间,我设的是30秒,跟snmp_exporter的抓取间隔保持一致。如果你把面板刷新设成5秒,Prometheus还没抓到新数据呢,面板上的曲线就有断层感,观感很差,还容易让领导误以为系统不稳定。

另一个经验是,国人对“电压220V”这个概念有习惯性认知,所以我把输出电压的单位直接显示成V,精度保留一位小数;电池容量单位显示成%,不带小数。反而是英文的Percent、Voltage这种标签能省则省,目标用户是电工师傅和护士长,他们不看英文缩写。

4.5 告警通道配置:企业微信、短信、电话语音,按优先级分开走

告警通道的配置,我用了Alertmanager的route和receiver。我的策略是:

  • P1级(后备时间不足10分钟、电池深度老化):短信+电话语音,全天候有效
  • P2级(电池容量低、输入电压异常):企业微信应用消息,工作时间提醒,非工作时间静默
  • P3级(负载率高、单次电压抖动):只记录到事件列表,不主动推送

Alertmanager的配置示例:

route: group_by: ["alertname", "location"] group_wait: 10s group_interval: 2m repeat_interval: 30m routes: - match: severity: critical receiver: phone-sms continue: false - match: severity: warning receiver: wechat continue: false receivers: - name: phone-sms webhook_configs: - url: "http://sms-gateway:8080/send" - name: wechat webhook_configs: - url: "http://wechat-bot:8080/notify"

这里给大家一个参考建议:第一次接UPS告警的人,总是把阈值设得很敏感,结果天天被自己搞出来的告警吵到神经衰弱。我的做法是分层分级,而且测试阶段把P3的推送全关掉,只保留面板上的红点提示,等系统跑两周数据稳定了再逐步放开。告警不是越多越好,是要在正确的时间把正确的事情告诉正确的人。

5. 现场部署遇到的坑与排查实录:六条真实经验分享

5.1 坑一:UPS网卡不支持SNMP v2c怎么办

现场遇到过两台老型号的UPS,网卡只支持SNMP v1。snmp_exporter默认配置是按v2c写的,直接连会报“authentication failure”。解决办法是给这两台单独加一个auth组,用v1去抓。snmp.yml里可以定义多个auth段,然后在模块里分别引用,Prometheus的抓取配置也可以给不同target指定不同auth,实测没有问题。

这里有个细节我提醒大家:v1和v2c在community上写法是一样的,但有些老设备的community字符串默认不是public,而是它出厂时写死的随机字符串。如果你不知道,可以从设备外壳标签上找,或者问厂家客服要默认值。

5.2 坑二:手术室电磁环境导致SNMP抓取偶尔失败

手术室里电刀、高频电灼设备一开,整个弱电链路里就容易出现偶发的干扰,表现为SNMP抓取查询超时,或返回的值偶尔是null。我在规则里遇到过几次因为查询失败导致面板上某台UPS的容量显示成0的情况,吓一跳,还以为电池瞬间炸了。

排查后确认不是UPS的问题,是网络丢包。对策是两条:第一,在snmp_exporter的抓取间隔上做重试,比如每15秒抓一次,失败间隔2秒重试,最多重试3次;第二,在Prometheus规则里加一层“防止数据缺失造成误报”的限定条件,只有当最近5分钟内有有效数据时才做告警判断:

expr: | ups_battery_capacity_percent < 50 and (time() - ups_last_updated_timestamp) < 300

这个ups_last_updated_timestamp是我自己额外打的一个时间戳指标,思路就是“没数据的时候别乱叫,数据新鲜才告警”。

5.3 坑三:电池组端电压正常,不代表每节电池都正常

打蛇打七寸,UPS电池的问题也在单体。很多UPS的SNMP MIB里只暴露了整个电池组的端电压和容量,但电池组里往往有几十节单体电池,某节落后会导致整组容量断崖式下跌,可端电压在浮充状态下看起来还是正常的。

我的经验是:不要只看端电压这一个量,要把容量变化率和内阻趋势放在一起看。在Grafana里建立一个“电池容量7日趋势”折线图,如果一周内容量从90%缓慢滑到75%,大概率有单体电池在恶化,趁还能撑着赶紧安排更换。这个问题用纯人工巡检很难察觉,因为我们不可能每天同一时间去看一次电池容量百分比。而这套系统能帮你做持续记录,趋势一旦出来,处理时机就从容得多。

5.4 坑四:告警恢复消息被当成新告警,值班人员被刷屏

Alertmanager默认是“告警触发和恢复都会通知”的,如果你的receiver没有做区分,值班人员会同时收到“UPS battery low”和“UPS battery recovered”两条消息。本来是想帮他们减负,结果反而增加了阅读负担。

解决方式是给恢复通知单独设一个webhook,或者在企业微信机器人那边把恢复消息合并成一条日报。我最后做的方式是:告警触发走实时推送,恢复消息只在上午9点统一汇总成一条“夜间告警回顾”发出来。这样既不漏报,又不打扰值班休息。

5.5 坑五:测试断电时,别真的把手术室的电断了

这个说起来有点搞笑,但在项目测试阶段我真的差点干了蠢事。当时想验证“输入断电后告警能不能正确触发”,差点直接去拉手术室配电箱的空开。被带我的老电工一把拦住,他说:“你拉这里,手术灯灭了怎么办?”

后来测试改成了在UPS监控屏上手动关断输入开关,或者直接用软件模拟SNMP的输入电压值。这种测试既验证了告警链路,又不影响真实负载。各位如果要模拟断电测试,建议在非手术时间(比如深夜)且确认负载可以短暂脱离UPS的情况下进行,或者干脆在测试环境用假数据源演练告警链路的通断,千万别拿真手术室开玩笑。

5.6 坑六:医院内网防火墙拦住了Alertmanager的出站请求

医院内网的防火墙策略往往比较严,Alertmanager所在的主机访问外部短信网关和企业微信API时,会被拦截。这个通常不是配置写错了,而是网络策略没放通。

处理办法是:提前把需要访问的域名或IP清单提给网络科,做好备案。另外,短信网关一般建议走医院自己的短信平台(大多数三甲都有),通过内网接口直接调用,不要试图让服务器直连公网短信服务商,安全上过不了。

6. 从单点监测到全院能管:这套系统后续还可以怎么长

说句实话,UPS监测只是医院能源管理的一小块拼图。这套架构跑顺之后,我发现它的扩展性非常好,因为所有数据都已经汇聚到Prometheus了,后续再接入其他设备只是“加采集器、加仪表盘、加规则”的事。

我后来在这个项目上做了两个扩展。第一个是接了配电间的温湿度传感器,协议走Modbus RTU,通过一个串口服务器把数据吐到网络上,再由modbus_exporter拉取。为什么接这个?因为UPS电池的寿命和温度强相关,环境温度每升高10度,铅酸电池寿命可能缩短一半。把温湿度数据并到电池趋势图里,能明显看出夏季高温月份电池容量掉得更快,数据说服力很强。

第二个扩展是做月报。每周一早上,系统自动把上周每台UPS的输入断电次数、电池介入时长、最低剩余容量、告警事件数汇总成一张PDF推送给药械科。如果某台机器一个月内出现了三次以上输入断电,说明它所在回路的市电质量有问题,需要往前端配电查原因。没有数据支撑的时候,这类问题只能靠老师傅模糊的“感觉这路电不太稳”来判断,现在有了数据,沟通效率完全不同。

对于想往深水区走的朋友,还可以考虑把这套系统和医院的BMS(楼宇管理系统)做联动,把UPS的关键告警同步到BMS大屏。但这块涉及医疗建筑智能化系统的接口协议,不同品牌差异很大,需要和原厂或集成商配合,建议作为二期工程考虑。

最后分享一个实际体会。能源监测这种项目,技术难度不高,难的是让使用它的人信任它。刚开始后勤老师也不太信一个开源面板能比原厂软件靠谱,但跑了三个月,真有两次电池劣化被提前发现,他们的态度就变了。这让我确认了一件事:在关键供电场景里,数据的连续性和可视化比任何花哨的功能都重要。开源方案最大的价值不只是省钱,而是把数据真正还给了使用者。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询