--- title: "命令" weight: 11 --- 可靠地要求设备执行单个操作并确认状态的一个请求实体。 ## 挑战 IoT 解决方案应该能以这样的方式与设备进行交互:解决方案或是使用该解决方案的人,可以可靠地要求设备执行某个动作。更进一步的,这样的交互需要在会出现间隙性中断的网络环境中进行,并通常需要使用资源非常有限的设备。 ## 解决方案 IoT 解决方案使用"命令"设计来要求设备执行操作,并通过利用一个简单的概念确保可靠的交互:除非被确认为成功,否则任何请求的操作都不会被视为成功。 下图中显示的"命令"设计可以提供此功能: ![Command Design](command.png) ([PPTx](/iot-atlas-patterns.pptx)) ### 步骤说明 1. [设备]({{< ref"/glossary/vocabulary#设备device" >}})将自身配置为与协议端点通信,以便可以发送和接收命令消息。 2. 解决方案的一个组件发布针对一个或多个设备的[命令消息]({{}}) 3. 服务器使用协议端点将命令消息发送到每个先前配置的设备。 4. 完成命令的请求操作后,设备通过协议端点向服务器发布命令完成消息。 ## 考虑点 值得注意的是,"命令"设计并不是“反向遥测”。相反,"命令"设计解决了需要在远程位置运行的设备上可靠地触发操作的解决方案所固有的挑战。 实施此设计时,请考虑以下问题: #### 您是否首先考虑了"设备状态副本"设计 由于命令的执行实际上导致设备中状态的改变,因此"[设备状态副本]({{}})"设计是在 IoT 解决方案中执行命令的首选方法。在"设备状态副本"设计不适合或超过某些实现限制的情况下,请考虑"命令"设计并定制化实现控制。 #### 该解决方案如何跟踪每个设备的命令进度 每个命令都应具有解决方案唯一的类型,并且每个命令消息应包含全局唯一的消息 ID。命令消息的 ID 允许解决方案跟踪不同命令的状态,通过命令类型可以诊断不同命令类别的潜在问题。消息应该是幂等的,不允许在不知道设备*和*请求者的情况下被丢失或重复。 #### 解决方案中的某些命令运行时间是否明显超过正常范围 当某些命令的运行时间超过正常范围时,简单的返回“SUCCESS”或“FAILURE”命令完成消息是不足够的。相反,解决方案应该至少利用三个命令状态:“SUCCESS”,“FAILURE”和“RUNNING”。设备应在预期的时间间隔内返回“RUNNING”,直到命令完成。通过使用在预期间隔上报告的“RUNNING”状态,解决方案可以确定长时间运行的命令在什么时候事实上已经失败了。 #### 特定类型的命令是否需要人为授权 当解决方案中的命令需要人为批准才能在设备执行操作之前,应该在解决方案中添加人为工作流(human-workflow)组件。该组件将拦截特定类型的命令,并在将它们实际发送到设备之前将它们排队等待人工批准。 #### 是否需要将某种类型的命令回滚到先前的状态 如果解决方案有一些可能需要回退的命令,那么大部分时候从解决方案本身来管理回滚是更容易的,而不是期望每个设备理解并记住回滚注意事项。例如,向设备发送命令以便将执行器(actuator)从当前报告的位置`0`°移动到 `45`°的位置。设备成功执行了该命令。在稍后的时刻,解决方案要求设备返回到先前的状态,先前的状态通常更容易在解决方案本身中进行跟踪,而不是期望每个设备跟踪其先前的状态。这种情况的回滚将由解决方案来执行,即向设备发送命令以将其位置改变为`0`°。 如果在没有与服务器连接的情况下也需要回滚的话,那解决方案可以利用[网关]({{}})来记录设备的先前状态并执行基于这些值的回滚。 ## 示例 ### 可靠传输上的简单的请求/响应 组件向设备发出启动电机的请求,并通过服务质量(Quality of Service)以保证命令传达。 #### 组件向目标设备发送命令 组件将命令请求消息发送到设备订阅的`commands/deviceID`主题: ```json { "cmd": "MOTOR_1_ON", "tid": "CAFED00D", "status": "REQUEST" } ``` 该组件同时跟踪消息的事务 ID “CAFED00D”,该消息已发布但未完成。 #### 设备处理消息 设备从主题`commands/deviceID`接收消息,启动`motor 1`,并对组件订阅的主题`commands/deviceID/ack`进行确认响应。该组件在一段时间后收到以下确认: ```json { "tid": "CAFED00D", "status": "SUCCESS" } ``` #### 设备与组件完成命令(事务)处理 设备不再跟踪命令请求。组件将`SUCCESS`值映射到`CAFED00D'的事务 ID,并从未完成的请求列表中删除该事务,表示该命令已完成。 “FAILURE”的结果可能表示需要调查物理设备问题。 ### 与离线或不可用设备相关的事务 组件向设备发出请求以启动电机,但设备处于离线状态 #### 组件向不可用设备发送命令 组件将命令请求消息发送到设备订阅的`commands/deviceID`主题: ```json { "cmd": "MOTOR_1_ON", "tid": "CAFED00D", "status": "REQUEST" } ``` 该组件还跟踪“CAFED00D”的消息事务 ID,该消息已发布且未完成。 **设备处于离线状态,但未收到消息。** #### 超时并重新发送命令 在一段设定的时间之后,组件将基于线性或退避(back-off)时间段,并使用*相同的事务 ID*重新发送命令请求消息,同时跟踪重试状态。经过一定次数的重试后,组件将确定设备没有收到命令,或者无法回复,并采取适当的措施。