- offlog.h: OfflogPart 运行时分区表 + g_offlog_part; AREA_BASE 改 0x090000 (参数64KB+OTA512KB); 容量宏展开为运行时值(主体零改动) - offlog.c: offlog_part_detect() 读 JEDEC ID → 事件区容量 W25Q32=512KB/16256条, Q64=1MB/32640, Q128=2MB/65408, Q256=4MB/130944 - storage.c/h: SPI_Flash_ReadJEDEC_ID() (0x9F, 校验 EF 40) - 旧固件事件区 0x010000 自动废弃(新地址无 magic → 重建), 预期行为 - 测试: mock JEDEC=0x16 + g_offlog_part, 15 例全过 - 文档: BLE/MQTT/TCP 协议 capacity 8064→动态, 交互示例, devlog
27 KiB
DLD960 IoT 接口协议(MQTT + JSON)
基于《DLD960 串口通信协议》V1.01,将设备管理、参数配置、数据上报映射到 MQTT 协议。 交互格式:JSON。
1 通信说明
1.1 连接参数
| 项目 | 说明 |
|---|---|
| 协议 | MQTT 3.1.1 / 5.0 |
| 传输层 | TCP (TLS 可选) |
| QoS | 配置类 QoS 1,数据上报类 QoS 0/1 |
| 编码 | UTF-8 |
| 序列化 | JSON |
1.2 Topic 结构
协议仅使用两个主题,所有消息类型通过 JSON 内 cmd 字段区分。
dld960/{dev_serial}/{direction}
| 字段 | 说明 |
|---|---|
dev_serial |
设备序列码(6字节十六进制字符串,如 A1B2C3D4E5F6) |
direction |
srv = 服务器下发(设备订阅),dev = 设备上报(服务器订阅) |
1.2.1 服务器下发 Topic — dld960/{sn}/srv
设备订阅此主题,接收服务器下发的所有命令(配置设置、查询、控制等)。 服务器发布到此主题。
对应串口 CMD:0x09 ~ 0x1F, 0x63, 0x64, 0xC5 等。
1.2.2 设备上报 Topic — dld960/{sn}/dev
设备发布到此主题,上报线圈数据、事件、心跳及命令响应。 服务器订阅此主题接收所有设备上行消息。
服务器端可订阅通配符 dld960/+/dev 监听所有设备。
2 JSON 消息格式
2.1 通用结构
{
"msg_id": 12345,
"cmd": "dev_info_query",
"ts": 1719000000,
"data": { ... }
}
| 字段 | 类型 | 说明 |
|---|---|---|
msg_id |
uint32 | 消息序列号,递增,用于请求-响应匹配(由发起方生成) |
cmd |
string | 命令标识符 |
ts |
uint32 | Unix 时间戳(秒),发起方填充 |
data |
object | 命令参数,结构依 cmd 而定 |
2.2 响应通用结构
{
"msg_id": 12345,
"cmd": "dev_info_query",
"ts": 1719000001,
"code": 0,
"msg": "success",
"data": { ... }
}
| 字段 | 类型 | 说明 |
|---|---|---|
code |
int | 0 = 成功,非 0 = 失败码 |
msg |
string | 错误描述(成功时为 "success") |
错误码定义
| code | 说明 |
|---|---|
| 0 | 成功 |
| 1 | 参数错误(格式/范围不正确) |
| 2 | 密码验证失败 |
| 3 | 设备忙(操作执行中) |
| 4 | 不支持的命令 |
| 5 | 内部错误 |
| 6 | 数据超长 |
2.3 设备时钟同步(ts 语义)
设备无 RTC/SNTP 时间源,上电后本地时钟为上电秒数(从 0 递增)。为使上行数据带真实 Unix 时间:
- 设备上电连接成功后发布
initialize(此时ts= 上电秒数,值很小,平台据此识别"未校准"); - 平台收到
initialize后,下发report_config命令,其信封ts字段填当前 Unix 时间; - 设备收到后以该
ts校准本地时钟基准,之后所有上行消息(loop_data/event_report/ 心跳 / 命令响应)的ts均为真实 Unix 时间。
补充约定:
report_config为约定的主同步点;设备亦接受任意下行命令中合法(≥ 1600000000,即 2020-09 之后)的ts进行校准,非法/过小值被忽略。- 校准前(含首个
initialize),ts为上电秒数;平台应能容忍并可按数量级区分。 - 设备重启后需重新校准(无掉电保持)。平台在每次设备
initialize后都应下发一次带ts的report_config。
脱机日志时间戳语义(V1.06 起):
- 设备侧事件日志(
log_query拉取)每条记录携带双时间戳:ts_ms(boot 内相对时间,单位 ms,断电归零)+unix_ts(已同步 Unix 秒,0 = 未同步)。 - 设备经本协议同步成功后,其后记录的
unix_ts均为真实 Unix 时间;同步前(含每次上电的boot事件)unix_ts = 0,仅ts_ms相对时间。 - 回算规则:
绝对时间 = 锚点.unix_ts + (记录.ts_ms - 锚点.ts_ms)/1000,锚点取该 boot 段内第一条time_anchor事件(unix_ts即平台下发值,严格一致)。从未同步过的 boot 段只有相对时间。
3 命令详表
| cmd | 说明 | 方向 | 对应串口 |
|---|---|---|---|
dev_serial_set |
更改设备序列码 | srv→dev | 0x09 |
dev_info_query |
查询设备信息 | srv→dev | 0x10 |
ssc_net_set |
设置 SSC 网络配置 | srv→dev | 0x11 |
ssc_net_query |
查询 SSC 网络配置 | srv→dev | 0x12 |
iot_net_set |
设置 IoT 网络配置 | srv→dev | 0x13 |
iot_net_query |
查询 IoT 网络配置 | srv→dev | 0x14 |
iot_topic_set |
设置设备 Topic | srv→dev | 0x15 |
iot_topic_query |
查询设备 Topic | srv→dev | 0x16 |
pwd_verify |
验证设备密码 | srv→dev | 0x1C |
pwd_set |
设置设备密码 | srv→dev | 0x1D |
factory_reset |
设备出厂初始化 | srv→dev | 0x1E |
device_reset |
设备复位 | srv→dev | 0x1F |
loop_param_set |
设置车检器多路参数 | srv→dev | 0x63 |
loop_param_query |
读取车检器多路参数 | srv→dev | 0x64 |
report_config |
设置主动上报 | srv→dev | 0xC5 |
log_stat |
查询脱机事件日志统计 | srv→dev | — |
log_query |
分页拉取脱机事件日志 | srv→dev | — |
log_clear |
清除脱机事件日志(审计留痕) | srv→dev | — |
initialize |
设备上电初始化登陆 | dev→srv | — |
loop_data |
线圈传感数据上报 | dev→srv | 0xC0 |
event_report |
事件上报(平台须应答,见 §5.3) | dev→srv | — |
heartbeat |
设备心跳 | dev→srv | — |
4 命令详情
4.1 更改设备序列码 dev_serial_set
Topic:
dld960/{sn}/srv
请求:
{
"msg_id": 1,
"cmd": "dev_serial_set",
"ts": 1719000000,
"data": {
"dev_serial": "A1B2C3D4E5F6"
}
}
响应: Topic: dld960/{sn}/dev
{
"msg_id": 1,
"cmd": "dev_serial_set",
"ts": 1719000001,
"code": 0,
"msg": "success"
}
4.2 查询设备信息 dev_info_query
Topic:
dld960/{sn}/srv
请求:
{
"msg_id": 2,
"cmd": "dev_info_query",
"ts": 1719000000
}
响应:
{
"msg_id": 2,
"cmd": "dev_info_query",
"ts": 1719000001,
"code": 0,
"msg": "success",
"data": {
"dev_serial": "A1B2C3D4E5F6",
"hard_ver": "1.1",
"soft_ver": "1.1",
"model": "DLD960",
"product_code": "960001",
"sub_code": {
"net": true,
"iot": true
},
"bus": {
"bus1": 0,
"bus2": 0,
"bus3": 0,
"bus4": 0
}
}
}
| data 字段 | 类型 | 说明 |
|---|---|---|
dev_serial |
string | 12 位十六进制序列码 |
hard_ver |
string | 硬件版本,格式 "主.次" |
soft_ver |
string | 软件版本,格式 "主.次" |
model |
string | 产品型号,1~10 字符 |
product_code |
string | 产品编码,6 位数字字符串 |
sub_code.net |
bool | 网络功能是否启用 |
sub_code.iot |
bool | IoT/MQTT 功能是否启用 |
bus.bus1~4 |
uint8 | 各总线探头数 |
4.3 设置 SSC 网络配置 ssc_net_set
Topic:
dld960/{sn}/srv
请求:
{
"msg_id": 3,
"cmd": "ssc_net_set",
"ts": 1719000000,
"data": {
"dev_ip": "192.168.1.100",
"subnet_mask": "255.255.255.0",
"route_ip": "192.168.1.1",
"lssc_ip": "192.168.1.200",
"dns": "8.8.8.8",
"port": 502
}
}
| data 字段 | 类型 | 说明 |
|---|---|---|
dev_ip |
string | 设备 IP 地址 |
subnet_mask |
string | 子网掩码 |
route_ip |
string | 网关地址 |
lssc_ip |
string | LSSC 服务器 IP |
dns |
string | DNS 服务器 IP |
port |
uint16 | 端口号 |
响应:
{
"msg_id": 3,
"cmd": "ssc_net_set",
"ts": 1719000001,
"code": 0,
"msg": "success"
}
4.4 查询 SSC 网络配置 ssc_net_query
Topic:
dld960/{sn}/srv
请求:
{
"msg_id": 4,
"cmd": "ssc_net_query",
"ts": 1719000000
}
响应: 返回字段同 4.3 的 data。
4.5 设置 IoT 网络配置 iot_net_set
Topic:
dld960/{sn}/srv
请求:
{
"msg_id": 5,
"cmd": "iot_net_set",
"ts": 1719000000,
"data": {
"host": "mqtt.example.com",
"port": 1883,
"client_id": "dld960_A1B2C3D4E5F6",
"username": "admin",
"password": "secret"
}
}
| data 字段 | 类型 | 说明 |
|---|---|---|
host |
string | MQTT Broker 域名或 IP |
port |
uint16 | MQTT 端口,默认 1883 |
client_id |
string | MQTT Client ID,空时用空格 |
username |
string | MQTT 用户名 |
password |
string | MQTT 密码 |
响应: 标准成功/失败。
4.6 查询 IoT 网络配置 iot_net_query
Topic:
dld960/{sn}/srv
请求:
{
"msg_id": 6,
"cmd": "iot_net_query",
"ts": 1719000000
}
响应: 返回字段同 4.5 的 data。
4.7 设置设备 Topic iot_topic_set
Topic:
dld960/{sn}/srv
请求:
{
"msg_id": 7,
"cmd": "iot_topic_set",
"ts": 1719000000,
"data": {
"client_id_enable": true,
"topic_pub": "dld960/data/A1B2C3D4E5F6",
"topic_sub": "dld960/cmd/A1B2C3D4E5F6"
}
}
响应: 标准成功/失败。
4.8 查询设备 Topic iot_topic_query
Topic:
dld960/{sn}/srv
请求:
{
"msg_id": 8,
"cmd": "iot_topic_query",
"ts": 1719000000
}
响应: 返回字段同 4.7 的 data。
4.9 验证设备密码 pwd_verify
Topic:
dld960/{sn}/srv
请求:
{
"msg_id": 9,
"cmd": "pwd_verify",
"ts": 1719000000,
"data": {
"password": "123456"
}
}
| data 字段 | 类型 | 说明 |
|---|---|---|
password |
string | 6 位数字密码 |
响应:
{
"msg_id": 9,
"cmd": "pwd_verify",
"ts": 1719000001,
"code": 0,
"msg": "success"
}
4.10 设置设备密码 pwd_set
Topic:
dld960/{sn}/srv
请求:
{
"msg_id": 10,
"cmd": "pwd_set",
"ts": 1719000000,
"data": {
"old_password": "123456",
"new_password": "654321"
}
}
响应: 标准成功/失败。旧密码错误时 code=2。
4.11 设备出厂初始化 factory_reset
Topic:
dld960/{sn}/srv
请求:
{
"msg_id": 11,
"cmd": "factory_reset",
"ts": 1719000000
}
响应:
{
"msg_id": 11,
"cmd": "factory_reset",
"ts": 1719000001,
"code": 0,
"msg": "success"
}
4.12 设备复位 device_reset
Topic:
dld960/{sn}/srv
请求:
{
"msg_id": 12,
"cmd": "device_reset",
"ts": 1719000000
}
无响应(设备复位后断开连接)。
4.13 设置车检器多路参数 loop_param_set
Topic:
dld960/{sn}/srv
请求:
{
"msg_id": 13,
"cmd": "loop_param_set",
"ts": 1719000000,
"data": {
"auto_mode": false,
"channels": [
{
"ch": 1,
"sens": 7,
"level": "high",
"delay": 0,
"output": "exist",
"exist": 0,
"dir": 0,
"safe": 0,
"fun_mode": 0
},
{
"ch": 2,
"sens": 7,
"level": "mid_high",
"delay": 5,
"output": "enter_pulse",
"exist": 10,
"dir": 0,
"safe": 0,
"fun_mode": 0
},
{
"ch": 3,
"sens": 5,
"level": "mid_low",
"delay": 0,
"output": "exist",
"exist": 0,
"dir": 1,
"safe": 5,
"fun_mode": 0
},
{
"ch": 4,
"sens": 8,
"level": "low",
"delay": 10,
"output": "leave_pulse",
"exist": 15,
"dir": 0,
"safe": 0,
"fun_mode": 0
}
]
}
}
| data 字段 | 类型 | 说明 |
|---|---|---|
auto_mode |
bool | 自动调频模式,默认 false |
channels |
array | 各路通道参数,1~4 路 |
channels[].ch |
uint8 | 通道号 1~4 |
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, 功能模式 |
响应:
{
"msg_id": 13,
"cmd": "loop_param_set",
"ts": 1719000001,
"code": 0,
"msg": "success"
}
4.14 读取车检器多路参数 loop_param_query
Topic:
dld960/{sn}/srv
请求:
{
"msg_id": 14,
"cmd": "loop_param_query",
"ts": 1719000000
}
响应:
{
"msg_id": 14,
"cmd": "loop_param_query",
"ts": 1719000001,
"code": 0,
"msg": "success",
"data": {
"auto_mode": false,
"channels": [
{
"ch": 1,
"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
}
]
}
}
| 额外字段 | 类型 | 单位 | 说明 |
|---|---|---|---|
f_initial |
uint32 | Hz | freq_initial, 初始频率 |
f_current |
uint32 | Hz | freq_current, 当前实时频率 |
diff |
uint32 | Hz | 变化量(绝对值) |
4.15 设置主动上报 report_config
Topic:
dld960/{sn}/srv⚠️ 兼任设备时钟同步点:本命令信封ts须填当前 Unix 时间,设备据此校准本地时钟(见 §2.3)。平台应在每次收到设备initialize后下发一次。
请求:
{
"msg_id": 15,
"cmd": "report_config",
"ts": 1719000000,
"data": {
"sensor_type": 12,
"enable": true,
"once": false,
"env_eval": false,
"interval": 5,
"ack_required": false,
"timeout": 0
}
}
| data 字段 | 类型 | 说明 |
|---|---|---|
sensor_type |
uint8 | 传感器类型,线圈=0x0C(12) |
enable |
bool | 是否使能主动上报 |
once |
bool | 仅上报一次(查询模式) |
env_eval |
bool | 环境评估使能 |
interval |
uint8 | 上报间隔(秒),0=实时 |
ack_required |
bool | 上报是否需要确认 |
timeout |
uint8 | 超时时间(分钟),0=无限制 |
响应: 标准成功/失败。
4.16 查询脱机事件日志统计 log_stat
Topic:
dld960/{sn}/srv设备本地 W25Qxx 环形事件日志(事件区动态:W25Q32=512KB/16256 条,掉电不丢)。用于日志拉取前的分页定位。
请求:
{
"msg_id": 16,
"cmd": "log_stat",
"ts": 1719000000,
"data": {}
}
响应 data:
{
"stream": "event",
"enabled": true,
"boot_seq": 2,
"count": 1234,
"capacity": 16256,
"seq_first": 100,
"seq_last": 1333
}
| data 字段 | 类型 | 说明 |
|---|---|---|
stream |
string | 日志流,当前仅 event(快照流预留) |
enabled |
bool | 日志功能是否启用(Flash 初始化成功) |
boot_seq |
uint16 | 当前启动序号(每次上电 +1,区分复位段) |
count |
uint16 | 有效记录条数(0~capacity,环形覆盖后 < capacity) |
capacity |
uint16 | 容量上限(随存储芯片动态:W25Q32=16256 / W25Q64=32640 / W25Q128=65408 / W25Q256=130944) |
seq_first |
uint32 | 逻辑首条记录全局序号(seq_last - count + 1) |
seq_last |
uint32 | 最新一条记录全局序号(跨 boot 单调递增) |
4.17 分页拉取脱机事件日志 log_query
Topic:
dld960/{sn}/srv分页按全局序号,不按时间(未同步段时间不可靠)。count上限 4(受 MQTT 发布 ≤500B 限制,MSS=576 教训)。
请求:
{
"msg_id": 17,
"cmd": "log_query",
"ts": 1719000000,
"data": {
"start_seq": 1330,
"count": 4
}
}
| data 字段 | 类型 | 说明 |
|---|---|---|
start_seq |
uint32 | 起始全局序号(含);越界(< seq_first 或 > seq_last)返回空 records |
count |
uint8 | 拉取条数,上限 4,超限按 4 处理 |
响应 data:
{
"start_seq": 1330,
"records": [
{
"seq": 1330,
"boot_seq": 2,
"ts_ms": 456789,
"unix_ts": 1784768575,
"type": "iot_ready",
"data": null
}
]
}
| 字段 | 类型 | 说明 |
|---|---|---|
seq |
uint32 | 全局序号 |
boot_seq |
uint16 | 所属启动段 |
ts_ms |
uint32 | boot 内相对时间(ms,断电归零) |
unix_ts |
uint32 | 已同步 Unix 秒;0 = 未同步(回算见 §2.3) |
type |
string | 事件类型名(下表) |
data |
object/null | 类型相关参数 |
事件类型表:
| type | 含义 | data 字段 |
|---|---|---|
boot |
上电/复位 | {"rst": 复位原因寄存器原始值},位解析:bit31=IWDG(看门狗) bit30=WWDG bit29=LPWR bit26=NRST引脚 bit25=POR(真断电) bit24=软件复位 |
iot_connect |
MQTT TCP 连接成功 | null |
iot_ready |
MQTT 订阅完成 → 发 initialize | null |
iot_disconnect |
MQTT 断连 | {"reason": N},1=断开 2=超时 3=CONNACK拒绝 4=连接超时 |
iot_reconn |
重连退避 | {"backoff_ms": 5000} |
evt_retry |
event_report ACK 超时重发 | {"msg_id":5,"retry":2} |
evt_giveup |
event_report 重试耗尽挂起 | {"msg_id":5} |
coil |
线圈事件 | {"sub":"car_enter","ch":1,"value":97};sub: car_enter/car_leave/loop_cut/loop_restore,value 为 50ms 单位时间量 |
time_anchor |
时钟同步锚点 | null(unix_ts 即平台下发值,严格一致) |
log_clear |
日志清除(审计) | null |
4.18 清除脱机事件日志 log_clear
Topic:
dld960/{sn}/srv⚠ 高风险操作:清除动作本身写入事件流(log_clear审计——谁在何时清了日志,留痕不可清除)。平台侧应做权限控制。
请求:
{
"msg_id": 18,
"cmd": "log_clear",
"ts": 1719000000,
"data": {
"stream": "event"
}
}
| data 字段 | 类型 | 说明 |
|---|---|---|
stream |
string | 日志流,当前仅 event;缺省等同 event |
响应: 标准成功/失败。成功后 log_stat 的 count 归 1(仅剩审计记录),seq_last 继续递增(序号不复位)。
5 设备主动上报
5.1 设备上电登陆信息 initialize
Topic:
dld960/{sn}/devQoS: 0/1
{
"msg_id": 1,
"cmd": "initialize",
"ts": 1719000000,
"data": {
"dev_serial":"A1B2C3D4E5F6",
"model": "DLD960",
"hard_ver": "1.0",
"soft_ver": "1.0",
"extra_info": {
"code": "869756049404948",
"csq": "21",
"location": "113.9237976,022.6400375",
}
}
}
| 字段 | 类型 | 说明 |
|---|---|---|
data.dev_serial |
string | 设备序列码 |
data.model |
string | 产品型号 |
data.hard_ver |
string | 硬件版本 |
data.soft_ver |
string | 固件版本 |
data.extra_info.code |
string | 可选,设备代码如IMSI/ICCID |
data.extra_info.csq |
string | 可选,当前信号强度 |
data.extra_info.location |
string | 可选,经纬度(经度,纬度) |
5.2 线圈传感数据 loop_data
Topic:
dld960/{sn}/devQoS: 0/1 上报节奏(三档):① 任一通道iscar翻转(进/出车)→ 立即上报,不受间隔限制;② 任一通道|diff|超阈值 → 300ms 快速档;③ 平稳 → 按report_config.interval(默认 60s)。
{
"msg_id": 100,
"cmd": "loop_data",
"ts": 1719000100,
"data": {
"channels": [
{
"ch": 1,
"level": "high",
"iscar": false,
"loop_ok": true,
"freq": 105280,
"diff": 20,
"sens": 7,
"cndtn": 0,
"misc": {
"type": "time",
"value": 0
}
},
{
"ch": 2,
"level": "mid_high",
"iscar": true,
"loop_ok": true,
"freq": 98700,
"diff": 1500,
"sens": 7,
"cndtn": 2,
"misc": {
"type": "time",
"value": 350
}
},
{
"ch": 3,
"level": "mid_low",
"iscar": false,
"loop_ok": false,
"freq": 0,
"diff": 0,
"sens": 5,
"cndtn": 0,
"misc": {
"type": "cut_count",
"value": 3
}
},
{
"ch": 4,
"level": "low",
"iscar": false,
"loop_ok": true,
"freq": 62100,
"diff": 5,
"sens": 8,
"cndtn": 0,
"misc": {
"type": "flow_count",
"value": 128
}
}
]
}
}
| 通道字段 | 类型 | 说明 |
|---|---|---|
ch |
uint8 | 通道号 1~4 |
level |
string | freq_level 线圈高低频档位 |
iscar |
bool | 是否有车 |
loop_ok |
bool | 线圈是否正常(false=断开) |
freq |
uint32 | 当前频率 (Hz) |
diff |
uint32 | 变化量 |
sens |
uint8 | sensitivity, 当前灵敏度等级 |
cndtn |
uint8 | condition, 环境状态评估值(越大干扰越大) |
misc.type |
string | "time"(时间量) / "cut_count"(断开次数) / "flow_count"(车流量) |
misc.value |
uint32 | 杂项数值(时间量单位 50ms) |
5.3 事件上报 event_report
上报 Topic:
dld960/{sn}/dev应答 Topic:dld960/{sn}/srvQoS: 1(建议) ⚠️ 本指令要求平台必须应答(区别于loop_data/heartbeat的单向上报)
设备检测到事件时主动上报,非周期性。事件(进车/出车/线圈断开等)是不可再生的关键数据,MQTT QoS 仅保证 broker 收到,不代表平台业务层已处理入库,因此引入应用层应答 + 设备重发机制闭环确认。
注:
event_report不受report_config.enable门控——设备上电即检测并上报事件。report_config的enable/interval仅控制loop_data周期上报,与事件上报解耦。
设备上报(dev topic):
{
"msg_id": 101,
"cmd": "event_report",
"ts": 1719000200,
"data": {
"events": [
{
"type": "car_enter",
"ch": 2,
"value": 0
},
{
"type": "car_leave",
"ch": 2,
"value": 350
},
{
"type": "loop_cut",
"ch": 3,
"value": 0
}
]
}
}
事件类型 type |
说明 | value 含义 |
|---|---|---|
car_enter |
车辆进入 | 0 |
car_leave |
车辆离开 | 通过时间 (×50ms) |
loop_cut |
线圈断开 | 0 |
loop_restore |
线圈恢复 | 断开持续时长 (×50ms) |
平台应答(srv topic,收到后必须立即回复):
{
"msg_id": 101,
"cmd": "event_report",
"ts": 1719000201,
"code": 0,
"msg": "success"
}
| 字段 | 说明 |
|---|---|
msg_id |
必须回显设备上报的 msg_id,设备以此匹配确认 |
cmd |
固定 "event_report" |
code |
0 = 已接收并处理;非 0 = 处理失败(设备视同未确认,进入重发) |
设备端确认与重发机制:
- 发出
event_report后启动确认定时器,5s 内未收到msg_id匹配且code=0的应答 → 重发; - 重发使用相同的
msg_id与原始ts(首次事件发生时间,不随重发刷新),平台以此去重; - 最多重发 3 次(含首发共 4 次)。仍未确认 → 事件保留在待发队列,待 MQTT 重连成功或下一次事件触发时合并上报;
- 等待确认期间新产生的事件,合并进下一包的
events数组(使用新msg_id)。单包长度受发布缓冲限制(≤500B),超出时拆包分批; - 待发队列建议深度 ≥16 条事件,溢出时丢弃最旧事件(先保新鲜数据)。
平台端要求:
- 收到
event_report先落库、后应答,应答即承诺数据已持久化; - 按
(dev_serial, msg_id)在近期窗口(建议 10 分钟)内去重——重复包为设备未收到应答所致,直接应答code=0,不重复入库(设备重启后msg_id从头递增,去重必须限定时间窗口); - 应答报文应控制在最小集(不带
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周期:默认 60 秒
{
"msg_id": 200,
"cmd": "heartbeat",
"ts": 1719000060,
"data": {
"uptime": 3600,
"loop_status": [true, true, false, true],
"net_status": true,
"iot_status": true
}
}
| data 字段 | 类型 | 说明 |
|---|---|---|
uptime |
uint32 | 设备运行时长(秒) |
loop_status |
bool[4] | 各路线圈是否正常 |
net_status |
bool | 以太网连接状态 |
iot_status |
bool | MQTT 连接状态 |
修订记录
| 版本 | 修订时间 | 修订说明 | 修订人 |
|---|---|---|---|
| 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 |
| V1.03 | 2026-07-09 | 增加设备上电初始化指令 | wangfq |
| V1.04 | 2026-07-15 | event_report 增加平台必答机制:应答格式(回显 msg_id)、设备 5s 超时重发(同 msg_id/ts,最多 3 次)、待发队列合并上报、平台去重与先落库后应答要求 |
wangfq |
| V1.05 | 2026-07-15 | 增加设备时钟同步(§2.3,方案B):设备无 RTC,initialize 上线后平台经 report_config 命令下发 Unix ts,设备据此校准,之后上行 ts 为真实 Unix 时间;校准前为上电秒数 |
wangfq |
| V1.06 | 2026-08-04 | 增加脱机事件日志命令:log_stat(统计/分页定位)、log_query(按全局序号分页,count≤4)、log_clear(清除+审计留痕);§2.3 补充日志双时间戳语义(ts_ms 相对 + unix_ts 已同步,0=未同步,锚点回算规则) |
wangfq |