ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

楼宇自控监测实战:Modbus与SNMP协议融合采集与告警

楼宇自控监测实战:Modbus与SNMP协议融合采集与告警 做楼宇自控的人应该都有体会真正让人头疼的往往不是控制逻辑本身而是环境数据采集那条链子。我最近接手了一套楼宇自控温湿度监测系统既有一批分布在机房、弱电井和重点库房的Modbus温湿度传感器又要配合网管把博科光纤交换机这类网络设备统一监控起来最终平台还要基于Modbus TCP/UDP与SNMP协议把数据全部串在一起。这篇文章就把项目从方案选型、设备配置、协议对接到写采集脚本和现场排障的过程整理出来特别是几个我在实际调试中踩过的坑给正在做类似楼宇环境监控或设备纳管项目的朋友做个参考。这个项目要解决的核心问题其实很直接楼宇自控系统里的温湿度传感器大多走Modbus而网络设备、存储交换机只认SNMP两个协议体系通常各管各的导致机房温度和网络设备温度告警无法放在同一个视图里看。如果你需要同时管好环境侧和IT侧就必须想清楚Modbus的寄存器地址怎么映射成SNMP的OID数据又是以什么周期和格式采集到平台上。下面我按项目实际推进的顺序来说从协议选择、硬件规划到具体的配置步骤和程序实现尽量让你看完就能用。1. 项目背景与协议选择1.1 为什么要把Modbus和SNMP放在一起用传统楼宇自控系统里温湿度传感器最常用的通信接口就是RS485加Modbus RTU通过网关再升级成Modbus TCP/IP。而网络监控这一侧交换机、路由器、光纤交换机这些设备几乎无一例外地集成了SNMP Agent运维平台通过SNMP管理协议获取端口状态、设备温度、光模块功率等信息。两套协议都有大量存量设备想把它们统一在一个监测系统里就必须同时打通Modbus和SNMP。单纯从温湿度监测角度看Modbus是非常合适的选择。它的协议简单报文格式公开寄存器地址可以直接映射到数据点工业传感器几乎都支持。SNMP则是一个树状的OID模型适合做网络设备状态采集但它本身不太适合作为海量环境传感器的上传通道因为每个点位定义私有MIB的维护成本会比较高。实际项目中我见过有人硬要用SNMP连全部温湿度传感器最后被私有MIB和类型定义折磨得不行所以我更推荐底层用Modbus采集环境数据上层通过支持SNMP的网关或自定义Agent把数据转化成OID再由统一监控平台上报。1.2 技术指标和系统边界怎么定项目在启动前需要把边界定清楚否则调试会陷入无止境的加需求。我这次负责的范围是32个温湿度监测点场地包括机房精密空调区域、弱电井、仓库和办公区另外还需要把2台博科光纤交换机、3台核心网络交换机的SNMP信息接到同一个监控平台。温湿度采集周期定在5秒以内温度分辨率0.1摄氏度湿度分辨率0.1%RH从传感器故障到平台告警的响应时间不超过30秒。系统边界还要考虑“谁触发联动”。楼宇自控里温湿度超限往往要联动新风机组和除湿机这部分通常走BA系统的点位联动我的项目只做监测和告警不直接控制空调避免跟既有楼宇控制系统发生冲突。这一点很关键如果你只是做监测系统就不要去抢BA系统原有的控制功能毕竟两边协议和权限管理都不一致强行联动后期维护会很乱。2. 系统架构与设备选型规划2.1 三级链路拆解传感器到网关再到平台整个系统可以拆成三级链路。最底下一层是现场温湿度变送器它们通过RS485总线手拉手连接使用Modbus RTU协议每个传感器分配一个唯一的从站地址。中间层是一个具备Modbus TCP/UDP主站功能的工业网关它定时轮询各个从站寄存器同时把采集到的数据转换为SNMP协议中的私有OID供上层监控平台读取。最上层就是监控主机部署采集程序、告警规则和可视化面板一类数据走Modbus直接读网关一类数据走SNMP读博科交换机和网关的OID。博科光纤交换机是独立接入的因为它本身支持SNMP Agent不需要经过Modbus网关。监控主机通过SNMP的get/walk命令定期读取交换机的系统温度、光模块状态等信息同时接收交换机发送的SNMP Trap告警事件。整体链路在项目里叫“双通道采集”环境温湿度走Modbus通道IT设备状态走SNMP通道最后在数据库里汇合。2.2 硬件选型时容易被忽略的细节温湿度传感器选型我建议直接选带RS485 Modbus输出的变送器不要买模拟量4-20mA输出的再配模块那样多一层转换精度和调试成本都吃亏。传感器参数上精度要温度正负0.3摄氏度、湿度正负2%RH以内供电按DC 12V或者24V统一探头尽量选防水型安装在机柜或空调出风口时要保证通风不要贴着金属面板。另外要看传感器寄存器是否可配置是否支持负温度有符号数这直接决定后面程序怎么写。网关是另一个关键点。市面上很多Modbus转以太网网关只支持Modbus TCP从站模式而楼宇项目需要的是主站模式去主动采集多个从站选型时必须确认支持Modbus TCP Master最好同时支持UDP模式方便现场网络环境变化时切换。网关还要支持自定义SNMP Agent和私有OID映射或者至少支持主动上报到上层平台否则数据只能写在Modbus侧没法跟SNMP设备统一。点位规模超过32个以上时注意网关的寄存器表容量和轮询周期上限避免配置很多点但实际刷新不过来。3. Modbus采集链路配置实战3.1 温湿度传感器寄存器参数初始化现场传感器的初始化是第一个容易出问题的地方。拿到传感器后先通过拨码开关或配置软件设置从站地址我统一按点位表编号从1到32固定分配避免后续维护时搞混。总线参数设置为波特率9600、数据位8、停止位1、无校验也就是常说的8N1。如果你的项目点位少于10个也可以调成19200但超过20个点时建议还是用9600总线长距离下更稳定。寄存器功能码是重点。多数温湿度变送器使用功能码03读取保持寄存器也有部分产品用04读输入寄存器。典型映射是寄存器地址0x0001存放温度0x0002存放湿度每个寄存器16位数值扩大10倍保存。我在项目里用的是0x0000开始连续读两个寄存器一次读完温度和湿度效率更高。实操时一定要以原厂手册为准因为不同厂家会把温度和湿度放在不同起始地址有的还会在中间插入状态字千万不要想当然。3.2 采集网关的Modbus TCP/UDP映射配置网关配置是所有联调工作的中间枢纽我的习惯是先通过网口登录网关配置页面关闭DHCP设置固定IP然后在“Modbus主站配置”里添加每个从站。每个点位需要填的信息有从站地址Unit ID、功能码03或04、起始寄存器地址、寄存器数量、数据类型、字节序、缩放系数。比如温度寄存器起始地址是0数量1数据类型是16位无符号整数缩放系数0.1那么原始值253读到平台里就显示25.3摄氏度。Modbus TCP和UDP的选择我给的方案是优先TCP。TCP是面向连接的数据包有序且可靠跨交换机跨网段不容易丢。UDP虽然开销小但楼宇网络里广播流量大时会出现丢包采集端必须实现超时重试和序列校验否则漏采很难发现。如果网关或传感器只支持Modbus UDP那建议限定在同一个二层广播域内使用并且采集程序要增加“连续读取失败3次就告警”的逻辑否则现场可能飘过一个瞬间数据就少了。3.3 寄存器数值换算与有符号数处理温湿度数据的换算看着简单实际上负温度和字节序是最容易翻车的。如果现场冬天温度低于零下寄存器原始值可能是补码表示比如-5.3摄氏度对应的无符号值是65035直接除以10就变成了6503.5完全错误。采集程序里必须检测原始值是否大于0x8000最大正值的一半是的话减0x10000后再除以缩放系数。字节序同样需要配置统一。很多传感器默认是大端模式但部分国产变送器会使用小端或者字节交换模式尤其支持32位浮点数据的传感器更要注意。我的做法是先在调试工具里读一个已知温度值调整字节序选项直到显示数值与标准温湿度计一致然后把这个参数记录下来。等全部点位配置完成后再统一抽查5个点位跟手工温湿度计比对精度在0.5摄氏度以内算通过。4. SNMP协议接入与网络设备纳管4.1 Windows上SNMP服务安装的正确姿势网上一搜“windows snmp下载”会出来一堆第三方软件包其实Windows系统自带SNMP服务根本不需要额外下载。我这次监控主机用的是Windows Server 2019只需要在“启用或关闭Windows功能”里找到“SNMP”服务并勾选安装后去服务管理器里把“SNMP Service”启动就可以。Windows 10专业版也支持不过微软已经开始逐步弃用SNMP功能入口在较新版本里可能被藏起来你可以通过PowerShell命令安装Install-WindowsFeature SNMP-Service安装完成后还要设置安全项。在服务列表中找到“SNMP Service”右键属性切到“安全”选项卡添加接受的团体名比如public权限选“只读”。然后在下方的“接受来自这些主机的SNMP数据包”里填监控主机的IP只允许需要采集的管理端过来不要开放给全网络。如果这一步漏了任何能访问161端口的主机都能随便读你的设备信息是个安全隐患。设置完记得把“陷阱”选项卡里的陷阱目标也填好这样后续告警才能上送。4.2 博科光交SNMP配置实录博科光纤交换机的SNMP配置比大多数网络交换机要简单但命令提示符是交互式的第一次用容易发懵。我用的是SSH登录交换机进入admin账号后执行snmpconfig --show先看当前配置。接着配置系统信息和团体名通常会进入一组问答式的配置界面snmpconfig --set snmpv1按照提示输入只读团体名和读写团体名生产环境我建议把只读团体名从public改成一个项目专用字符串避免被扫描工具直接进来自查。然后配置Trap目标地址在交互菜单里找到SNMP trap host设置填入监控主机IP这样交换机的告警才能主动推送到监控平台。有个细节要提醒你博科交换机的SNMP v1和v3是分开配置的旧固件对SNMPv3支持不太好如果纳管平台支持v2c那直接让交换机开启v2c模式最省事。配置完成后不要在交换机本机上用snmpwalk自测那只是自欺欺人必须从监控主机上去访问交换机的管理IP才能真正验证网络路径、防火墙和团体名是否都正常。不同版本Fabric OS的命令交互略有差异以设备上的实际提示为准但总体思路就是“先show后set”改一步验一步。4.3 用snmpwalk验证温湿度私有OID如果你的Modbus网关自带SNMP Agent那么温湿度会映射成一串私有OID。比如我使用的网关把温度映射到1.3.6.1.4.1.50000.1.1.1湿度映射到1.3.6.1.4.1.50000.1.1.2后面再加一个递增索引对应不同点位。这时我习惯从监控主机上用snmpwalk验证整个分支snmpwalk -v2c -c public 192.168.1.200 1.3.6.1.4.1.50000如果返回的数据对应上各点位温湿度说明Modbus网关的SNMP侧配置成功。如果返回值为空先检查团体名是否匹配再到MIB-2.system分支里用snmpwalk看设备基础信息通不通能通说明问题是私有OID没定义好需要重新导出网关MIB文件。我的建议是每个点位都建立一个OID对照表把点位编号、Modbus地址、寄存器地址、OID后缀、缩放系数五列记录在一张表里后面写采集程序或配置网管平台时能少走大量弯路。5. 采集程序开发与告警联动5.1 Python轮询脚本从寄存器到数据库在监控主机上我用Python写了一个轮询程序用pymodbus库读取Modbus网关的数据再用requests写入本地InfluxDB。程序逻辑不难但有几个细节长连接复用、异常重试、超时控制。下面是关键代码片段from pymodbus.client import ModbusTcpClient import time GATEWAY_IP 192.168.1.200 GATEWAY_PORT 502 client ModbusTcpClient(GATEWAY_IP, portGATEWAY_PORT, timeout3) def read_temp_humi(unit_id, reg_addr0, count2): rr client.read_holding_registers(reg_addr, countcount, unitunit_id) if rr.isError(): return None raw_temp rr.registers[0] raw_humi rr.registers[1] if raw_temp 0x8000: raw_temp - 0x10000 temperature raw_temp / 10.0 humidity raw_humi / 10.0 return temperature, humidity try: client.connect() while True: for point in point_list: # each point has {unit: 1, name: zone1} result read_temp_humi(point[unit]) if result: temp, humi result write_to_db(point[name], temp, humi) else: log_failure(point[name]) time.sleep(5) except KeyboardInterrupt: client.close()如果你的现场只有Modbus UDP可以将ModbusTcpClient换成ModbusUdpClient但一定要加上连续失败次数统计连续读取失败3次就发告警因为UDP丢包后程序往往不会主动报错只有数据缺失才能暴露问题。程序部署成Windows服务或Linux systemd服务时别忘了设置开机自启动监控主机断电离线和内存泄漏这类场景要提前考虑到。5.2 温湿度越限告警与SNMP Trap联动数据采集只是基础真正体现价值的是告警联动。我在平台里给每个点位定义了温度上线值比如机房精密空调区域温度超过26摄氏度、湿度超过75%RH就触发告警。告警消息通过钉钉机器人Webhook推到工作群同时在企业微信里通知运维人员。对于博科光纤交换机这一类SNMP设备则依赖它主动发送的SNMP Trap当交换机温度异常或光模块故障时平台接收Trap后能自动创建一条告警事件。接收SNMP Trap我推荐直接用现成的网管平台比如Zabbix或自家已有的监控系统不必从零写trap服务。如果确实需要轻量实现可以用Python生态里的pysnmp库接收UDP 162端口的Trap报文然后把关键字段解析后写入同一个告警表。但trap报文格式千差万别不同厂商MIB都在不同OID分支下自己解析容易漏字段所以我这次是把Trap收口到监控平台上再把平台里的告警统一推送给企业微信省去大量解析开发。5.3 可视化面板与通知渠道接入可视化我用了Grafana加InfluxDB配置比较简单。InfluxDB里建立一张env_metrics表字段包括location、temperature、humidity时间戳由采集程序写入。Grafana里的温湿度曲线用“温度”和“湿度”两个面板拖拽查询即可。除了基本面板我还要在Dashboard上做一个“点位状态”表格显示最后一次采集时间和是否离线方便值班人员一眼看出哪条链路断了。通知渠道那边我没有用Grafana自带的邮件报警而是直接用Grafana的Webhook联系到企业微信群机器人。规则里设置“超过阈值持续30秒才触发”避免瞬时毛刺造成误报恢复通知单独配置一条“恢复正常”消息。这样一套链路下来从传感器到微信通知的端到端时间实测在20秒左右满足项目里30秒响应时间的指标。6. 排障实录与避坑清单6.1 Modbus连接失败的六个排查点Modbus通信失败是我在项目里遇到最多的故障整理成六步排查法可以省很多时间。第一步先ping网关IP网络不通就查网线和VLAN。第二步用Modbus调试工具单独读一个点位能连通说明网关正常不能则检查TCP端口502和Unit ID。第三步确认寄存器功能码到底是03还是04很多传感器手册把输入寄存器写得很模糊我用工具里“读保持寄存器/读输入寄存器”各试一次马上能定位。第四步看寄存器起始地址是否按0基地址还是1基地址这两个差一位看起来小返回的数据错得离谱。第五步检查字节序配置大端小端颠倒先调byteorder选项。第六步查看总线侧RS485的A/B接线和终端电阻这个只影响整条总线上所有设备出现“所有点都不通”时优先怀疑。排查时把每一步都记到运维手册里后期值班人员不用重复踩坑。6.2 温湿度读数跳变与精度误差处理传感器读数跳变是最烦人的问题。数据在某个点位每过几秒就突然出现一个巨大的值大概率不是传感器坏了而是总线或供电质量问题。我先用万用表测传感器供电电压要求在标称值的正负5%以内长线供电尾端经常压降大导致芯片复位读数就会跳。另外检查RS485屏蔽层是否单端接地我遇到过屏蔽层两端都接地后形成地环路数据间歇性出错的现象断开一端后恢复正常。程序侧我在采集函数里加了一个简单的滑动平均过滤器保存最近5次数据取中间值而不是平均值这样可以过滤掉一瞬间的通讯毛刺。但要注意滑动平均会增加响应延迟温度本身的滞后本来就不小所以5次窗口已经足够。读数的长期漂移则靠定期校准我在项目里安排每半年用标准温湿度计在同一个空间里对比一次误差超出范围的传感器马上返厂校准。6.3 SNMP不可达和博科配置的常见坑SNMP采集超时第一反应别急着查设备先在监控主机上确认UDP 161端口是否被本机防火墙拦截Windows自带防火墙经常会拦掉来自网段的164端口访问添加允许规则后问题立刻消失。然后确认团体名是否区分大小写SNMP的community string是明文字符串大小写敏感一旦配置成Public而设备是public读取就直接超时。博科光交这边我遇到过配置完SNMP后怎么都读不到数据的情况。最后发现是交换机默认使用SNMPv3而我只设置了SNMPv1的团体名v1的配置完全不生效。处理办法是把监控平台切换到SNMPv3并在博科交换机上设置v3用户和认证密码或者如果现场网络足够封闭就显式开启SNMPv1/v2c模式。另外博科光交的MIB文件不是默认就加载到监控平台里的你需要从博科官网下载SWS-MIB文件编译到监控系统中才能在OID树里看到光模块温度、端口收发功率这些对象。没有MIB文件OID分支只能看到一堆数字和字符串解释不了含义。结尾一点个人经验回头再看这个项目我觉得最值得花时间的不是写代码而是前期的点位规划和协议映射。Modbus和SNMP是两个完全不同的数据模型一个是寄存器地址一个是OID树但只要把每个点位的地址、类型、换算关系和对应OID整理清楚后面所有调试都会顺畅很多。如果你准备复刻这套方案我的建议是先拿一个传感器和一个网关把链路完整跑通验证读数和告警都没问题再批量铺开。不要一上来就接32个点一旦总线地址冲突或寄存器类型填错排查范围会大到让你崩溃。后续如果想扩展这套架构可以比较方便地接入BACnet IP协议直接对接主流楼宇自控平台也可以把无线传感器通过网关接入统一到Modbus链路里。先聊到这有问题欢迎评论区一起讨论。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进