proto: event_report 增加平台/客户端必答确认机制 (MQTT V1.04 / TCP V1.01)

事件为不可再生关键数据, QoS/TCP送达不代表业务层落库, 引入应用层闭环:
- 应答格式: 回显 msg_id + code/msg, 不带 data
- 设备重发: 5s 超时, 同 msg_id/原始 ts, 最多 3 次, 失败留队列
  待重连或下一事件合并上报 (MQTT ≤500B / TCP ≤4096B 拆包)
- 平台/客户端: 先落库后应答; msg_id 十分钟窗口去重, 重复包答 code=0 不重复入库
- 附正常/应答丢失重发时序图; 命令详表与交互示例同步
This commit is contained in:
wangfq
2026-07-15 11:55:21 +08:00
parent dc7dd1cb26
commit 0861a1c1f8
2 changed files with 90 additions and 4 deletions
+55 -3
View File
@@ -119,7 +119,7 @@ dld960/{dev_serial}/{direction}
| `report_config` | 设置主动上报 | srv→dev | 0xC5 |
| `initialize` | 设备上电初始化登陆 | dev→srv | — |
| `loop_data` | 线圈传感数据上报 | dev→srv | 0xC0 |
| `event_report` | 事件上报 | dev→srv | — |
| `event_report` | 事件上报**平台须应答**,见 §5.3 | dev→srv | — |
| `heartbeat` | 设备心跳 | dev→srv | — |
---
@@ -748,9 +748,14 @@ dld960/{dev_serial}/{direction}
## 5.3 事件上报 `event_report`
> Topic: `dld960/{sn}/dev`
> 上报 Topic: `dld960/{sn}/dev`
> 应答 Topic: `dld960/{sn}/srv`
> QoS: 1(建议)
> **⚠️ 本指令要求平台必须应答**(区别于 `loop_data` / `heartbeat` 的单向上报)
设备检测到事件时主动上报,非周期性。
设备检测到事件时主动上报,非周期性。事件(进车/出车/线圈断开等)是**不可再生的关键数据**,MQTT QoS 仅保证 broker 收到,不代表平台业务层已处理入库,因此引入**应用层应答 + 设备重发**机制闭环确认。
**设备上报(dev topic):**
```json
{
@@ -786,6 +791,52 @@ dld960/{dev_serial}/{direction}
| `loop_cut` | 线圈断开 | 0 |
| `loop_restore` | 线圈恢复 | 断开持续时长 (×50ms) |
**平台应答(srv topic,收到后必须立即回复):**
```json
{
"msg_id": 101,
"cmd": "event_report",
"ts": 1719000201,
"code": 0,
"msg": "success"
}
```
| 字段 | 说明 |
|------|------|
| `msg_id` | **必须回显**设备上报的 `msg_id`,设备以此匹配确认 |
| `cmd` | 固定 `"event_report"` |
| `code` | 0 = 已接收并处理;非 0 = 处理失败(设备视同未确认,进入重发) |
**设备端确认与重发机制:**
1. 发出 `event_report` 后启动确认定时器,**5s** 内未收到 `msg_id` 匹配且 `code=0` 的应答 → 重发;
2. 重发使用**相同的 `msg_id` 与原始 `ts`**(首次事件发生时间,不随重发刷新),平台以此去重;
3. 最多重发 **3 次**(含首发共 4 次)。仍未确认 → 事件保留在待发队列,待 **MQTT 重连成功或下一次事件触发**时合并上报;
4. 等待确认期间新产生的事件,合并进下一包的 `events` 数组(使用新 `msg_id`)。单包长度受发布缓冲限制(≤500B),超出时拆包分批;
5. 待发队列建议深度 **≥16 条事件**,溢出时丢弃最旧事件(先保新鲜数据)。
**平台端要求:**
1. 收到 `event_report` **先落库、后应答**,应答即承诺数据已持久化;
2.`(dev_serial, msg_id)` 在近期窗口(建议 10 分钟)内去重——重复包为设备未收到应答所致,**直接应答 `code=0`,不重复入库**(设备重启后 `msg_id` 从头递增,去重必须限定时间窗口);
3. 应答报文应控制在最小集(不带 `data`),减轻设备下行解析负担。
**时序(正常 / 应答丢失重发):**
```
设备 平台
│── event_report(id=101) ──▶│ 落库
│◀─ ack(id=101, code=0) ────│ 确认, 事件出队
│── event_report(id=102) ──▶│ 落库
│ ✗ 应答丢失 │
│ [5s 超时] │
│── event_report(id=102) ──▶│ (dev_serial,102) 命中去重 → 不入库
│◀─ ack(id=102, code=0) ────│ 确认, 事件出队
```
## 5.4 设备心跳 `heartbeat`
> Topic: `dld960/{sn}/dev`
@@ -822,4 +873,5 @@ dld960/{dev_serial}/{direction}
| V1.01 | 2026-07-07 | Topic 压缩为双主题(`{sn}/srv` + `{sn}/dev`),消息类型由 `cmd` 字段区分 | wangfq |
| V1.02 | 2026-07-09 | 缩写相关字段 | wangfq |
| V1.03 | 2026-07-09 | 增加设备上电初始化指令 | wangfq |
| V1.04 | 2026-07-15 | `event_report` 增加**平台必答**机制:应答格式(回显 `msg_id`)、设备 5s 超时重发(同 `msg_id`/`ts`,最多 3 次)、待发队列合并上报、平台去重与先落库后应答要求 | wangfq |