--- title: "设备状态副本" weight: 20 summary: "物理设备报告状态或所需未来状态的逻辑表示。" --- ## 挑战 IoT 解决方案需要与设备进行交互以执行并跟踪设备状态变化。这种挑战有两种表现方式。首先,即使在经历间歇性网络中断时,IoT 解决方案也需要设备执行改变状态的动作。其次,设备需要 IoT 解决方案来反映设备上发生的状态变化。 验证状态变化是所有命令和控制场景下所必需的关键功能。 ## 解决方案 利用了"设备状态副本“设计的 IoT 解决方案能够以可靠,可扩展且直接的方式管理与设备相关的状态变化。 "设备状态副本"设计描述了如何复制设备的当前状态,期望的未来状态以及当前状态和期望状态之间的差异。"设备状态副本"设计类似于"[命令]({{}})"设计,因为它们都使用[消息]({{}})作为动作触发器和动作完成的确认消息。但是,设备状态副本设计比命令设计更进一步,通过规范化的方式来进行设备相关状态的管理以及状态和变化的通信。使用"设备状态副本"设计允许 IoT 解决方案了解并验证设备状态和状态变化。 ### 组件到设备的状态副本 当 IoT 解决方案的某个*组件*是期望状态变化的发起者,而且变化需要被复制到设备端时,那以下的设计可以为 IoT 解决方案所用: ![Component-to-device State Replica](c2d-state.png) ### 组件到设备的步骤说明 1. 设备以[消息]({{}})的方式在`state/deviceID/update` [主题]({{< ref "/glossary/vocabulary#消息主题message-topic" >}}) 上发布状态,从而报告“初始设备状态” 2. 追踪这个设备的"设备状态副本"会从`state/deviceID/update`主题读取消息,并将设备状态保存在一个持久化的数据存储中 3. 设备订阅差异消息主题`state/deviceID/update/delta`,设备相关的状态变更消息会发送到该主题 4. IoT 解决方案中的某个组件会将期望状态消息发布到主题`state/deviceID/update`,追踪这个设备的设备状态副本会将期望设备状态记录在一个持久化的数据存储中 5. 设备状态副本会在主题`state/deviceID/update/delta`上发布一个差异消息,服务器将该消息发送给设备 6. 设备获取差异消息,并进行期望状态的变更 7. 设备发送一个反映新状态的消息到更新主题`state/deviceID/update`,同时追踪这个设备的设备状态副本会把新状态记录在持久化数据存储中 8. 设备状态副本发布消息到主题`state/deviceID/update/accepted` 9. IoT 解决方案中的组件可以从设备状态副本中请求到更新后且是当前的状态 ### 设备到组件的状态副本 当*设备*是状态变更的发起者,而且状态变更需要通知到 IoT 解决方案中的组件时,以下设计可以为 IoT 解决方案所用: ![Device-to-component State Replica](d2c-state.png) ### 设备到组件的步骤说明 1. 设备以消息的方式在更新主题`state/deviceID/update`上发布状态,从而报告“初始设备状态” 2. 组件订阅差异消息主题`state/deviceID/update/delta`,与设备相关的状态变更消息会发布到该主题上 3. 设备检测到自身状态发生变化,并在更新主题`state/deviceID/update`上报告新的状态值 4. 追踪该设备的设备状态副本会将期望设备状态记录在一个持久化的数据存储中 5. 设备状态副本在主题`state/deviceID/update/delta`上发布差异消息,服务器将该消息发送给订阅该主题的组件 6. 组件接受到差异消息,根据需要使用变化后的值 ## 考虑点 当实现这个设计时,需要考虑如下问题: #### 组件如何简单的获取设备状态副本的当前状态 组件可以采用发布/订阅模式,监听`state/deviceID/get/accepted`和`state/deviceID/get/rejected`两个主题,并发送消息到`state/deviceID/get`主题。设备状态副本会在`state/deviceID/get/accepted`主题上回复状态。如果设备状态副本对外暴露一个 REST 接口,那组件可以对`state/deviceID/get`主题发起一个 GET 操作并获得直接的响应。 #### 设备如何知道在其离线期间发生的变化? 当设备连接或重连时,第一个应该采取的动作是获取当前期望状态并与其已最后已知状态进行对比。理想情况下监控设备状态副本的服务器应该可以自动计算出差异值,因此发起连接的设备需要订阅`state/deviceID/update/delta`主题,以便可以应对其离线状态时发生的变化。 ## 示例