# 正博物联中心开发平台客户接口开发文档

接口版本 v1    文档整理日期 2026-10-21    适用范围 客户正式 OpenAPI

本文面向客户后端开发、应用集成和联调人员，说明如何使用 App 签名访问设备、查询控制结果、配置告警及回调。先完成应用与设备授权，再按本文构造请求。

文档覆盖 4 个客户 Controller、18 个路径和 19 个接口操作。回调配置 GET 与 PUT 分别说明；内部管理、Mock 和历史兼容入口不在本手册范围内。

接口定义、部署地址或权限发生变更时，以服务方发布的新版文档和在线文档为准。回调配置章节说明地址与渠道的读取、更新规则；事件报文的字段和验签规则以服务方交付的配套事件协议为准。

## 一 接入概览

### 服务地址和在线入口

服务方交付正式 HTTPS 入口及必要网关前缀。本文 API_ROOT 表示该入口加 /openapi/v1；例如入口为 https://api.example.com/iot-foundation，则 API_ROOT 为 https://api.example.com/iot-foundation/openapi/v1。example.com 仅为格式示意，请替换实际地址。

| 用途 | 相对服务入口的地址 | 说明 |
| --- | --- | --- |
| 客户开发文档 | /openapi/guide/ | 无需 App 凭据即可阅读；是否开放由部署控制。 |
| 在线调试 | /openapi/docs/ | 输入 App ID、App Secret 后验证应用，按权限调试正式业务。 |
| 正式 API | /openapi/v1/ | 每次请求需要新的签名，接口权限与设备范围独立校验。 |

### 推荐调用顺序

- 向服务方取得 App ID、App Secret、有效期及所需接口和设备授权。

- 使用应用访问接口核对应用身份、权限码及可访问端点。

- 分页查询设备，取得 deviceSn，再查询详情、点位、最新数据或历史。

- 需要控制时先查询可控命令并确认 WRITE 权限；使用幂等键提交，再通过服务端 messageId 查询结果。

- 保存告警配置创建返回的 ID，供更新和删除使用；配置回调前先读取原配置。

### 阅读导航

- 第二章：签名、权限、数据类型、空值和分页约定。

- 第三章：全部接口索引。

- 第四至第八章：19 个接口的用途、参数、返回值、示例及注意事项。

- 第九章：全部公共模型及模板详情的嵌套字段。

- 第十章：错误码和排查方法；第十一章：交付接入检查。

## 二 认证与公共约定

### 签名请求头

| 请求头 | 必填 | 填写方式 |
| --- | --- | --- |
| X-App-Id | 是 | 平台分配的 App ID，始终按字符串保存与拼接。 |
| salt | 是 | 每个请求生成新的安全随机串；不要复用上次完整请求头。 |
| timestamp | 是 | Unix 毫秒时间戳的十进制字符串，不是秒时间戳。 |
| sign | 是 | UTF-8 编码后计算 HMAC-SHA256，再对原始摘要字节做标准 Base64。 |
| X-Request-Id | 否 | 可选请求追踪标识；不传时平台自动生成。通过响应头和 requestId 返回，不参与上述签名拼接。 |

```text
message = appId + salt + timestamp
sign = Base64(HMAC-SHA256(key=appSecret, message=UTF8(message)))
```

拼接字段之间不加分隔符。不要先转十六进制再 Base64。App Secret 仅在调用端计算签名，不写入 URL、请求体或 X-App-Secret 请求头。请在可信服务端保管正式密钥。

严格校验模式下默认允许时间偏差 300 秒，防重放缓存默认至少 600 秒，实际可由部署配置调整。时间戳过期、签名错误、随机串重复、停用或过期应用均可能拒绝请求。

### 接口权限和设备授权

签名用于识别 App，不直接授予所有接口或设备权限。接口按权限码匹配，ALL 表示满足全部，ANY 表示满足任意一项。现有权限支持父级匹配下级，最终以应用访问接口返回的 endpoints 为准。

设备授权区分 READ 与 WRITE；WRITE 可读写，READ 仅可读取。设备查询还受当前租户与 App 范围限制。控制能力查询虽为 GET，仍要求设备可写。原始控制路由扩展还可能需要 openapi:iot:device:control.raw 权限。

### 请求格式和字段约定

- 带 JSON 请求体的接口使用 Content-Type: application/json；没有请求体的接口不要自行拼装 JSON body。

- 查询参数通过 URL 编码传递，类型列表示服务端解析后的类型。数组查询参数 snList 使用 snList=SN001&snList=SN002。

- 路径参数使用 URL 编码。SN 是设备序列号；设备 ID、点位 ID 和告警配置 ID 不是 SN。

- 字段必填、字段允许 null、响应字段一定返回是不同概念。可选字段可省略；未声明可空的字段不保证接受 null。

- 回调更新例外需要特别注意：省略、null 或空白会清空对应配置。

### 公共响应结构

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| message | string | 结果说明；失败时包含错误提示<br>示例："OK" |
| requestId | string | 请求标识，排查问题时提供给服务方<br>示例："example-request-id" |
| traceId | string | 服务链路追踪标识，可能为空 |
| data | object | 业务数据；具体结构随接口变化，空值字段可能不输出 |
| details | 字典 {键: object} | 可选的错误附加信息，不保证每次返回 |
| resultCode | string | 兼容字段，与 code 一致；新接入请使用 code<br>接口定义标记为已弃用。 |
| code | string | 业务码，字符串 200 表示成功；失败时同时检查 HTTP 状态和此字段<br>示例："200" |

业务成功码为字符串 200。必须同时检查 HTTP 状态与 code；部分业务异常仍可能使用 HTTP 200，不能只看 HTTP 状态。控制接口还需检查 data 中的执行状态。requestId 用于问题定位，traceId 是可选链路标识。

### ID 时间和空值

平台将 Java Long 响应序列化为字符串，所以 schema 中标注 int64 的 ID、计数和部分分页值可能表现为 JSON 字符串。客户端应保留完整精度，尤其不要在 JavaScript 中先转成 Number。请求示例中的数值 ID 使用小整数，实际大整数应按客户端精度能力处理。

LocalDateTime 常见格式为 2026-10-21T10:00:00，不含时区偏移；查询时间按服务约定时区理解。点位详情 gmtPositionValue 明确使用 2026-10-21 10:00:00，GMT+8。温室厂商原生 updateTime 按对应协议解释，不混同统一毫秒签名时间戳。

默认不输出 null 字段。对象缺失与空数组、空字符串、0、false 含义不同；客户端应兼容可选字段缺失。点位值可为数字、字符串、布尔值或对象，按实际 JSON 值和 valueType 解析。

### 分页和控制结果

| 接口类型 | 分页请求 | 返回结构 | 默认与上限 |
| --- | --- | --- | --- |
| 设备分页 | page、pageSize | page、pageSize、total、items | 默认 1 / 20，每页最多 50。 |
| 快照历史 | pageIndex、pageSize | current、size、total、pages、records | 默认 1 / 20，每页最多 1000。 |
| 点位变化历史 | pageIndex、pageSize | current、size、total、pages、records | 默认 1 / 20，每页最多 100。 |
| 控制日志 | pageIndex、pageSize | current、size、total、pages、records | 默认 1 / 20，每页最多 50。 |

历史接口使用 POST 查询，不下发控制。查询时间默认近 1 天，默认最长 31 天，部署可调整。pageSize 超上限的处理以具体接口说明为准。

| 状态字段 | 取值 | 客户侧理解 |
| --- | --- | --- |
| dispatchStatus | PENDING、DISPATCHED、ACCEPTED、FAILED | 描述平台向接入方下发，不单独代表设备已执行。 |
| executionStatus | UNKNOWN、EXECUTING、SUCCEEDED、FAILED、TIMEOUT | UNKNOWN 无法确认；SUCCEEDED 才表示已收到相应执行成功确认。 |
| ackMode | NONE、PROVIDER、DEVICE、STATE_CONFIRMED | 分别表示无回执、厂商回执、设备回执、状态确认。 |
| status | CREATED、VALIDATED、DISPATCHED、ACCEPTED、EXECUTING、SUCCEEDED、FAILED、TIMEOUT、UNKNOWN | 总体控制轨迹状态，结合上下两个状态及 statusDesc 解释。 |
| 历史兼容 status | REQUEST_ENTERED、PARSE_SUCCESS、CONTROL_DEVICE、COMMAND_SENT、DEVICE_EXECUTE_SUCCESS、CONTROL_SUCCESS、CONTROL_FAILED | 旧轨迹可能仍返回兼容状态，不把所有带 SUCCESS 的字符串一概认定为设备物理动作成功。 |

一次业务动作使用稳定幂等键；同一业务重试保持相同键与请求内容，同时重新生成 salt、timestamp、sign。网络超时后先查询已有 messageId 的状态，不直接盲目重发控制。

## 三 接口目录

| 编号 | 功能 | 方法与相对路径 | 接口用途 |
| --- | --- | --- | --- |
| 01 | 应用访问 | GET<br>/apps/me/endpoints | 列出当前应用可用的 OpenAPI 端点 |
| 02 | 设备查询 | GET<br>/devices | 分页查询当前应用可访问的设备 |
| 03 | 设备查询 | GET<br>/devices/selectDeviceBySn/{sn} | 按设备序列号查询设备详情 |
| 04 | 设备查询 | GET<br>/devices/selectDeviceBySnList | 按设备序列号列表批量查询设备详情 |
| 05 | 设备查询 | GET<br>/devices/deviceTemplateDetail/{sn} | 按设备序列号查询模板化设备详情 |
| 06 | 设备查询 | GET<br>/devices/selectPositionBySnCode/{sn}/{positionCode} | 按设备序列号和点位编码查询点位详情 |
| 07 | 设备查询 | GET<br>/devices/latestParamState/{sn} | 查询设备最新参数状态详情 |
| 08 | 设备查询 | POST<br>/devices/snapshotHistory/page | 查询设备点位快照历史 |
| 09 | 设备查询 | POST<br>/devices/pointChangeHistory/page | 查询设备点位变化历史 |
| 10 | 设备控制 | GET<br>/devices/controlCapabilities/{sn} | 查询设备可控命令 |
| 11 | 设备控制 | POST<br>/devices/executeCmd | 下发设备控制指令 |
| 12 | 设备控制 | POST<br>/devices/executeCmd/batch | 批量下发设备控制指令 |
| 13 | 设备控制 | GET<br>/devices/executeCmd/status/{messageId} | 查询设备控制指令执行状态 |
| 14 | 设备控制 | POST<br>/devices/executeCmd/logs/page | 分页查询设备控制操作日志 |
| 15 | 告警配置 | POST<br>/alerts/createAlertConfig | 创建设备告警配置 |
| 16 | 告警配置 | POST<br>/alerts/updateAlertConfig | 更新设备告警配置 |
| 17 | 告警配置 | POST<br>/alerts/deleteAlertConfig | 删除设备告警配置 |
| 18 | 回调配置 | GET<br>/callback-config | 查询当前应用的回调配置 |
| 19 | 回调配置 | PUT<br>/callback-config | 修改当前应用的回调配置 |

## 四 应用访问接口

确认当前 App 的身份、权限与可访问接口。

### 接口 01 列出当前应用可用的 OpenAPI 端点

请求方式：GET    接口路径：/openapi/v1/apps/me/endpoints

作用：返回当前应用的基础信息、已授权权限码以及可访问接口列表。接口列表由控制器上的 OpenAPI 权限声明和当前应用授权结果共同决定。

调用权限：有效应用签名，无需额外接口权限码。权限匹配方式：ALL。

操作性质：只读查询。

#### 请求参数

无业务参数、无请求体；仍需携带公共签名请求头。

#### 请求示例

```http
GET {API_ROOT}/apps/me/endpoints HTTP/1.1
X-App-Id: {APP_ID}
salt: {本次新随机串}
timestamp: {当前毫秒时间戳}
sign: {本次计算的签名}
```

示例中的 SN、点位编码、命令值、ID 和地址需替换为已授权数据；签名占位符不能原样发送。

#### 响应字段

成功响应使用公共响应结构。以下说明 data；code、message、requestId、traceId、details、resultCode 见公共响应章节。

| 字段 | 类型 | 含义 |
| --- | --- | --- |
| data | 对象 M27 | 当前应用可调用的 OpenAPI 接口清单，用于确认本应用已授权的权限码以及实际可访问的接口列表<br>完整子字段见模型 M27。 |

data 对象字段：

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| appId | 字符串 int64 | 当前接入应用 ID，对应调用方在请求头 X-App-Id 中使用的应用标识<br>示例：1001 |
| appCode | string | 当前接入应用编码，用于区分客户侧不同接入应用<br>示例："customer-iot-app" |
| tenantId | 字符串 int64 | 当前应用所属租户 ID，接口返回的数据会限定在该租户范围内<br>示例：10 |
| permissionCodes | 数组 [string] | 当前应用已授权的权限码列表。授权父级权限时，可访问其下级权限对应的接口，例如 openapi:iot:device:read 可匹配 openapi:iot:device:read.detail |
| endpoints | 数组 [对象 M28] | 当前应用根据已授权权限实际可调用的 OpenAPI 接口列表 |

#### 成功响应示例

以下为说明字段结构的示意数据，省略了部分可选字段，不是本次接口实测结果。完整字段以字段表和模型定义为准。

```json
{
  "code": "200",
  "message": "OK",
  "requestId": "request-example-001",
  "data": {
    "appId": "1001",
    "appCode": "customer-app",
    "tenantId": "10",
    "permissionCodes": [
      "openapi:iot:device:read"
    ],
    "endpoints": [
      {
        "methods": [
          "GET"
        ],
        "path": "/openapi/v1/devices",
        "summary": "分页查询当前应用可访问的设备",
        "permissionCodes": [
          "openapi:iot:device:read"
        ],
        "permissionMode": "ALL"
      }
    ]
  }
}
```

#### 业务约束和排查

- 建议作为接入验证的第一步。返回 appId、appCode、tenantId、权限码和端点列表；本接口无需额外权限码。

- 返回的端点权限不代表已授权全部设备；设备范围仍由设备接口校验。

排查时可参考公共错误码：1000、1003、1004、1005、1006。这不是该接口所有业务分支的穷举；应结合 message 和 requestId。

## 五 设备查询接口

按授权范围获取设备、点位、模板及历史数据。

### 接口 02 分页查询当前应用可访问的设备

请求方式：GET    接口路径：/openapi/v1/devices

作用：按设备名称、序列号、类型、在线状态和启用状态查询当前应用授权范围内的设备。

调用权限：openapi:iot:device:read。权限匹配方式：ALL。

操作性质：只读查询。

#### 请求参数

| 参数与位置 | 类型 | 必填 | 说明与示例 |
| --- | --- | --- | --- |
| deviceName<br>查询参数 | string | 否 | 设备名称，支持模糊查询<br>示例："温室传感器" |
| deviceSn<br>查询参数 | string | 否 | 设备序列号<br>示例："SN001" |
| typeCode<br>查询参数 | string | 否 | 设备类型编码<br>示例："greenhouse" |
| onlineStatus<br>查询参数 | int32 | 否 | 在线状态，1 表示在线，0 表示离线<br>最小值：0<br>最大值：1<br>示例：1 |
| enabled<br>查询参数 | int32 | 否 | 启用状态，1 表示启用，0 表示禁用<br>最小值：0<br>最大值：1<br>示例：1 |
| page<br>查询参数 | int32 | 否 | 页码，从 1 开始<br>默认值："1"<br>最小值：1<br>示例：1 |
| pageSize<br>查询参数 | int32 | 否 | 每页数量，最大 50<br>默认值："20"<br>最小值：1<br>最大值：50<br>示例：20 |

