# 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 结构

```
dld960/{dev_serial}/{direction}/{category}[/{sub}]
```

| 字段 | 说明 |
|------|------|
| `dev_serial` | 设备序列码（6字节十六进制字符串，如 `A1B2C3D4E5F6`） |
| `direction` | `srv` = 服务器下发，`dev` = 设备上报 |
| `category` | 消息类别 |
| `sub` | 子类别（可选） |

### 1.2.1 服务器下发 Topic（设备订阅）

| Topic | 说明 | 对应串口 CMD |
|-------|------|-------------|
| `dld960/{sn}/srv/config/set` | 设置配置参数 | 0x11, 0x13, 0x15, 0x63 |
| `dld960/{sn}/srv/config/query` | 查询配置参数 | 0x10, 0x12, 0x14, 0x16, 0x64 |
| `dld960/{sn}/srv/ctrl` | 控制命令 | 0x09, 0x1C, 0x1D, 0x1E, 0x1F, 0xC5 |

### 1.2.2 设备上报 Topic（服务器订阅）

| Topic | 说明 | 对应串口 CMD |
|-------|------|-------------|
| `dld960/{sn}/dev/config/resp` | 配置查询/设置响应 | 各命令返回 |
| `dld960/{sn}/dev/data/loop` | 线圈传感数据上报 | 0xC0 (SensType=0x0C) |
| `dld960/{sn}/dev/data/event` | 事件上报（有车/无车、故障等） | — |
| `dld960/{sn}/dev/status` | 设备状态（在线心跳、自检） | — |

---

# 2 JSON 消息格式

## 2.1 通用结构

```json
{
  "msg_id": 12345,
  "cmd": "dev_info_query",
  "ts": 1719000000,
  "data": { ... }
}
```

| 字段 | 类型 | 说明 |
|------|------|------|
| `msg_id` | uint32 | 消息序列号，递增，用于请求-响应匹配（由发起方生成） |
| `cmd` | string | 命令标识符 |
| `ts` | uint32 | Unix 时间戳（秒），发起方填充 |
| `data` | object | 命令参数，结构依 cmd 而定 |

## 2.2 响应通用结构

