Skip to content

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/postPub设备 -> 云端
属性设置sys/{pid}/{did}/thing/service/property/setSub云端 -> 设备
属性设置回复sys/{pid}/{did}/thing/service/property/set_replyPub设备 -> 云端
事件上报sys/{pid}/{did}/thing/event/{eventId}/postPub设备 -> 云端
服务调用sys/{pid}/{did}/thing/service/{serviceId}/callSub云端 -> 设备
OTA 升级通知sys/{pid}/{did}/thing/ota/upgradeSub云端 -> 设备
OTA 进度上报sys/{pid}/{did}/thing/ota/progressPub设备 -> 云端

参数说明

  • {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”。

  1. 订阅 (初始化):设备开机连接 MQTT 后,必须订阅 Topic sys/{pid}/{did}/thing/service/property/set,监听云端指令。
  2. 下发:云端收到小程序请求,向该 Topic 发布消息:
    json
    {
      "msgId": "12345",
      "params": {
        "relay_1": true
      }
    }
  3. 执行:设备收到消息,解析出 relay_1true,驱动 GPIO 输出高电平,继电器吸合。
  4. 回复:设备向 sys/{pid}/{did}/thing/service/property/set_reply 回复执行结果:
    json
    {
      "msgId": "12345",
      "code": 200,
      "msg": "success"
    }
  5. 同步:同时,设备应触发一次属性上报(见场景二),确保云端影子状态最新。

3.2 场景二:本地按键控制 (Local -> Cloud)

场景描述:用户走到设备前,按下了“按键 1”,灯亮了。此时云端的小程序界面也应该同步变为“开启”状态。

  1. 动作:设备检测到按键 1 被按下,执行本地逻辑,将继电器 1 吸合。
  2. 上报:设备主动向 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.3 场景三:OTA 固件升级

场景描述:开发者发布了新固件 V1.1.0,修复了某个 Bug。

  1. 通知:云端向 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..."
    }
  2. 下载:设备收到消息,暂停业务逻辑,开始通过 HTTP/HTTPS 下载固件。
  3. 进度:下载过程中,设备每隔 10% 向 sys/{pid}/{did}/thing/ota/progress 上报进度:
    json
    {
      "progress": 50,
      "desc": "downloading"
    }
  4. 完成:下载完成并校验通过后,设备重启并运行新固件。重启后上报一次版本号。