本接口无 JSON 请求体。公共签名头见认证章节。

#### 请求示例

```http
GET {API_ROOT}/devices?page=1&pageSize=20 HTTP/1.1
X-App-Id: {APP_ID}
salt: {本次新随机串}
timestamp: {当前毫秒时间戳}
sign: {本次计算的签名}
```

示例中的 SN、点位编码、命令值、ID 和地址需替换为已授权数据；签名占位符不能原样发送。

#### 响应字段

成功响应使用公共响应结构。以下说明 data；code、message、requestId、traceId、details、resultCode 见公共响应章节。

| 字段 | 类型 | 含义 |
| --- | --- | --- |
| data | 对象 M52 | 分页响应<br>完整子字段见模型 M52。 |

data 对象字段：

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| page | int32 | 当前页码，从 1 开始<br>示例：1 |
| pageSize | int32 | 每页数量<br>示例：20 |
| total | 字符串 int64 | 符合条件的记录总数<br>示例：100 |
| items | 数组 [对象 M12] | 当前页记录 |

#### 成功响应示例

以下为说明字段结构的示意数据，省略了部分可选字段，不是本次接口实测结果。完整字段以字段表和模型定义为准。

```json
{
  "code": "200",
  "message": "OK",
  "requestId": "request-example-001",
  "data": {
    "page": 1,
    "pageSize": 20,
    "total": "1",
    "items": [
      {
        "deviceSn": "SN001",
        "deviceName": "温室设备",
        "typeCode": "MET",
        "onlineStatus": 1,
        "enabled": 1,
        "accessMode": "READ",
        "dataMode": "READ_ONLY"
      }
    ]
  }
}
```

#### 业务约束和排查

- page 默认 1，pageSize 默认 20，范围为 1 至 50；所有过滤条件在当前 App 的设备授权范围内生效。

- onlineStatus、enabled 只接受 0 或 1。设备列表为空时先核对授权范围与筛选条件。

排查时可参考公共错误码：1000、1003、1004、1005、1006。这不是该接口所有业务分支的穷举；应结合 message 和 requestId。

### 接口 03 按设备序列号查询设备详情

请求方式：GET    接口路径：/openapi/v1/devices/selectDeviceBySn/{sn}

作用：根据设备 SN 查询单台设备详情，返回设备基础信息、启用状态、在线状态和参数明细。

调用权限：openapi:iot:device:read.detail。权限匹配方式：ALL。

操作性质：只读查询。

#### 请求参数

| 参数与位置 | 类型 | 必填 | 说明与示例 |
| --- | --- | --- | --- |
| sn<br>路径参数 | string | 是 | 设备 SN<br>示例："SN001" |

本接口无 JSON 请求体。公共签名头见认证章节。

#### 请求示例

```http
GET {API_ROOT}/devices/selectDeviceBySn/SN001 HTTP/1.1
X-App-Id: {APP_ID}
salt: {本次新随机串}
timestamp: {当前毫秒时间戳}
sign: {本次计算的签名}
```

示例中的 SN、点位编码、命令值、ID 和地址需替换为已授权数据；签名占位符不能原样发送。

#### 响应字段

成功响应使用公共响应结构。以下说明 data；code、message、requestId、traceId、details、resultCode 见公共响应章节。

| 字段 | 类型 | 含义 |
| --- | --- | --- |
| data | 对象 M11 | 设备详情<br>完整子字段见模型 M11。 |

data 对象字段：

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| id | 字符串 int64 | 平台内设备 ID<br>示例：1 |
| deviceName | string | 设备名称<br>示例："设备1" |
| deviceSn | string | 设备序列号<br>示例："1001" |
| typeCode | string | 面向客户的设备分类编码；优先使用外部分类，未配置时回退内部类型编码<br>示例："MET" |
| typeName | string | 面向客户的设备分类名称；优先使用外部分类，未配置时回退内部类型名称<br>示例："气象设备" |
| internalTypeCode | string | 平台内部设备类型编码，供系统间对接识别<br>示例："FNKJ_LAMP" |
| providerCode | string | 设备厂商接入编码<br>示例："THIRD_PLATFORM_FNKJ" |
| manufacturerName | string | 厂商名称<br>示例："zwyk" |
| onlineStatus | int32 | 在线状态，1 表示在线，0 表示离线<br>示例：1 |
| enabledStatus | int32 | 启用状态，1 表示启用，0 表示禁用<br>示例：1 |
| lastOnlineTime | string date-time | 最近一次上线时间 |
| lastOfflineTime | string date-time | 最近一次离线时间 |
| queryTime | string date-time | 本次查询时间 |
| variableDetail | 对象 M24 | 设备变量详情<br>完整子字段见模型 M24。 |
| dataMode | string | 设备数据模式：READ_ONLY-只读，READ_WRITE-读写<br>示例："READ_ONLY" |

#### 成功响应示例

以下为说明字段结构的示意数据，省略了部分可选字段，不是本次接口实测结果。完整字段以字段表和模型定义为准。

```json
{
  "code": "200",
  "message": "OK",
  "requestId": "request-example-001",
  "data": {
    "id": "1001",
    "deviceSn": "SN001",
    "deviceName": "温室设备",
    "onlineStatus": 1,
    "enabledStatus": 1,
    "dataMode": "READ_ONLY"
  }
}
```

#### 业务约束和排查

- sn 为设备序列号，不是平台数字设备 ID。

- 未找到或不可读取的设备可能返回 1007；不要将此结果作为判断其他客户设备是否存在的依据。

- variableDetail 为嵌套变量详情；异常或缺失数据的字段可能省略。

排查时可参考公共错误码：1000、1003、1004、1005、1006、1007。这不是该接口所有业务分支的穷举；应结合 message 和 requestId。

### 接口 04 按设备序列号列表批量查询设备详情

请求方式：GET    接口路径：/openapi/v1/devices/selectDeviceBySnList

作用：根据多个设备 SN 批量查询设备详情，不存在或无权限访问的设备不会返回。

调用权限：openapi:iot:device:read.list。权限匹配方式：ALL。

操作性质：只读查询。

#### 请求参数

| 参数与位置 | 类型 | 必填 | 说明与示例 |
| --- | --- | --- | --- |
| snList<br>查询参数 | 数组 [string] | 是 | 设备 SN 列表，可重复传递 snList 参数，例如 snList=SN001&snList=SN002<br>示例："SN001" |
| includeVariableDetail<br>查询参数 | boolean | 否 | 是否包含变量详情；默认 false，传 true 时返回变量详情。<br>默认值：false |

本接口无 JSON 请求体。公共签名头见认证章节。

#### 请求示例

```http
GET {API_ROOT}/devices/selectDeviceBySnList?snList=SN001&snList=SN002&includeVariableDetail=false HTTP/1.1
X-App-Id: {APP_ID}
salt: {本次新随机串}
timestamp: {当前毫秒时间戳}
sign: {本次计算的签名}
```

示例中的 SN、点位编码、命令值、ID 和地址需替换为已授权数据；签名占位符不能原样发送。

#### 响应字段

成功响应使用公共响应结构。以下说明 data；code、message、requestId、traceId、details、resultCode 见公共响应章节。

| 字段 | 类型 | 含义 |
| --- | --- | --- |
| data | 数组 [对象 M11] | 业务数据；具体结构随接口变化，空值字段可能不输出 |

data 数组元素字段：

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| id | 字符串 int64 | 平台内设备 ID<br>示例：1 |
| deviceName | string | 设备名称<br>示例："设备1" |
| deviceSn | string | 设备序列号<br>示例："1001" |
| typeCode | string | 面向客户的设备分类编码；优先使用外部分类，未配置时回退内部类型编码<br>示例："MET" |
| typeName | string | 面向客户的设备分类名称；优先使用外部分类，未配置时回退内部类型名称<br>示例："气象设备" |
| internalTypeCode | string | 平台内部设备类型编码，供系统间对接识别<br>示例："FNKJ_LAMP" |
| providerCode | string | 设备厂商接入编码<br>示例："THIRD_PLATFORM_FNKJ" |
| manufacturerName | string | 厂商名称<br>示例："zwyk" |
| onlineStatus | int32 | 在线状态，1 表示在线，0 表示离线<br>示例：1 |
| enabledStatus | int32 | 启用状态，1 表示启用，0 表示禁用<br>示例：1 |
| lastOnlineTime | string date-time | 最近一次上线时间 |
| lastOfflineTime | string date-time | 最近一次离线时间 |
| queryTime | string date-time | 本次查询时间 |
| variableDetail | 对象 M24 | 设备变量详情<br>完整子字段见模型 M24。 |
| dataMode | string | 设备数据模式：READ_ONLY-只读，READ_WRITE-读写<br>示例："READ_ONLY" |

#### 成功响应示例

以下为说明字段结构的示意数据，省略了部分可选字段，不是本次接口实测结果。完整字段以字段表和模型定义为准。

```json
{
  "code": "200",
  "message": "OK",
  "requestId": "request-example-001",
  "data": [
    {
      "id": "1001",
      "deviceSn": "SN001",
      "deviceName": "温室设备",
      "onlineStatus": 1,
      "enabledStatus": 1,
      "dataMode": "READ_ONLY"
    }
  ]
}
```

#### 业务约束和排查

- snList 必须至少包含一个非空 SN，按重复查询参数传递。

- includeVariableDetail 默认为 false；需要变量详情时显式传 true。

- 返回数组仅包含可访问且存在的设备，数量可能少于请求 SN 数量。

排查时可参考公共错误码：1000、1003、1004、1005、1006、1007。这不是该接口所有业务分支的穷举；应结合 message 和 requestId。

### 接口 05 按设备序列号查询模板化设备详情

请求方式：GET    接口路径：/openapi/v1/devices/deviceTemplateDetail/{sn}

作用：根据设备绑定的业务模板，将原始点位转换为泵、肥通道和电磁阀等业务结构。

调用权限：openapi:iot:device:read.detail。权限匹配方式：ALL。

操作性质：只读查询。

#### 请求参数

| 参数与位置 | 类型 | 必填 | 说明与示例 |
| --- | --- | --- | --- |
| sn<br>路径参数 | string | 是 | 设备 SN<br>示例："SN001" |
| tempModel<br>查询参数 | int32 | 否 | 模板模式：1-手动，0-自动<br>默认值：1<br>示例：1 |

本接口无 JSON 请求体。公共签名头见认证章节。

#### 请求示例

```http
GET {API_ROOT}/devices/deviceTemplateDetail/SN001?tempModel=1 HTTP/1.1
X-App-Id: {APP_ID}
salt: {本次新随机串}
timestamp: {当前毫秒时间戳}
sign: {本次计算的签名}
```

示例中的 SN、点位编码、命令值、ID 和地址需替换为已授权数据；签名占位符不能原样发送。

#### 响应字段

成功响应使用公共响应结构。以下说明 data；code、message、requestId、traceId、details、resultCode 见公共响应章节。

| 字段 | 类型 | 含义 |
| --- | --- | --- |
| data | 对象 M23 | 客户设备模板化详情响应<br>完整子字段见模型 M23。 |

data 对象字段：

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| device | 对象 M25 | OpenAPI 设备变量身份信息<br>完整子字段见模型 M25。 |
| templateCode | string | 业务模板编码 |
| templateType | string | 业务模板类型，用于识别 detail 的具体结构<br>示例："WATER_FERTILIZER_MACHINE" |
| templateVersion | int32 | 业务模板版本 |
| tempModel | int32 | 模板模式：1 为手动 MANUAL，0 为自动 AUTO；与本接口查询参数保持一致。<br>示例：1 |
| modeCode | string | 模板模式编码：MANUAL-手动，AUTO-自动<br>示例："MANUAL" |
| detail | object | 模板业务详情，结构由 templateType 决定 按 templateType 选择水肥机、变频柜或温室模型，详见模板详情说明。 |
| missingSlotList | 数组 [string] | 模板必填槽位缺失列表 |

#### 成功响应示例

以下为说明字段结构的示意数据，省略了部分可选字段，不是本次接口实测结果。完整字段以字段表和模型定义为准。

```json
{
  "code": "200",
  "message": "OK",
  "requestId": "request-example-001",
  "data": {
    "device": {
      "deviceSn": "SN001"
    },
    "templateType": "VFD_CABINET",
    "templateCode": "vfd-demo",
    "templateVersion": 2,
    "tempModel": 1,
    "modeCode": "MANUAL",
    "detail": {
      "points": {
        "YLSD1": {
          "code": "YLSD1",
          "name": "压力设定",
          "value": 0.3,
          "variableReadWriteType": "READ_WRITE"
        }
      }
    },
    "missingSlotList": []
  }
}
```

#### 业务约束和排查

- tempModel=1 表示手动 MANUAL，tempModel=0 表示自动 AUTO，默认 1；其他值返回 1000。

- 按 templateType 和 templateVersion 解析 detail，不能将任意模板都当作同一结构。

- VFD_CABINET 版本 2 及以上主要通过 detail.points 点位字典输出；旧版本通过 outputVoltage 等命名点位输出。

- 字段值为空、缺少模板槽位时，不推断设备已停止或离线；结合 missingSlotList 和数据状态处理。

排查时可参考公共错误码：1000、1003、1004、1005、1006、1007、1015、1016、1017、1018。这不是该接口所有业务分支的穷举；应结合 message 和 requestId。

### 接口 06 按设备序列号和点位编码查询点位详情

请求方式：GET    接口路径：/openapi/v1/devices/selectPositionBySnCode/{sn}/{positionCode}

作用：根据设备 SN 和点位编码查询单个设备点位详情。

调用权限：openapi:iot:device:read.detail。权限匹配方式：ALL。

操作性质：只读查询。

#### 请求参数

| 参数与位置 | 类型 | 必填 | 说明与示例 |
| --- | --- | --- | --- |
| sn<br>路径参数 | string | 是 | 设备 SN<br>示例："SN001" |
| positionCode<br>路径参数 | string | 是 | 点位编码<br>示例："temperature" |

本接口无 JSON 请求体。公共签名头见认证章节。

#### 请求示例

```http
GET {API_ROOT}/devices/selectPositionBySnCode/SN001/temperature HTTP/1.1
X-App-Id: {APP_ID}
salt: {本次新随机串}
timestamp: {当前毫秒时间戳}
sign: {本次计算的签名}
```

示例中的 SN、点位编码、命令值、ID 和地址需替换为已授权数据；签名占位符不能原样发送。

#### 响应字段

成功响应使用公共响应结构。以下说明 data；code、message、requestId、traceId、details、resultCode 见公共响应章节。

| 字段 | 类型 | 含义 |
| --- | --- | --- |
| data | 对象 M19 | 设备点位详情<br>完整子字段见模型 M19。 |

