

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

# 与影子交互
<a name="device-shadow-data-flow"></a>

本主题介绍了 AWS IoT 为处理影子而提供的三种方法的关联消息。这些方法包括：

`UPDATE`  <a name="update"></a>
创建影子（如果不存在），或使用消息正文中提供的状态信息更新现有影子的内容。 AWS IoT 记录每次更新的时间戳，以指示上次更新状态的时间。当影子的状态发生变化时， AWS IoT 会向所有 MQTT 订阅者发送带有`desired`和`reported`状态差异的`/delta`消息。收到 `/delta` 消息的设备或应用程序可以根据该差异执行操作。例如，设备可以将其状态更新为所需的状态，或者应用程序可以更新其 UI 以反映设备的状态变化。

`GET`  <a name="get"></a>
检索包含影子的完整状态的当前影子文档，包括元数据。

`DELETE`  <a name="delete"></a>
删除设备影子及其内容。  
您无法还原已删除的设备影子文档，但可以创建具有已删除设备影子文档的名称的新设备影子。如果您创建的设备影子文档与过去48小时内删除的文档同名，新设备影子文档的版本号和已删除文档的版本号相同。如果设备影子文档已删除超过 48 小时，具有相同名称的新设备影子文档的版本号为 0。

## 协议支持
<a name="protocol-support"></a>

AWS IoT 支持 [MQTT](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/mqtt-v3.1.1.html) 和通过 HTTPS 协议的 REST API 来与阴影进行交互。 AWS IoT 为 MQTT 发布和订阅操作提供了一组保留的请求和响应主题。设备和应用程序应在发布请求主题之前订阅响应主题，以获取有关如何 AWS IoT 处理请求的信息。有关更多信息，请参阅[Device Shadow MQTT 主题](device-shadow-mqtt.md)和[Device Shadow REST API](device-shadow-rest-api.md)。

## 请求和报告状态
<a name="shadow-reporting-state"></a>

在使用 AWS IoT and shadows 设计物联网解决方案时，应确定将请求更改的应用程序或设备以及将实施变更的应用程序或设备。通常，设备实施更改并向影子报告更改，而应用程序和服务响应并请求影子中的更改。您的解决方案可能有所不同，但本主题中的示例假定客户端应用程序或服务请求影子中的更改，而设备执行更改并向影子报告更改。

## 更新影子
<a name="update-device-shadow"></a>

