学习笔记 · Obsidian

MQTT、EMQX 与 Java:建立可解释的设备闭环

ESP-IDFC / C++

MQTT 解决异步消息分发

客户端向 broker 发布消息,broker 按订阅关系分发。主题组织路由,payload 的格式由应用约定,MQTT 本身不强制 JSON。MQTT 5.0 的规范由 OASIS 发布。MQTT 规范入口

flowchart LR
    C[CoreS3] -->|telemetry / ack| B[EMQX]
    B -->|订阅消息| J[Java 消费者]
    J --> D[(数据库)]
    J -->|command| B
    B -->|设备订阅| C
    J --> W[Web 或 App]

这是一份学习项目草案,没有据此修改现有后端或创建 EMQX 配置。Redis 仅在确有缓存、在线状态或协调需求时加入。

先分清 QoS、保留消息和遗嘱

机制它负责什么应用仍要负责什么
QoS 0至多一次的协议交付方式能否接受丢失
QoS 1至少一次,可能重复幂等与去重
QoS 2协议接收方范围内恰好一次交付数据库、外部动作与业务端到端一致性
Retain为主题保留最近的保留消息过期、清除、消息是否适合后到订阅者
Will连接异常结束等协议条件下发布预设消息心跳、业务健康与及时性判断

准确语义以 OASIS MQTT 5.0 为准。QoS 1 的 PUBACK 或客户端 published 事件不代表 Java 已落库,更不代表设备已经执行命令。

一份可以讨论的 topic 契约

以下全是教学命名。tenantId、deviceId 来自认证与授权绑定,不能相信 payload 自报身份。

Topic 后缀(前缀 lab/{tenantId}/{deviceId}/)发布 → 订阅建议 QoS / Retain语义
telemetry设备 → Java1 / false观测值;应用层可能重复
status设备 → 平台1 / true最近连接状态,附时间与启动标识
commandJava → 设备1 / false指令;带 commandId、有效期及参数
ack设备 → Java1 / false对某条指令的处理结果

状态 retained 消息表示最近已知值,不证明此刻在线。命令默认不保留,避免重连后自动执行很早以前的动作;配置同步可另设计“期望状态”模型。

命令成功必须有业务证据

第一条练习命令用“把采样周期设置为 1000 ms”,便于重复执行和观察。

平台创建 commandId
  → 发布 command
  → 设备校验身份、有效期、参数、重复性
  → 应用配置
  → 发布 ack(同一个 commandId)
  → 平台记录最终结果

本课程草案把状态分为 accepted、applied、rejected、failed。accepted 仅表示接收;若选择承诺配置掉电保存,applied 应在保存成功且运行参数生效后回传。平台等不到回执时显示“结果未知/等待查询”,不能直接推断执行失败。

相同 commandId 重发应返回已知结果,不重复执行有副作用动作。设备重启后若丢了内存中的去重记录,保证也会丢失:因此有副作用指令需要持久化或其他可恢复协议。第一轮选“设置绝对值”,先避开难以恢复的“再加一次”。

设备和 broker 的职责边界

设备使用唯一身份、TLS 和最小主题权限。EMQX 的认证解决“是谁”,授权解决“允许发布/订阅哪些 topic”。设备不能读取其他设备命令,后端按可信身份映射消息归属。EMQX Authorization

Java 消费者要对去重键设置唯一约束或使用等效的原子写入。遥测可以采用 (deviceId, bootId, sequence);命令采用 commandId。数据库中的具体表和事务边界,待实现时再确认。

ESP-MQTT 收包的缓冲区边界

消息可能分片到达。接收端检查 data_len、total_data_len、current_data_offset,在大小上限内组装完整消息,再解析 JSON。不能假定一次回调就是完整 payload,或 payload 自带零终止符。ESP-MQTT Events

过关测试

正常上报;broker 重启后恢复;QoS 1 重复消息;设备重启后重复命令;过期命令;无权限 topic;超大/分片/非法 payload;命令已生效但回执丢失。逐项记录预期与实测,才算设备到后端链路验收。


返回学习入口 · 来源与版本