data 对象字段：

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| id | 字符串 int64 | 点位 ID<br>示例：1 |
| positionName | string | 点位名称<br>示例："点位1" |
| positionCode | string | 点位编码<br>示例："point1" |
| latestPositionValue | string | 点位最新值<br>示例："12" |
| gmtPositionValue | string date-time | 点位最新值采集时间；实际 JSON 格式 yyyy-MM-dd HH:mm:ss，时区 GMT+8。 |
| positionUnit | string | 点位单位<br>示例："m³/h" |

#### 成功响应示例

以下为说明字段结构的示意数据，省略了部分可选字段，不是本次接口实测结果。完整字段以字段表和模型定义为准。

```json
{
  "code": "200",
  "message": "OK",
  "requestId": "request-example-001",
  "data": {
    "id": "1001",
    "positionName": "温度",
    "positionCode": "temperature",
    "latestPositionValue": "23.5",
    "gmtPositionValue": "2026-10-21 10:00:00",
    "positionUnit": "℃"
  }
}
```

#### 业务约束和排查

- positionCode 为当前设备的点位编码。路径变量含特殊字符时进行 URL 编码。

- gmtPositionValue 使用 yyyy-MM-dd HH:mm:ss，GMT+8，不使用本接口其他字段的 ISO-8601 格式代替。

排查时可参考公共错误码：1000、1003、1004、1005、1006、1007。这不是该接口所有业务分支的穷举；应结合 message 和 requestId。

### 接口 07 查询设备最新参数状态详情

请求方式：GET    接口路径：/openapi/v1/devices/latestParamState/{sn}

作用：根据设备 SN 查询设备最新一次参数状态快照。

调用权限：openapi:iot:device:read.detail。权限匹配方式：ALL。

操作性质：只读查询。

#### 请求参数

| 参数与位置 | 类型 | 必填 | 说明与示例 |
| --- | --- | --- | --- |
| sn<br>路径参数 | string | 是 | 设备 SN<br>示例："SN001" |

本接口无 JSON 请求体。公共签名头见认证章节。

#### 请求示例

```http
GET {API_ROOT}/devices/latestParamState/SN001 HTTP/1.1
X-App-Id: {APP_ID}
salt: {本次新随机串}
timestamp: {当前毫秒时间戳}
sign: {本次计算的签名}
```

示例中的 SN、点位编码、命令值、ID 和地址需替换为已授权数据；签名占位符不能原样发送。

#### 响应字段

成功响应使用公共响应结构。以下说明 data；code、message、requestId、traceId、details、resultCode 见公共响应章节。

| 字段 | 类型 | 含义 |
| --- | --- | --- |
| data | 对象 M13 | 设备最新参数状态详情<br>完整子字段见模型 M13。 |

data 对象字段：

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| device | 对象 M25 | OpenAPI 设备变量身份信息<br>完整子字段见模型 M25。 |
| paramInfoResList | 数组 [对象 M14] | 参数最新状态列表 |

#### 成功响应示例

以下为说明字段结构的示意数据，省略了部分可选字段，不是本次接口实测结果。完整字段以字段表和模型定义为准。

```json
{
  "code": "200",
  "message": "OK",
  "requestId": "request-example-001",
  "data": {
    "device": {
      "deviceSn": "SN001"
    },
    "paramInfoResList": [
      {
        "variableCode": "temperature",
        "variableName": "温度",
        "unit": "℃",
        "lastValue": 23.5,
        "changeTime": "2026-10-21T10:00:00"
      }
    ]
  }
}
```

#### 业务约束和排查

- 读取已存在的最新参数状态，调用本接口不保证向设备发起一次新的采集。

- paramInfoResList[].lastValue 的 JSON 类型随点位变化；不要将所有值强制解析为数字。

排查时可参考公共错误码：1000、1003、1004、1005、1006、1007。这不是该接口所有业务分支的穷举；应结合 message 和 requestId。

### 接口 08 查询设备点位快照历史

请求方式：POST    接口路径：/openapi/v1/devices/snapshotHistory/page

作用：只读分页查询设备点位快照；使用 POST 提交筛选条件，不下发控制。

调用权限：openapi:iot:device:read。权限匹配方式：ALL。

操作性质：只读查询。

#### 请求参数

请求体：application/json，必填。快照历史分页条件，deviceSn 必填。

| 字段 | 类型 | 必填与可空 | 说明 约束和示例 |
| --- | --- | --- | --- |
| deviceSn | string | 是<br>不可为 null | 设备序列号，必须在当前应用授权范围内<br>示例："SN001" |
| positionCode | string | 否<br>未声明可空 | 按点位编码筛选，不填时不限制点位 |
| startTime | string date-time | 否<br>未声明可空 | 查询起始时间，ISO-8601 本地日期时间<br>示例："2026-10-20T00:00:00" |
| endTime | string date-time | 否<br>未声明可空 | 查询结束时间，ISO-8601 本地日期时间<br>示例："2026-10-21T00:00:00" |
| pageIndex | int64 | 否<br>未声明可空 | 历史分页页码<br>默认值：1<br>最小值：1<br>示例：1 |
| pageSize | int64 | 否<br>未声明可空 | 历史分页每页条数<br>默认值：20<br>最小值：1<br>最大值：1000<br>示例：10 |

#### 请求示例

```http
POST {API_ROOT}/devices/snapshotHistory/page HTTP/1.1
X-App-Id: {APP_ID}
salt: {本次新随机串}
timestamp: {当前毫秒时间戳}
sign: {本次计算的签名}
Content-Type: application/json

{
  "deviceSn": "SN001",
  "startTime": "2026-10-20T00:00:00",
  "endTime": "2026-10-21T00:00:00",
  "pageIndex": 1,
  "pageSize": 20
}
```

示例中的 SN、点位编码、命令值、ID 和地址需替换为已授权数据；签名占位符不能原样发送。

#### 响应字段

成功响应使用公共响应结构。以下说明 data；code、message、requestId、traceId、details、resultCode 见公共响应章节。

| 字段 | 类型 | 含义 |
| --- | --- | --- |
| data | 对象 M21 | 业务数据；具体结构随接口变化，空值字段可能不输出<br>完整子字段见模型 M21。 |

data 对象字段：

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| device | 对象 M25 | OpenAPI 设备变量身份信息<br>完整子字段见模型 M25。 |
| records | 数组 [对象 M22] | 本页快照记录 |
| total | 字符串 int64 | 总记录数 |
| size | 字符串 int64 | 每页条数 |
| current | 字符串 int64 | 当前页码 |
| pages | 字符串 int64 | 总页数 |

#### 成功响应示例

以下为说明字段结构的示意数据，省略了部分可选字段，不是本次接口实测结果。完整字段以字段表和模型定义为准。

```json
{
  "code": "200",
  "message": "OK",
  "requestId": "request-example-001",
  "data": {
    "device": {
      "deviceSn": "SN001"
    },
    "current": "1",
    "size": "20",
    "total": "1",
    "pages": "1",
    "records": [
      {
        "dataTime": "2026-10-21T10:00:00",
        "variables": [
          {
            "code": "temperature",
            "name": "温度",
            "value": 23.5,
            "unit": "℃"
          }
        ]
      }
    ]
  }
}
```

#### 业务约束和排查

- 本接口为只读查询，POST 用于提交筛选条件。

- pageIndex 缺省或小于 1 时按 1 处理；pageSize 缺省或小于 1 时为 20，超过 1000 时限制为 1000。

- 时间均不传时查询最近 1 天；只传一个端点时以该端点补齐 1 天范围。startTime 必须早于 endTime，默认最长范围 31 天，部署可调整。

- records 表示采集快照；同一快照可以有多个点位。positionCode 用于筛选快照中的点位。

排查时可参考公共错误码：1000、1003、1004、1005、1006、1007。这不是该接口所有业务分支的穷举；应结合 message 和 requestId。

### 接口 09 查询设备点位变化历史

请求方式：POST    接口路径：/openapi/v1/devices/pointChangeHistory/page

作用：只读分页查询点位值变化记录；使用 POST 提交筛选条件，不修改点位。

调用权限：openapi:iot:device:read。权限匹配方式：ALL。

操作性质：只读查询。

#### 请求参数

请求体：application/json，必填。点位变化历史分页条件，deviceSn 必填。

| 字段 | 类型 | 必填与可空 | 说明 约束和示例 |
| --- | --- | --- | --- |
| deviceSn | string | 是<br>不可为 null | 设备序列号，必须在当前应用授权范围内<br>示例："SN001" |
| positionCode | string | 否<br>未声明可空 | 按点位编码筛选，不填时不限制点位 |
| startTime | string date-time | 否<br>未声明可空 | 查询起始时间，ISO-8601 本地日期时间<br>示例："2026-10-20T00:00:00" |
| endTime | string date-time | 否<br>未声明可空 | 查询结束时间，ISO-8601 本地日期时间<br>示例："2026-10-21T00:00:00" |
| pageIndex | int64 | 否<br>未声明可空 | 历史分页页码<br>默认值：1<br>最小值：1<br>示例：1 |
| pageSize | int64 | 否<br>未声明可空 | 历史分页每页条数<br>默认值：20<br>最小值：1<br>最大值：100<br>示例：10 |

#### 请求示例

```http
POST {API_ROOT}/devices/pointChangeHistory/page HTTP/1.1
X-App-Id: {APP_ID}
salt: {本次新随机串}
timestamp: {当前毫秒时间戳}
sign: {本次计算的签名}
Content-Type: application/json

{
  "deviceSn": "SN001",
  "pageIndex": 1,
  "pageSize": 20
}
```

示例中的 SN、点位编码、命令值、ID 和地址需替换为已授权数据；签名占位符不能原样发送。

#### 响应字段

成功响应使用公共响应结构。以下说明 data；code、message、requestId、traceId、details、resultCode 见公共响应章节。

| 字段 | 类型 | 含义 |
| --- | --- | --- |
| data | 对象 M16 | 业务数据；具体结构随接口变化，空值字段可能不输出<br>完整子字段见模型 M16。 |

data 对象字段：

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| device | 对象 M25 | OpenAPI 设备变量身份信息<br>完整子字段见模型 M25。 |
| records | 数组 [对象 M17] | 本页点位变化记录 |
| total | 字符串 int64 | 总记录数 |
| size | 字符串 int64 | 每页条数 |
| current | 字符串 int64 | 当前页码 |
| pages | 字符串 int64 | 总页数 |

#### 成功响应示例

以下为说明字段结构的示意数据，省略了部分可选字段，不是本次接口实测结果。完整字段以字段表和模型定义为准。

```json
{
  "code": "200",
  "message": "OK",
  "requestId": "request-example-001",
  "data": {
    "device": {
      "deviceSn": "SN001"
    },
    "current": "1",
    "size": "20",
    "total": "1",
    "pages": "1",
    "records": [
      {
        "dataTime": "2026-10-21T10:00:00",
        "changedPoints": [
          {
            "code": "temperature",
            "beforeValue": 23.1,
            "afterValue": 23.5,
            "unit": "℃",
            "changeTime": "2026-10-21T10:00:00"
          }
        ]
      }
    ]
  }
}
```

#### 业务约束和排查

- 本接口为只读查询，返回点位值发生变化的记录，不等于全部采集快照。

- 分页默认 pageIndex=1、pageSize=20，每页最多 100 条；超过上限会限制为 100。

- 时间缺省规则同快照历史；默认最长范围 31 天。扫描快照过多会返回 1000，需要缩小时间范围。

- beforeValue 和 afterValue 保留原点位值类型；无变化时可能返回空记录。

排查时可参考公共错误码：1000、1003、1004、1005、1006、1007。这不是该接口所有业务分支的穷举；应结合 message 和 requestId。

## 六 设备控制接口

查询控制能力、下发命令并追踪结果。

### 接口 10 查询设备可控命令

请求方式：GET    接口路径：/openapi/v1/devices/controlCapabilities/{sn}

作用：根据设备 SN 查询当前应用可写范围内设备支持的标准控制命令。

调用权限：openapi:iot:device:control.execute。权限匹配方式：ALL。

操作性质：只读查询。

#### 请求参数

| 参数与位置 | 类型 | 必填 | 说明与示例 |
| --- | --- | --- | --- |
| sn<br>路径参数 | string | 是 | 设备 SN<br>示例："SN001" |

本接口无 JSON 请求体。公共签名头见认证章节。

#### 请求示例

```http
GET {API_ROOT}/devices/controlCapabilities/SN001 HTTP/1.1
X-App-Id: {APP_ID}
salt: {本次新随机串}
timestamp: {当前毫秒时间戳}
sign: {本次计算的签名}
```

示例中的 SN、点位编码、命令值、ID 和地址需替换为已授权数据；签名占位符不能原样发送。

#### 响应字段

成功响应使用公共响应结构。以下说明 data；code、message、requestId、traceId、details、resultCode 见公共响应章节。

| 字段 | 类型 | 含义 |
| --- | --- | --- |
| data | 数组 [对象 M06] | 业务数据；具体结构随接口变化，空值字段可能不输出 |

data 数组元素字段：

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| commandCode | string | 控制命令编码，调用 executeCmd 时作为 cmds[].cmd 传入<br>示例："stir_1_set" |
| commandName | string | 命令名称<br>示例："A搅拌时间设置" |
| currentValue | object | 当前值 可为字符串、数字、布尔值或对象，客户端按实际 JSON 值解析。 |
| unit | string | 单位<br>示例："s" |
| valueType | string | 值类型<br>示例："INT" |
| variableReadWriteType | string | 读写类型<br>示例："READ_WRITE" |
| remoteWritable | boolean | 是否允许远程写入 |
| defaultValue | string | 默认值 |
| valueConvertType | string | 值转换类型<br>示例："ENUM" |
| valueConvertRule | string | 值转换规则 |
| collectTime | string date-time | 最近采集时间 |

#### 成功响应示例

以下为说明字段结构的示意数据，省略了部分可选字段，不是本次接口实测结果。完整字段以字段表和模型定义为准。

```json
{
  "code": "200",
  "message": "OK",
  "requestId": "request-example-001",
  "data": [
    {
      "commandCode": "stir_1_set",
      "commandName": "搅拌时间设置",
      "valueType": "INT",
      "unit": "s",
      "variableReadWriteType": "READ_WRITE",
      "remoteWritable": true
    }
  ]
}
```

#### 业务约束和排查

- 查询本身不下发控制，但要求控制接口权限与该设备 WRITE 范围。

- 将返回的 commandCode 作为控制请求 cmds[].cmd，结合 remoteWritable、valueType、valueConvertRule 和单位构造命令值。

- READ_ONLY 数据模式的设备不可控制；控制能力为空时不要自行猜测命令编码。

排查时可参考公共错误码：1000、1003、1004、1005、1006、1007。这不是该接口所有业务分支的穷举；应结合 message 和 requestId。

### 接口 11 下发设备控制指令

请求方式：POST    接口路径：/openapi/v1/devices/executeCmd

作用：向单台设备下发控制指令。设备必须在当前应用授权范围内，且应用需具备控制权限。

调用权限：openapi:iot:device:control.execute。权限匹配方式：ALL。

操作性质：实际修改或控制，调用后会生效。

#### 请求参数

