ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

商用热水工程IoT监控实战:Modbus与MQTT数据采集及Grafana可视化

商用热水工程IoT监控实战:Modbus与MQTT数据采集及Grafana可视化 1. 商用热水工程为什么必须上IoT监控商用热水工程和家用热水器完全是两个物种。家用热水器坏了大不了洗个冷水澡骂两句完事。商用热水工程一旦出问题影响的是酒店几十个房间的客人、医院住院部的洗漱用水、工厂几百号员工的宿舍淋浴甚至是游泳池的恒温系统。我见过最惨的一个案例某连锁酒店的热水循环泵半夜故障第二天早上前台被投诉电话打爆店长直接被区域经理约谈。传统做法是什么靠人工巡检。安排一个师傅每天早晚各去机房看一次抄表、看温度、听声音、闻味道。这种模式的问题非常明显巡检间隔期内的故障完全不可知。晚上十点水泵电流异常升高凌晨两点彻底卡死等到早上八点师傅上班才发现中间六个小时系统处于异常状态。如果水箱保温性能差一点早上六点客人起床时水温可能已经掉到四十度以下。更麻烦的是很多商用热水工程的机房位置很偏。地下室角落、楼顶天台、设备夹层这些地方平时没人去巡检师傅去一趟要走十分钟夏天一身汗冬天一身寒。时间长了巡检质量必然下降抄表变成估抄听声音变成走个过场。IoT监控要解决的核心问题就三个实时性、连续性、可追溯。温度、水位、水泵电流、阀门状态这些关键参数每几秒采集一次通过Modbus协议从PLC或仪表读上来再经MQTT推送到云端或本地服务器存进InfluxDB这样的时序数据库最后用Grafana做可视化看板。整套链路跑通之后你在手机或电脑上就能看到整个热水系统的实时状态历史曲线随时调取异常自动告警。这套方案适合谁商用热水工程的运维负责人、暖通公司的技术主管、想做设备远程运维的集成商以及有一定动手能力的物业工程人员。不需要你是专业程序员但需要你对Modbus协议有基本了解能看懂寄存器地址表会配置简单的采集软件。下面我把整个实战过程拆开讲包括我踩过的坑和最终稳定的方案。2. 整体架构设计与关键选型考量2.1 从现场设备到云端看板的完整链路整套系统的数据流向是这样的现场的热水机组、水箱、循环泵、电动阀等设备通过传感器和仪表把物理量转换成电信号再由PLC或数据采集模块读取。这些设备之间用Modbus RTURS485或Modbus TCP以太网通信。采集层用一台工控机或边缘网关运行采集程序把Modbus数据读上来转换成MQTT消息发布到MQTT Broker。Broker可以在本地服务器上也可以用云服务。订阅端把消息写入InfluxDBGrafana从InfluxDB读取数据展示。这个架构里每个环节都有选型空间我逐个说我的选择和理由。采集层我最终用的是边缘网关方案而不是工控机采集软件。原因很简单工控机在机房环境里故障率不低风扇积灰、硬盘震动、系统更新导致重启这些都是隐患。边缘网关是嵌入式系统无风扇设计功耗低稳定性好很多。当然如果你已经有工控机在跑其他系统复用也可以但要注意采集程序要设置开机自启和看门狗。通信协议Modbus是绝对主流。商用热水工程里的PLC、温控仪、流量计、电能表几乎都支持Modbus。区别在于有些是Modbus RTU串口有些是Modbus TCP网口。老设备基本都是RTU新设备逐渐转向TCP。我的建议是如果设备支持TCP优先用TCP布线简单速率高不需要额外的串口服务器。如果只有RTU就用串口服务器转成TCP或者直接用网关的RS485口。MQTT Broker我用的是Mosquitto轻量、稳定、配置简单。如果项目规模大设备数量超过几百台可以考虑EMQX或HiveMQ但一般商用热水工程几十个点位Mosquitto完全够用。Broker部署在本地服务器上不依赖外网断网时数据还能在局域网内流转。时序数据库InfluxDB是首选。它的数据模型天然适合存储带时间戳的传感器数据写入性能好压缩率高查询语言Flux虽然学习曲线陡一点但功能强大。我试过用MySQL存时序数据数据量一大查询就慢得离谱而且磁盘占用是InfluxDB的好几倍。可视化Grafana没有悬念。开源、插件丰富、告警功能完善而且社区模板多很多面板可以直接导入修改。我见过有人用Kibana或自研前端但综合成本和效果Grafana是最优解。2.2 为什么不用现成的云平台市面上有不少商用热水工程的云监控平台插卡即用扫码看数据。为什么我还要自己搭三个原因。第一数据自主权。云平台的数据存在别人服务器上哪天平台倒闭或者改收费策略你的历史数据可能就拿不到了。自己搭的InfluxDB数据在本地想存多久存多久想怎么分析怎么分析。第二定制化需求。商用热水工程的监控逻辑各不一样。有的项目要监控水箱分层温度有的要监控热泵机组COP有的要联动控制补水阀。云平台提供的功能是标准化的很难满足这些个性化需求。自己搭的系统想加什么逻辑加什么逻辑。第三长期成本。云平台通常按点位或按年收费一个几十个点位的项目一年费用几千到上万。自己搭一套硬件边缘网关加服务器一次性投入可能也就这个数但后续没有持续费用。当然前提是你有技术能力维护。注意自己搭系统意味着你要对整套链路负责。网络断了、服务器挂了、数据库满了都是你的问题。如果团队没有相应的技术储备用云平台反而是更稳妥的选择。2.3 关键参数的计算与设备选型采集频率怎么定这取决于参数的变化速率和你的告警响应要求。水温变化是慢过程一分钟采集一次完全够用。水泵电流变化相对快但也不需要毫秒级五秒一次足够。我的做法是分两组温度、水位这类慢变量采集周期60秒电流、电压、阀门状态这类快变量采集周期5秒。这样既保证了关键参数的实时性又不会产生过多数据。数据存储周期怎么算假设有50个点位平均采集周期30秒那么每天的数据量是50×2880144000条。InfluxDB每条记录压缩后大约几字节到几十字节一天的数据量在几MB到几十MB之间。一年下来也就几个GB对服务器磁盘空间要求不高。我一般建议保留至少两年的历史数据方便做同比分析。边缘网关选型看几个指标RS485口数量、网口数量、CPU性能、内存大小、是否支持容器化部署。我用的网关有4个RS485口、2个网口、4核CPU、2GB内存跑一个采集程序和MQTT客户端绰绰有余。如果点位特别多或者要做本地数据缓存和边缘计算可以选更高配置的。服务器选型如果只是本地监控一台小型工控机或者迷你主机就够。如果要外网访问需要公网IP或者内网穿透。我一般建议用云服务器配置2核4G起步装Ubuntu 22.04跑Mosquitto、InfluxDB、Grafana三个服务资源占用不高。3. Modbus数据采集的核心细节与实操要点3.1 Modbus RTU与TCP的区别及选择Modbus RTU和Modbus TCP的本质区别在传输层。RTU走串口数据帧里包含地址、功能码、数据、CRC校验。TCP走以太网数据帧里包含事务标识、协议标识、长度、单元标识、功能码、数据。TCP没有CRC校验因为以太网本身有校验机制。实际使用中RTU的布线成本低一根双绞线可以串接多个设备但速率慢典型波特率9600或19200传输距离理论上1200米实际受干扰影响可能只有几百米。TCP速率快100Mbps起步但每个设备都要网口或者通过串口服务器转换。我的经验是新建项目优先用TCP。现在很多PLC和仪表都带网口直接走TCP布线简单调试方便。改造项目如果原有RTU设备可以保留通过串口服务器转TCP但要注意串口服务器的稳定性和延迟。3.2 寄存器地址映射与数据解析Modbus的数据存在寄存器里分为线圈Coil、离散输入Discrete Input、保持寄存器Holding Register、输入寄存器Input Register。线圈和离散输入是1位表示开关状态。保持寄存器和输入寄存器是16位表示数值。商用热水工程里常用的点位参数寄存器类型数据格式说明水箱温度输入寄存器16位有符号整数实际值寄存器值/10水泵电流输入寄存器16位无符号整数实际值寄存器值/100水泵运行状态线圈1位0停止1运行补水阀开关线圈1位0关1开水位输入寄存器16位无符号整数实际值寄存器值/10设定温度保持寄存器16位有符号整数可读写实际值寄存器值/10这里有个坑字节序。Modbus协议本身没有规定多字节数据的字节序不同厂家的设备可能不一样。有的用大端高字节在前有的用小端低字节在前。32位浮点数更麻烦还有字序问题。我遇到过同一个项目里温度仪表用大端电流表用小端解析的时候要分别处理。实操心得调试阶段一定要用Modbus Poll或类似工具手动读取每个寄存器对照设备说明书确认数值是否正确。不要想当然地按默认字节序解析否则数据全是错的。3.3 采集程序的编写与优化我用Python写采集程序库选的是pymodbus。代码结构很简单建立Modbus连接循环读取寄存器解析数据发布MQTT消息。from pymodbus.client import ModbusTcpClient import paho.mqtt.client as mqtt import struct import time # Modbus连接 modbus_client ModbusTcpClient(192.168.1.100, port502) modbus_client.connect() # MQTT连接 mqtt_client mqtt.Client() mqtt_client.connect(localhost, 1883, 60) mqtt_client.loop_start() def read_temperature(): result modbus_client.read_input_registers(0, 2, slave1) if result.isError(): return None # 假设32位浮点数大端字节序 raw struct.pack(HH, result.registers[0], result.registers[1]) return struct.unpack(f, raw)[0] while True: temp read_temperature() if temp is not None: mqtt_client.publish(hotwater/tank/temperature, temp) time.sleep(60)这段代码看起来简单但有几个优化点。异常处理Modbus通信可能因为干扰、设备忙、线路问题失败。每次读取都要判断是否出错出错后不要立即重试等一个采集周期再试。连续出错超过阈值再告警。连接保活Modbus TCP连接可能被设备端断开要定期检查连接状态断了就重连。MQTT连接也要设置keepalive和遗嘱消息Broker发现客户端异常断开时可以发布告警。数据缓存网络中断时采集程序应该把数据缓存到本地等网络恢复后补发。我用SQLite做本地缓存简单可靠。多设备轮询一个网关可能接多个Modbus设备要合理安排轮询顺序和间隔避免某个设备响应慢拖累整体。我的做法是每个设备独立线程互不干扰。3.4 MQTT主题设计与消息格式MQTT主题设计要遵循层次清晰、易于订阅的原则。我的命名规则是项目名/设备类型/设备编号/参数名。比如hotwater/tank/01/temperaturehotwater/pump/01/currenthotwater/valve/01/status消息格式用JSON包含时间戳、数值、单位、质量码。{ timestamp: 2025-01-15T10:30:00Z, value: 55.3, unit: ℃, quality: good }质量码很重要。如果Modbus读取失败可以发布一条quality为bad的消息Grafana里可以据此判断数据有效性避免用错误数据做告警。注意MQTT主题不要用中文不要用特殊字符不要用空格。虽然协议支持但实际使用中容易出问题尤其是跨平台的时候。4. 数据存储与可视化实战4.1 InfluxDB的安装与配置Ubuntu 22.04上安装InfluxDB 2.x官方有apt源几条命令搞定。wget -q https://repos.influxdata.com/influxdb.key echo 23a1c8836f0afc5b4b5b7b7b7b7b7b7b7b7b7b7b | sudo apt-key add - source /etc/os-release echo deb https://repos.influxdata.com/ubuntu $(lsb_release -cs) stable | sudo tee /etc/apt/sources.list.d/influxdb.list sudo apt update sudo apt install influxdb2 sudo systemctl start influxdb sudo systemctl enable influxdb安装完成后访问8086端口创建组织、桶、令牌。桶相当于数据库令牌是写入和查询的凭证。InfluxDB的数据模型是measurementtagfieldtimestamp。measurement相当于表名tag是索引字段field是数值字段timestamp是时间戳。对于热水工程监控我这样设计measurement:sensor_datatag:project项目名、device_type设备类型、device_id设备编号、parameter参数名field:value数值、quality质量码timestamp: 采集时间这种设计的好处是查询灵活。比如查某个项目所有温度传感器的数据或者查某个设备的所有参数都很方便。4.2 Grafana看板配置与告警设置Grafana安装更简单也是apt源。sudo apt install -y software-properties-common sudo add-apt-repository deb https://packages.grafana.com/oss/deb stable main wget -q -O - https://packages.grafana.com/gpg.key | sudo apt-key add - sudo apt update sudo apt install grafana sudo systemctl start grafana-server sudo systemctl enable grafana-server访问3000端口默认账号admin/admin。添加InfluxDB数据源填入URL、组织、令牌、桶名。看板设计我一般分几个区域实时状态区用Stat面板显示当前水温、水位、水泵状态、阀门状态。水温用阈值着色低于45度黄色低于40度红色。趋势曲线区用Time Series面板显示过去24小时的水温变化、水泵电流变化。可以叠加多个设备的曲线做对比。告警状态区用Alert List面板显示当前活跃的告警。统计汇总区用Bar Gauge或Pie Chart显示今日告警次数、设备在线率、平均水温等。告警规则在Grafana里配置支持多种条件。比如水温低于40度持续5分钟触发告警。告警通知渠道支持邮件、Webhook、钉钉、企业微信等。我一般用Webhook推送到自建的告警服务再分发到各个渠道。实操心得Grafana的告警规则要设置合理的评估间隔和持续时间。评估间隔太短数据抖动容易误报持续时间太长告警不及时。我的经验是评估间隔1分钟持续时间5分钟对于慢变量比较合适。4.3 数据写入的几种方式MQTT到InfluxDB的桥接我试过三种方式。方式一Telegraf。Telegraf是InfluxData官方的数据采集器支持MQTT输入和InfluxDB输出。配置简单性能好推荐。[[inputs.mqtt_consumer]] servers [tcp://localhost:1883] topics [hotwater/#] data_format json tag_keys [device_type, device_id, parameter] [[outputs.influxdb_v2]] urls [http://localhost:8086] token your-token organization your-org bucket hotwater方式二Python脚本。用paho-mqtt订阅消息用influxdb-client写入。灵活可以处理复杂逻辑但性能和稳定性不如Telegraf。方式三Node-RED。图形化编程拖拽节点即可。适合快速原型但大规模部署不如前两种。我最终用Telegraf因为它是专门做这个的稳定可靠配置一次就不用管了。5. 常见问题与排查技巧实录5.1 Modbus通信故障排查Modbus通信故障是最常见的问题。表现是读不到数据或者数据明显错误。排查思路如下第一步确认物理连接。RS485的A接AB接B不要接反。用万用表量一下A-B之间的电压空闲时应该有1-2V的差分电压。如果电压为零说明线路断了或者设备没供电。第二步确认通信参数。波特率、数据位、停止位、校验位必须和设备说明书一致。我遇到过设备默认波特率是19200但说明书上写的是9600折腾了半天。第三步确认从站地址。每个Modbus设备的从站地址必须唯一。如果两个设备地址相同通信会冲突。用Modbus Poll扫描一下看看能扫到哪些地址。第四步确认寄存器地址。Modbus地址有0基和1基的区别。说明书上写40001实际寄存器地址可能是0也可能是1。用Modbus Poll从0开始逐个试。第五步确认字节序。读到的数值如果明显不对比如温度读到几千度大概率是字节序问题。试试交换高低字节或者交换字序。常见Modbus错误码9003通常表示网关路径错误或目标设备无响应。检查网关配置和从站地址。5.2 MQTT连接与消息丢失问题MQTT连接不上先检查Broker地址和端口。如果Broker在本地用localhost或127.0.0.1。如果在远程确认防火墙开放了1883端口。消息丢失通常是因为QoS设置不当。QoS 0是至多一次可能丢消息。QoS 1是至少一次可能重复。QoS 2是恰好一次开销最大。对于监控数据QoS 1足够偶尔重复可以在写入InfluxDB时去重。还有一个坑是客户端ID冲突。两个客户端用同一个ID连接Broker后连接的会把先连接的踢掉。确保每个客户端ID唯一。5.3 InfluxDB写入失败与查询慢写入失败常见原因是令牌错误、桶不存在、数据格式不对。检查Telegraf日志通常会有详细错误信息。查询慢通常是因为没有建索引或者查询范围太大。InfluxDB的tag是自动索引的field不是。所以查询条件尽量用tag。另外查询时间范围不要太大Grafana看板默认查最近24小时不要设成最近一年。5.4 Grafana看板加载慢与告警误报看板加载慢通常是查询太复杂或者数据点太多。优化方法减少面板数量降低查询精度用aggregateWindow限制返回点数。告警误报通常是阈值设置不合理或者数据抖动。解决方法设置持续时间比如连续5分钟满足条件才告警。或者用移动平均平滑数据。5.5 常见问题速查表问题现象可能原因排查方法解决方案Modbus读不到数据物理连接断开检查A/B线、供电重新接线、更换线缆Modbus数据错误字节序不对用Modbus Poll手动读调整解析方式MQTT连接失败Broker地址错误ping Broker、telnet端口修正地址、开放端口MQTT消息丢失QoS设置不当检查发布订阅QoS改为QoS 1InfluxDB写入失败令牌或桶错误查看Telegraf日志修正配置Grafana查询慢查询范围太大检查时间范围缩小范围、加聚合告警误报阈值或持续时间不当查看历史数据调整阈值、加持续时间6. 几个让我印象深刻的踩坑经历第一个坑是串口服务器的延迟。某项目用串口服务器把RS485转成TCP采集程序读数据时快时慢。后来发现串口服务器有缓冲机制多个请求排队处理导致延迟不稳定。换成直接走网关的RS485口问题消失。所以如果设备是RTU优先用网关自带的串口不要用外置串口服务器。第二个坑是InfluxDB的保留策略。默认情况下InfluxDB的数据永久保留。时间长了磁盘会满。我设置了一个保留策略原始数据保留一年降采样后的数据保留五年。降采样用InfluxDB的任务功能每小时跑一次把一分钟精度的数据聚合成一小时精度。第三个坑是Grafana的时区问题。服务器时区是UTCGrafana默认也是UTC但看板显示的时候没注意导致告警时间对不上。后来统一改成东八区问题解决。建议从一开始就设置好时区避免后续混乱。第四个坑是MQTT主题通配符的坑。订阅hotwater/#可以收到所有子主题的消息但#必须放在最后。hotwater/#/temperature是无效的。另外是单层通配符hotwater//temperature可以匹配hotwater/tank01/temperature但不能匹配hotwater/tank01/room01/temperature。第五个坑是Modbus TCP的单元标识。Modbus TCP的报文里有一个单元标识字段通常用于区分网关后面的多个RTU设备。如果直接连TCP设备单元标识一般填1或者0。我遇到过填错单元标识导致读不到数据的情况折腾了很久才发现。7. 系统扩展与后续优化方向这套系统跑通之后可以做的事情很多。联动控制现在只是监控下一步可以做控制。比如水温低于设定值自动启动热泵水位低于下限自动打开补水阀。控制指令通过MQTT下发到网关网关转成Modbus写寄存器。能耗分析采集电能表数据计算热泵机组的COP分析不同时段的能耗规律优化运行策略。预测维护采集水泵电流、振动、温度等数据用简单的阈值或机器学习模型预测设备故障提前维护。多项目集中管理如果有多个热水工程可以在云端部署一套集中管理平台所有项目的数据汇总到一个InfluxDB用Grafana的统一看板管理。移动端适配Grafana的看板可以在手机浏览器上查看但体验一般。可以用Grafana的API获取数据自己开发一个简单的移动端页面。这套系统我从第一版到现在迭代了大概半年时间。最开始用Python脚本采集后来换成Telegraf再后来加了边缘缓存和断点续传。硬件也从工控机换成了边缘网关稳定性提升明显。现在这套系统在几个项目上跑着最长的已经稳定运行一年多没出过大问题。偶尔有网络波动或者设备重启都能自动恢复。如果你也在做类似的商用热水工程监控我的建议是先从一个小项目试点把整条链路跑通再逐步推广。不要一上来就搞大而全容易翻车。遇到问题多查文档多动手试Modbus和MQTT的坑我都踩过了你按上面的思路走能省不少时间。
RELATED READING

延伸阅读

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