3、数据采集协议:Modbus RTU/TCP协议详解、IEC 61850/104规约、MQTT在物联网中的应用
说到储能监控,数据采集协议就是整个系统的“神经末梢”。没有它,你连电池电压都读不到,更别提什么运维了。今天咱们就把这几个主流协议掰开揉碎,聊聊我在实际项目中是怎么选型和落地的。
3.1 Modbus RTU/TCP:储能行业的“普通话”
Modbus这玩意儿,说实话,老归老,但真管用。我最早接触它是在2015年做光伏电站的时候,那时候BMS(电池管理系统)厂家清一色都支持Modbus。你想想看,一个1979年诞生的协议,到现在还在用,说明什么?说明它足够简单、足够稳定。
3.1.1 Modbus RTU vs Modbus TCP
| 特性 | Modbus RTU | Modbus TCP |
|---|---|---|
| 物理层 | RS-232/RS-485 | 以太网 |
| 传输速率 | 9.6kbps ~ 115.2kbps | 10/100/1000Mbps |
| 最大节点数 | 32(RS-485) | 理论上无限制 |
| 传输距离 | 1200米(RS-485) | 100米(网线) |
| 数据格式 | 二进制(含CRC校验) | 二进制(TCP/IP封装) |
| 典型场景 | 就地采集、短距离 | 站内通信、远程监控 |
我个人习惯是:柜内设备用RTU,跨机柜用TCP。为什么?因为RS-485抗干扰能力强,在机柜这种电磁环境复杂的地方反而比网线靠谱。我曾经在一个项目中,网线走线不规范,结果通信老是丢包,换成RS-485后问题迎刃而解。
3.1.2 数据模型与寄存器
Modbus的数据模型其实就四种:线圈、离散输入、保持寄存器、输入寄存器。在储能场景中,我们最常用的是保持寄存器和输入寄存器。
- 保持寄存器(03功能码):可读可写,用来设置参数。比如PCS的功率指令、BMS的均衡开关。
- 输入寄存器(04功能码):只读,用来采集数据。比如电池电压、SOC、温度。
3.1.3 代码示例:Python读取Modbus数据
这里给一个我常用的Python示例,用pymodbus库读取BMS数据:
from pymodbus.client import ModbusTcpClient
# 连接BMS(假设IP为192.168.1.100,端口502)
client = ModbusTcpClient('192.168.1.100', port=502)
client.connect()
# 读取保持寄存器,起始地址0,读取10个寄存器
result = client.read_holding_registers(0, 10, unit=1)
if not result.isError():
# 假设寄存器0-1存储电压值(高16位+低16位)
voltage = (result.registers[0] << 16) | result.registers[1]
voltage = voltage / 1000.0 # 转换为实际值
print(f"当前电压: {voltage}V")
# 寄存器2存储SOC(百分比)
soc = result.registers[2] / 10.0
print(f"当前SOC: {soc}%")
client.close()
嗯,这里要注意:Modbus地址是从0开始的,但很多厂家文档里写的是“地址1”,实际上是协议地址0。这个坑我踩过不止一次。
3.2 IEC 61850/104:电力系统的“贵族协议”
IEC 61850,说白了就是电力行业的“高级货”。它不像Modbus那样简单粗暴,而是有一套完整的建模体系。在大型储能电站(尤其是并网型)中,调度端要求必须用61850。
3.2.1 为什么需要IEC 61850?
你想想看,一个储能电站可能有几十台PCS、几百个电池簇,如果用Modbus,你得定义一大堆寄存器地址表,而且不同厂家的定义还不一样。但61850不一样,它用逻辑节点(LN)来标准化设备模型。
- MMXU:测量单元(电压、电流、功率)
- ZBAT:电池系统(SOC、SOH、温度)
- ZPCS:储能变流器(功率指令、运行状态)
每个逻辑节点都有标准的数据对象(DO),比如MMXU.PhV表示相电压。这样一来,不同厂家的设备就能“说同一种语言”。
3.2.2 IEC 104:远动通信的“老大哥”
IEC 104是IEC 60870-5-104的简称,主要用于远动通信。在储能场景中,它通常用来把数据上传到调度中心。
我记得有一次做电网侧储能项目,调度端要求用104协议上传遥测、遥信数据。当时我查了标准文档,发现104的ASDU(应用服务数据单元)结构其实挺清晰的:
| 类型标识 | 含义 | 示例 |
|---|---|---|
| 1 | 单点遥信 | 断路器状态(合/分) |
| 3 | 双点遥信 | 刀闸状态(合/分/中间) |
| 9 | 归一化遥测 | 电压、电流(标幺值) |
| 13 | 浮点遥测 | 功率、频率(实际值) |
说白了,104就是一套“打包上传”的规则。你只要把数据按照标准格式封装好,调度端就能解析。但要注意:104的地址分配需要和调度端提前确认,否则数据对不上。
3.3 MQTT:物联网时代的“新宠”
MQTT这几年在储能行业越来越火,尤其是分布式储能和户用储能场景。为什么?因为它轻量、支持发布/订阅模式,而且能穿透防火墙。
3.3.1 MQTT的核心机制
MQTT有三个角色:发布者、订阅者、代理(Broker)。在储能系统中,通常是这样用的:
- BMS/PCS作为发布者:定时上报电压、SOC、温度等数据
- 监控平台作为订阅者:接收数据并存储、展示
- 云端Broker:负责消息路由(比如EMQX、Mosquitto)
我个人习惯用EMQX作为Broker,因为它支持集群部署,而且有Web管理界面,调试起来很方便。
3.3.2 主题设计
主题(Topic)是MQTT的核心。我建议用分层结构来设计:
储能电站ID/设备类型/设备ID/数据点
示例:station_001/bms/bms_01/voltage
station_001/pcs/pcs_01/power
为什么要这样设计?因为订阅者可以灵活订阅。比如运维人员想监控所有BMS的电压,只需要订阅station_001/bms/+/voltage,用+通配符匹配所有设备ID。
bms/voltage),结果设备多了之后,订阅者收到大量无关消息,导致性能下降。所以主题一定要分层,而且每层含义要清晰。
3.3.3 代码示例:MQTT发布数据
用Python的paho-mqtt库发布BMS数据:
import paho.mqtt.client as mqtt
import json
import time
# 创建客户端
client = mqtt.Client()
client.connect("broker.emqx.io", 1883, 60)
# 模拟BMS数据
while True:
data = {
"voltage": 48.5,
"soc": 85.2,
"temperature": 25.3
}
# 发布到主题
client.publish("station_001/bms/bms_01/data",
json.dumps(data),
qos=1) # QoS=1确保至少一次送达
time.sleep(5) # 每5秒上报一次
嗯,这里要注意QoS(服务质量)的选择。QoS=0可能丢消息,QoS=2性能开销大。我一般用QoS=1,既保证可靠性,又不会太慢。
3.4 协议选型建议
说了这么多,到底怎么选?我总结了一张图,你可以参考:
说白了,选型就三个原则:
- 看规模:大型电站必须上61850/104,中小型用Modbus就够了
- 看距离:就地通信用RTU,远程通信用TCP或MQTT
- 看生态:如果设备厂家都支持Modbus,就别强行上61850
好了,这一章的内容就到这里。数据采集协议这块,说白了就是“因地制宜”。你只要理解了每种协议的特点和适用场景,选型就不会出错。下一章咱们聊聊数据存储和时序数据库,那又是另一个有意思的话题了。