1. 矿山传感器MQTT主题层级设计
为什么矿山场景必须先定主题层级
井下传感器数量多、分布广,且同一类设备会在多个区域重复出现。如果主题随手写成 gas/001 或 sensor/data,后续做区域统计、按类型批量订阅、故障隔离时都会失去可筛选的维度。可扩展的主题设计核心是:把“设备类型、区域、编号”拆成固定层级,把“数据/状态/报警”放在末级,让订阅方既能精确订阅单点,也能用通配符按区域或类型聚合。
层级命名规则
本案例采用 5 级结构,全部小写、用 / 分隔,禁止空格与中文:
| 层级 | 含义 | 取值规则 | 示例 |
|---|---|---|---|
| L1 | 矿山标识 | 固定 mine | mine |
| L2 | 设备类型 | gas / wind / water | gas |
| L3 | 区域 | 区号,如 a1、b2 | a1 |
| L4 | 设备编号 | 类型缩写+3位序号 | g001 |
| L5 | 数据类别 | data / status / alarm | data |
完整主题示例:mine/gas/a1/g001/data。这样设计后,区域、类型、编号各自独立成层,通配符可以精确落在需要聚合的那一层。
通配符匹配关系
MQTT 有两种通配符:+ 匹配单层,# 匹配多层且只能出现在末尾。下图展示同一批传感器主题与几种典型订阅的匹配关系,用于验证层级设计是否让“按区域聚合”“按类型聚合”“单点精确订阅”都能成立。
用代码验证匹配正确性
层级设计是否成立,不能只靠肉眼判断。下面用 Python 的 paho-mqtt 自带主题匹配函数 topic_matches_sub 对订阅规则做离线验证,无需连接 Broker 即可确认通配符行为。
from paho.mqtt.client import topic_matches_sub
published = [
"mine/gas/a1/g001/data",
"mine/gas/a1/g002/alarm",
"mine/wind/b2/w001/data",
"mine/water/a1/t001/status",
"mine/water/b2/t002/data",
]
subscriptions = {
"mine/gas/+/+/data": 1,
"mine/+/a1/+/+": 3,
"mine/water/#": 2,
"mine/gas/a1/g001/data": 1,
"mine/+/+/+/alarm": 1,
}
for sub, expected in subscriptions.items():
hits = [t for t in published if topic_matches_sub(sub, t)]
ok = "PASS" if len(hits) == expected else "FAIL"
print(f"[{ok}] {sub} -> {len(hits)} 条 (期望 {expected})")
for h in hits:
print(f" {h}")
预期输出中每条订阅都应为 PASS。若某条出现 FAIL,通常说明层级顺序写错(例如把区域放在类型之前),或 # 没有放在末尾。
编号层建议用“类型缩写+序号”,如
g001、w001、t001,避免不同区域出现相同编号时无法从主题本身区分设备类型。不要用
# 作为订阅首层(如 # 或 +/+/+/+/+)来“图省事”接收全部数据。井下带宽和 Broker 负载有限,全量订阅会放大无关流量,也削弱按区域隔离故障的能力。