请求体：application/json，必填。设备控制请求。deviceSn 必填，cmds 至少包含一条控制命令；messageId 可由客户传入。

| 字段 | 类型 | 必填与可空 | 说明 约束和示例 |
| --- | --- | --- | --- |
| deviceSn | string | 是<br>不可为 null | 需要下发控制的设备序列号<br>示例："1001" |
| cmds | 数组 [对象 M50] | 是<br>不可为 null | 兼容旧版调用的命令参数列表 |
| commandCode | string | 否<br>未声明可空 | 标准化命令编码，用于指定本次要执行的控制命令<br>示例："manualValve" |
| commandType | string | 否<br>未声明可空 | 命令类型，用于区分控制命令类别<br>示例："PARAM_SET" |
| routingOptions | 对象 M53 | 否<br>未声明可空 | 厂商控制路由参数<br>完整子字段见模型 M53。 |
| providerOptions | 字典 {键: object} | 否<br>未声明可空 | 厂商扩展参数，按设备接入方约定透传 |
| messageId | string | 否<br>未声明可空 | 旧版幂等键，建议改用 idempotencyKey；平台返回的 messageId 始终由服务端生成<br>示例："msg-001"<br>接口定义标记为已弃用。 |
| idempotencyKey | string | 否<br>未声明可空 | 调用方幂等键；相同应用下，相同键和相同请求返回首次结果，不会重复下发<br>示例："order-20260712-001" |

#### 请求示例

```http
POST {API_ROOT}/devices/executeCmd HTTP/1.1
X-App-Id: {APP_ID}
salt: {本次新随机串}
timestamp: {当前毫秒时间戳}
sign: {本次计算的签名}
Content-Type: application/json

{
  "deviceSn": "SN001",
  "cmds": [
    {
      "cmd": "stir_1_set",
      "param": "30"
    }
  ],
  "idempotencyKey": "customer-order-001"
}
```

示例中的 SN、点位编码、命令值、ID 和地址需替换为已授权数据；签名占位符不能原样发送。

#### 响应字段

成功响应使用公共响应结构。以下说明 data；code、message、requestId、traceId、details、resultCode 见公共响应章节。

| 字段 | 类型 | 含义 |
| --- | --- | --- |
| data | 对象 M10 | 设备控制执行记录<br>完整子字段见模型 M10。 |

data 对象字段：

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| messageId | string | 本次控制请求的消息 ID<br>示例："msg-001" |
| idempotencyKey | string | 调用方幂等键 |
| providerRequestId | string | 供应商侧请求或任务 ID |
| appId | 字符串 int64 | 发起调用的应用 ID<br>示例：1001 |
| appCode | string | 发起调用的应用编码<br>示例："weather" |
| deviceSn | string | 被控制设备的序列号<br>示例："1001" |
| cmdParam | 对象 M07 | 设备控制命令明细<br>完整子字段见模型 M07。 |
| status | string | 控制执行状态<br>允许值：["CREATED", "VALIDATED", "DISPATCHED", "ACCEPTED", "EXECUTING", "SUCCEEDED", "FAILED", "TIMEOUT", "UNKNOWN", "REQUEST_ENTERED", "PARSE_SUCCESS", "CONTROL_DEVICE", "COMMAND_SENT", "DEVICE_EXECUTE_SUCCESS", "CONTROL_SUCCESS", "CONTROL_FAILED"] |
| dispatchStatus | string | 命令下发状态<br>允许值：["PENDING", "DISPATCHED", "ACCEPTED", "FAILED"] |
| executionStatus | string | 设备执行确认状态；UNKNOWN 表示接入方无法提供设备级确认<br>允许值：["UNKNOWN", "EXECUTING", "SUCCEEDED", "FAILED", "TIMEOUT"] |
| ackMode | string | 设备执行回执模式：NONE、PROVIDER、DEVICE、STATE_CONFIRMED |
| timeoutSeconds | 字符串 int64 | 本次控制采用的执行确认超时秒数；不期待回执时为空 |
| timeoutPolicySource | string | 超时策略来源：DEVICE_TYPE_COMMAND、PROVIDER、SYSTEM_DEFAULT |
| lateReceiptStatus | string | 终态之后收到的迟到回执状态 |
| statusDesc | string | 执行状态说明 |
| errorCode | string | 控制失败时返回的错误码<br>示例："DEVICE_NOT_FOUND" |
| errorMessage | string | 控制失败时返回的错误信息<br>示例："未找到对应设备" |

#### 成功响应示例

以下为说明字段结构的示意数据，省略了部分可选字段，不是本次接口实测结果。完整字段以字段表和模型定义为准。

```json
{
  "code": "200",
  "message": "OK",
  "requestId": "request-example-001",
  "data": {
    "messageId": "cmd-server-example-001",
    "idempotencyKey": "customer-order-001",
    "deviceSn": "SN001",
    "status": "ACCEPTED",
    "dispatchStatus": "ACCEPTED",
    "executionStatus": "UNKNOWN",
    "ackMode": "NONE",
    "statusDesc": "provider accepted"
  }
}
```

#### 业务约束和排查

- cmds 至少一项，每项 cmd 非空；仅提供 commandCode 不能替代必填 cmds。

- 优先使用 idempotencyKey。旧请求 messageId 作为兼容幂等键，不是服务端返回的控制消息 ID。

- 同一 App、相同幂等键与相同请求复用首次结果；相同键对应不同请求返回 1014。

- 平台返回的 messageId 用于后续状态查询；HTTP 成功及 code=200 不代表设备已实际执行。

- routingOptions 或原始协议扩展属于高级控制，存在扩展路由参数时还可能要求 openapi:iot:device:control.raw 权限；普通接入使用标准命令。

排查时可参考公共错误码：1000、1003、1004、1005、1006、1007、1014、1013。这不是该接口所有业务分支的穷举；应结合 message 和 requestId。

### 接口 12 批量下发设备控制指令

请求方式：POST    接口路径：/openapi/v1/devices/executeCmd/batch

作用：一次提交多台设备或多组控制请求，逐条生成控制轨迹，调用方可根据返回的 messageId 继续查询执行状态。

调用权限：openapi:iot:device:control.execute。权限匹配方式：ALL。

操作性质：实际修改或控制，调用后会生效。

#### 请求参数

请求体：application/json，必填。批量设备控制请求，requestList 至少包含一条控制请求。

| 字段 | 类型 | 必填与可空 | 说明 约束和示例 |
| --- | --- | --- | --- |
| requestList | 数组 [对象 M08] | 是<br>不可为 null | 批量控制请求列表 |

#### 请求示例

```http
POST {API_ROOT}/devices/executeCmd/batch HTTP/1.1
X-App-Id: {APP_ID}
salt: {本次新随机串}
timestamp: {当前毫秒时间戳}
sign: {本次计算的签名}
Content-Type: application/json

{
  "requestList": [
    {
      "deviceSn": "SN001",
      "cmds": [
        {
          "cmd": "stir_1_set",
          "param": "30"
        }
      ],
      "idempotencyKey": "customer-order-001"
    },
    {
      "deviceSn": "SN002",
      "cmds": [
        {
          "cmd": "stir_1_set",
          "param": "30"
        }
      ],
      "idempotencyKey": "customer-order-002"
    }
  ]
}
```

示例中的 SN、点位编码、命令值、ID 和地址需替换为已授权数据；签名占位符不能原样发送。

#### 响应字段

成功响应使用公共响应结构。以下说明 data；code、message、requestId、traceId、details、resultCode 见公共响应章节。

| 字段 | 类型 | 含义 |
| --- | --- | --- |
| data | 数组 [对象 M10] | 业务数据；具体结构随接口变化，空值字段可能不输出 |

data 数组元素字段：

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| messageId | string | 本次控制请求的消息 ID<br>示例："msg-001" |
| idempotencyKey | string | 调用方幂等键 |
| providerRequestId | string | 供应商侧请求或任务 ID |
| appId | 字符串 int64 | 发起调用的应用 ID<br>示例：1001 |
| appCode | string | 发起调用的应用编码<br>示例："weather" |
| deviceSn | string | 被控制设备的序列号<br>示例："1001" |
| cmdParam | 对象 M07 | 设备控制命令明细<br>完整子字段见模型 M07。 |
| status | string | 控制执行状态<br>允许值：["CREATED", "VALIDATED", "DISPATCHED", "ACCEPTED", "EXECUTING", "SUCCEEDED", "FAILED", "TIMEOUT", "UNKNOWN", "REQUEST_ENTERED", "PARSE_SUCCESS", "CONTROL_DEVICE", "COMMAND_SENT", "DEVICE_EXECUTE_SUCCESS", "CONTROL_SUCCESS", "CONTROL_FAILED"] |
| dispatchStatus | string | 命令下发状态<br>允许值：["PENDING", "DISPATCHED", "ACCEPTED", "FAILED"] |
| executionStatus | string | 设备执行确认状态；UNKNOWN 表示接入方无法提供设备级确认<br>允许值：["UNKNOWN", "EXECUTING", "SUCCEEDED", "FAILED", "TIMEOUT"] |
| ackMode | string | 设备执行回执模式：NONE、PROVIDER、DEVICE、STATE_CONFIRMED |
| timeoutSeconds | 字符串 int64 | 本次控制采用的执行确认超时秒数；不期待回执时为空 |
| timeoutPolicySource | string | 超时策略来源：DEVICE_TYPE_COMMAND、PROVIDER、SYSTEM_DEFAULT |
| lateReceiptStatus | string | 终态之后收到的迟到回执状态 |
| statusDesc | string | 执行状态说明 |
| errorCode | string | 控制失败时返回的错误码<br>示例："DEVICE_NOT_FOUND" |
| errorMessage | string | 控制失败时返回的错误信息<br>示例："未找到对应设备" |

#### 成功响应示例

以下为说明字段结构的示意数据，省略了部分可选字段，不是本次接口实测结果。完整字段以字段表和模型定义为准。

```json
{
  "code": "200",
  "message": "OK",
  "requestId": "request-example-001",
  "data": [
    {
      "messageId": "cmd-server-example-001",
      "idempotencyKey": "customer-order-001",
      "deviceSn": "SN001",
      "status": "ACCEPTED",
      "dispatchStatus": "ACCEPTED",
      "executionStatus": "UNKNOWN",
      "ackMode": "NONE",
      "statusDesc": "provider accepted"
    },
    {
      "messageId": "cmd-server-example-002",
      "deviceSn": "SN002",
      "status": "FAILED",
      "dispatchStatus": "FAILED",
      "executionStatus": "UNKNOWN",
      "errorCode": "1006",
      "errorMessage": "device is not writable"
    }
  ]
}
```

#### 业务约束和排查

- requestList 至少一项，每项字段与单台控制接口一致。

- 逐项检查 status、dispatchStatus、executionStatus、errorCode；整体 code=200 不代表每项成功。

- 当前调用按条处理，不保证全有或全无的事务效果；不同设备使用独立幂等键。

排查时可参考公共错误码：1000、1003、1004、1005、1006、1007、1014、1013。这不是该接口所有业务分支的穷举；应结合 message 和 requestId。

### 接口 13 查询设备控制指令执行状态

请求方式：GET    接口路径：/openapi/v1/devices/executeCmd/status/{messageId}

作用：根据控制接口返回的 messageId 查询设备控制指令的最新执行状态。

调用权限：openapi:iot:device:control.status。权限匹配方式：ALL。

操作性质：只读查询。

#### 请求参数

| 参数与位置 | 类型 | 必填 | 说明与示例 |
| --- | --- | --- | --- |
| messageId<br>路径参数 | string | 是 | 控制指令消息 ID<br>示例："cmd-202406010001" |

本接口无 JSON 请求体。公共签名头见认证章节。

#### 请求示例

```http
GET {API_ROOT}/devices/executeCmd/status/cmd-server-example-001 HTTP/1.1
X-App-Id: {APP_ID}
salt: {本次新随机串}
timestamp: {当前毫秒时间戳}
sign: {本次计算的签名}
```

示例中的 SN、点位编码、命令值、ID 和地址需替换为已授权数据；签名占位符不能原样发送。

#### 响应字段

成功响应使用公共响应结构。以下说明 data；code、message、requestId、traceId、details、resultCode 见公共响应章节。

| 字段 | 类型 | 含义 |
| --- | --- | --- |
| data | 对象 M10 | 设备控制执行记录<br>完整子字段见模型 M10。 |

data 对象字段：

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| messageId | string | 本次控制请求的消息 ID<br>示例："msg-001" |
| idempotencyKey | string | 调用方幂等键 |
| providerRequestId | string | 供应商侧请求或任务 ID |
| appId | 字符串 int64 | 发起调用的应用 ID<br>示例：1001 |
| appCode | string | 发起调用的应用编码<br>示例："weather" |
| deviceSn | string | 被控制设备的序列号<br>示例："1001" |
| cmdParam | 对象 M07 | 设备控制命令明细<br>完整子字段见模型 M07。 |
| status | string | 控制执行状态<br>允许值：["CREATED", "VALIDATED", "DISPATCHED", "ACCEPTED", "EXECUTING", "SUCCEEDED", "FAILED", "TIMEOUT", "UNKNOWN", "REQUEST_ENTERED", "PARSE_SUCCESS", "CONTROL_DEVICE", "COMMAND_SENT", "DEVICE_EXECUTE_SUCCESS", "CONTROL_SUCCESS", "CONTROL_FAILED"] |
| dispatchStatus | string | 命令下发状态<br>允许值：["PENDING", "DISPATCHED", "ACCEPTED", "FAILED"] |
| executionStatus | string | 设备执行确认状态；UNKNOWN 表示接入方无法提供设备级确认<br>允许值：["UNKNOWN", "EXECUTING", "SUCCEEDED", "FAILED", "TIMEOUT"] |
| ackMode | string | 设备执行回执模式：NONE、PROVIDER、DEVICE、STATE_CONFIRMED |
| timeoutSeconds | 字符串 int64 | 本次控制采用的执行确认超时秒数；不期待回执时为空 |
| timeoutPolicySource | string | 超时策略来源：DEVICE_TYPE_COMMAND、PROVIDER、SYSTEM_DEFAULT |
| lateReceiptStatus | string | 终态之后收到的迟到回执状态 |
| statusDesc | string | 执行状态说明 |
| errorCode | string | 控制失败时返回的错误码<br>示例："DEVICE_NOT_FOUND" |
| errorMessage | string | 控制失败时返回的错误信息<br>示例："未找到对应设备" |

#### 成功响应示例

以下为说明字段结构的示意数据，省略了部分可选字段，不是本次接口实测结果。完整字段以字段表和模型定义为准。

```json
{
  "code": "200",
  "message": "OK",
  "requestId": "request-example-001",
  "data": {
    "messageId": "cmd-server-example-001",
    "idempotencyKey": "customer-order-001",
    "deviceSn": "SN001",
    "status": "ACCEPTED",
    "dispatchStatus": "ACCEPTED",
    "executionStatus": "UNKNOWN",
    "ackMode": "NONE",
    "statusDesc": "provider accepted"
  }
}
```

#### 业务约束和排查

- 使用服务端返回的 messageId；不能使用客户端 idempotencyKey 替代。

- 只允许查询当前 App 的记录，同时校验设备读取范围。

