背景: MQTT 快照流实测 MQTTSerialize_publish failed — JSON 化快照记录 ~810B/条 超 800B 发送缓冲
方案(用户拍板): 对齐 BLE 通道, 原始字节 hex 上报
固件 (V4.3):
- offlog.c/h: 新增 offlog_evt_to_hex() (32B→64 hex)
- snapshot.c/h: 新增 snap_rec_to_hex() (64B→128 hex); 删 SNAP_MAX_QUERY_JSON, 恢复 count=2
- tcp_json_srv.c / iot_mqtt_srv.c: log_query 改 {"seq":N,"hex":"..."}; SEND_BUF 保持 800
- 2 条快照 hex 响应 406B < 800B
文档: TCP JSON V1.03 / MQTT V1.07 §4.17 records 改 hex + 解析表引用 BLE §6.4/§7
工具: parse_offlog_hex/parse_snap_hex/offlog_payload_desc + hex 展示; 验证: gcc 9 断言 + 工具解析全过 + offscreen UI
11 KiB
DBNMQTTool 开发日志
DLD960 IoT MQTT 桌面工具 | Python 3.11+ | PySide6 | paho-mqtt v2 | 跨平台 (Windows/Linux/macOS)
定位: DLD960 车检器 MQTT 调试工具 — 设备管理、实时数据监控、模拟上报、主题订阅/发布
2026-08-18 — log_query 响应改 hex 原始字节解析展示(协议 V1.07 修订)
背景
MQTT 快照流实测 MQTTSerialize_publish failed——JSON 化快照记录超 800B 发送缓冲。协议修订为原始字节 hex 上报(与 BLE 通道同语义),工具同步改为 hex 解析。
变更
- protocol.py:新增
parse_offlog_hex(OfflogEvt 32B,<BBBBIIIHH12s)、parse_snap_hex(SnapRec 64B,<BBBBIIHH48s)、offlog_payload_desc(boot 复位位/coil/evt_retry/evt_giveup/iot_disconnect/reconn)、OFFLOG_TYPE_NAMES——字段表与 BLE 协议 §6.4/§7 一致 data_log_querysnapshot count 恢复 2(hex 体积可控)- main.py:
_apply_log_query_data解析records[].hex(hex 长度 128=快照 / 64=事件);事件流展示 type 描述 + payload 可读化,快照流逐通道字段
验证
- 构造事件/快照二进制→hex→解析回断言全过(POR/SFT 复位位、coil payload、evt_retry、快照 4ch、负 variation 符号扩展)
- 2 条快照 hex 响应 payload = 406B < 800B
- offscreen UI:事件流(上电/复位、线圈事件、event 重发)+ 快照流(4ch/2ch)展示 + 翻页正常
2026-08-18 — 脱机日志翻页:上一页/下一页 + 自动填充起始序号
变更
- 脱机日志区按钮行新增 ◀ 上一页 / 下一页 ▶(初始禁用,拉取成功后启用)
- 下一页:起始序号 = 当前页最后一条
seq+ 1(锚点法,不依赖请求条数,快照流 2 条/事件流 4 条均精确);空记录兜底按start + count步进 - 上一页:起始序号 =
max(1, 当前起始 - 条数),边界保护 - 翻页后自动填充起始序号 SpinBox 并触发拉取;页锚点在
_apply_log_query_data更新(_log_page_last_seq)
验证
- offscreen 实测 6 场景全过:初始禁用 / 锚点=103 / 下一页→104 / 上一页→100 / 边界→1 / 空记录步进→504 / 快照流 2 条→12
2026-08-18 — 命令集对齐:禁用固件未实现的 MQTT 命令按钮
背景
实测发现 MQTT 通道 ssc_net_query / iot_net_query 返回 code=4 unsupported command——固件 MQTT 分发只实现 6 条命令,工具按协议文档命令表做了全按钮。
变更
- 固件同步补齐(vd960DBN V4.2):
ssc_net_query/iot_net_query/iot_topic_query三条查询命令已实现,工具对应查询按钮保持可用 - 工具禁用固件仍未实现的命令按钮:
ssc_net_set/iot_net_set/iot_topic_set/pwd_set/factory_reset/device_reset(setEnabled(False)+ tooltip 引导走 TCP JSON/BLE 通道) - 设备刷新列表移除
CMD_LOOP_PARAM_QUERY(固件未实现,刷新时不再报 error)
验证
- offscreen 实例化:6 个按钮禁用 + tooltip 正确,查询类/验证密码/report_config/log_* 可用
2026-08-18 — 脱机日志支持快照流 (stream=snapshot, 协议 V1.07)
变更
- protocol.py:新增
STREAM_EVENT/STREAM_SNAPSHOT常量;data_log_query加stream参数(快照流显式传stream字段 + count≤2);新增data_log_clear(stream)(事件流省略 data 兼容老固件);新增SNAP_MISC_TYPE_DESC(time/cut_count/flow_count/relay_count 中文描述) - main.py:脱机日志区加"日志流"选择器(事件日志/传感快照);统计/拉取/清除三按钮按当前流发请求(log_clear 确认框提示阻塞时长 2.8s/45ms);
log_stat/log_query响应展示区分流——快照记录解析channels[]逐字段(freq_level/direction/freq_type/sens/cond/loop/car/freq/variation/misc)
验证
- protocol 数据构建器断言 6 例全过(事件流不带 stream / 快照流 count≤2 / log_clear 流参数)
QT_QPA_PLATFORM=offscreen实例化 MainWindow 实测:log_stat(snapshot)capacity=48064 展示、log_query(snapshot)2 条快照记录逐字段展示(含负 variation、misc_type 中文)、事件流展示回归无损、空记录边界- 依赖:venv + PySide6 + paho-mqtt(
venv/已加 .gitignore)
配套
- 固件 vd960DBN
log_*stream=snapshot 分支(同日实现,devlog V4.1) - 协议文档:TCP JSON V1.03 / IoT MQTT V1.07
2026-07-06 (晚) — 模拟上报 + 协议Topic + 自定义Topic c19e465
1. 模拟上报 Tab
- loop_data / event_report / heartbeat 三类上报携带独立可编辑 JSON 编辑区
- 范例填充:首次切换类型时自动填入协议定义的标准载荷
- 单次发送 + 周期上报(QSpinBox 可调间隔)
- 周期开关由
QPushButtontoggle 控制
2. 协议Topic Tab
- 预加载双主题:
dld960/{sn}/srv(下发)、dld960/{sn}/dev(上报) - QListWidget 展示,双击自动填充到发布区
- 发布区可编辑 JSON 载荷,一键发布
- 主题列表受 SN 输入框驱动,实时更新
3. 自定义Topic Tab
- 自由输入 topic + JSON 载荷,QoS (0/1/2) 可调
- 订阅 / 取消订阅,接收消息实时展示在 QPlainTextEdit
#/+通配符支持,paho.mqtt.topic_matches_sub路由匹配- 自定义订阅的消息自动分发到接收区,附带 topic 前缀
4. 新增依赖
paho.mqtt.client导入新增topic_matches_sub- UI 控件: QComboBox, QSpinBox, QPlainTextEdit
2026-07-06 — paho-mqtt v2 回调修复 213c0dd
问题
断开连接时报错:
TypeError: MqttClient._on_disconnect() missing 1 required positional argument: 'reason_code'
根因
paho-mqtt v2 默认 callback_api_version=VERSION2,on_disconnect 回调签名为 5 参数 (client, userdata, flags, reason_code, properties),而 v1 为 3 参数 (client, userdata, rc)。
修复
_on_disconnect改用*args兼容 v1/v2Client构造显式指定callback_api_version=CallbackAPIVersion.VERSION2_on_connect保持 v2 签名不变
2026-07-06 — tkinter → PySide6 迁移 e1bf3dc
决策
放弃 tkinter,改用 PySide6 (Qt for Python),理由:
- 跨平台原生外观 (Fusion 风格)
- Qt 信号/槽机制替代 tkinter 回调,更易维护
- 组件丰富 (QGroupBox, QSplitter, QTabWidget 等)
改动
main.py全量重写为 PySide6 主窗口- 布局: QGroupBox 分组 → QSplitter 分栏 → QTabWidget 功能分区
requirements.txt新增PySide6>=6.6.0- tkinter → Qt 映射:
StringVar→信号/槽,Listbox→QListWidget,Text→QTextEdit
2026-07-06 — 项目初始化 a2cfe46
功能 (初始版本, tkinter)
- MQTT Broker 连接管理
- 设备自动发现 (
dld960/+/dev通配符订阅) - 设备信息查询 + 主题配置
- 实时线圈数据 / 事件上报 / 心跳 监控
- 控制命令: 密码验证/设置、出厂初始化、设备复位
项目结构
DBNMQTTool/
├── main.py # 主窗口 (tkinter → 后迁移至 PySide6)
├── dbn_mqtt_tool/
│ ├── protocol.py # DLD960 IoT MQTT 协议定义 (主题/命令/载荷模板)
│ ├── mqtt_client.py # MQTT 客户端封装 (paho-mqtt v2)
│ └── device_manager.py # 设备发现与状态管理
└── requirements.txt # paho-mqtt>=2.0.0 + PySide6>=6.6.0
协议依据
DLD960_IoT_MQTT协议.md V1.00
当前状态
| 组件 | 状态 |
|---|---|
| MQTT 连接/断开 | ✅ 已实现,v1/v2 兼容 |
| 设备发现 | ✅ 通配符订阅 |
| 实时数据监控 | ✅ loop_data/event_report/heartbeat |
| 控制命令 | ✅ 15 条命令 |
| 模拟上报 | ✅ c19e465 |
| 协议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 引用丢失
2026-08-05 — 脱机事件日志命令支持 (MQTT V1.06)
配合 vd960DBN 固件 P1.3(commit 1a01316)+ 协议 V1.06,工具新增脱机事件日志面板(参数配置 Tab 底部):
新增命令
| 命令 | 按钮 | 说明 |
|---|---|---|
log_stat |
统计 | 日志统计/分页定位: enabled/boot_seq/count/capacity/seq_first/seq_last |
log_query |
拉取日志 | 按全局序号分页拉取, 起始序号 + 条数(1~4) 可调 |
log_clear |
清除日志 | 二次确认弹窗, 审计留痕不可撤销 |
实现要点
protocol.py: 新增CMD_LOG_*常量、LOG_COMMANDS集合、data_log_query()构建器(start_seq≥1 / count 1~4 边界钳制)、LOG_EVENT_TYPE_DESC事件类型中文描述(10 类 + unknown)main.py: 参数配置 Tab 新增 g6 组(起始序号/条数 spinbox + 三按钮 + 只读显示区 QPlainTextEdit)_on_messagecode==0 分支新增log_stat/log_query/log_clear响应处理- 显示优化: log_query 记录带事件类型中文描述; unix_ts 已同步显示真实时间, 未同步显示
boot+ts_ms(未同步) - 清除日志前 QMessageBox 二次确认(防误触, 与出厂初始化/设备复位同模式)
验证
py_compile四个模块通过- protocol 逻辑单测: data_log_query 边界钳制 (0→1, 99→4, 0→1)、命令枚举一致性、build_request 带 data