

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 在设备中使用影子
<a name="device-shadow-comms-device"></a>

本节介绍使用 MQTT 消息与影子进行设备通信，MQTT 消息是设备与 Device Shadow 服务通信的 AWS IoT 首选方法。

影子通信使用 request/response MQTT 的发布/订阅通信模型来模拟模型。每个影子操作包含请求主题、成功的响应主题 (`accepted`) 和错误响应主题 (`rejected`)。

如果您希望应用程序和服务能够确定是否连接了设备，请参阅 [检测是否连接了设备](device-shadow-comms-app.md#thing-connection)。

**重要**  
由于 MQTT 使用 publish/subscribe 通信模型，因此您应该在发布请求主题*之前*订阅响应主题。否则，您不会收到您发布请求的响应。  
如果您使用调用 De [AWS IoT Device SDK](iot-sdks.md)vice Shadow 服务 APIs，则由您处理。

本节中的示例使用主题的缩写形式，其中*ShadowTopicPrefix*可以指已命名或未命名的影子，如下表所述。

影子可以是命名或未命名（经典）的。每个影子使用的主题仅在主题前缀上有所不同。下表显示每种影子类型使用的主题前缀。


| *ShadowTopicPrefix* 值 | 影子类型 | 
| --- | --- | 
| \$1aws/things/thingName/shadow | 未命名的（经典）影子 | 
| \$1aws/things/thingName/shadow/name/shadowName | 命名的影子 | 

**重要**  
确保应用程序或服务使用的影子与设备中的相应实施保持一致，并且该实施支持使用这些影子。例如，考虑如何创建、更新和删除影子。还要考虑如何在设备以及通过影子访问设备的应用程序或服务中处理更新。您的设计应明确指定如何更新和报告设备的状态，以及应用程序和服务如何与设备及其影子进行交互。

要创建完整的主题，请为要表示的影子类型选择 `ShadowTopicPrefix`，将 `thingName` 和 `shadowName`（如果适用）替换为相应的值，然后在其后面附加主题存根，如下表中所示。请记住，主题区分大小写。

有关影子的保留主题的更多信息，请参阅 [影子主题](reserved-topics.md#reserved-topics-shadow)。

## 在首次连接设备时初始化设备 AWS IoT
<a name="device-shadow-comms-device-first-connect"></a>

设备注册后 AWS IoT，应订阅这些 MQTT 消息以获取其支持的阴影。


| Topic | 含义 | 在收到该主题时设备应执行的操作 | 
| --- | --- | --- | 
|  `ShadowTopicPrefix/delete/accepted`  |  `delete`请求被接受并 AWS IoT 删除了影子。  |  为满足删除的影子要求而需要执行的操作，例如，停止发布更新。  | 
|  `ShadowTopicPrefix/delete/rejected`  |  `delete`请求被拒绝 AWS IoT ，影子未被删除。消息正文包含错误信息。  |  响应消息正文中的错误消息。  | 
|  `ShadowTopicPrefix/get/accepted`  |  `get`请求已被接受 AWS IoT，消息正文包含当前的影子文档。  |  处理消息正文中的状态文档所需的操作。  | 
|  `ShadowTopicPrefix/get/rejected`  |  `get`请求被拒绝 AWS IoT，消息正文包含错误信息。  |  响应消息正文中的错误消息。  | 
|  `ShadowTopicPrefix/update/accepted`  |  `update`请求已被接受 AWS IoT，消息正文包含当前的影子文档。  |  确认消息正文中的更新数据与设备状态匹配。  | 
|  `ShadowTopicPrefix/update/rejected`  |  `update`请求被拒绝 AWS IoT，消息正文包含错误信息。  |  响应消息正文中的错误消息。  | 
|  `ShadowTopicPrefix/update/delta`  |  对的请求更新了影子文档 AWS IoT，邮件正文包含所请求的更改。  |  更新设备的状态以与消息正文中的所需状态匹配。  | 
|  `ShadowTopicPrefix/update/documents`  |  最近完成了影子更新，并且消息正文包含当前影子文档。  |  确认消息正文中的更新状态与设备的状态匹配。  | 

在为每个影子订阅上表中的消息后，设备应进行测试，以确定是否已将 `/get` 主题发布到它支持的每个影子以创建这些影子。如果收到 `/get/accepted` 消息，则消息正文包含影子文档，设备可以使用该文档初始化其状态。如果收到 `/get/rejected` 消息，应发布具有当前设备状态的 `/update` 消息以创建影子。

例如，假设您有事物 `My_IoT_Thing`，但其没有任何经典或命名影子。如果现在发布关于预留主题 `$aws/things/My_IoT_Thing/shadow/get` 的 `/get` 请求，其会在 `$aws/things/My_IoT_Thing/shadow/get/rejected` 主题返回一条错误，因为该事物没有任何影子。要想解决此错误，请先使用含当前设备状态（例如以下有效载荷）的 `$aws/things/My_IoT_Thing/shadow/update` 主题发布一条 `/update` 消息。

```
{
	"state": {
		"reported": {
			"welcome": "aws-iot",
			"color": "yellow"
		}
	}
}
```

现在为该事物创建了经典影子，消息将发布到 `$aws/things/My_IoT_Thing/shadow/update/accepted` 主题。如果发布到 `$aws/things/My_IoT_Thing/shadow/get` 主题，其会将含设备状态的响应返回到 `$aws/things/My_IoT_Thing/shadow/get/accepted` 主题。

对于命名影子，必须先创建命名影子或发布含影子名称的更新，才能使用 get 请求。例如，要创建命名影子 `namedShadow1`，首先将设备状态信息发布到 `$aws/things/My_IoT_Thing/shadow/name/namedShadow1/update` 主题。若要检索状态信息，请将 `/get` 请求用于命名影子 `$aws/things/My_IoT_Thing/shadow/name/namedShadow1/get`。

## 在设备连接时处理消息 AWS IoT
<a name="device-shadow-comms-device-while-connected"></a>

当设备连接时 AWS IoT，它可以接收 **/update/delta** 消息，并应通过以下方式使设备状态与其阴影中的变化保持一致：

1. 读取所有收到的 **/update/delta** 消息并同步设备状态以保持匹配。

1. 以 `reported` 消息正文发布 **/update** 消息，该消息正文包含设备的当前状态，无论设备状态何时发生变化。

在连接设备后，它应在出现指示时发布这些消息。


| 指示 | Topic | 有效载荷 | 
| --- | --- | --- | 
|  设备的状态已发生变化。  |  `ShadowTopicPrefix/update`  |  具有 `reported` 属性的影子文档。  | 
| 设备可能与影子不同步。 |  `ShadowTopicPrefix/get`  | （空） | 
|  对设备执行的操作指示设备不再支持影子，例如在移除或更换设备时。  |  `ShadowTopicPrefix/delete`  | （空） | 

## 设备重新连接时处理消息 AWS IoT
<a name="device-shadow-comms-device-reconnect"></a>

当带有一个或多个阴影的设备连接到时 AWS IoT，它应通过以下方式将其状态与其支持的所有阴影的状态同步：

1. 读取所有收到的 **/update/delta** 消息并同步设备状态以保持匹配。

1. 使用 `reported` 消息正文发布 **/update** 消息，该消息正文包含设备的当前状态。