- executionStatus=UNKNOWN 表示无法确认设备实际执行，不等同于执行成功。

排查时可参考公共错误码：1000、1003、1004、1005、1006、1007、1009。这不是该接口所有业务分支的穷举；应结合 message 和 requestId。

### 接口 14 分页查询设备控制操作日志

请求方式：POST    接口路径：/openapi/v1/devices/executeCmd/logs/page

作用：按设备 SN 和分页参数查询当前应用的设备控制操作日志；当前请求不提供时间或状态筛选字段。

调用权限：openapi:iot:device:control.log.page。权限匹配方式：ALL。

操作性质：只读查询。

#### 请求参数

请求体：application/json，必填。控制日志分页查询条件；deviceSn 必填。

| 字段 | 类型 | 必填与可空 | 说明 约束和示例 |
| --- | --- | --- | --- |
| deviceSn | string | 是<br>不可为 null | 设备序列号<br>示例："1001" |
| pageIndex | int64 | 否<br>未声明可空 | 页码，从 1 开始<br>默认值：1<br>示例：1 |
| pageSize | int64 | 否<br>未声明可空 | 每页条数，最大 50<br>默认值：20<br>最大值：50<br>示例：20 |

#### 请求示例

```http
POST {API_ROOT}/devices/executeCmd/logs/page HTTP/1.1
X-App-Id: {APP_ID}
salt: {本次新随机串}
timestamp: {当前毫秒时间戳}
sign: {本次计算的签名}
Content-Type: application/json

{
  "deviceSn": "SN001",
  "pageIndex": 1,
  "pageSize": 20
}
```

示例中的 SN、点位编码、命令值、ID 和地址需替换为已授权数据；签名占位符不能原样发送。

#### 响应字段

成功响应使用公共响应结构。以下说明 data；code、message、requestId、traceId、details、resultCode 见公共响应章节。

| 字段 | 类型 | 含义 |
| --- | --- | --- |
| data | 对象 M51 | 业务数据；具体结构随接口变化，空值字段可能不输出<br>完整子字段见模型 M51。 |

data 对象字段：

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| size | 字符串 int64 | 每页条数 |
| total | 字符串 int64 | 总记录数 |
| records | 数组 [对象 M10] | 本页记录列表 |
| current | 字符串 int64 | 当前页码 |
| pages | 字符串 int64 | 总页数<br>接口定义标记为已弃用。 |

#### 成功响应示例

以下为说明字段结构的示意数据，省略了部分可选字段，不是本次接口实测结果。完整字段以字段表和模型定义为准。

```json
{
  "code": "200",
  "message": "OK",
  "requestId": "request-example-001",
  "data": {
    "current": "1",
    "size": "20",
    "total": "1",
    "pages": "1",
    "records": [
      {
        "messageId": "cmd-server-example-001",
        "idempotencyKey": "customer-order-001",
        "deviceSn": "SN001",
        "status": "ACCEPTED",
        "dispatchStatus": "ACCEPTED",
        "executionStatus": "UNKNOWN",
        "ackMode": "NONE",
        "statusDesc": "provider accepted"
      }
    ]
  }
}
```

#### 业务约束和排查

- 只读查询当前 App、指定设备的控制轨迹，不触发控制。

- 当前请求 DTO 仅支持 deviceSn、pageIndex、pageSize，不提供时间或状态过滤参数。

- pageIndex 默认 1；pageSize 默认 20，上限 50。records 中的状态含义与状态查询一致。

排查时可参考公共错误码：1000、1003、1004、1005、1006、1007、1014、1013。这不是该接口所有业务分支的穷举；应结合 message 和 requestId。

## 七 告警配置接口

维护当前 App 的设备告警规则。

### 接口 15 创建设备告警配置

请求方式：POST    接口路径：/openapi/v1/alerts/createAlertConfig

作用：为指定设备和点位创建告警规则。设备必须在当前应用授权范围内，且应用需具备告警控制权限。

调用权限：openapi:iot:device:control.alert。权限匹配方式：ALL。

操作性质：实际修改或控制，调用后会生效。

#### 请求参数

请求体：application/json，必填。告警配置创建请求。deviceSn、type、title、compareType、value 必填；positionId 和 positionCode 至少传一个。

| 字段 | 类型 | 必填与可空 | 说明 约束和示例 |
| --- | --- | --- | --- |
| deviceSn | string | 是<br>不可为 null | 需要配置预警的设备序列号<br>示例："SN0001" |
| positionId | int64 | 条件必填<br>未声明可空 | 预警监测点位 ID，优先按该字段定位设备点位<br>示例：1<br>positionId 与 positionCode 至少提供一项。 |
| positionCode | string | 条件必填<br>未声明可空 | 预警监测点位编码，未传点位 ID 时可使用该字段定位<br>示例："temperature"<br>positionId 与 positionCode 至少提供一项。 |
| type | string | 是<br>不可为 null | 告警规则类型。YJ 表示预警，适用于较轻或提前提醒类风险；BJ 表示报警，适用于较严重或需要立即处置的异常。<br>允许值：["YJ", "BJ"]<br>示例："YJ" |
| title | string | 是<br>不可为 null | 预警标题，触发后用于展示或通知<br>示例："温度过高预警" |
| compareType | string | 是<br>不可为 null | 阈值比较方式，支持 >、<、=、!=、>=、<=<br>示例：">=" |
| value | number | 是<br>不可为 null | 触发预警的阈值<br>示例：30 |
| alertContent | string | 否<br>未声明可空 | 预警内容，触发后返回或通知给客户的文案<br>示例："当前温度超过阈值，请及时处理" |
| alertIntervalTime | int32 | 否<br>未声明可空 | 同一规则重复通知的最小间隔，单位：秒<br>示例：60 |
| remark | string | 否<br>未声明可空 | 备注，便于标记规则用途<br>示例："温室大棚温度预警" |

#### 请求示例

```http
POST {API_ROOT}/alerts/createAlertConfig HTTP/1.1
X-App-Id: {APP_ID}
salt: {本次新随机串}
timestamp: {当前毫秒时间戳}
sign: {本次计算的签名}
Content-Type: application/json

{
  "deviceSn": "SN001",
  "positionCode": "temperature",
  "type": "YJ",
  "title": "温度过高预警",
  "compareType": ">=",
  "value": 30,
  "alertIntervalTime": 60
}
```

示例中的 SN、点位编码、命令值、ID 和地址需替换为已授权数据；签名占位符不能原样发送。

#### 响应字段

成功响应使用公共响应结构。以下说明 data；code、message、requestId、traceId、details、resultCode 见公共响应章节。

| 字段 | 类型 | 含义 |
| --- | --- | --- |
| data | 字符串 int64 | 新创建的告警配置 ID；保存后用于更新和删除。 |

#### 成功响应示例

以下为说明字段结构的示意数据，省略了部分可选字段，不是本次接口实测结果。完整字段以字段表和模型定义为准。

```json
{
  "code": "200",
  "message": "OK",
  "requestId": "request-example-001",
  "data": "1001"
}
```

#### 业务约束和排查

- deviceSn、type、title、compareType、value 必填；positionId 与 positionCode 至少填一项。

- type 允许 YJ 预警、BJ 报警；compareType 允许 >、<、=、!=、>=、<=。

- 同一 App、设备、点位及告警类型不能重复创建。

- title 最长 200 字符，type 最长 32，compareType 最长 16，alertContent 和 remark 最长 500。

- alertIntervalTime 缺省或小于 1 时按 60 秒处理；成功后保存返回的配置 ID，供更新和删除使用。

排查时可参考公共错误码：1000、1003、1004、1005、1006、1011、1012。这不是该接口所有业务分支的穷举；应结合 message 和 requestId。

### 接口 16 更新设备告警配置

请求方式：POST    接口路径：/openapi/v1/alerts/updateAlertConfig

作用：根据告警配置 ID 更新告警规则。设备必须在当前应用授权范围内，且应用需具备告警控制权限。

调用权限：openapi:iot:device:control.alert。权限匹配方式：ALL。

操作性质：实际修改或控制，调用后会生效。

#### 请求参数

请求体：application/json，必填。告警配置更新请求。id 必填；deviceSn、type、title、compareType、value 必填；positionId 和 positionCode 至少传一个。

| 字段 | 类型 | 必填与可空 | 说明 约束和示例 |
| --- | --- | --- | --- |
| id | int64 | 是<br>不可为 null | 预警规则 ID<br>示例：1 |
| deviceSn | string | 是<br>不可为 null | 需要配置预警的设备序列号<br>示例："SN0001" |
| positionId | int64 | 条件必填<br>未声明可空 | 预警监测点位 ID，优先按该字段定位设备点位<br>示例：1<br>positionId 与 positionCode 至少提供一项。 |
| positionCode | string | 条件必填<br>未声明可空 | 预警监测点位编码，未传点位 ID 时可使用该字段定位<br>示例："temperature"<br>positionId 与 positionCode 至少提供一项。 |
| type | string | 是<br>不可为 null | 告警规则类型。YJ 表示预警，适用于较轻或提前提醒类风险；BJ 表示报警，适用于较严重或需要立即处置的异常。<br>允许值：["YJ", "BJ"]<br>示例："YJ" |
| title | string | 是<br>不可为 null | 预警标题，触发后用于展示或通知<br>示例："温度过高预警" |
| compareType | string | 是<br>不可为 null | 阈值比较方式，支持 >、<、=、!=、>=、<=<br>示例：">=" |
| value | number | 是<br>不可为 null | 触发预警的阈值<br>示例：30 |
| alertContent | string | 否<br>未声明可空 | 预警内容，触发后返回或通知给客户的文案<br>示例："当前温度超过阈值，请及时处理" |
| alertIntervalTime | int32 | 否<br>未声明可空 | 同一规则重复通知的最小间隔，单位：秒<br>示例：60 |
| remark | string | 否<br>未声明可空 | 备注，便于标记规则用途<br>示例："温室大棚温度预警" |

#### 请求示例

```http
POST {API_ROOT}/alerts/updateAlertConfig HTTP/1.1
X-App-Id: {APP_ID}
salt: {本次新随机串}
timestamp: {当前毫秒时间戳}
sign: {本次计算的签名}
Content-Type: application/json

{
  "id": 1001,
  "deviceSn": "SN001",
  "positionCode": "temperature",
  "type": "YJ",
  "title": "温度过高预警",
  "compareType": ">=",
  "value": 32,
  "alertIntervalTime": 60
}
```

示例中的 SN、点位编码、命令值、ID 和地址需替换为已授权数据；签名占位符不能原样发送。

#### 响应字段

成功响应使用公共响应结构。以下说明 data；code、message、requestId、traceId、details、resultCode 见公共响应章节。

| 字段 | 类型 | 含义 |
| --- | --- | --- |
| data | 字符串 int64 | 已更新的告警配置 ID。 |

#### 成功响应示例

以下为说明字段结构的示意数据，省略了部分可选字段，不是本次接口实测结果。完整字段以字段表和模型定义为准。

```json
{
  "code": "200",
  "message": "OK",
  "requestId": "request-example-001",
  "data": "1001"
}
```

#### 业务约束和排查

- id 必填，且配置须属于当前 App；设备须有 WRITE 授权。

- 这是重新填写规则参数的更新，不是仅传 id 与单个变化字段的局部修改。

- 创建接口的类型、比较符、长度与点位组合约束同样适用。

- 更新会重置规则的触发记忆状态，后续基于新的规则重新判断。

排查时可参考公共错误码：1000、1003、1004、1005、1006、1011、1012。这不是该接口所有业务分支的穷举；应结合 message 和 requestId。

### 接口 17 删除设备告警配置

请求方式：POST    接口路径：/openapi/v1/alerts/deleteAlertConfig

作用：根据告警配置ID删除告警规则。

调用权限：openapi:iot:device:control.alert。权限匹配方式：ALL。

操作性质：实际修改或控制，调用后会生效。

#### 请求参数

| 参数与位置 | 类型 | 必填 | 说明与示例 |
| --- | --- | --- | --- |
| id<br>查询参数 | int64 | 是 | 告警配置 ID<br>示例：1001 |

本接口无 JSON 请求体。公共签名头见认证章节。

#### 请求示例

```http
POST {API_ROOT}/alerts/deleteAlertConfig?id=1001 HTTP/1.1
X-App-Id: {APP_ID}
salt: {本次新随机串}
timestamp: {当前毫秒时间戳}
sign: {本次计算的签名}
```

示例中的 SN、点位编码、命令值、ID 和地址需替换为已授权数据；签名占位符不能原样发送。

#### 响应字段

成功响应使用公共响应结构。以下说明 data；code、message、requestId、traceId、details、resultCode 见公共响应章节。

| 字段 | 类型 | 含义 |
| --- | --- | --- |
| data | boolean | 布尔删除结果；true 表示本次删除成功。 |

#### 成功响应示例

以下为说明字段结构的示意数据，省略了部分可选字段，不是本次接口实测结果。完整字段以字段表和模型定义为准。

```json
{
  "code": "200",
  "message": "OK",
  "requestId": "request-example-001",
  "data": true
}
```

#### 业务约束和排查

- id 为 URL 查询参数，本接口没有 JSON 请求体。

- 仅能删除当前 App 的配置，并要求对应设备 WRITE 授权。

- data 为布尔值，表示本次删除是否成功；不要将 HTTP 200 单独作为删除成功依据。

排查时可参考公共错误码：1000、1003、1004、1005、1006、1011、1012。这不是该接口所有业务分支的穷举；应结合 message 和 requestId。

## 八 回调配置接口

读取及整体更新当前 App 的回调地址。

### 接口 18 查询当前应用的回调配置

请求方式：GET    接口路径：/openapi/v1/callback-config

作用：查看当前签名应用的回调地址和告警通知渠道，不修改配置。

调用权限：openapi:iot:callback.config。权限匹配方式：ALL。

操作性质：只读查询。

#### 请求参数

无业务参数、无请求体；仍需携带公共签名请求头。

#### 请求示例

```http
GET {API_ROOT}/callback-config HTTP/1.1
X-App-Id: {APP_ID}
salt: {本次新随机串}
timestamp: {当前毫秒时间戳}
sign: {本次计算的签名}
```

示例中的 SN、点位编码、命令值、ID 和地址需替换为已授权数据；签名占位符不能原样发送。

#### 响应字段

成功响应使用公共响应结构。以下说明 data；code、message、requestId、traceId、details、resultCode 见公共响应章节。

| 字段 | 类型 | 含义 |
| --- | --- | --- |
| data | 对象 M03 | 当前应用的回调配置；未配置的地址可能不输出<br>完整子字段见模型 M03。 |

data 对象字段：

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| appId | 字符串 int64 | 当前应用 ID，客户端按字符串处理，避免大整数精度损失<br>示例：1001 |
| appCode | string | 当前应用编码<br>示例："customer-iot-app" |
| deviceStatusCallbackUrl | string | 设备上下线回调地址 |
| deviceDataCallbackUrl | string | 设备数据回调地址 |
| alertCallbackUrl | string | 设备告警回调地址 |
| alertNotifyChannels | string | 告警通知渠道，逗号分隔的 CALLBACK、SMS、EMAIL |

#### 成功响应示例

