MQTT 通信协议与规范
1. 核心设计原则
1.1 弱绑定原则
- 物理 ID 与 业务 ID 分离:
- Physical ID: 如 MAC 地址、IMEI 或芯片唯一 ID。
- Logical ID (Device ID): 系统生成的 UUID。
- 原则:系统中所有业务逻辑(绑定关系、历史数据)均关联到 Logical ID。当设备损坏更换时,只需更新 Logical ID 与 Physical ID 的映射关系,历史数据依然保留。
1.2 安全设计原则
- 零信任:不信任任何来自设备的输入,必须进行格式和范围校验。
- 权限隔离:
- 小程序端指令不直接发给 MQTT Broker,而是发给后端 API,由后端鉴权后代发。
- 设备仅拥有其所属 Topic 的 Pub/Sub 权限(通过 EMQX ACL 控制)。
2. MQTT Topic 规范
我们采用类阿里云 IoT 的 Topic 结构设计:
| 用途 | Topic 模板 | 权限 | 说明 |
|---|---|---|---|
| 属性上报 | sys/{pid}/{did}/thing/event/property/post | Pub | 设备 -> 云端 |
| 属性设置 | sys/{pid}/{did}/thing/service/property/set | Sub | 云端 -> 设备 |
| 属性设置回复 | sys/{pid}/{did}/thing/service/property/set_reply | Pub | 设备 -> 云端 |
| 事件上报 | sys/{pid}/{did}/thing/event/{eventId}/post | Pub | 设备 -> 云端 |
| 服务调用 | sys/{pid}/{did}/thing/service/{serviceId}/call | Sub | 云端 -> 设备 |
| OTA 升级通知 | sys/{pid}/{did}/thing/ota/upgrade | Sub | 云端 -> 设备 |
| OTA 进度上报 | sys/{pid}/{did}/thing/ota/progress | Pub | 设备 -> 云端 |
参数说明:
{pid}: Product ID (产品 ID){did}: Device ID (逻辑设备 ID){eventId}: 事件标识符 (如error,alert){serviceId}: 服务标识符 (如restart)
3. 场景通信示例:四路继电器模块
为了让硬件开发同学更好地理解,我们以“四路继电器模块”为例,还原真实的使用场景。
设备特性:
- 输入:4 个物理按键 (Btn1 ~ Btn4),支持本地控制继电器。
- 输出:4 路继电器 (Relay1 ~ Relay4),控制灯光或电源。
- 通信:ESP32 Wi-Fi + MQTT。
3.1 场景一:用户远程控制 (App -> Device)
场景描述:用户在小程序上点击“打开继电器 1”。
- 订阅 (初始化):设备开机连接 MQTT 后,必须订阅 Topic
sys/{pid}/{did}/thing/service/property/set,监听云端指令。 - 下发:云端收到小程序请求,向该 Topic 发布消息:json
{ "msgId": "12345", "params": { "relay_1": true } } - 执行:设备收到消息,解析出
relay_1为true,驱动 GPIO 输出高电平,继电器吸合。 - 回复:设备向
sys/{pid}/{did}/thing/service/property/set_reply回复执行结果:json{ "msgId": "12345", "code": 200, "msg": "success" } - 同步:同时,设备应触发一次属性上报(见场景二),确保云端影子状态最新。
3.2 场景二:本地按键控制 (Local -> Cloud)
场景描述:用户走到设备前,按下了“按键 1”,灯亮了。此时云端的小程序界面也应该同步变为“开启”状态。
- 动作:设备检测到按键 1 被按下,执行本地逻辑,将继电器 1 吸合。
- 上报:设备主动向
sys/{pid}/{did}/thing/event/property/post发布当前最新状态:json{ "msgId": "abcde", "params": { "relay_1": true, "relay_2": false, "relay_3": false, "relay_4": false } } - 同步:云端收到消息后,更新数据库中的设备状态,并推送给正在观看的小程序用户。
3.3 场景三:OTA 固件升级
场景描述:开发者发布了新固件 V1.1.0,修复了某个 Bug。
- 通知:云端向
sys/{pid}/{did}/thing/ota/upgrade发布升级信息:json{ "version": "1.1.0", "url": "https://oss.iotforgex.com/firmware/v1.1.0.bin", "size": 102400, "md5": "a1b2c3d4..." } - 下载:设备收到消息,暂停业务逻辑,开始通过 HTTP/HTTPS 下载固件。
- 进度:下载过程中,设备每隔 10% 向
sys/{pid}/{did}/thing/ota/progress上报进度:json{ "progress": 50, "desc": "downloading" } - 完成:下载完成并校验通过后,设备重启并运行新固件。重启后上报一次版本号。
