

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

# AWS IoT Device Shadow 服务
<a name="iot-device-shadows"></a>

 AWS IoT Device Shadow 服务为 AWS IoT 事物对象添加阴影。无论设备是否已连接，Shadows 都可以将设备的状态提供给 AWS IoT 应用程序和其他服务。 AWS IoT 事物对象可以有多个命名的阴影，这样您的物联网解决方案就有更多选项可以将您的设备连接到其他应用程序和服务。

AWS IoT 事物对象在明确创建之前没有任何阴影。可以使用 AWS IoT 控制台创建、更新和删除阴影。设备、其它 Web 客户端和服务可以使用 MQTT 和[预留的 MQTT 主题](reserved-topics.md#reserved-topics-shadow)、使用 [Device Shadow REST API](device-shadow-rest-api.md) 的 HTTP 以及[适用于 AWS IoT的AWS CLI](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/iot-data/index.html) 创建、更新和删除影子。由于影子存储 AWS 在云中，因此无论设备是否已连接，它们都可以从应用程序和其他云服务中收集和报告设备状态数据。

## 使用影子
<a name="device-shadow-using"></a>

影子为设备、应用程序和其它云服务提供可靠的数据存储以共享数据。它们允许设备、应用程序和其它云服务连接和断开连接，而不会丢失设备的状态。

当设备、应用程序和其他云服务连接到时 AWS IoT，它们可以通过设备的阴影访问和控制设备的当前状态。例如，应用程序可以通过更新影子来请求更改设备的状态。 AWS IoT 发布一条消息，指明对设备的更改。设备接收该消息，更新其状态以保持匹配，然后发布一条消息以指示其更新状态。Device Shadow 服务在相应的影子中反映该更新状态。应用程序可以订阅影子的更新，也可以查询影子以获取其当前状态。

当设备离线时，应用程序仍然可以 AWS IoT 与设备的影子进行通信。在设备重新连接时，它接收其影子的当前状态，以便它可以更新其状态以与其影子的状态匹配，然后发布一条消息以指示其更新状态。同样，如果应用程序脱机并且设备状态在其脱机时发生变化，则设备将影子保持更新状态，以便应用程序可以在设备重新连接时查询影子以获取其当前状态。

如果设备经常处于离线状态，但您希望将其配置为在重新连接后接收增量消息，则可以使用持久会话特征。有关持久会话过期期限的更多信息，请参阅[持久会话过期期限](https://docs.aws.amazon.com//general/latest/gr/iot-core.html#message-broker-limits)。

### 选择使用命名或未命名的影子
<a name="iot-device-shadow-named"></a>

设备影子服务支持命名的影子和未命名或经典的影子。事物对象可以具有多个命名的影子，并且最多可以具有一个未命名的影子。事物对象也可以有一个预留命名影子，它的运行方式与命名影子类似，只是您无法更新其名称。有关更多信息，请参阅[预留命名影子](https://docs.aws.amazon.com/iot/latest/developerguide/preparing-to-use-software-package-catalog.html#reserved-named-shadow)。

事物对象可以同时具有命名和未命名的影子；不过，用于访问每种影子的 API 略有不同，因此，决定哪种类型的影子最适合您的解决方案并仅使用该类型可能更高效。有关用于访问影子的 API 的更多信息，请参阅 [影子主题](reserved-topics.md#reserved-topics-shadow)。

通过使用命名的影子，您可以为事物对象的状态创建不同的视图。例如，您可以将一个具有很多属性的事物对象划分为具有逻辑属性组的影子，每个影子由其影子名称标识。您也可以将属性分组到不同的影子，并使用策略控制访问以限制对属性的访问。有关与设备影子配合使用的策略的更多信息，请参阅 [AWS IoT的操作、资源和条件键](https://docs.aws.amazon.com//service-authorization/latest/reference/list_awsiot.html)以及 [AWS IoT Core 策略](https://docs.aws.amazon.com//iot/latest/developerguide/iot-policies.html)。

经典的未命名影子比命名的影子更简单，但在某些程度上比命名的影子更受限制。每个 AWS IoT 事物对象只能有一个未命名的阴影。如果预计您的物联网解决方案对影子数据的需求有限，您可能希望以这种方式开始使用影子。不过，如果您认为将来可能要添加其它影子，请考虑从一开始就使用命名的影子。

实例集索引支持不同的未命名影子和命名影子。有关更多信息，请参阅[管理实例集索引](managing-fleet-index.md)。

### 访问影子
<a name="device-shadow-using-access"></a>

每个影子具有保留的 [MQTT 主题](reserved-topics.md#reserved-topics-shadow)和 [HTTP URL](device-shadow-rest-api.md)，该 URL 支持对影子执行 `get`、`update` 和 `delete` 操作。

影子使用 [JSON 影子文档](device-shadow-document.md)以存储和检索数据。影子的文档包含一个状态属性，以描述设备状态的以下方面：
+ `desired`

  应用程序更新 `desired` 对象以指定设备属性的所需状态。
+ `reported`

  设备在 `reported` 对象中报告其当前状态。
+ `delta`

  AWS IoT 报告`delta`对象中所需状态和报告状态之间的差异。

存储在影子中的数据是由更新操作的消息正文的状态属性确定的。后续的更新操作可以修改现有数据对象的值，也可以在影子的状态对象中添加和删除键和其它元素。有关访问影子的更多信息，请参阅 [在设备中使用影子](device-shadow-comms-device.md) 和 [在应用程序和服务中使用影子](device-shadow-comms-app.md)。

**重要**  
发出更新请求的权限应限制为受信任的应用程序和设备。这可防止意外更改影子的状态属性；否则，使用影子的设备和应用程序应设计为需要更改状态属性中的键。

### 在设备、应用程序和其它云服务中使用影子
<a name="device-shadow-implementing"></a>

要在设备、应用程序和其它云服务中使用影子，需要在它们之间保持一致性和协调性。 AWS IoT Device Shadow 服务存储影子状态，在影子状态发生变化时发送消息，并对更改其状态的消息做出响应。您的物联网解决方案中的设备、应用程序和其它云服务必须管理其状态，并使其与设备影子的状态保持一致。

影子状态数据是动态的，有权访问影子的设备、应用程序和其它云服务可以对其进行更改。因此，请务必考虑每个设备、应用程序和其它云服务如何与影子进行交互。例如：
+ 在将状态数据传送到影子时，*设备* 应仅写入到影子状态的 `reported` 属性中。
+ 在通过影子将状态更改请求传送到设备时，*应用程序和其它云服务* 应仅写入到 `desired` 属性中。

**重要**  
影子数据对象中包含的数据与其它影子和其他事物对象属性的数据（例如事物的属性以及事物对象的设备可能发布的 MQTT 消息内容）无关。不过，如果需要，设备可以在不同的 MQTT 主题和影子中报告相同的数据。  
支持多个影子的设备必须将它在不同影子中报告的数据保持一致。

### 消息顺序
<a name="message-ordering"></a>

无法保证来自该 AWS IoT 服务的消息会按任何特定的顺序到达设备。以下方案显示了此时发生的情况。

初始状态文档：

```
{
  "state": {
    "reported": {
      "color": "blue"
    }
  },
  "version": 9,
  "timestamp": 123456776
}
```

更新 1：

```
{
  "state": {
    "desired": {
      "color": "RED"
    }
  },
  "version": 10,
  "timestamp": 123456777
}
```

更新 2：

```
{
  "state": {
    "desired": {
      "color": "GREEN"
    }
  },
  "version": 11,
  "timestamp": 123456778
}
```

最终状态文档：

```
{
  "state": {
    "reported": {
      "color": "GREEN"
    }
  },
  "version": 12,
  "timestamp": 123456779
}
```

这将产生两个增量消息：

```
{
  "state": {
    "color": "RED"
  },
  "version": 11,
  "timestamp": 123456778
}
```

```
{
  "state": {
    "color": "GREEN"
  },
  "version": 12,
  "timestamp": 123456779
}
```

设备可能不会按次序收到这些消息。由于这些消息中的状态是累计的，设备可以安全地弃用版本号比正在追踪的版本号更早的所有消息。如果设备在接收版本 11 的增量之前收到版本 12 的增量，则可以安全地弃用版本 11 的消息。

### 修剪影子消息
<a name="device-shadow-trim-messages"></a>

要降低发送到您的设备的影子消息的大小，请定义一项规则，以仅选择设备所需的字段然后将消息重新发布到设备正在侦听的 MQTT 主题。

规则应在 JSON 中指定，且应与以下内容类似：

```
{
  "sql": "SELECT state, version FROM '$aws/things/+/shadow/update/delta'",
  "ruleDisabled": false,
  "actions": [
    {
      "republish": {
        "topic": "${topic(3)}/delta",
        "roleArn": "arn:aws:iam:123456789012:role/my-iot-role"
      }
    }
  ]
}
```

SELECT 语句用于确定将消息中的哪些字段重新发布到指定的主题。“\$1”通配符用于匹配所有影子名称。该规则指定，应将所有匹配的消息重新发布到指定的主题。在此情况下，可以使用 `"topic()"` 函数指定将消息重新发布到哪个主题。`topic(3)` 用于评估原始主题中的事物名称。有关创建规则的更多信息，请参阅 [的规则 AWS IoT](iot-rules.md)。