以下为说明字段结构的示意数据，省略了部分可选字段，不是本次接口实测结果。完整字段以字段表和模型定义为准。

```json
{
  "code": "200",
  "message": "OK",
  "requestId": "request-example-001",
  "data": {
    "appId": "1001",
    "appCode": "customer-app",
    "deviceDataCallbackUrl": "https://customer.example.com/iot/data",
    "alertNotifyChannels": "CALLBACK"
  }
}
```

#### 业务约束和排查

- 返回当前签名 App 的配置，不接受通过参数指定另一个 App。

- 未配置地址可能直接省略，不保证返回空字符串。

排查时可参考公共错误码：1000、1003、1004、1005、1006。这不是该接口所有业务分支的穷举；应结合 message 和 requestId。

### 接口 19 修改当前应用的回调配置

请求方式：PUT    接口路径：/openapi/v1/callback-config

作用：整体更新当前应用的四项回调配置，省略、null 或空白字段会清空对应配置。修改会影响后续回调投递；地址必须为有效 http(s) URL。

调用权限：openapi:iot:callback.config。权限匹配方式：ALL。

操作性质：实际修改或控制，调用后会生效。

#### 请求参数

请求体：application/json，必填。整体更新回调配置，省略字段会被清空。

| 字段 | 类型 | 必填与可空 | 说明 约束和示例 |
| --- | --- | --- | --- |
| deviceStatusCallbackUrl | string | 否<br>未声明可空 | 设备上下线回调 http(s) 地址；省略、null 或空白表示关闭。<br>示例："https://example.com/iot/device/status" |
| deviceDataCallbackUrl | string | 否<br>未声明可空 | 设备数据回调 http(s) 地址；省略、null 或空白表示关闭。<br>示例："https://example.com/iot/device/data" |
| alertCallbackUrl | string | 否<br>未声明可空 | 设备告警回调 http(s) 地址；省略、null 或空白表示关闭。<br>示例："https://example.com/iot/device/alert" |
| alertNotifyChannels | string | 否<br>未声明可空 | 告警通知渠道，CALLBACK、SMS、EMAIL，以逗号分隔；省略、null 或空白会清空。<br>示例："CALLBACK" |

#### 请求示例

```http
PUT {API_ROOT}/callback-config HTTP/1.1
X-App-Id: {APP_ID}
salt: {本次新随机串}
timestamp: {当前毫秒时间戳}
sign: {本次计算的签名}
Content-Type: application/json

{
  "deviceStatusCallbackUrl": "https://customer.example.com/iot/status",
  "deviceDataCallbackUrl": "https://customer.example.com/iot/data",
  "alertCallbackUrl": "https://customer.example.com/iot/alert",
  "alertNotifyChannels": "CALLBACK"
}
```

示例中的 SN、点位编码、命令值、ID 和地址需替换为已授权数据；签名占位符不能原样发送。

#### 响应字段

成功响应使用公共响应结构。以下说明 data；code、message、requestId、traceId、details、resultCode 见公共响应章节。

| 字段 | 类型 | 含义 |
| --- | --- | --- |
| data | 对象 M03 | 当前应用的回调配置；未配置的地址可能不输出<br>完整子字段见模型 M03。 |

data 对象字段：

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| appId | 字符串 int64 | 当前应用 ID，客户端按字符串处理，避免大整数精度损失<br>示例：1001 |
| appCode | string | 当前应用编码<br>示例："customer-iot-app" |
| deviceStatusCallbackUrl | string | 设备上下线回调地址 |
| deviceDataCallbackUrl | string | 设备数据回调地址 |
| alertCallbackUrl | string | 设备告警回调地址 |
| alertNotifyChannels | string | 告警通知渠道，逗号分隔的 CALLBACK、SMS、EMAIL |

#### 成功响应示例

以下为说明字段结构的示意数据，省略了部分可选字段，不是本次接口实测结果。完整字段以字段表和模型定义为准。

```json
{
  "code": "200",
  "message": "OK",
  "requestId": "request-example-001",
  "data": {
    "appId": "1001",
    "appCode": "customer-app",
    "deviceStatusCallbackUrl": "https://customer.example.com/iot/status",
    "deviceDataCallbackUrl": "https://customer.example.com/iot/data",
    "alertCallbackUrl": "https://customer.example.com/iot/alert",
    "alertNotifyChannels": "CALLBACK"
  }
}
```

#### 业务约束和排查

- 四项配置整体替换。任何省略、null 或空白字段都会被清空，不是部分更新。

- 修改前先 GET 读取原配置，将要保留的值与要修改的值一起提交。

- 回调地址必须为有效 http(s) URL；空白表示关闭对应回调。

- alertNotifyChannels 允许 CALLBACK、SMS、EMAIL；建议使用逗号分隔。保存配置不会立即发送设备数据回调。

排查时可参考公共错误码：1000、1003、1004、1005、1006。这不是该接口所有业务分支的穷举；应结合 message 和 requestId。

## 九 公共数据模型和模板详情

字段表列出本版公开模型的全部字段。对象、数组元素和字典值通过模型编号关联；接口响应表引用相同编号。响应字段未声明必返时，不保证始终输出；空值默认省略。请求对象的必填约束以相应接口表为准。

### 模板详情的选择规则

| templateType | detail 对应模型 | 解释 |
| --- | --- | --- |
| VFD_CABINET | M36 | 变频柜。版本 2 及以上使用 points 字典；旧版本提供命名测量点。 |
| WATER_FERTILIZER_MACHINE | M37 | 水肥机，包含消耗统计、全局读数、施肥通道、泵和电磁阀。 |
| PZG_GREENHOUSE | M29 | 温室控制器，包含卷帘、风口、开关、传感器等厂商原生结构。 |

tempModel 的调用约定为 1 手动、0 自动，modeCode 分别为 MANUAL、AUTO。detail 子字段随模板类型、版本、槽位与设备协议变化；没有采集值的点位可能省略，单位和控制范围以实际点位返回为准。

### 模型 M01 告警配置创建请求

模型标识：CAlertConfigCreateReqDto

| 字段 | 类型 | 必填与可空 | 说明 约束和示例 |
| --- | --- | --- | --- |
| deviceSn | string | 是<br>不可为 null | 需要配置预警的设备序列号<br>示例："SN0001" |
| positionId | int64 | 条件必填<br>未声明可空 | 预警监测点位 ID，优先按该字段定位设备点位<br>示例：1<br>positionId 与 positionCode 至少提供一项。 |
| positionCode | string | 条件必填<br>未声明可空 | 预警监测点位编码，未传点位 ID 时可使用该字段定位<br>示例："temperature"<br>positionId 与 positionCode 至少提供一项。 |
| type | string | 是<br>不可为 null | 告警规则类型。YJ 表示预警，适用于较轻或提前提醒类风险；BJ 表示报警，适用于较严重或需要立即处置的异常。<br>允许值：["YJ", "BJ"]<br>示例："YJ" |
| title | string | 是<br>不可为 null | 预警标题，触发后用于展示或通知<br>示例："温度过高预警" |
| compareType | string | 是<br>不可为 null | 阈值比较方式，支持 >、<、=、!=、>=、<=<br>示例：">=" |
| value | number | 是<br>不可为 null | 触发预警的阈值<br>示例：30 |
| alertContent | string | 否<br>未声明可空 | 预警内容，触发后返回或通知给客户的文案<br>示例："当前温度超过阈值，请及时处理" |
| alertIntervalTime | int32 | 否<br>未声明可空 | 同一规则重复通知的最小间隔，单位：秒<br>示例：60 |
| remark | string | 否<br>未声明可空 | 备注，便于标记规则用途<br>示例："温室大棚温度预警" |

### 模型 M02 告警配置更新请求

模型标识：CAlertConfigUpdateReqDto

| 字段 | 类型 | 必填与可空 | 说明 约束和示例 |
| --- | --- | --- | --- |
| id | int64 | 是<br>不可为 null | 预警规则 ID<br>示例：1 |
| deviceSn | string | 是<br>不可为 null | 需要配置预警的设备序列号<br>示例："SN0001" |
| positionId | int64 | 条件必填<br>未声明可空 | 预警监测点位 ID，优先按该字段定位设备点位<br>示例：1<br>positionId 与 positionCode 至少提供一项。 |
| positionCode | string | 条件必填<br>未声明可空 | 预警监测点位编码，未传点位 ID 时可使用该字段定位<br>示例："temperature"<br>positionId 与 positionCode 至少提供一项。 |
| type | string | 是<br>不可为 null | 告警规则类型。YJ 表示预警，适用于较轻或提前提醒类风险；BJ 表示报警，适用于较严重或需要立即处置的异常。<br>允许值：["YJ", "BJ"]<br>示例："YJ" |
| title | string | 是<br>不可为 null | 预警标题，触发后用于展示或通知<br>示例："温度过高预警" |
| compareType | string | 是<br>不可为 null | 阈值比较方式，支持 >、<、=、!=、>=、<=<br>示例：">=" |
| value | number | 是<br>不可为 null | 触发预警的阈值<br>示例：30 |
| alertContent | string | 否<br>未声明可空 | 预警内容，触发后返回或通知给客户的文案<br>示例："当前温度超过阈值，请及时处理" |
| alertIntervalTime | int32 | 否<br>未声明可空 | 同一规则重复通知的最小间隔，单位：秒<br>示例：60 |
| remark | string | 否<br>未声明可空 | 备注，便于标记规则用途<br>示例："温室大棚温度预警" |

### 模型 M03 当前应用回调配置

模型标识：CCallbackConfigResDto

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| appId | 字符串 int64 | 当前应用 ID，客户端按字符串处理，避免大整数精度损失<br>示例：1001 |
| appCode | string | 当前应用编码<br>示例："customer-iot-app" |
| deviceStatusCallbackUrl | string | 设备上下线回调地址 |
| deviceDataCallbackUrl | string | 设备数据回调地址 |
| alertCallbackUrl | string | 设备告警回调地址 |
| alertNotifyChannels | string | 告警通知渠道，逗号分隔的 CALLBACK、SMS、EMAIL |

### 模型 M04 回调配置整体更新请求

模型标识：CCallbackConfigUpdateReqDto

| 字段 | 类型 | 必填与可空 | 说明 约束和示例 |
| --- | --- | --- | --- |
| deviceStatusCallbackUrl | string | 否<br>未声明可空 | 设备上下线回调 http(s) 地址；省略、null 或空白表示关闭。<br>示例："https://example.com/iot/device/status" |
| deviceDataCallbackUrl | string | 否<br>未声明可空 | 设备数据回调 http(s) 地址；省略、null 或空白表示关闭。<br>示例："https://example.com/iot/device/data" |
| alertCallbackUrl | string | 否<br>未声明可空 | 设备告警回调 http(s) 地址；省略、null 或空白表示关闭。<br>示例："https://example.com/iot/device/alert" |
| alertNotifyChannels | string | 否<br>未声明可空 | 告警通知渠道，CALLBACK、SMS、EMAIL，以逗号分隔；省略、null 或空白会清空。<br>示例："CALLBACK" |

### 模型 M05 批量控制请求

模型标识：CDeviceControlBatchReqDto

| 字段 | 类型 | 必填与可空 | 说明 约束和示例 |
| --- | --- | --- | --- |
| requestList | 数组 [对象 M08] | 是<br>不可为 null | 批量控制请求列表 |

### 模型 M06 设备可控命令

模型标识：CDeviceControlCapabilityResDto

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| commandCode | string | 控制命令编码，调用 executeCmd 时作为 cmds[].cmd 传入<br>示例："stir_1_set" |
| commandName | string | 命令名称<br>示例："A搅拌时间设置" |
| currentValue | object | 当前值 可为字符串、数字、布尔值或对象，客户端按实际 JSON 值解析。 |
| unit | string | 单位<br>示例："s" |
| valueType | string | 值类型<br>示例："INT" |
| variableReadWriteType | string | 读写类型<br>示例："READ_WRITE" |
| remoteWritable | boolean | 是否允许远程写入 |
| defaultValue | string | 默认值 |
| valueConvertType | string | 值转换类型<br>示例："ENUM" |
| valueConvertRule | string | 值转换规则 |
| collectTime | string date-time | 最近采集时间 |

### 模型 M07 设备控制命令明细

模型标识：CDeviceControlCmdParamResDto

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| cmd | string | 命令编码<br>示例："switch" |
| param | string | 命令值<br>示例："1" |

### 模型 M08 单台设备控制请求

模型标识：CDeviceControlReqDto

| 字段 | 类型 | 必填与可空 | 说明 约束和示例 |
| --- | --- | --- | --- |
| deviceSn | string | 是<br>不可为 null | 需要下发控制的设备序列号<br>示例："1001" |
| cmds | 数组 [对象 M50] | 是<br>不可为 null | 兼容旧版调用的命令参数列表 |
| commandCode | string | 否<br>未声明可空 | 标准化命令编码，用于指定本次要执行的控制命令<br>示例："manualValve" |
| commandType | string | 否<br>未声明可空 | 命令类型，用于区分控制命令类别<br>示例："PARAM_SET" |
| routingOptions | 对象 M53 | 否<br>未声明可空 | 厂商控制路由参数<br>完整子字段见模型 M53。 |
| providerOptions | 字典 {键: object} | 否<br>未声明可空 | 厂商扩展参数，按设备接入方约定透传 |
| messageId | string | 否<br>未声明可空 | 旧版幂等键，建议改用 idempotencyKey；平台返回的 messageId 始终由服务端生成<br>示例："msg-001"<br>接口定义标记为已弃用。 |
| idempotencyKey | string | 否<br>未声明可空 | 调用方幂等键；相同应用下，相同键和相同请求返回首次结果，不会重复下发<br>示例："order-20260712-001" |

### 模型 M09 控制日志分页请求

模型标识：CDeviceControlTracePageReqDto

| 字段 | 类型 | 必填与可空 | 说明 约束和示例 |
| --- | --- | --- | --- |
| deviceSn | string | 是<br>不可为 null | 设备序列号<br>示例："1001" |
| pageIndex | int64 | 否<br>未声明可空 | 页码，从 1 开始<br>默认值：1<br>示例：1 |
| pageSize | int64 | 否<br>未声明可空 | 每页条数，最大 50<br>默认值：20<br>最大值：50<br>示例：20 |

### 模型 M10 控制执行轨迹

