From c515638032cadc35671cc570c73ad61b4e6dda9b Mon Sep 17 00:00:00 2001 From: wangfq Date: Thu, 9 Jul 2026 10:18:03 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20MQTT=E5=8D=8F=E8=AE=AE=20V1.02=20?= =?UTF-8?q?=E5=90=8C=E6=AD=A5=20=E2=80=94=20=E5=AD=97=E6=AE=B5=E5=90=8D?= =?UTF-8?q?=E7=BC=A9=E7=9F=AD=20+=20=E6=97=B6=E9=97=B4=E5=8D=95=E4=BD=8D?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - docs/DLD960_IoT_MQTT协议.md: 字段缩写 + 时间单位 5ms→50ms - vd960DBN/iot_mqtt_srv.c: 6字段缩短对齐协议 (level/iscar/freq/diff/sens/cndtn) - vd960DBN/tcp_json_srv.c: gap_ms5/passtime_ms → gap/passtime - vd960DBN/loop_uart_proto.h: 注释 5ms→50ms - DBNMQTTool/main.py: 模拟样本数据字段同步 --- DBNMQTTool/docs/devlog.md | 32 ++++ DBNMQTTool/main.py | 8 +- docs/DLD960_IoT_MQTT协议.md | 176 +++++++++--------- .../APP/include/loop_uart_proto.h | 2 +- .../APP/iot_mqtt_srv.c | 101 +++++----- .../APP/tcp_json_srv.c | 2 +- vd960DBN/docs/devlog.md | 104 +++++++++++ 7 files changed, 275 insertions(+), 150 deletions(-) diff --git a/DBNMQTTool/docs/devlog.md b/DBNMQTTool/docs/devlog.md index afe0980..0c1b003 100644 --- a/DBNMQTTool/docs/devlog.md +++ b/DBNMQTTool/docs/devlog.md @@ -107,3 +107,35 @@ DBNMQTTool/ | 协议Topic订阅/发布 | ✅ c19e465 | | 自定义Topic订阅/发布 | ✅ c19e465 | | 固件联调 | ✅ vd960DBN IoT 模式稳定上报 | + +--- + +## 2026-07-07 — MQTT V1.01 适配 + 稳定性修复 + +### 1. MQTT 协议 V1.01 适配 + +- Topic 从多主题(`/loop_data`, `/event_report`, `/heartbeat`, `/cmd`…)压缩为双主题 `dld960/{sn}/dev`(上报)、`dld960/{sn}/srv`(下发) +- `manage_mqtt_recv_message()` 实现 V1.01 协议命令分发,支持 `cmd`/`Method` 双格式 +- MQTT PUBLISH 接收修复:topic 过滤 + 通配符路由修正 + +### 2. MqttClient 重构:tkinter 回调 → QObject 信号/槽 + +**问题**: `paho.mqtt` C 层回调直接操作 Qt UI 控件 → `RuntimeError: wrapped C/C++ object has been deleted` 崩溃。 + +**修复**: +- `MqttClient` 继承 `QObject`,使用 Qt 信号/槽机制 +- `on_message` → `message_received` 信号 → 主线程 slot 安全更新 UI +- 所有 publish 路径增加通用异常捕获,防止未捕获异常导致静默崩溃 +- 回退 Qt 信号排队方案,改用 `QMetaObject.invokeMethod` + 日志追踪定位阻塞点 + +### 3. DeviceManager 死锁修复 + +`threading.Lock` 在单线程 Qt 事件循环中自锁 → `RLock`。`add_device()` 和 `remove_device()` 同线程互调时 `Lock` 阻塞自身。 + +### 4. UI/UX 改进 + +- **日志增强**: 收发打印 topic + payload 详情,调试信息更直观 +- **查询响应自动回填**: 设备信息查询后自动填充 SN 等输入框 +- **主动上报配置**: `report_config` 面板支持完整 7 参数独立开关 +- `right` 局部变量 → `self._notebook`,修复 tab 引用丢失 + diff --git a/DBNMQTTool/main.py b/DBNMQTTool/main.py index ed11c73..47008b7 100644 --- a/DBNMQTTool/main.py +++ b/DBNMQTTool/main.py @@ -458,11 +458,11 @@ class MainWindow(QMainWindow): "ts": 1719000100, "data": { "channels": [ - {"ch": 1, "freq_level": "high", "has_car": False, "loop_ok": True, - "freq_current": 105280, "freq_diff": 20, "sensitivity": 7, "condition": 0, + {"ch": 1, "level": "high", "iscar": False, "loop_ok": True, + "freq": 105280, "diff": 20, "sens": 7, "cndtn": 0, "misc": {"type": "time", "value": 0}}, - {"ch": 2, "freq_level": "mid_high", "has_car": True, "loop_ok": True, - "freq_current": 98700, "freq_diff": 1500, "sensitivity": 7, "condition": 2, + {"ch": 2, "level": "mid_high", "iscar": True, "loop_ok": True, + "freq": 98700, "diff": 1500, "sens": 7, "cndtn": 2, "misc": {"type": "time", "value": 350}}, ] } diff --git a/docs/DLD960_IoT_MQTT协议.md b/docs/DLD960_IoT_MQTT协议.md index 7bb9a73..da96102 100644 --- a/docs/DLD960_IoT_MQTT协议.md +++ b/docs/DLD960_IoT_MQTT协议.md @@ -462,47 +462,47 @@ dld960/{dev_serial}/{direction} "channels": [ { "ch": 1, - "sensitivity": 7, - "freq_level": "high", - "loop_delay": 0, - "output_mode": "exist", - "exist_mode": 0, - "direction_mode": 0, - "safe_mode": 0, - "function_mode": 0 + "sens": 7, + "level": "high", + "delay": 0, + "output": "exist", + "exist": 0, + "dir": 0, + "safe": 0, + "fun_mode": 0 }, { "ch": 2, - "sensitivity": 7, - "freq_level": "mid_high", - "loop_delay": 5, - "output_mode": "enter_pulse", - "exist_mode": 10, - "direction_mode": 0, - "safe_mode": 0, - "function_mode": 0 + "sens": 7, + "level": "mid_high", + "delay": 5, + "output": "enter_pulse", + "exist": 10, + "dir": 0, + "safe": 0, + "fun_mode": 0 }, { "ch": 3, - "sensitivity": 5, - "freq_level": "mid_low", - "loop_delay": 0, - "output_mode": "exist", - "exist_mode": 0, - "direction_mode": 1, - "safe_mode": 5, - "function_mode": 0 + "sens": 5, + "level": "mid_low", + "delay": 0, + "output": "exist", + "exist": 0, + "dir": 1, + "safe": 5, + "fun_mode": 0 }, { "ch": 4, - "sensitivity": 8, - "freq_level": "low", - "loop_delay": 10, - "output_mode": "leave_pulse", - "exist_mode": 15, - "direction_mode": 0, - "safe_mode": 0, - "function_mode": 0 + "sens": 8, + "level": "low", + "delay": 10, + "output": "leave_pulse", + "exist": 15, + "dir": 0, + "safe": 0, + "fun_mode": 0 } ] } @@ -514,14 +514,14 @@ dld960/{dev_serial}/{direction} | `auto_mode` | bool | 自动调频模式,默认 false | | `channels` | array | 各路通道参数,1~4 路 | | `channels[].ch` | uint8 | 通道号 1~4 | -| `channels[].sensitivity` | uint8 | 灵敏度 0~9,默认 7 | -| `channels[].freq_level` | string | `"high"`(33nF) / `"mid_high"`(43nF) / `"mid_low"`(66nF) / `"low"`(76nF) | -| `channels[].loop_delay` | uint8 | 延时时间,0~200(×0.1s),最大 20s | -| `channels[].output_mode` | string | `"exist"` / `"enter_pulse"` / `"leave_pulse"` / `"direction"` | -| `channels[].exist_mode` | uint8 | 存在方式,0=永久,非0=分钟数 | -| `channels[].direction_mode` | uint8 | 方向判别模式,0=触发,1~6=方向输出 | -| `channels[].safe_mode` | uint8 | 安全模式,0=关闭,非0=分钟数 | -| `channels[].function_mode` | uint8 | 功能模式 | +| `channels[].sens` | uint8 | sensitivity, 灵敏度 0~9,默认 7 | +| `channels[].level` | string | freq_level, `"high"`(33nF) / `"mid_high"`(43nF) / `"mid_low"`(66nF) / `"low"`(76nF) | +| `channels[].delay` | uint8 | loop_delay, 延时时间,0~200(×0.1s),最大 20s | +| `channels[].output` | string | exist_mode, `"exist"` / `"enter_pulse"` / `"leave_pulse"` / `"direction"` | +| `channels[].exist` | uint8 | output_mode, 存在方式,0=永久,非0=分钟数 | +| `channels[].dir` | uint8 | direction_mode, 方向判别模式,0=触发,1~6=方向输出 | +| `channels[].safe` | uint8 | safe_mode, 安全模式,0=关闭,非0=分钟数 | +| `channels[].fun_mode` | uint8 | function_mode, 功能模式 | **响应:** @@ -563,17 +563,17 @@ dld960/{dev_serial}/{direction} "channels": [ { "ch": 1, - "sensitivity": 7, - "freq_level": "high", - "loop_delay": 0, - "output_mode": "exist", - "exist_mode": 0, - "direction_mode": 0, - "safe_mode": 0, - "function_mode": 0, - "freq_initial": 105300, - "freq_current": 105280, - "freq_diff": 20 + "sens": 7, + "level": "high", + "delay": 0, + "output": "exist", + "exist": 0, + "dir": 0, + "safe": 0, + "fun_mode": 0, + "f_initial": 105300, + "f_current": 105280, + "diff": 20 } ] } @@ -582,9 +582,9 @@ dld960/{dev_serial}/{direction} | 额外字段 | 类型 | 单位 | 说明 | |----------|------|------|------| -| `freq_initial` | uint32 | Hz | 初始频率 | -| `freq_current` | uint32 | Hz | 当前实时频率 | -| `freq_diff` | uint32 | Hz | 频率变化量(绝对值) | +| `f_initial` | uint32 | Hz | freq_initial, 初始频率 | +| `f_current` | uint32 | Hz | freq_current, 当前实时频率 | +| `diff` | uint32 | Hz | 变化量(绝对值) | ## 4.15 设置主动上报 `report_config` @@ -639,13 +639,13 @@ dld960/{dev_serial}/{direction} "channels": [ { "ch": 1, - "freq_level": "high", - "has_car": false, + "level": "high", + "iscar": false, "loop_ok": true, - "freq_current": 105280, - "freq_diff": 20, - "sensitivity": 7, - "condition": 0, + "freq": 105280, + "diff": 20, + "sens": 7, + "cndtn": 0, "misc": { "type": "time", "value": 0 @@ -653,13 +653,13 @@ dld960/{dev_serial}/{direction} }, { "ch": 2, - "freq_level": "mid_high", - "has_car": true, + "level": "mid_high", + "iscar": true, "loop_ok": true, - "freq_current": 98700, - "freq_diff": 1500, - "sensitivity": 7, - "condition": 2, + "freq": 98700, + "diff": 1500, + "sens": 7, + "cndtn": 2, "misc": { "type": "time", "value": 350 @@ -667,13 +667,13 @@ dld960/{dev_serial}/{direction} }, { "ch": 3, - "freq_level": "mid_low", - "has_car": false, + "level": "mid_low", + "iscar": false, "loop_ok": false, - "freq_current": 0, - "freq_diff": 0, - "sensitivity": 5, - "condition": 0, + "freq": 0, + "diff": 0, + "sens": 5, + "cndtn": 0, "misc": { "type": "cut_count", "value": 3 @@ -681,13 +681,13 @@ dld960/{dev_serial}/{direction} }, { "ch": 4, - "freq_level": "low", - "has_car": false, + "level": "low", + "iscar": false, "loop_ok": true, - "freq_current": 62100, - "freq_diff": 5, - "sensitivity": 8, - "condition": 0, + "freq": 62100, + "diff": 5, + "sens": 8, + "cndtn": 0, "misc": { "type": "flow_count", "value": 128 @@ -701,15 +701,15 @@ dld960/{dev_serial}/{direction} | 通道字段 | 类型 | 说明 | |----------|------|------| | `ch` | uint8 | 通道号 1~4 | -| `freq_level` | string | 线圈高低频档位 | -| `has_car` | bool | 是否有车 | +| `level` | string | freq_level 线圈高低频档位 | +| `iscar` | bool | 是否有车 | | `loop_ok` | bool | 线圈是否正常(false=断开) | -| `freq_current` | uint32 | 当前频率 (Hz) | -| `freq_diff` | uint32 | 频率变化量 (Hz) | -| `sensitivity` | uint8 | 当前灵敏度等级 | -| `condition` | uint8 | 环境状态评估值(越大干扰越大) | +| `freq` | uint32 | 当前频率 (Hz) | +| `diff` | uint32 | 变化量 | +| `sens` | uint8 | sensitivity, 当前灵敏度等级 | +| `cndtn` | uint8 | condition, 环境状态评估值(越大干扰越大) | | `misc.type` | string | `"time"`(时间量) / `"cut_count"`(断开次数) / `"flow_count"`(车流量) | -| `misc.value` | uint32 | 杂项数值(时间量单位 5ms) | +| `misc.value` | uint32 | 杂项数值(时间量单位 50ms) | ## 5.2 事件上报 `event_report` @@ -747,9 +747,9 @@ dld960/{dev_serial}/{direction} | 事件类型 `type` | 说明 | `value` 含义 | |----------------|------|-------------| | `car_enter` | 车辆进入 | 0 | -| `car_leave` | 车辆离开 | 通过时间 (×5ms) | +| `car_leave` | 车辆离开 | 通过时间 (×50ms) | | `loop_cut` | 线圈断开 | 0 | -| `loop_restore` | 线圈恢复 | 断开持续时长 (×5ms) | +| `loop_restore` | 线圈恢复 | 断开持续时长 (×50ms) | ## 5.3 设备心跳 `heartbeat` @@ -785,3 +785,5 @@ dld960/{dev_serial}/{direction} |------|----------|----------|--------| | V1.00 | 2026-06-22 | 初始版本,基于串口协议 V1.01 | wangfq | | V1.01 | 2026-07-07 | Topic 压缩为双主题(`{sn}/srv` + `{sn}/dev`),消息类型由 `cmd` 字段区分 | wangfq | +| V1.02 | 2026-07-09 | 缩写相关字段 | wangfq | + diff --git a/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/include/loop_uart_proto.h b/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/include/loop_uart_proto.h index 951985f..66ea99c 100644 --- a/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/include/loop_uart_proto.h +++ b/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/include/loop_uart_proto.h @@ -100,7 +100,7 @@ typedef struct { uint32_t freq; // 频率 (3 bytes, little-endian) uint16_t variation; // 变化量 (2 bytes, little-endian) union { - uint32_t passtime_ms; // 通过时间/车间距, 5ms单位 (misc_type=0) + uint32_t passtime_ms; // 通过时间/车间距, 50ms单位 (misc_type=0) uint32_t cut_amount; // 线圈断开次数 (misc_type=1) uint32_t flow_amount; // 车流量数 (misc_type=2) uint32_t relay_count; // 继电器输出次数 (misc_type=3) diff --git a/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/iot_mqtt_srv.c b/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/iot_mqtt_srv.c index f6bc36d..9bfa2ed 100644 --- a/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/iot_mqtt_srv.c +++ b/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/iot_mqtt_srv.c @@ -386,72 +386,59 @@ void iot_mqtt_publish_sensor(void) { return; } - /* Batch-publish: 2 channels per message to keep each under 512 bytes. - Full-field JSON (freq_current, freq_diff, condition, misc) per the protocol doc. */ - static char data_json[1024]; // single buffer for 2-channel JSON - static char payload[1024]; - char *pub_topic = (char *)g_iot_topic.topic_pub; - uint8_t batch_start = 0; + /* 全通道一次性上报,字段按 DLD960_TCP_JSON协议.md §5.1: + ch, freq_level, has_car, loop_ok, freq_current, freq_diff, + sensitivity, condition, misc.type, misc.value + 注意: mqttBuf 需 ≥ 1024 才能容纳 4 通道全字段封包 (~846 字节) */ + static char data_json[1024]; + static char payload[1400]; + char *p = data_json; + int remaining = sizeof(data_json); + int written; + const char *freq_level_names[] = {"high", "mid_high", "mid_low", "low"}; uint8_t i; - while (batch_start < sr.coil_count) { - char *p = data_json; - int remaining = sizeof(data_json); - int written; - uint8_t batch_end = batch_start + 2; - if (batch_end > sr.coil_count) batch_end = sr.coil_count; + written = snprintf(p, remaining, "{\"channels\":["); + if (written < 0 || written >= remaining) goto done; + p += written; remaining -= written; + + for (i = 0; i < sr.coil_count; i++) { + const LUP_CoilSensor *cs = &sr.coils[i]; + const char *misc_type_str = "time"; + uint32_t misc_val = 0; + + if (cs->misc_type == 0) { misc_type_str = "time"; misc_val = cs->misc.passtime_ms; } + else if (cs->misc_type == 1) { misc_type_str = "cut_count"; misc_val = cs->misc.cut_amount; } + else if (cs->misc_type == 2) { misc_type_str = "flow_count"; misc_val = cs->misc.flow_amount; } + else if (cs->misc_type == 3) { misc_type_str = "relay_count"; misc_val = cs->misc.relay_count; } written = snprintf(p, remaining, - "{\"channels\":["); + "%s{\"ch\":%d,\"level\":\"%s\",\"iscar\":%s," + "\"loop_ok\":%s,\"freq\":%lu,\"diff\":%d," + "\"sens\":%d,\"cndtn\":%d," + "\"misc\":{\"type\":\"%s\",\"value\":%lu}}", + (i > 0) ? "," : "", + i + 1, + freq_level_names[cs->freq_level], + cs->car_state ? "true" : "false", + cs->loop_state ? "false" : "true", + cs->freq, cs->variation, + cs->sensitivity, cs->condition, + misc_type_str, misc_val); if (written < 0 || written >= remaining) goto done; p += written; remaining -= written; - - for (i = batch_start; i < batch_end; i++) { - const LUP_CoilSensor *cs = &sr.coils[i]; - const char *misc_type_str = "time"; - uint32_t misc_val = 0; - - if (cs->misc_type == 0) { misc_type_str = "time"; misc_val = cs->misc.passtime_ms; } - else if (cs->misc_type == 1) { misc_type_str = "cut_count"; misc_val = cs->misc.cut_amount; } - else if (cs->misc_type == 2) { misc_type_str = "flow_count"; misc_val = cs->misc.flow_amount; } - else if (cs->misc_type == 3) { misc_type_str = "relay_count"; misc_val = cs->misc.relay_count; } - - const char *freq_level_names[] = {"high", "mid_high", "mid_low", "low"}; - - written = snprintf(p, remaining, - "%s{\"ch\":%d,\"freq_level\":\"%s\",\"has_car\":%s," - "\"loop_ok\":%s,\"freq_current\":%lu,\"freq_diff\":%d," - "\"sensitivity\":%d,\"condition\":%d," - "\"misc\":{\"type\":\"%s\",\"value\":%lu}}", - (i > batch_start) ? "," : "", - i + 1, - freq_level_names[cs->freq_level], - cs->car_state ? "true" : "false", - cs->loop_state ? "false" : "true", - cs->freq, cs->variation, - cs->sensitivity, cs->condition, - misc_type_str, misc_val); - if (written < 0 || written >= remaining) goto done; - p += written; remaining -= written; - } - - snprintf(p, remaining, "]}"); - - /* Wrap in outer message and publish */ - snprintf(payload, sizeof(payload), - "{\"msg_id\":%d,\"cmd\":\"loop_data\",\"ts\":%lu,\"data\":%s}", - ++g_iot_msg_id, mstick() / 1000, data_json); - - uint16_t plen = (uint16_t)strlen(payload); - mqtt_publish(pub_topic, payload, 0); - - batch_start = batch_end; } -done: - InitPkgUart(&g_pkg_uart_2); -} + snprintf(p, remaining, "]}"); + /* Wrap and publish */ + snprintf(payload, sizeof(payload), + "{\"msg_id\":%d,\"cmd\":\"loop_data\",\"ts\":%lu,\"data\":%s}", + ++g_iot_msg_id, mstick() / 1000, data_json); + + mqtt_publish((char *)g_iot_topic.topic_pub, payload, 0); + +done: InitPkgUart(&g_pkg_uart_2); } diff --git a/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/tcp_json_srv.c b/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/tcp_json_srv.c index d7fc1e9..34564c4 100644 --- a/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/tcp_json_srv.c +++ b/vd960DBN/BLE/OnlyUpdateApp_Peripheral/APP/tcp_json_srv.c @@ -1044,7 +1044,7 @@ static int format_sensor_json(char *buf, uint16_t buf_size, const LUP_SensorRepo switch (cs->misc_type) { case 0: // car_state=0(无车)→通过时间, car_state=1(有车)→车间距 - misc_field = cs->car_state ? "\"gap_ms5\"" : "\"passtime_ms\""; + misc_field = cs->car_state ? "\"gap\"" : "\"passtime\""; misc_val = cs->misc.passtime_ms; break; case 1: misc_field = "\"cut_amount\""; misc_val = cs->misc.cut_amount; break; diff --git a/vd960DBN/docs/devlog.md b/vd960DBN/docs/devlog.md index 225e0a2..f39e346 100644 --- a/vd960DBN/docs/devlog.md +++ b/vd960DBN/docs/devlog.md @@ -107,10 +107,114 @@ --- +## 2026-07-06 — MQTT IoT 基础打通 + +### 背景 + +在 CH32V208(RISC-V, 栈仅 2KB)上实现 MQTT IoT 协议栈,对标 DBN101GA 参考项目。WCHNET TCP MSS=576, Publish 须 ≤500B。 + +### 1. MQTT 重构对标 DBN101GA + +- `iot_mqtt_srv.c` 对标 DBN101GA 参考实现重写 +- MQTT socket 复用 `SocketId_TCP`(而非独立 socket) +- `iot_connect_broker` 加 `SourPort` 参数 +- 出厂默认 topic 使用真实设备序列号 + +### 2. 栈溢出系列修复 + +| 问题 | 修复 | +|------|------| +| MQTT buffer 在栈上 → 溢出 | 改为 `static` 全局分配 | +| `iot_mqtt_publish_sensor`: `data_json[2KB] + payload[2KB] = 4KB` 远超 2KB 栈 | 减小缓冲区 + static 分配 | +| 缓冲区 2048 → 1024 | 单次交互不超 1KB | + +### 3. MQTT CONNECT 延迟发送 + +**根因**: `MQTT_connect()` 在中断上下文调用 `WCHNET_SocketSend` → 崩溃。 + +**修复**: CONNECT 包延到 poll 轮询内发送,避免中断内调用网络 API。 + +### 4. MQTTPacket 初始化修复 + +`MQTTPacket_connectData_initializer` 是复合字面量,不能用于赋值。改用临时变量中转。 + +### 5. IoT socket 重复创建 + broker IP 解析修复 + +- IoT socket 重复创建 → 连接失败,改为复用已有 socket +- broker IP 字符串解析修正 + +--- + +## 2026-07-07 — MQTT 协议 V1.01 + 命令分发 + +### 1. MQTT 主题压缩:多主题 → 双主题 + +协议从 V1.00 的多 topic(`dld960/{sn}/loop_data`, `/event_report`, `/heartbeat`, `/cmd`, `/cfg`…)压缩为 V1.01 双主题: + +| 方向 | V1.00 | V1.01 | +|------|-------|-------| +| 设备→平台 | 5+ topics | `dld960/{sn}/dev` | +| 平台→设备 | 5+ topics | `dld960/{sn}/srv` | + +### 2. MQTT 命令分发 + +`manage_mqtt_recv_message()` 实现 V1.01 协议命令分发,支持 `cmd` / `Method` 双格式:`pwd_verify`, `dev_info_query`, `loop_param_set/query`, `loop_version_query`, `loop_factory_init`, `device_reset`, `factory_reset` 等。 + +### 3. report_config 完整 7 参数 + +MQTT/TCP `report_config` 支持完整 7 参数配置:`period`, `loop_data`, `event_report`, `heartbeat`, `passtime`, `cut_amount`, `flow_amount`。与 TCP JSON 协议统一。 + +### 4. MQTT 网络配置 + +`ssc_net_set` / `iot_net_set` / `iot_topic_set` 三条命令实现,支持通过 MQTT 远程配置设备网络参数和主题。 + +--- + +## 2026-07-08 — MQTT 稳定性修复系列 + +### 1. g_iot_socket 未初始化 → 硬故障重启 + +`g_iot_socket` 声明为全局变量但未初始化,值为 `0xFF` → `WCHNET_SocketSend(0xFF)` 直接触发硬件故障重启。 + +**修复**: 初始化为 `INVALID_SOCKET`。 + +### 2. loop_data JSON 超 MSS 导致 SocketSend 溢出 + +WCHNET TCP MSS=576,原 `loop_data` JSON 四通道全字段 ~800B → `WCHNET_SocketSend` 溢出崩溃重启。 + +**修复**: 精简 JSON 字段至 ~400B(单包达标),再**分批发送**(2通道/包 × 2包)。 + +### 3. iot_mqtt_send() hex dump 循环 → 栈溢出 + +调试用的 hex dump 循环(65次 `PRINT`)在仅 2KB 栈的 CH32V208 上直接栈溢出重启。 + +**修复**: 移除 hex dump 循环。 + +### 4. MQTT 主动上报无数据 + PINGREQ 缺失 + +`poll_mqtt()` 未正确触发 `MQTT_Yield()` 和 `MQTT_Live()`,导致主动上报无数据、PINGREQ 缺失断连。 + +**修复**: 改用 `net_srv.c` 统一的 `mqtt_publish()` + 修正 `poll_mqtt()` 调度逻辑。 + +### 5. 传感数据 topic 修正 + +topic 修正为 V1.01 双主题协议 `dld960/{sn}/dev`(此前遗留旧 topic 格式)。 + +### 6. 恢复 loop_data 完整字段 + +精简 JSON 后缺失部分字段(`freq`, `passtime_ms` 等),恢复完整字段并在分批框架内发送。 + +--- + ## 修订记录 | 版本 | 时间 | 说明 | |------|------|------| +| V3.0 | 2026-07-08 | MQTT 稳定性修复: socket初始化/buffer溢出/分批发送/hex dump/PINGREQ | +| V2.9 | 2026-07-07 | MQTT V1.01 双主题协议 + 命令分发 + report_config 7参数 | +| V2.8 | 2026-07-07 | MQTT 网络配置: ssc_net_set / iot_net_set / iot_topic_set | +| V2.7 | 2026-07-06 | MQTT IoT 基础打通: 对标DBN101GA + 栈溢出修复 + CONNECT延迟发送 | +| V2.6 | 2026-07-06 | IoT 模式配置 bug 修复 | | V2.5 | 2026-07-03 | tcp_json_restart 只关数据socket, listen保持不动 (WCHNET限制) | | V2.4 | 2026-07-03 | 去掉 Auth 60s timeout, 改为3次失败即重启 | | V2.3 | 2026-07-03 | Auth timeout 不计入重启限额, 修复冷却期阻断连接 |