设备影子
设备影子
影子用于解决「设备离线时也能下发期望值、上线后自动对齐」的问题。每台设备建档时自动生成影子,初始为:
{ "state": { "reported": {}, "desired": {} }, "metadata": { "reported": {}, "desired": {} }, "timestamp": 0, "version": 0 }reported:设备实际上报的状态。desired:云端期望状态。version:单调递增,用于乐观并发控制。metadata:每个键的最后更新时间戳(毫秒)。
Topic:请求 /shadow/update/{pk}/{dn},回复 /shadow/get/{pk}/{dn}(QoS1)。设备必须订阅 /shadow/get/{pk}/{dn} 才能拿到回复。
上报实际状态
{ "method": "update", "state": { "reported": { "color": "green", "brightness": 80 } }, "version": 3 }约束:version 必须是整数且 大于 平台已存版本(或传 -1 表示强制),reported 为非空对象且键数量 ≤ 128。
传 version: -1 可跳过版本冲突,但副作用是平台会把库内影子版本写成 -1(回复里的 version 显示为 0),此后任意版本号都能通过校验。除非用于异常兜底,否则请正常递增本地版本。
成功回复:
{ "method": "reply", "payload": { "status": "success", "version": 3 }, "clientToken": null, "timestamp": 1700000000000 }拉取影子
{ "method": "get" }回复包含完整状态:
{
"method": "reply",
"payload": {
"status": "success",
"state": { "reported": { "color": "red" }, "desired": { "color": "green" } },
"metadata": { "reported": { "color": { "timestamp": 1700000000000 } },
"desired": { "color": { "timestamp": 1700000000000 } } }
},
"version": 2, "timestamp": 1700000000000
}设备据此对比 desired 与 reported,差异项执行后回写 reported。
删除与清空
delete 方法会移除 state.reported 中列出的键(键对应的值被忽略),例如删除 color:
{ "method": "delete", "state": { "reported": { "color": "" } }, "version": 4 }清空全部 reported 请逐键列出(删除分支是逐键移除,不识别整体字符串):
{ "method": "delete", "state": { "reported": { "color": "", "brightness": "" } }, "version": 4 }把 reported 整体写成字符串 "null"({ "method": "delete", "state": { "reported": "null" } })在当前实现中会触发类型转换异常,设备只会收到 errorcode:500,请勿使用(见已知限制)。
清空全部 desired(在 update 方法中,desired 为任意非空字符串即触发清空):
{ "method": "update", "state": { "desired": "null" }, "version": 6 }当前实现不支持设备侧读取或删除单个 desired 键(见已知限制)。
错误回复
{ "method": "reply",
"payload": { "status": "error", "content": { "errorcode": 409, "errormessage": "shadow version conflict" } },
"clientToken": null, "timestamp": 1700000000000 }| errorcode | 含义 |
|---|---|
| 400 | payload 不是合法 JSON |
| 401 | method 为空 |
| 402 | state 为空 |
| 403 | version 不是整数 |
| 404 | state.reported 为空 |
| 405 | state.reported 为空对象 |
| 406 | method 不是 get/update/delete |
| 408 | reported 键数量超过 128 |
| 409 | 版本号冲突(未大于已存版本) |
| 410 | version 缺失 |
| 500 | 平台内部异常 |
云端修改影子时的下发
后台/规则更新影子后,平台向 /shadow/get/{pk}/{dn} 推送:
{
"method": "control",
"timestamp": 1700000000000,
"payload": {
"state": {
"reported": { "color": "red" },
"desired": { "color": "green" }
},
"metadata": {
"reported": { "color": { "timestamp": 1700000000000 } },
"desired": { "color": { "timestamp": 1700000000000 } }
}
},
"version": 3
}设备要把 method 为 control 与 reply 的消息分开处理。注意当前实现后台更新影子时库内版本 +1,而推送报文里的版本号又在此基础上再 +1(即比设备拉取影子看到的版本大 1,见已知限制),设备端不要假设 version 连续递增步长为 1。