模型标识：CDeviceControlTraceResDto

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| messageId | string | 本次控制请求的消息 ID<br>示例："msg-001" |
| idempotencyKey | string | 调用方幂等键 |
| providerRequestId | string | 供应商侧请求或任务 ID |
| appId | 字符串 int64 | 发起调用的应用 ID<br>示例：1001 |
| appCode | string | 发起调用的应用编码<br>示例："weather" |
| deviceSn | string | 被控制设备的序列号<br>示例："1001" |
| cmdParam | 对象 M07 | 设备控制命令明细<br>完整子字段见模型 M07。 |
| status | string | 控制执行状态<br>允许值：["CREATED", "VALIDATED", "DISPATCHED", "ACCEPTED", "EXECUTING", "SUCCEEDED", "FAILED", "TIMEOUT", "UNKNOWN", "REQUEST_ENTERED", "PARSE_SUCCESS", "CONTROL_DEVICE", "COMMAND_SENT", "DEVICE_EXECUTE_SUCCESS", "CONTROL_SUCCESS", "CONTROL_FAILED"] |
| dispatchStatus | string | 命令下发状态<br>允许值：["PENDING", "DISPATCHED", "ACCEPTED", "FAILED"] |
| executionStatus | string | 设备执行确认状态；UNKNOWN 表示接入方无法提供设备级确认<br>允许值：["UNKNOWN", "EXECUTING", "SUCCEEDED", "FAILED", "TIMEOUT"] |
| ackMode | string | 设备执行回执模式：NONE、PROVIDER、DEVICE、STATE_CONFIRMED |
| timeoutSeconds | 字符串 int64 | 本次控制采用的执行确认超时秒数；不期待回执时为空 |
| timeoutPolicySource | string | 超时策略来源：DEVICE_TYPE_COMMAND、PROVIDER、SYSTEM_DEFAULT |
| lateReceiptStatus | string | 终态之后收到的迟到回执状态 |
| statusDesc | string | 执行状态说明 |
| errorCode | string | 控制失败时返回的错误码<br>示例："DEVICE_NOT_FOUND" |
| errorMessage | string | 控制失败时返回的错误信息<br>示例："未找到对应设备" |

### 模型 M11 设备详情

模型标识：CDeviceDetailResDto

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| id | 字符串 int64 | 平台内设备 ID<br>示例：1 |
| deviceName | string | 设备名称<br>示例："设备1" |
| deviceSn | string | 设备序列号<br>示例："1001" |
| typeCode | string | 面向客户的设备分类编码；优先使用外部分类，未配置时回退内部类型编码<br>示例："MET" |
| typeName | string | 面向客户的设备分类名称；优先使用外部分类，未配置时回退内部类型名称<br>示例："气象设备" |
| internalTypeCode | string | 平台内部设备类型编码，供系统间对接识别<br>示例："FNKJ_LAMP" |
| providerCode | string | 设备厂商接入编码<br>示例："THIRD_PLATFORM_FNKJ" |
| manufacturerName | string | 厂商名称<br>示例："zwyk" |
| onlineStatus | int32 | 在线状态，1 表示在线，0 表示离线<br>示例：1 |
| enabledStatus | int32 | 启用状态，1 表示启用，0 表示禁用<br>示例：1 |
| lastOnlineTime | string date-time | 最近一次上线时间 |
| lastOfflineTime | string date-time | 最近一次离线时间 |
| queryTime | string date-time | 本次查询时间 |
| variableDetail | 对象 M24 | 设备变量详情<br>完整子字段见模型 M24。 |
| dataMode | string | 设备数据模式：READ_ONLY-只读，READ_WRITE-读写<br>示例："READ_ONLY" |

### 模型 M12 设备分页查询结果

模型标识：CDevicePageResDto

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| deviceName | string | 设备名称<br>示例："设备1" |
| deviceSn | string | 设备序列号<br>示例："1001" |
| typeCode | string | 面向客户的设备分类编码；优先使用外部分类，未配置时回退内部类型编码<br>示例："MET" |
| typeName | string | 面向客户的设备分类名称；优先使用外部分类，未配置时回退内部类型名称<br>示例："气象设备" |
| internalTypeCode | string | 平台内部设备类型编码，供系统间对接识别<br>示例："FNKJ_LAMP" |
| providerCode | string | 设备厂商接入编码<br>示例："THIRD_PLATFORM_FNKJ" |
| onlineStatus | int32 | 在线状态，1 表示在线，0 表示离线<br>示例：1 |
| enabled | int32 | 启用状态，1 表示启用，0 表示禁用<br>示例：1 |
| lastOnlineTime | string date-time | 最近一次上线时间 |
| lastOfflineTime | string date-time | 最近一次离线时间 |
| queryTime | string date-time | 本次查询时间 |
| accessMode | string | 当前应用对该设备的访问权限。WRITE 表示可读写，READ 表示仅可读取<br>示例："WRITE" |
| dataMode | string | 设备数据模式：READ_ONLY-只读，READ_WRITE-读写<br>示例："READ_ONLY" |

### 模型 M13 设备最新参数状态详情

模型标识：CDeviceParamDetailResDto

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| device | 对象 M25 | OpenAPI 设备变量身份信息<br>完整子字段见模型 M25。 |
| paramInfoResList | 数组 [对象 M14] | 参数最新状态列表 |

### 模型 M14 设备最新参数状态

模型标识：CDeviceParamInfoResDto

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| variableCode | string | 参数编码<br>示例："temperature" |
| variableName | string | 参数名称<br>示例："温度" |
| unit | string | 参数单位<br>示例："℃" |
| changeTime | string date-time | 最新采集时间 |
| lastValue | object | 参数当前值 可为字符串、数字、布尔值或对象，客户端按实际 JSON 值解析。 |

### 模型 M15 设备点位变化历史分页查询参数

模型标识：CDevicePointChangeHistoryPageReqDto

| 字段 | 类型 | 必填与可空 | 说明 约束和示例 |
| --- | --- | --- | --- |
| deviceSn | string | 是<br>不可为 null | 设备序列号，必须在当前应用授权范围内<br>示例："SN001" |
| positionCode | string | 否<br>未声明可空 | 按点位编码筛选，不填时不限制点位 |
| startTime | string date-time | 否<br>未声明可空 | 查询起始时间，ISO-8601 本地日期时间<br>示例："2026-10-20T00:00:00" |
| endTime | string date-time | 否<br>未声明可空 | 查询结束时间，ISO-8601 本地日期时间<br>示例："2026-10-21T00:00:00" |
| pageIndex | int64 | 否<br>未声明可空 | 历史分页页码<br>默认值：1<br>最小值：1<br>示例：1 |
| pageSize | int64 | 否<br>未声明可空 | 历史分页每页条数<br>默认值：20<br>最小值：1<br>最大值：100<br>示例：10 |

### 模型 M16 点位变化历史分页结果

模型标识：CDevicePointChangeHistoryPageResDto

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| device | 对象 M25 | OpenAPI 设备变量身份信息<br>完整子字段见模型 M25。 |
| records | 数组 [对象 M17] | 本页点位变化记录 |
| total | 字符串 int64 | 总记录数 |
| size | 字符串 int64 | 每页条数 |
| current | 字符串 int64 | 当前页码 |
| pages | 字符串 int64 | 总页数 |

### 模型 M17 一条点位变化记录

模型标识：CDevicePointChangeHistoryRecordResDto

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| dataTime | string date-time | 变化记录时间，ISO-8601 本地日期时间 |
| changedPoints | 数组 [对象 M18] | 发生变化的点位列表 |

### 模型 M18 单个点位变化

模型标识：CDevicePointChangeResDto

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| code | string | 点位编码 |
| name | string | 点位名称 |
| beforeValue | object | 变化前的值，类型取决于点位 可为字符串、数字、布尔值或对象，客户端按实际 JSON 值解析。 |
| afterValue | object | 变化后的值，类型取决于点位 可为字符串、数字、布尔值或对象，客户端按实际 JSON 值解析。 |
| unit | string | 点位单位，未设置时可能省略 |
| changeTime | string date-time | 点位变化时间，ISO-8601 本地日期时间 |

### 模型 M19 设备点位详情

模型标识：CDevicePosDetailResDto

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| id | 字符串 int64 | 点位 ID<br>示例：1 |
| positionName | string | 点位名称<br>示例："点位1" |
| positionCode | string | 点位编码<br>示例："point1" |
| latestPositionValue | string | 点位最新值<br>示例："12" |
| gmtPositionValue | string date-time | 点位最新值采集时间；实际 JSON 格式 yyyy-MM-dd HH:mm:ss，时区 GMT+8。 |
| positionUnit | string | 点位单位<br>示例："m³/h" |

### 模型 M20 设备点位快照历史分页查询参数

模型标识：CDeviceSnapshotHistoryPageReqDto

| 字段 | 类型 | 必填与可空 | 说明 约束和示例 |
| --- | --- | --- | --- |
| deviceSn | string | 是<br>不可为 null | 设备序列号，必须在当前应用授权范围内<br>示例："SN001" |
| positionCode | string | 否<br>未声明可空 | 按点位编码筛选，不填时不限制点位 |
| startTime | string date-time | 否<br>未声明可空 | 查询起始时间，ISO-8601 本地日期时间<br>示例："2026-10-20T00:00:00" |
| endTime | string date-time | 否<br>未声明可空 | 查询结束时间，ISO-8601 本地日期时间<br>示例："2026-10-21T00:00:00" |
| pageIndex | int64 | 否<br>未声明可空 | 历史分页页码<br>默认值：1<br>最小值：1<br>示例：1 |
| pageSize | int64 | 否<br>未声明可空 | 历史分页每页条数<br>默认值：20<br>最小值：1<br>最大值：1000<br>示例：10 |

### 模型 M21 快照历史分页结果

模型标识：CDeviceSnapshotHistoryPageResDto

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| device | 对象 M25 | OpenAPI 设备变量身份信息<br>完整子字段见模型 M25。 |
| records | 数组 [对象 M22] | 本页快照记录 |
| total | 字符串 int64 | 总记录数 |
| size | 字符串 int64 | 每页条数 |
| current | 字符串 int64 | 当前页码 |
| pages | 字符串 int64 | 总页数 |

### 模型 M22 一条点位快照记录

模型标识：CDeviceSnapshotHistoryRecordResDto

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| dataTime | string date-time | 快照采集时间，ISO-8601 本地日期时间 |
| variables | 数组 [对象 M26] | 该快照的点位数据 |

### 模型 M23 设备模板化详情

模型标识：CDeviceTemplateDetailResDto

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| device | 对象 M25 | OpenAPI 设备变量身份信息<br>完整子字段见模型 M25。 |
| templateCode | string | 业务模板编码 |
| templateType | string | 业务模板类型，用于识别 detail 的具体结构<br>示例："WATER_FERTILIZER_MACHINE" |
| templateVersion | int32 | 业务模板版本 |
| tempModel | int32 | 模板模式：1 为手动 MANUAL，0 为自动 AUTO；与本接口查询参数保持一致。<br>示例：1 |
| modeCode | string | 模板模式编码：MANUAL-手动，AUTO-自动<br>示例："MANUAL" |
| detail | object | 模板业务详情，结构由 templateType 决定 按 templateType 选择水肥机、变频柜或温室模型，详见模板详情说明。 |
| missingSlotList | 数组 [string] | 模板必填槽位缺失列表 |

### 模型 M24 设备变量详情

模型标识：CDeviceVariableDetailResDto

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| device | 对象 M25 | OpenAPI 设备变量身份信息<br>完整子字段见模型 M25。 |
| variables | 数组 [对象 M26] | 变量列表 |
| queryTime | string date-time | 本次查询时间 |
| varDetailTime | string date-time | 变量详情数据时间 |
| onlineStatus | int32 | 在线状态，1 表示在线，0 表示离线<br>示例：1 |
| rawData | 字典 {键: object} | 原始调试数据，便于联调排查 |

### 模型 M25 设备身份信息

模型标识：CDeviceVariableIdentityResDto

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| deviceId | 字符串 int64 | 设备 ID<br>示例：1 |
| deviceSn | string | 设备 SN<br>示例："1001" |
| deviceName | string | 设备名称 |
| deviceTypeId | 字符串 int64 | 设备类型 ID<br>示例：2001 |
| typeCode | string | 面向客户的设备分类编码；优先使用外部分类，未配置时回退内部类型编码 |
| typeName | string | 面向客户的设备分类名称；优先使用外部分类，未配置时回退内部类型名称 |
| providerCode | string | 厂商接入编码<br>示例："SELF" |
| productCode | string | 产品编码<br>示例："product-001" |
| onlineStatus | int32 | 在线状态，1 表示在线，0 表示离线 |

### 模型 M26 设备变量明细

模型标识：CDeviceVariableItemResDto

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| id | 字符串 int64 | 对应的设备点位 ID |
| code | string | 变量编码<br>示例："temperature" |
| codeType | string | 变量编码类型。DYNAMIC_NODE 表示第三方动态节点变量；FIXED_FIELD 表示固定字段变量<br>示例："DYNAMIC_NODE" |
| nodeId | 字符串 int64 | 第三方动态节点 ID；固定字段变量为空<br>示例：11 |
| nodeName | string | 第三方节点名称<br>示例："节点11" |
| metricCode | string | 节点指标编码<br>示例："tem" |
| metricName | string | 节点指标名称<br>示例："温度" |
| displayName | string | 面向用户的显示名称<br>示例："节点11温度" |
| name | string | 变量名称<br>示例："温度" |
| value | object | 变量当前值 可为字符串、数字、布尔值或对象，客户端按实际 JSON 值解析。 |
| unit | string | 变量单位<br>示例："℃" |
| valueType | string | 变量值类型<br>示例："number" |
| valueRange | string | 变量可用取值范围描述<br>示例："0-100" |
| variableReadWriteType | string | 变量读写能力。READ_ONLY 表示只读，只能查看设备上报值；READ_WRITE 表示可读写，可在设备控制接口中作为控制参数下发。<br>允许值：["READ_ONLY", "READ_WRITE"]<br>示例："READ_ONLY" |
| quality | int32 | 数据质量标识 |
| dataStatus | string | 变量业务数据状态<br>示例："NORMAL" |
| statusReason | string | 非正常状态的说明 |
| collectTime | string date-time | 本次数值的采集时间 |

### 模型 M27 当前应用身份和访问权限

模型标识：COpenApiAccessibleEndpointResDto

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| appId | 字符串 int64 | 当前接入应用 ID，对应调用方在请求头 X-App-Id 中使用的应用标识<br>示例：1001 |
| appCode | string | 当前接入应用编码，用于区分客户侧不同接入应用<br>示例："customer-iot-app" |
| tenantId | 字符串 int64 | 当前应用所属租户 ID，接口返回的数据会限定在该租户范围内<br>示例：10 |
| permissionCodes | 数组 [string] | 当前应用已授权的权限码列表。授权父级权限时，可访问其下级权限对应的接口，例如 openapi:iot:device:read 可匹配 openapi:iot:device:read.detail |
| endpoints | 数组 [对象 M28] | 当前应用根据已授权权限实际可调用的 OpenAPI 接口列表 |

### 模型 M28 当前应用可访问接口

模型标识：COpenApiAccessibleRouteResDto

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| methods | 数组 [string] | 接口支持的 HTTP 请求方法，例如 GET、POST；客户端调用时需要使用列表中的方法<br>示例：["GET"] |
| path | string | 接口请求路径，已包含 OpenAPI 版本前缀，调用时与服务域名拼接使用<br>示例："/openapi/v1/devices/selectDeviceBySn/{sn}" |
| summary | string | 接口功能摘要，用于快速了解该接口的业务用途<br>示例："按 SN 查询设备详情" |
| permissionCodes | 数组 [string] | 调用该接口需要匹配的权限码列表。当前应用拥有相同权限码或其父级权限码时，视为具备访问权限 |
| permissionMode | string | 权限匹配方式。ALL 表示需要满足全部权限码；ANY 表示满足任意一个权限码即可访问<br>允许值：["ALL", "ANY"]<br>示例："ALL" |