应用程序或服务可以使用 [UpdateThingShadow](device-shadow-rest-api.md#API_UpdateThingShadow) API 或发布到 [/update](device-shadow-mqtt.md#update-pub-sub-topic) 主题以更新影子的状态。更新仅影响请求中指定的字段。

### 在客户端请求状态更改时更新影子
<a name="update-pub-sub-topic-client"></a>

**在客户端使用 MQTT 协议请求影子中的状态更改时**

1. 客户端应具有当前影子文档，以便它可以确定要更改的属性。有关如何获取当前影子文档的信息，请参阅 /get 操作。

1. 客户端订阅以下 MQTT 主题：
   + `$aws/things/thingName/shadow/name/shadowName/update/accepted`
   + `$aws/things/thingName/shadow/name/shadowName/update/rejected`
   + `$aws/things/thingName/shadow/name/shadowName/update/delta`
   + `$aws/things/thingName/shadow/name/shadowName/update/documents`

1. 客户端使用包含影子的所需状态的状态文档发布 `$aws/things/thingName/shadow/name/shadowName/update` 请求主题。只需在文档中包含要更改的属性。以下是具有所需状态的文档的示例。

   ```
   {
     "state": {
       "desired": {
         "color": {
           "r": 10
         },
         "engine": "ON"
       }
     }
   }
   ```

1. 如果更新请求有效，则在影子中 AWS IoT 更新所需的状态并发布有关以下主题的消息：
   + `$aws/things/thingName/shadow/name/shadowName/update/accepted`
   + `$aws/things/thingName/shadow/name/shadowName/update/delta`

   `/update/accepted` 消息包含一个 [/accepted 响应状态文档](device-shadow-document.md#device-shadow-example-response-json-accepted) 影子文档，而 `/update/delta` 消息包含一个 [/delta 响应状态文档](device-shadow-document.md#device-shadow-example-response-json-delta) 影子文档。

1. 如果更新请求无效，则 AWS IoT 发布带有`$aws/things/thingName/shadow/name/shadowName/update/rejected`主题的消息以及描述错误的[错误响应文档](device-shadow-document.md#device-shadow-example-error-json)影子文档。

**在客户端使用 API 请求影子中的状态更改时**

1. 客户端调用 `UpdateThingShadow` API 并将 [请求状态文档](device-shadow-document.md#device-shadow-example-request-json) 状态文档作为其消息正文。

1. 如果请求有效，则 AWS IoT 返回一个 HTTP 成功响应代码和一个[/accepted 响应状态文档](device-shadow-document.md#device-shadow-example-response-json-accepted)影子文档作为其响应消息正文。

   AWS IoT 还将向该`$aws/things/thingName/shadow/name/shadowName/update/delta`主题发布 MQTT 消息，其中包含订阅该消息的任何设备或客户端的[/delta 响应状态文档](device-shadow-document.md#device-shadow-example-response-json-delta)影子文档。

1. 如果请求无效，则 AWS IoT 返回 HTTP 错误响应代码 a [错误响应文档](device-shadow-document.md#device-shadow-example-error-json) 作为其响应消息正文。

当设备在 `/update/delta` 主题上收到 `/desired` 状态时，它将在设备中进行所需的更改。然后，它向 `/update` 主题发送一条消息，以向影子报告其当前状态。

### 在设备报告其当前状态时更新影子
<a name="update-pub-sub-topic-device"></a>

**在设备使用 MQTT 协议向影子报告其当前状态时**

1. 在更新影子之前，设备应订阅以下 MQTT 主题：
   + `$aws/things/thingName/shadow/name/shadowName/update/accepted`
   + `$aws/things/thingName/shadow/name/shadowName/update/rejected`
   + `$aws/things/thingName/shadow/name/shadowName/update/delta`
   + `$aws/things/thingName/shadow/name/shadowName/update/documents`

1. 设备向 `$aws/things/thingName/shadow/name/shadowName/update` 主题发布一条消息以报告其当前状态，例如，在该示例中。

   ```
   {
       "state": {
           "reported" : {
               "color" : { "r" : 10 },
               "engine" : "ON"
           }
       }
   }
   ```

1. 如果 AWS IoT 接受更新，则会向`$aws/things/thingName/shadow/name/shadowName/update/accepted`主题发布带有[/accepted 响应状态文档](device-shadow-document.md#device-shadow-example-response-json-accepted)影子文档的消息。

1. 如果更新请求无效，则 AWS IoT 发布带有`$aws/things/thingName/shadow/name/shadowName/update/rejected`主题的消息以及描述错误的[错误响应文档](device-shadow-document.md#device-shadow-example-error-json)影子文档。

**在设备使用 API 向影子报告其当前状态时**

1. 设备调用 `UpdateThingShadow` API 并将 [请求状态文档](device-shadow-document.md#device-shadow-example-request-json) 状态文档作为其消息正文。

1. 如果请求有效，则 AWS IoT 更新影子并返回以影子文档作为其响应消息正文的 HTTP 成功响应代码。[/accepted 响应状态文档](device-shadow-document.md#device-shadow-example-response-json-accepted)

   AWS IoT 还将向该`$aws/things/thingName/shadow/name/shadowName/update/delta`主题发布 MQTT 消息，其中包含订阅该消息的任何设备或客户端的[/delta 响应状态文档](device-shadow-document.md#device-shadow-example-response-json-delta)影子文档。

1. 如果请求无效，则 AWS IoT 返回 HTTP 错误响应代码 a [错误响应文档](device-shadow-document.md#device-shadow-example-error-json) 作为其响应消息正文。

### 乐观锁
<a name="optimistic-locking"></a>

您可以使用状态文档版本来确保正在更新的设备影子文档为最新版本。当您为更新请求提供版本时，如果状态文档的当前版本与提供的版本不符，该服务将显示 HTTP 409 冲突响应代码并拒绝请求。冲突响应代码也可能出现在任何修改 `ThingShadow` 的 API 上，包括 `DeleteThingShadow`。

例如：

初始文档：

```
{
  "state": {
    "desired": {
      "colors": [
        "RED",
        "GREEN",
        "BLUE"
      ]
    }
  },
  "version": 10
}
```

更新：（版本不匹配；该请求将被拒绝）

```
{
  "state": {
    "desired": {
      "colors": [
        "BLUE"
      ]
    }
  },
  "version": 9
}
```

结果：

```
{
  "code": 409,
  "message": "Version conflict",
  "clientToken": "426bfd96-e720-46d3-95cd-014e3ef12bb6"
}
```

更新：（版本匹配；请求将被接受）

```
{
  "state": {
    "desired": {
      "colors": [
        "BLUE"
      ]
    }
  },
  "version": 10
}
```

最终状态：

```
{
  "state": {
    "desired": {
      "colors": [
        "BLUE"
      ]
    }
  },
  "version": 11
}
```

## 检索影子文档
<a name="retrieving-device-shadow"></a>

您可以使用 [GetThingShadow](device-shadow-rest-api.md#API_GetThingShadow) API 或订阅并发布到 [/get](device-shadow-mqtt.md#get-pub-sub-topic) 主题以检索影子文档。这会检索完整的影子文档，包括 `desired` 和 `reported` 状态之间的任何增量。无论设备还是客户端发出请求，该任务的流程都是相同的。

**使用 MQTT 协议检索影子文档**

1. 在更新影子之前，设备或客户端应订阅以下 MQTT 主题：
   + `$aws/things/thingName/shadow/name/shadowName/get/accepted`
   + `$aws/things/thingName/shadow/name/shadowName/get/rejected`

1. 设备或客户端使用空消息正文向 `$aws/things/thingName/shadow/name/shadowName/get` 主题发布一条消息。

1. 如果请求成功，则向`$aws/things/thingName/shadow/name/shadowName/get/accepted`主题 AWS IoT 发布一条消息，消息正文[/accepted 响应状态文档](device-shadow-document.md#device-shadow-example-response-json-accepted)中包含一个。

1. 如果请求无效，则向`$aws/things/thingName/shadow/name/shadowName/get/rejected`主题 AWS IoT 发布一条消息，并在消息正文[错误响应文档](device-shadow-document.md#device-shadow-example-error-json)中加上。

**使用 REST API 检索影子文档**

1. 设备或客户端使用空消息正文调用 `GetThingShadow` API。

1. 如果请求有效，则 AWS IoT 返回一个 HTTP 成功响应代码，其响应消息正文为[/accepted 响应状态文档](device-shadow-document.md#device-shadow-example-response-json-accepted)影子文档。

1. 如果请求无效，则 AWS IoT 返回一个 HTTP 错误响应代码[错误响应文档](device-shadow-document.md#device-shadow-example-error-json)作为其响应消息正文。

## 删除影子数据
<a name="deleting-thing-data"></a>

可以使用两种方法删除影子数据：您可以在影子文档中删除特定的属性，也可以完全删除影子。
+ 要从影子中删除特定的属性，请更新影子，但将您要删除的属性的值设置为 `null`。将从影子文档中删除值为 `null` 的字段。
+ 要删除整个影子，请使用 [DeleteThingShadow](device-shadow-rest-api.md#API_DeleteThingShadow) API 或发布到 [/delete](device-shadow-mqtt.md#delete-pub-sub-topic) 主题。

**注意**  
删除影子不会立即将其版本号重置为 0。将在 48 小时后重置为零。

### 从影子文档中删除属性
<a name="deleting-shadow-property"></a>

**使用 MQTT 协议从影子中删除属性**

1. 设备或客户端应具有当前影子文档，以便它可以确定要更改的属性。有关如何获取当前影子文档的信息，请参阅 [检索影子文档](#retrieving-device-shadow)。

1. 设备或客户端订阅以下 MQTT 主题：
   + `$aws/things/thingName/shadow/name/shadowName/update/accepted`
   + `$aws/things/thingName/shadow/name/shadowName/update/rejected`

1. 设备或客户端使用将 `null` 值分配给要删除的影子属性的状态文档以发布 `$aws/things/thingName/shadow/name/shadowName/update` 请求主题。只需在文档中包含要更改的属性。以下是删除 `engine` 属性的文档的示例。

   ```
   {
     "state": {
       "desired": {
         "engine": null
       }
     }
   }
   ```

1. 如果更新请求有效，则 AWS IoT 删除影子中的指定属性，并发布带有`$aws/things/thingName/shadow/name/shadowName/update/accepted`主题的消息，消息正文中包含[/accepted 响应状态文档](device-shadow-document.md#device-shadow-example-response-json-accepted)影子文档。

1. 如果更新请求无效，则 AWS IoT 发布带有`$aws/things/thingName/shadow/name/shadowName/update/rejected`主题的消息以及描述错误的[错误响应文档](device-shadow-document.md#device-shadow-example-error-json)影子文档。

**使用 REST API 从影子中删除属性**

1. 设备或客户端使用 [请求状态文档](device-shadow-document.md#device-shadow-example-request-json) 将 `null` 值分配给要删除的影子属性的以调用 `UpdateThingShadow` API。仅在文档中包含要删除的属性。以下是删除 `engine` 属性的文档的示例。

   ```
   {
     "state": {
       "desired": {
         "engine": null
       }
     }
   }
   ```

1. 如果请求有效，则 AWS IoT 返回一个 HTTP 成功响应代码和一个[/accepted 响应状态文档](device-shadow-document.md#device-shadow-example-response-json-accepted)影子文档作为其响应消息正文。

1. 如果请求无效，则 AWS IoT 返回 HTTP 错误响应代码 a [错误响应文档](device-shadow-document.md#device-shadow-example-error-json) 作为其响应消息正文。

### 删除影子
<a name="deleting-device-shadow"></a>

以下是删除设备影子时的一些注意事项。
+ 将设备的影子状态设置为 `null` 并不会删除影子。在下次更新时，影子版本将会增加。
+ 删除设备的影子并不会删除事物对象。删除事物对象并不会删除相应设备的影子。
+ 删除影子不会立即将其版本号重置为 0。将在 48 小时后重置为零。

**使用 MQTT 协议删除影子**

1. 设备或客户端订阅以下 MQTT 主题：
   + `$aws/things/thingName/shadow/name/shadowName/delete/accepted`
   + `$aws/things/thingName/shadow/name/shadowName/delete/rejected`

1. 设备或客户端使用空消息缓冲区发布 `$aws/things/thingName/shadow/name/shadowName/delete`。

1. 如果删除请求有效，则 AWS IoT 删除影子并在消息正文中发布带有`$aws/things/thingName/shadow/name/shadowName/delete/accepted`主题和缩写[/accepted 响应状态文档](device-shadow-document.md#device-shadow-example-response-json-accepted)影子文档的消息。以下是接受的删除消息的示例：

   ```
   {
     "version": 4,
     "timestamp": 1591057529
   }
   ```

1. 如果更新请求无效，则 AWS IoT 发布带有`$aws/things/thingName/shadow/name/shadowName/delete/rejected`主题的消息以及描述错误的[错误响应文档](device-shadow-document.md#device-shadow-example-error-json)影子文档。

**使用 REST API 删除影子**

1. 设备或客户端使用空消息缓冲区调用 `DeleteThingShadow` API。

1. 如果请求有效，则在消息正文中 AWS IoT 返回一个 HTTP 成功响应代码[/accepted 响应状态文档](device-shadow-document.md#device-shadow-example-response-json-accepted)和一个缩写的[/accepted 响应状态文档](device-shadow-document.md#device-shadow-example-response-json-accepted)影子文档。以下是接受的删除消息的示例：

   ```
   {
     "version": 4,
     "timestamp": 1591057529
   }
   ```

1. 如果请求无效，则 AWS IoT 返回 HTTP 错误响应代码 a [错误响应文档](device-shadow-document.md#device-shadow-example-error-json) 作为其响应消息正文。