数据模型
大约 3 分钟deviceshadow
影子文档结构
每个设备影子是一份结构化的 JSON 文档,包含状态域(state)、元数据域(metadata)、版本号(version)和时间戳(timestamp)。
一、完整 JSON 结构
{
"state": {
"reported": {
"temperature": 25.6,
"humidity": 68,
"switch": 1,
"mode": "auto"
},
"desired": {
"temperature": 26,
"switch": 0
},
"delta": {
"temperature": 26,
"switch": 0
}
},
"metadata": {
"reported": {
"temperature": { "timestamp": 1711584000000 },
"humidity": { "timestamp": 1711584000000 },
"switch": { "timestamp": 1711583900000 },
"mode": { "timestamp": 1711583900000 }
},
"desired": {
"temperature": { "timestamp": 1711584100000 },
"switch": { "timestamp": 1711584100000 }
}
},
"version": 12,
"timestamp": 1711584100000
}二、字段详细说明
1. state 状态域
| 字段 | 写入方 | 更新时机 | 说明 |
|---|---|---|---|
state.reported | 设备 | 设备属性上报时 | 设备最近一次上报的属性键值对 |
state.desired | 应用 | 应用通过 API/MQTT 设置时 | 应用期望设备达到的目标状态 |
state.delta | 平台自动计算 | reported 或 desired 变更时 | reported 与 desired 的差异值(派生值,不持久化到数据库,读取时实时重算) |
2. metadata 元数据域
元数据结构与 state 镜像,但每个属性记录的是最后更新的毫秒时间戳:
{
"metadata": {
"reported": {
"temperature": { "timestamp": 1711584000000 }
},
"desired": {
"temperature": { "timestamp": 1711584100000 }
}
}
}| 字段 | 说明 |
|---|---|
metadata.reported.{属性}.timestamp | 该属性最后一次被设备上报的时间 |
metadata.desired.{属性}.timestamp | 该属性最后一次被应用设置的时间 |
3. version 版本号
版本号是影子并发控制的核心机制,遵循以下规则:
| 规则 | 说明 |
|---|---|
| 请求不带 version | 直接更新,不做版本检查 |
| 请求的 version == 当前 version | 更新成功,version + 1 |
| 请求的 version != 当前 version | 更新失败,返回版本冲突错误(code=6300) |
| version = -1 | 跳过版本校验,强制执行(配合删除操作时清除整个影子文档) |
版本冲突处理示例
应用 A 读取影子 version=5
应用 B 读取影子 version=5
应用 A 提交修改(version=5) → 成功,version 变为 6
应用 B 提交修改(version=5) → 失败,返回版本冲突
应用 B 重新读取(version=6),再次提交 → 成功,version 变为 7三、Delta 计算规则
Delta 计算核心逻辑
平台遍历 desired 中的每个属性,与 reported 对比:
- desired 中有该属性,但 reported 中不存在或值不同 → 保留在 delta 中(取 desired 值)
- desired 与 reported 值相同 → 不包含在 delta 中
- desired 中没有该属性 → 不包含在 delta 中
计算示例
输入:
| reported(设备上报) | desired(应用期望) |
|---|---|
| temperature = 25 | temperature = 26 |
| humidity = 68 | (无此属性) |
| switch = 1 | switch = 1 |
计算过程:
| 属性 | reported 值 | desired 值 | 比较结果 | delta |
|---|---|---|---|---|
| temperature | 25 | 26 | 25 ≠ 26,值不同 | 26 |
| humidity | 68 | — | desired 中不存在 | (忽略) |
| switch | 1 | 1 | 1 == 1,值相同 | (移除) |
输出 Delta:
{ "temperature": 26 }Delta 为空时的处理
当所有 desired 属性都已被 reported 满足时:
delta变为空对象{}- 平台不再向设备推送 Delta 消息
- 自动清除
desired中已满足的属性
四、限制与约束
| 限制项 | 限制值 | 说明 |
|---|---|---|
| 影子文档最大大小 | 64 KB | 超过限制的更新请求将被拒绝 |
| 单设备最大属性数 | 256 个 | reported + desired 合计 |
五、错误码定义
| 错误码 | 标识 | 说明 |
|---|---|---|
| 200 | SUCCESS | 操作成功 |
| 6300 | SHADOW_VERSION_CONFLICT | 影子版本冲突 |
| 6301 | SHADOW_NOT_FOUND | 影子文档不存在 |
| 6302 | SHADOW_SIZE_EXCEEDED | 影子文档大小超限 |
| 6303 | SHADOW_RATE_LIMITED | 影子更新频率超限 |
| 6304 | SHADOW_PROPERTY_COUNT_EXCEEDED | 属性数量超限 |
| 6305 | SHADOW_LOCK_TIMEOUT | 影子操作锁超时 |