### 模型 M29 温室模板详情

模型标识：CPzgGreenHouseTemplateDetailResDto

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| data | 数组 [对象 M30] | 温室控制器及其挂载设备列表。 |

### 模型 M30 温室 控制器及其子设备

模型标识：CPzgGreenHouseTemplateDetailResDto.DeviceData

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| devId | string | 厂商控制器标识。 |
| devName | string | 控制器名称。 |
| devSort | int32 | 厂商设备排序或类别值，按厂商协议解释。 |
| onlineState | int32 | 厂商在线状态值，按厂商协议解释。 |
| warningType | int32 | 厂商告警类型值，按厂商协议解释。 |
| warningTypes | string | 厂商告警类型集合或描述。 |
| rolls | 数组 [对象 M31] | 卷帘设备列表。 |
| winds | 数组 [对象 M35] | 风口或风帘设备列表。 |
| switches | 数组 [对象 M34] | 开关设备列表。 |
| sensors | 数组 [对象 M32] | 传感器列表。 |

### 模型 M31 温室 卷帘

模型标识：CPzgGreenHouseTemplateDetailResDto.Roll

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| rollId | string | 卷帘标识。 |
| rollName | string | 卷帘名称。 |
| channelNo | int32 | 厂商设备通道编号。 |
| rollState | int32 | 卷帘状态值，按厂商协议解释。 |
| curPosition | string | 当前开度或位置，字符串表示，量纲由厂商约定。 |

### 模型 M32 温室 传感器

模型标识：CPzgGreenHouseTemplateDetailResDto.Sensor

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| sensorId | string | 传感器标识。 |
| sensorName | string | 传感器名称。 |
| channelNo | int32 | 厂商设备通道编号。 |
| sensorValue | 数组 [对象 M33] | 传感器指标值或指标值列表，类型见本行类型列。 |

### 模型 M33 温室 传感器指标

模型标识：CPzgGreenHouseTemplateDetailResDto.SensorValue

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| sensorType | string | 厂商传感器指标类型。 |
| sensorValue | string | 传感器指标值或指标值列表，类型见本行类型列。 |
| updateTime | 字符串 int64 | 厂商上报的更新时间原值，单位按设备协议约定。 |

### 模型 M34 温室 开关

模型标识：CPzgGreenHouseTemplateDetailResDto.SwitchData

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| switchId | string | 开关标识。 |
| switchName | string | 开关名称。 |
| channelNo | int32 | 厂商设备通道编号。 |
| switchState | int32 | 开关状态值，按厂商协议解释。 |

### 模型 M35 温室 风口或风帘

模型标识：CPzgGreenHouseTemplateDetailResDto.Wind

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| windId | string | 风口或风帘标识。 |
| windName | string | 风口或风帘名称。 |
| channelNo | int32 | 厂商设备通道编号。 |
| windState | int32 | 风口或风帘状态值，按厂商协议解释。 |
| curPosition | string | 当前开度或位置，字符串表示，量纲由厂商约定。 |

### 模型 M36 变频柜模板详情

模型标识：CVfdCabinetTemplateDetailResDto

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| points | 字典 {键: 对象 M26} | 模板版本 2 及以上使用的点位字典，键为原始点位编码，例如 YLSD1。 |
| outputVoltage | 对象 M26 | 输出电压点位。<br>完整子字段见模型 M26。 |
| outputCurrent | 对象 M26 | 输出电流点位。<br>完整子字段见模型 M26。 |
| outputFrequency | 对象 M26 | 输出频率点位。<br>完整子字段见模型 M26。 |
| dcBusVoltage | 对象 M26 | 母线电压点位。<br>完整子字段见模型 M26。 |
| pressureSetpoint | 对象 M26 | 压力设定点位，单位与范围按设备协议确认。<br>完整子字段见模型 M26。 |
| pressureFeedback | 对象 M26 | 压力反馈点位。<br>完整子字段见模型 M26。 |
| runState | 对象 M26 | 运行状态点位，值为 0 停止、1 运行。<br>完整子字段见模型 M26。 |

### 模型 M37 水肥机模板详情

模型标识：CWaterFertilizerTemplateDetailResDto

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| waterUseToday | number | 当日用水累计值，数值单位由设备模板约定。 |
| electricityUseToday | number | 当日用电累计值，数值单位由设备模板约定。 |
| fertilizerUseToday | number | 当日用肥累计值，数值单位由设备模板约定。 |
| readings | 对象 M44 | 采集值集合；具体子字段见对应模型。<br>完整子字段见模型 M44。 |
| fertilizerFlowList | 数组 [对象 M41] | 施肥流量通道列表。 |
| pumpList | 数组 [对象 M48] | 泵分组列表。 |
| electricValveList | 数组 [对象 M40] | 按区域分组的电磁阀列表。 |

### 模型 M38 水肥机 电磁阀

模型标识：CWaterFertilizerTemplateDetailResDto.ElectricValve

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| name | string | 显示名称。 |
| controls | 对象 M39 | 可控制点位集合；下发前检查点位读写能力及设备授权。<br>完整子字段见模型 M39。 |

### 模型 M39 水肥机 电磁阀控制点

模型标识：CWaterFertilizerTemplateDetailResDto.ElectricValveControls

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| switchStatus | 对象 M45 | 开关状态或开关控制点位，取值见点位定义。<br>完整子字段见模型 M45。 |
| timeSet | 对象 M45 | 运行时间设定点位，单位见该点位 unit。<br>完整子字段见模型 M45。 |

### 模型 M40 水肥机 区域电磁阀组

模型标识：CWaterFertilizerTemplateDetailResDto.ElectricValveGroup

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| region | string | 阀门所属区域名称或编码。 |
| electricValvePositionList | 数组 [对象 M38] | 本区域的电磁阀列表。 |

### 模型 M41 水肥机 施肥流量通道

模型标识：CWaterFertilizerTemplateDetailResDto.FertilizerFlow

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| channelName | string | 通道名称。 |
| readings | 对象 M43 | 采集值集合；具体子字段见对应模型。<br>完整子字段见模型 M43。 |
| controls | 对象 M42 | 可控制点位集合；下发前检查点位读写能力及设备授权。<br>完整子字段见模型 M42。 |

### 模型 M42 水肥机 施肥通道控制点

模型标识：CWaterFertilizerTemplateDetailResDto.FertilizerFlowControls

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| clearTotal | 对象 M45 | 累计流量清零控制点位。<br>完整子字段见模型 M45。 |

### 模型 M43 水肥机 施肥通道采集值

模型标识：CWaterFertilizerTemplateDetailResDto.FertilizerFlowReadings

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| instantFlow | 对象 M45 | 瞬时流量点位。<br>完整子字段见模型 M45。 |
| totalFlow | 对象 M45 | 累计流量点位。<br>完整子字段见模型 M45。 |

### 模型 M44 水肥机 全局采集值

模型标识：CWaterFertilizerTemplateDetailResDto.GlobalReadings

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| ec | 对象 M45 | 电导率采集点位。<br>完整子字段见模型 M45。 |
| ph | 对象 M45 | 酸碱度采集点位。<br>完整子字段见模型 M45。 |
| fertilizerFlowTotal | 对象 M45 | 施肥累计流量点位。<br>完整子字段见模型 M45。 |
| mainPipeInstantFlow | 对象 M45 | 主管瞬时流量点位。<br>完整子字段见模型 M45。 |
| mainPipeTotalFlow | 对象 M45 | 主管累计流量点位。<br>完整子字段见模型 M45。 |

### 模型 M45 水肥机 通用点位

模型标识：CWaterFertilizerTemplateDetailResDto.Point

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| code | string | 实际设备变量编码；作为控制参数时使用该编码。 |
| codeName | string | 模板点位显示名称。 |
| value | string | 点位当前值，字符串表示；含义与单位由点位定义。 |
| readWriteType | string | READ_ONLY 只读，READ_WRITE 可读写。 |
| unit | string | 点位单位，未配置时可省略。 |
| valueTime | string date-time | 点位数值时间，ISO-8601 本地日期时间。 |

### 模型 M46 水肥机 泵

模型标识：CWaterFertilizerTemplateDetailResDto.Pump

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| pumpName | string | 泵名称。 |
| readings | 对象 M49 | 采集值集合；具体子字段见对应模型。<br>完整子字段见模型 M49。 |
| controls | 对象 M47 | 可控制点位集合；下发前检查点位读写能力及设备授权。<br>完整子字段见模型 M47。 |

### 模型 M47 水肥机 泵控制点

模型标识：CWaterFertilizerTemplateDetailResDto.PumpControls

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| switchStatus | 对象 M45 | 开关状态或开关控制点位，取值见点位定义。<br>完整子字段见模型 M45。 |
| timeSet | 对象 M45 | 运行时间设定点位，单位见该点位 unit。<br>完整子字段见模型 M45。 |

### 模型 M48 水肥机 泵分组

模型标识：CWaterFertilizerTemplateDetailResDto.PumpGroup

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| type | int32 | 泵分组类型编码，具体值由绑定的设备模板约定。 |
| pumpDetailList | 数组 [对象 M46] | 当前分组中的泵列表。 |

### 模型 M49 水肥机 泵采集值

模型标识：CWaterFertilizerTemplateDetailResDto.PumpReadings

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| useTime | 对象 M45 | 已使用时间点位，单位见该点位 unit。<br>完整子字段见模型 M45。 |
| remainingTime | 对象 M45 | 剩余时间点位，单位见该点位 unit。<br>完整子字段见模型 M45。 |

### 模型 M50 单条控制参数

模型标识：CmdParam

| 字段 | 类型 | 必填与可空 | 说明 约束和示例 |
| --- | --- | --- | --- |
| cmd | string | 是<br>不可为 null | 命令编码<br>示例："cmd" |
| param | string | 否<br>未声明可空 | 命令值<br>示例："1" |

### 模型 M51 控制日志分页结果

模型标识：IPageCDeviceControlTraceResDto

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| size | 字符串 int64 | 每页条数 |
| total | 字符串 int64 | 总记录数 |
| records | 数组 [对象 M10] | 本页记录列表 |
| current | 字符串 int64 | 当前页码 |
| pages | 字符串 int64 | 总页数<br>接口定义标记为已弃用。 |

### 模型 M52 分页响应

模型标识：OpenApiPageResDtoCDevicePageResDto

| 字段 | 类型 | 说明与示例 |
| --- | --- | --- |
| page | int32 | 当前页码，从 1 开始<br>示例：1 |
| pageSize | int32 | 每页数量<br>示例：20 |
| total | 字符串 int64 | 符合条件的记录总数<br>示例：100 |
| items | 数组 [对象 M12] | 当前页记录 |

### 模型 M53 控制路由扩展参数

模型标识：RoutingOptions

| 字段 | 类型 | 必填与可空 | 说明 约束和示例 |
| --- | --- | --- | --- |
| topic | string | 否<br>未声明可空 | MQTT 下发主题<br>示例："cmd/common/default/1001" |
| endpoint | string | 否<br>未声明可空 | HTTP 接口地址<br>示例："/api/v2.0/worm/device/deviceOper/wormOper" |
| path | string | 否<br>未声明可空 | HTTP 接口路径<br>示例："/SDK/setWormOperation" |
| payload | object | 否<br>未声明可空 | 结构化请求体，按厂商协议透传 |
| rawPayload | string | 否<br>未声明可空 | 原始请求体字符串，按厂商协议透传 |

## 十 错误码和问题排查

公共错误码来自当前接口错误定义；message 可能包含更具体原因。控制轨迹内部的 errorCode 还可能使用接入方或命令域错误码，不限于本表。

| 业务码 | 含义 | 处理建议 |
| --- | --- | --- |
| 200 | 成功 | 接口调用成功；控制类接口还需判断业务执行状态。 |
| 1000 | 请求参数不合法 | 核对必填、类型、时间范围、枚举与组合约束。 |
| 1001 | 缺少应用 ID | 补齐 X-App-Id。 |
| 1003 | 应用认证失败 | 检查 App、签名、时间戳与 salt 是否重复。 |
| 1004 | 应用已停用 | 联系服务方确认应用状态。 |
| 1005 | 应用已过期 | 联系服务方更新有效期。 |
| 1006 | 访问被拒绝 | 核对接口权限、设备 READ/WRITE 范围和资源所属 App。 |
| 1007 | 设备未找到或不可访问 | 检查设备 SN、设备范围及设备是否可用。 |
| 1008 | 消息标识冲突 | 检查重复提交及消息标识使用规则。 |
| 1009 | 消息不存在 | 使用控制接口返回的 messageId。 |
| 1010 | 请求方法不支持 | 按接口说明使用 GET、POST 或 PUT。 |
| 1011 | 告警配置不存在 | 核对创建后保存的配置 ID。 |
| 1012 | 设备点位不存在 | 核对点位 ID、编码与设备对应关系。 |
| 1013 | 请求过于频繁 | 降低请求频率；写请求先查状态再决定是否重试。 |
| 1014 | 幂等键冲突 | 同一幂等键不可用于不同请求。 |
| 1015 | 设备未配置模板 | 联系服务方配置业务模板。 |
| 1016 | 设备模板不可用 | 联系服务方检查模板状态或适用范围。 |
| 1017 | 不支持模板转换 | 确认设备接入方支持该模板类型。 |
| 1018 | 模板类型不匹配 | 核对设备类型与模板绑定关系。 |
| 500 | 服务内部异常 | 记录 requestId、时间及脱敏请求后联系服务方。 |

### 错误响应示例

```json
{
  "code": "1003",
  "message": "signature mismatch",
  "requestId": "request-example-002",
  "resultCode": "1003"
}
```

常见 HTTP 状态包括：400 参数不合法，401 认证失败，403 无权限，404 设备或控制消息不存在，409 幂等冲突，422 模板不可用，429 请求过频，500 内部错误。状态由具体处理分支决定，例如部分告警或点位业务错误仍可能以 HTTP 200 返回失败 code。

### 排查顺序

- 认证：确认 App 已启用且未过期，时间为毫秒值；重新生成 salt，核对 UTF-8 拼接和 Base64 原始摘要。

- 权限：先调用应用访问接口查看 endpoints，再核对设备 READ/WRITE 范围与当前 App。

- 参数：核对路径与查询参数的位置，尤其删除告警的 id 在查询串中；检查 JSON 类型、分页和时间区间。

- 控制：核对命令编码、点位读写能力、幂等键与消息 ID，检查 executionStatus，勿根据单一 HTTP 成功判断动作完成。

- 联系支持时提供 requestId、请求时间、接口方法与路径、脱敏后的参数和错误响应，不发送 App Secret。

## 十一 接入检查和版本说明

- 已取得实际 HTTPS 服务入口、App 信息与设备授权，不将示例域名当作生产地址。

- 应用访问、设备分页、设备详情及业务所需查询已完成联调。

- 客户客户端兼容 Long 字符串、可选字段省略、空列表与动态点位值类型。

- 控制前取得明确测试设备授权，完成幂等与状态回查；正式设备动作由业务方确认。

- 更新回调前读取并保留需要保留的配置；保存回调地址后另行验证客户接收端。

- 保留告警创建返回的 ID；错误同时检查 HTTP 与 code，排查日志不记录密钥。
