物联网平台支持创建设备的“影子”设备影子是一个JSON文档,用于存储设备上报状态、在线状态、设备最近一次上报的设备属性值以及应用服务器期望下发的配应用程序期望状态信息。
每个设备有且只有一个设备影子,设备可以通过MQTT获取和设置设备影子来同步状态,该同步可以是影子同步给设备,也可以是设备同步给影子。
应用场景
- 场景1:网络不稳定,设备频繁上下线。由于网络不稳定,设备频繁上下线。应用程序发出需要获取当前的设备状态请求时,设备掉线,无法获取设备状态,但下一秒设备又连接成功,应用程序无法正确发起请求。
使用设备影子机制存储设备最新状态,一旦设备状态产生变化,设备会将状态同步到设备影子。应用程序在请求设备当前状态时,只需要获取影子中的状态即可,不需要关心设备是否在线。 - 场景2:多程序同时请求获取设备状态。如果设备网络稳定,很多应用程序请求获取设备状态,设备需要根据请求响应多次,即使响应的结果是一样的,设备本身处理能力有限,无法负载被请求多次的情况。
使用设备影子机制,设备只需要主动同步状态给设备影子一次,多个应用程序请求设备影子获取设备状态,即可获取设备最新状态,做到应用程序和设备的解耦。 - 场景3:设备掉线。
- 设备网络不稳定,导致设备频繁上下线,应用程序发送控制指令给设备时,设备掉线,指令无法下达到设备。
- 通过QoS=1或者2实现,但是该方法对于服务端的压力比较大,一般不建议使用。
- 使用设备影子机制,应用程序发送控制指令,指令携带时间戳保存在设备影子中。当设备掉线重连时,获取指令并根据时间戳确定是否执行。
- 设备真实掉线,指令发送失败。设备再上线时,设备影子功能通过指令加时间戳的模式,保证设备不会执行过期指令。
- 设备网络不稳定,导致设备频繁上下线,应用程序发送控制指令给设备时,设备掉线,指令无法下达到设备。
设备影子数据流
设备影子上有desired区和report区。
- desired区用于存储对设备属性的配置,即期望值。当需要修改设备的服务属性值时,可修改设备影子的desired属性值,设备在线时,desired属性值立即同步到设备。如果设备不在线,待设备上线或上报数据时,desired属性值同步到设备。
- report区用于存储设备最新上报的设备属性值,即上报值。当设备上报数据时,平台刷新report属性值为设备上报的设备属性值。
说明:
设备影子可以通过调用应用侧API接口配置,也可以通过登录控制台,在设备详情->设备影子->属性配置页面配置。(设备影子主要针对设备属性配置,它的配置依赖产品模型)。
设备影子配置属于异步命令,物联网平台会直接回复配置响应,然后平台通过设备在线状态,决定立即下发还是缓存下发。
设备上线后,影子服务会下发desired值给设备,待设备属性上报时,影子服务检查属性值与下发的desired值是否匹配。若匹配,则说明影子数据在设备侧配置成功,缓存清除;若不匹配,则说明影子数据在设备侧未配置成功,在下次设备上线或属性上报时,会继续下发缓存desired值给设备,直到下发配置成功。
通用业务流程
设备主动上报状态
设备在线时,主动上报设备状态到影子,应用程序主动获取设备影子状态。
数据流转过程如下图所示。
当灯泡lightbulb上线时,使用Topic
/shadow/update/a1PbRCF****/lightbulb
上报最新状态到影子。发送的JSON消息格式:{
"method": "update",
"state": {
"reported": {
"color": "red"
}
},
"version": 1
}
表 1. 上报参数说明 | 参数 | 说明 | | :—- | :—- | | method | 表示设备或者应用程序请求设备影子时的操作类型。当执行更新操作时,method为必填字段,设置为update。 | | state | 表示设备发送给设备影子的状态信息。reported为必填字段,状态信息会同步更新到设备影子的reported部分。 | | version | 表示设备影子检查请求中的版本信息。只有当新版本大于当前版本时,设备影子才会接收设备端的请求,并更新设备影子版本。
如果version设置为-1
时,表示清空设备影子数据,设备影子会接收设备端的请求,并将设备影子版本更新为0
。 |设备影子接收到灯泡上报的状态数据后,更新影子文档。
{
"state": {
"reported": {
"color": "red"
}
},
"metadata": {
"reported": {
"color": {
"timestamp": 1469564492
}
}
},
"timestamp": 1469564492,
"version": 1
}
影子文件更新后,设备影子会返回结果给设备(灯泡),即发送消息到设备订阅的Topic
/shadow/get/a1PbRCF****/lightbulb
中。若更新成功,发送到该Topic中的消息为:
{
"method": "reply",
"payload": {
"status": "success",
"version": 1
},
"timestamp": 1469564576
}
若更新失败,发送到该Topic中的消息为:
{
"method": "reply",
"payload": {
"status": "error",
"content": {
"errorcode": "${errorcode}",
"errormessage": "${errormessage}"
}
},
"timestamp": 1469564576
}
表 2. 错误码说明 | errorCode | errorMessage | | :—- | :—- | | 400 | 不正确的JSON格式。 | | 401 | 影子数据缺少method信息。 | | 402 | 影子数据缺少state字段。 | | 403 | 影子数据中version值不是数字。 | | 404 | 影子数据缺少reported字段。 | | 405 | 影子数据中 reported属性字段为空。 | | 406 | 影子数据中 method是无效的方法。 | | 407 | 影子内容为空。 | | 408 | 影子数据中reported属性个数超过128个。 | | 409 | 影子版本冲突。 | | 500 | 服务端处理异常。 |
修改设备属性值
修改desired属性值,如果设备在线,则设备影子直接同步设备属性值到设备,否则等待设备上线或上报数据时,再同步设备属性值到设备。
应用程序调用云端API UpdateDeviceShadow,下发消息要求更改灯泡状态,例如要求将灯泡的color属性值改为green。调用API时,参数ShadowMessage的值为:
{
"method": "update",
"state": {
"desired": {
"color": "green"
}
},
"version": 2
}
设备影子接收到更新请求,更新其影子文档为:
{
"state": {
"reported": {
"color": "red"
},
"desired": {
"color": "green"
}
},
"metadata": {
"reported": {
"color": {
"timestamp": 1469564492
}
},
"desired": {
"color": {
"timestamp": 1469564576
}
}
},
"timestamp": 1469564576,
"version": 2
}
设备影子更新完成后,发送返回结果到Topic
/shadow/get/a1PbRCF****/lightbulb
中。返回结果信息构成由设备影子决定。{
"method": "control",
"payload": {
"state": {
"reported": {
"color": "red"
},
"desired": {
"color": "green"
}
},
"metadata": {
"reported": {
"color": {
"timestamp": 1469564492
}
},
"desired": {
"color": {
"timestamp": 1469564576
}
}
}
},
"version": 2,
"timestamp": 1469564576
}
如果设备灯泡在线,并且订阅了Topic
/shadow/get/a1PbRCF****/lightbulb
,则会立即收到消息。收到消息后,根据请求文档中desired的值,将灯泡颜色变成绿色。
灯泡更新完状态后,上报最新状态到物联网平台。{
"method": "update",
"state": {
"reported": {
"color": "green"
}
},
"version": 3
}
说明 如果有时间戳判断指令过期,也可以选择不更新。最新状态上报成功后, 设备端和设备影子进行以下操作。
设备端发消息到Topic
/shadow/update/a1PbRCFQWfX/lightbulb
中清空desired属性。消息如下:{
"method": "update",
"state": {
"desired": "null"
},
"version": 4
}
设备影子会同步更新影子文档,此时的影子文档如下:
{
"state": {
"reported": {
"color": "green"
}
},
"metadata": {
"reported": {
"color": {
"timestamp": 1469564577
}
},
"desired": {
"timestamp": 1469564576
}
},
"version": 4
}
查询设备属性值
设备影子保存的是设备最新的设备属性值,一旦设备属性值产生变化,设备会将设备属性值同步到设备影子。用户便可以及时获取查询结果,无需关注设备是否在线。
若应用程序发送指令时,设备离线。设备再次上线后,将主动获取设备影子内容。
数据流转过程如下图所示。
灯泡主动发送以下消息到Topic
/shadow/update/a1PbRCF****/lightbulb
中,请求获取设备影子中保存的最新状态。{
"method": "get"
}
当设备影子收到这条消息后,发送最新状态到Topic
/shadow/get/a1PbRCF****/lightbulb
。灯泡通过订阅该Topic获取最新状态。消息内容如下:{
"method": "reply",
"payload": {
"status": "success",
"state": {
"reported": {
"color": "red"
},
"desired": {
"color": "green"
}
},
"metadata": {
"reported": {
"color": {
"timestamp": 1469564492
}
},
"desired": {
"color": {
"timestamp": 1469564492
}
}
}
},
"version": 2,
"timestamp": 1469564576
}
设备主动删除影子属性
若设备端已经是最新状态,设备端可以主动发送指令,删除设备影子中保存的某条属性状态。
数据流转过程如下图所示。
设备发送以下内容到Topic/shadow/update/a1PbRCF****/lightbulb
中。
其中,method为delete,属性的值为null。
删除影子中某一属性。
{
"method": "delete",
"state": {
"reported": {
"color": "null",
"temperature": "null"
}
},
"version": 1
}
删除影子全部属性。
{
"method": "delete",
"state": {
"reported": "null"
},
"version": 1
}