```json
{
  "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 | 数据超长 |

---

# 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 |
| `loop_data` | 线圈传感数据上报 | dev→srv | 0xC0 |
| `event_report` | 事件上报 | dev→srv | — |
| `heartbeat` | 设备心跳 | dev→srv | — |

---

# 4 命令详情

## 4.1 更改设备序列码 `dev_serial_set`

> Topic: `dld960/{sn}/srv/config/set`

**请求：**

```json
{
  "msg_id": 1,
  "cmd": "dev_serial_set",
  "ts": 1719000000,
  "data": {
    "dev_serial": "A1B2C3D4E5F6"
  }
}
```

**响应：** Topic: `dld960/{sn}/dev/config/resp`

```json
{
  "msg_id": 1,
  "cmd": "dev_serial_set",
  "ts": 1719000001,
  "code": 0,
  "msg": "success"
}
```

## 4.2 查询设备信息 `dev_info_query`

> Topic: `dld960/{sn}/srv/config/query`

**请求：**

```json
{
  "msg_id": 2,
  "cmd": "dev_info_query",
  "ts": 1719000000
}
```

**响应：**

```json
{
  "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/config/set`

**请求：**

```json
{
  "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 | 端口号 |

**响应：**

```json
{
  "msg_id": 3,
  "cmd": "ssc_net_set",
  "ts": 1719000001,
  "code": 0,
  "msg": "success"
}
```

## 4.4 查询 SSC 网络配置 `ssc_net_query`

> Topic: `dld960/{sn}/srv/config/query`

**请求：**

```json
{
  "msg_id": 4,
  "cmd": "ssc_net_query",
  "ts": 1719000000
}
```

**响应：** 返回字段同 4.3 的 `data`。

## 4.5 设置 IoT 网络配置 `iot_net_set`

> Topic: `dld960/{sn}/srv/config/set`

**请求：**

```json
{
  "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/config/query`

**请求：**

```json
{
  "msg_id": 6,
  "cmd": "iot_net_query",
  "ts": 1719000000
}
```

**响应：** 返回字段同 4.5 的 `data`。

## 4.7 设置设备 Topic `iot_topic_set`

> Topic: `dld960/{sn}/srv/config/set`

**请求：**

```json
{
  "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/config/query`

**请求：**

```json
{
  "msg_id": 8,
  "cmd": "iot_topic_query",
  "ts": 1719000000
}
```

**响应：** 返回字段同 4.7 的 `data`。

## 4.9 验证设备密码 `pwd_verify`

> Topic: `dld960/{sn}/srv/ctrl`

**请求：**

```json
{
  "msg_id": 9,
  "cmd": "pwd_verify",
  "ts": 1719000000,
  "data": {
    "password": "123456"
  }
}
```

| data 字段 | 类型 | 说明 |
|-----------|------|------|
| `password` | string | 6 位数字密码 |

**响应：**

```json
{
  "msg_id": 9,
  "cmd": "pwd_verify",
  "ts": 1719000001,
  "code": 0,
  "msg": "success"
}
```

## 4.10 设置设备密码 `pwd_set`

> Topic: `dld960/{sn}/srv/ctrl`

**请求：**

```json
{
  "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/ctrl`

**请求：**

```json
{
  "msg_id": 11,
  "cmd": "factory_reset",
  "ts": 1719000000
}
```

**响应：**

```json
{
  "msg_id": 11,
  "cmd": "factory_reset",
  "ts": 1719000001,
  "code": 0,
  "msg": "success"
}
```

## 4.12 设备复位 `device_reset`

> Topic: `dld960/{sn}/srv/ctrl`

**请求：**

```json
{
  "msg_id": 12,
  "cmd": "device_reset",
  "ts": 1719000000
}
```

无响应（设备复位后断开连接）。

## 4.13 设置车检器多路参数 `loop_param_set`

> Topic: `dld960/{sn}/srv/config/set`

**请求：**

```json
{
  "msg_id": 13,
  "cmd": "loop_param_set",
  "ts": 1719000000,
  "data": {
    "auto_mode": false,
    "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
      },
      {
        "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
      },
      {
        "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
      },
      {
        "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
      }
    ]
  }
}
```

| data 字段 | 类型 | 说明 |
|-----------|------|------|
| `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 | 功能模式 |

**响应：**

```json
{
  "msg_id": 13,
  "cmd": "loop_param_set",
  "ts": 1719000001,
  "code": 0,
  "msg": "success"
}
```

## 4.14 读取车检器多路参数 `loop_param_query`

> Topic: `dld960/{sn}/srv/config/query`

**请求：**

```json
{
  "msg_id": 14,
  "cmd": "loop_param_query",
  "ts": 1719000000
}
```

**响应：**

```json
{
  "msg_id": 14,
  "cmd": "loop_param_query",
  "ts": 1719000001,
  "code": 0,
  "msg": "success",
  "data": {
    "auto_mode": false,
    "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
      }
    ]
  }
}
```

| 额外字段 | 类型 | 单位 | 说明 |
|----------|------|------|------|
| `freq_initial` | uint32 | Hz | 初始频率 |
| `freq_current` | uint32 | Hz | 当前实时频率 |
| `freq_diff` | uint32 | Hz | 频率变化量（绝对值） |

## 4.15 设置主动上报 `report_config`

> Topic: `dld960/{sn}/srv/ctrl`

**请求：**

```json
{
  "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=无限制 |

**响应：** 标准成功/失败。

---

# 5 设备主动上报

## 5.1 线圈传感数据 `loop_data`

> Topic: `dld960/{sn}/dev/data/loop`
> QoS: 0/1

```json
{
  "msg_id": 100,
  "cmd": "loop_data",
  "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,
        "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,
        "misc": {
          "type": "time",
          "value": 350
        }
      },
      {
        "ch": 3,
        "freq_level": "mid_low",
        "has_car": false,
        "loop_ok": false,
        "freq_current": 0,
        "freq_diff": 0,
        "sensitivity": 5,
        "condition": 0,
        "misc": {
          "type": "cut_count",
          "value": 3
        }
      },
      {
        "ch": 4,
        "freq_level": "low",
        "has_car": false,
        "loop_ok": true,
        "freq_current": 62100,
        "freq_diff": 5,
        "sensitivity": 8,
        "condition": 0,
        "misc": {
          "type": "flow_count",
          "value": 128
        }
      }
    ]
  }
}
```

| 通道字段 | 类型 | 说明 |
|----------|------|------|
| `ch` | uint8 | 通道号 1~4 |
| `freq_level` | string | 线圈高低频档位 |
| `has_car` | bool | 是否有车 |
| `loop_ok` | bool | 线圈是否正常（false=断开） |
| `freq_current` | uint32 | 当前频率 (Hz) |
| `freq_diff` | uint32 | 频率变化量 (Hz) |
| `sensitivity` | uint8 | 当前灵敏度等级 |
| `condition` | uint8 | 环境状态评估值（越大干扰越大） |
| `misc.type` | string | `"time"`(时间量) / `"cut_count"`(断开次数) / `"flow_count"`(车流量) |
| `misc.value` | uint32 | 杂项数值（时间量单位 5ms） |

## 5.2 事件上报 `event_report`

> Topic: `dld960/{sn}/dev/data/event`

设备检测到事件时主动上报，非周期性。

```json
{
  "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` | 车辆离开 | 通过时间 (×5ms) |
| `loop_cut` | 线圈断开 | 0 |
| `loop_restore` | 线圈恢复 | 断开持续时长 (×5ms) |

## 5.3 设备心跳 `heartbeat`

> Topic: `dld960/{sn}/dev/status`
> 周期：默认 60 秒

```json
{
  "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 |
