3. MQTT协议基础:发布/订阅模型、主题(Topic)、服务质量(QoS)

好,咱们进入正题。这一章是MQTT的核心,也是你在储能监控里用得最多的东西。说白了,MQTT就是个“传话”的协议,但它传话的方式很特别——不是点对点,而是通过一个中间人。

3.1 发布/订阅模型:不是“你找我”,而是“我等你”

传统的HTTP通信,就像你打电话给朋友:“喂,给我查一下电池电压。”朋友查完告诉你。这叫请求/响应模式。但在储能系统里,设备数量动不动就成百上千,每个设备都主动去问,服务器早崩了。

MQTT用的是另一种模式:发布/订阅。我习惯把它比作“电台广播”。

  • 发布者(Publisher):只管往外发消息,不管谁在听。比如BMS(电池管理系统)每隔1秒发一次电压数据。
  • 订阅者(Subscriber):只管接收自己感兴趣的消息。比如监控大屏只订阅“电压”主题,不关心“温度”。
  • 代理(Broker):中间人,负责接收发布者的消息,再转发给所有订阅者。

你看,发布者和订阅者完全解耦。它们不需要知道对方的存在,甚至不需要同时在线。我在一个光伏储能项目里就遇到过这种情况:现场网络不稳定,BMS偶尔掉线。但用MQTT,BMS上线后把数据一推,Broker自动缓存,订阅者该收还是能收到。这要是用HTTP,掉线期间的数据全丢了。

核心优势:发布/订阅模型天然支持一对多通信,非常适合储能系统中“一个数据源,多个消费端”的场景。

下面这张图,是我手绘的MQTT通信流程,你看一眼就明白了。

发布者 (BMS/电表) 代理(Broker) (EMQX/Mosquitto) 订阅者1 (监控大屏) 订阅者2 (历史数据库) 发布消息 转发 转发 MQTT 发布/订阅模型

3.2 主题(Topic):消息的“门牌号”

有了发布/订阅模型,消息怎么分类?靠的就是主题(Topic)。你可以把主题想象成快递上的地址,Broker根据这个地址把消息送到对应的订阅者手里。

主题的格式是分层的,用斜杠“/”分隔。比如在储能系统里,我常用的主题结构是这样的:

储能电站ID/设备类型/设备ID/数据点
示例:sz_station_01/bms/bms_001/voltage
      sz_station_01/bms/bms_001/temperature
      sz_station_01/pcs/pcs_001/power

为什么要分层?因为MQTT支持通配符订阅,这在实际项目中太有用了。

  • 单级通配符“+”:匹配一层。比如订阅 sz_station_01/+/bms_001/voltage,就能收到所有设备类型下bms_001的电压数据。
  • 多级通配符“#”:匹配剩余所有层。比如订阅 sz_station_01/#,就能收到这个电站的所有数据。

我的经验:主题设计一定要提前规划好。我曾经在一个项目中,因为主题层级太浅(比如直接用“data/voltage”),导致后期设备多了,订阅过滤非常困难。建议至少包含“站点/设备类型/设备ID/数据点”这四层。

另外,主题名不要用中文,也不要用特殊字符。Broker对UTF-8支持没问题,但客户端库不一定。我见过有人用中文主题,结果某个嵌入式设备解析不了,数据全丢了。老老实实用英文加下划线。

3.3 服务质量(QoS):消息能丢吗?

储能系统里,有些数据丢了无所谓,比如环境温度,5秒一次,丢一两次不影响。但有些数据绝对不能丢,比如保护动作信号、告警信息。MQTT用QoS来解决这个问题。

QoS有三个等级,我一个个说。

QoS等级 含义 可靠性 适用场景
0 最多发一次 最低,可能丢 遥测数据(电压、电流、温度)
1 至少发一次 中等,可能重复 状态变更(设备启停、模式切换)
2 恰好发一次 最高,不丢不重 告警、保护动作、控制指令

QoS 0:说白了就是“发完拉倒”。Broker收到消息后直接转发,不确认,不存储。性能最高,但可能丢消息。我在项目中,像电池电压、SOC这种高频数据,都用QoS 0。丢了就丢了,下一秒还有。

QoS 1:保证消息至少到达一次。Broker收到后会回复一个PUBACK确认包。如果发布者没收到确认,会重发。但这就可能导致订阅者收到重复消息。嗯,这里要注意:你的业务逻辑必须能处理重复数据。比如设备状态变更,如果重复收到“开机”指令,设备会不会重复执行?

避坑指南:我曾经在一个储能项目中,用QoS 1下发“停止充电”指令。结果因为网络抖动,指令重复发了两次,BMS执行了两次停止操作,导致充电桩报错。后来我改成QoS 2,并在应用层加了去重逻辑,才彻底解决。

QoS 2:最严格,保证消息恰好到达一次。它用了四次握手协议(PUBLISH → PUBREC → PUBREL → PUBCOMP),开销最大,速度最慢。但像“电池过温保护”、“断路器跳闸”这种关键指令,必须用QoS 2。命只有一条,不能丢,也不能重。

你可能会问:那所有消息都用QoS 2不就行了?不行。你想想看,一个储能电站每秒可能有上千条遥测数据,如果都用QoS 2,Broker的CPU和内存直接拉满,延迟飙升。所以我的原则是:按数据价值分配QoS

3.4 实际项目中的QoS选择策略

我整理了一份储能监控中常见数据的QoS配置表,供你参考。

数据类型 推荐QoS 理由
遥测数据(电压、电流、温度) 0 高频、可丢失、有冗余
状态数据(设备启停、模式) 1 低频、需可靠、可容忍重复
告警数据(过压、过温、绝缘故障) 2 关键、不可丢、不可重复
控制指令(充电、放电、停机) 2 关键、需确认、需幂等
日志/事件记录 1 重要但允许少量重复

最后说一句:QoS是MQTT协议层面的保证,但应用层最好也做一层校验。比如每条消息带一个唯一ID,订阅者收到后检查ID是否重复。这叫“双重保险”。我在实际项目中就是这么干的,效果很好。

总结一下:发布/订阅模型解耦了生产者和消费者;主题用分层结构组织消息;QoS根据数据重要性选择。这三样东西,是你在储能监控里用好MQTT的基础。下一章咱们聊MQTT的会话和遗嘱机制,那才是真正让系统“健壮”的关键。


专注资料整理