下行命令
接口
POST /api/v1/open/downlink/commands:受理一条云端到设备命令并返回平台受理结果。
交互模型
001 的下行命令接口实现 同步受理、异步投递事件创建:- 接入方提交命令。
- 平台完成签名鉴权、nonce 防重放、租户解析、Casbin 授权、请求校验和幂等判断。
- 平台在同一个 PostgreSQL 事务中写入 command fact 和 dispatch event。
- 平台返回
command_id、ACCEPTED、accepted_at和request_id。 - 事务提交后,API 服务尝试发布 NATS 事件
tenant.<tenant_id>.command.accepted。
202 Accepted 只表示平台已受理并持久化命令,不表示设备已经执行成功。
命令事件与状态模型
Open Platform 把“可订阅事件”和“命令状态”分开建模。当前可订阅的 command 事件是:| event_type | 含义 |
|---|---|
command.accepted | 平台已经完成鉴权、授权、幂等校验和持久化,命令进入受理事实。 |
command.completed | adapter 或设备返回终态结果,事件 payload 携带具体执行结果。 |
command.problem | adapter 在命令边界发现无法安全关联到具体命令的诊断问题,例如 malformed accepted-command payload。 |
command.completed 的 payload 以及命令查询响应中。command.problem 不表示正常命令失败;它会作为设备 recent event 保留原始诊断 payload。
命令查询响应中的聚合状态使用 public_status:
| public_status |
|---|
ACCEPTED |
DISPATCHING |
DELIVERED |
RUNNING |
SUCCEEDED |
FAILED |
TIMED_OUT |
UNSUPPORTED |
CANCELLED |
UNKNOWN |
adapter_status:
| adapter_status |
|---|
RECEIVED |
REJECTED_BY_ADAPTER |
SENT_TO_DEVICE |
TRANSPORT_FAILED |
RESPONSE_TIMEOUT |
device_execution_status:
| device_execution_status |
|---|
ACCEPTED_BY_DEVICE |
SUCCEEDED |
TEMPORARILY_REJECTED |
DENIED |
UNSUPPORTED |
TIMED_OUT |
command.completed.status 中返回的原始终态包括:
| status |
|---|
rejected_by_agent |
sent_to_px4 |
ack_accepted |
ack_temporarily_rejected |
ack_denied |
ack_unsupported |
ack_timeout |
transport_failed |
parameter_value_confirmed |
parameter_error |
parameter_response_mismatch |
parameter_timeout |
adapter_status、device_execution_status 和 public_status。
PX4 adapter 的查询响应还会在 adapter_result 中返回:
| 字段 | 说明 |
|---|---|
human_summary | agent 生成的中文可读终态摘要。 |
hardware_response | PX4 硬件响应 typed payload。MAV_CMD 使用 COMMAND_ACK,参数读写使用 PARAM_VALUE 或 PARAM_ERROR;mission、FTP、timesync 接入时分别使用 MISSION_ACK、FILE_TRANSFER_PROTOCOL、TIMESYNC typed payload。 |
source_evidence | agent 采用的 PX4/MAVLink 本地源码证据路径和说明。 |
鉴权
- 必须通过开放平台签名鉴权:
X-Api-Id、X-Api-Timestamp、X-Api-Nonce、X-Api-Signature X-Request-Id可选;未传时平台生成并在响应与日志中返回- 创建命令需要租户域内授权:
open:command:create - 签名计算示例见 鉴权与签名
请求体
| Field | Type | Required | Description |
|---|---|---|---|
| vendor | string | yes | 厂商标识,如 dji |
| device_id | string | yes | 目标设备 ID |
| command_type | string | yes | 命令类型,必须使用平台支持清单中的值 |
| payload | object | yes | 命令负载 |
| idempotency_key | string | yes | 幂等键 |
| timeout_seconds | integer | no | 超时秒数;缺省为 30,有效范围 1~300 |
payload 不是任意对象。它必须匹配对应厂商和 command_type 的命令协议。DJI 全量命令 payload 字段、JSON 示例和代码演示见 命令 Payload。
响应
202 Accepted:首次受理成功200 OK:命中幂等重放,返回已存在命令4xx/5xx:返回标准错误结构
幂等语义
- 幂等作用域为认证后的
tenant_id + client_id + idempotency_key - 同一作用域内,相同业务请求体重放时返回同一
command_id - 同一作用域内,相同幂等键但不同业务请求体返回
IDEMPOTENCY_CONFLICT - 语义哈希包含
vendor、device_id、command_type、规范化后的payload和规范化后的timeout_seconds - 语义哈希不包含
X-Request-Id、X-Api-Nonce、X-Api-Timestamp或签名头
持久化与投递语义
命令受理响应表示平台已经把 command fact 与 dispatch event 写入同一个 PostgreSQL 事务。事务提交后,API 服务会立即尝试向 NATS 发布:ACCEPTED。平台会保留 dispatch event 及失败原因,供后续恢复流程补偿。
常见错误
| code | HTTP | 说明 |
|---|---|---|
UNAUTHORIZED | 401 | 缺少或无效的认证身份 |
SIGNATURE_INVALID | 401 | 签名不匹配 |
TIMESTAMP_EXPIRED | 401 | 请求时间戳超过允许偏差窗口 |
NONCE_REPLAYED | 401 | nonce 在重放窗口内重复使用 |
FORBIDDEN | 403 | 当前客户端无租户域内权限 |
TENANT_NOT_FOUND | 404 | 无法解析有效租户 |
TENANT_BINDING_INVALID | 403 | 客户端与租户绑定关系无效 |
INVALID_REQUEST_BODY | 400 | JSON 请求体非法 |
VALIDATION_FAILED | 400 | 字段缺失、类型非法或超出范围 |
UNSUPPORTED_VENDOR | 400 | 厂商未在平台命令目录中注册 |
UNSUPPORTED_COMMAND | 400 | 命令类型不受支持或不在可信能力范围内 |
IDEMPOTENCY_CONFLICT | 409 | 同一幂等键对应不同语义请求 |
INTERNAL_ERROR | 500 | 平台内部错误 |
示例
下面示例只演示调用结构。生产环境必须按照 鉴权与签名 计算X-Api-Signature。