

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

# 模拟 Device Shadow 服务通信
<a name="using-device-shadows"></a>

本主题说明了 Device Shadow 服务如何充当中介，并允许设备和应用程序使用影子以更新、存储和检索设备的状态。

要演示本主题中描述的交互并对其进行进一步探索，您需要一个 AWS 账户 和一个可以运行的系统 AWS CLI。如果没有该账户和系统，您仍然可以在代码示例中看到交互。

在此示例中， AWS IoT 控制台代表设备。 AWS CLI 表示通过影子访问设备的应用程序或服务。该 AWS CLI 接口与应用可能用于通信的 API 非常相似 AWS IoT。该示例中的设备是一个智能灯泡，应用程序显示灯泡的状态，并且可以更改灯泡的状态。

## 设置模拟
<a name="using-device-shadows-setup"></a>

这些流程打开模拟设备的 [AWS IoT 控制台](https://console.aws.amazon.com/iot/home)和模拟应用程序的命令行窗口以初始化模拟。

**设置模拟环境**

1. 你需要一个 AWS 账户 才能自己运行本主题中的示例。如果您没有 AWS 账户，请按中所述创建一个[设置 AWS 账户](setting-up.md)。

1. 打开 [AWS IoT 控制台](https://console.aws.amazon.com/iot/home)，然后在左侧菜单中选择**测试**以打开 **MQTT 客户端**。

1. 在另一个窗口中，在已安装 AWS CLI 的系统上打开一个终端窗口。

你应该打开两个窗口：一个在 “**测试**” 页面上显示 AWS IoT 控制台，另一个窗口带有命令行提示符。

## 初始化设备
<a name="using-device-shadows-init-device"></a>

在这个模拟中，我们将使用一个名为、的事物对象 *mySimulatedThing*，其阴影名为 *simShadow1*。

**创建事物对象及其物联网策略**  
要创建事物对象，请在 **AWS IoT 控制台**：

1. 选择 **Manage**（管理），然后选择 **Things**（事物）。

1. 如果已列出事物，请单击 “**创建**” 按钮，否则单击 “**注册单个事物**” 来创建单个 AWS IoT 事物。

1. 输入名称 `mySimulatedThing`，将其它设置保留为默认值，然后单击 **Next**（下一步）。

1. 使用单击证书创建可生成证书，以验证设备与 AWS IoT的连接。单击 **Activate**（激活）以激活证书。

1. 您可以附上策略 `My_IoT_Policy`，这将授予设备发布和订阅 MQTT 预留主题的权限。有关如何创建 AWS IoT 事物以及如何创建此策略的更多详细步骤，请参阅[创建一个事物对象](create-iot-resources.md#create-aws-thing)。

**创建事物对象的命名影子**  
按如下方式向 `$aws/things/mySimulatedThing/shadow/name/simShadow1/update` 主题发布更新请，您可以为物件创建命名影子。

也可以按以下方式创建命名影子：

1. 在 **AWS IoT 控制台**中，在显示的事物列表中选择您的事物对象，然后选择 **Shadows**（影子）。

1. 选择 **Add a shadow**（添加影子），输入名称 `simShadow1`，然后选择 **Create**（创建）添加命名的影子。

**订阅并发布预留的 MQTT 主题**  
在控制台中，订阅预留的 MQTT 影子主题。这些主题是 `get`、`update` 和 `delete` 操作的响应，以便设备在发布操作后准备好接收响应。

**在 **MQTT 客户端**中订阅 MQTT 主题**

1. 在 **MQTT 客户端**中，选择 **Subscribe to a topic**（订阅主题）。

1. 输入 `get`、`update` 和 `delete` 要订阅的主题。每次从以下列表中复制一个主题，然后将其粘贴到 **Topic filter**（主题筛选条件）字段，然后单击 **Subscribe**（订阅）。您应看到主题显示在 **Subscriptions**（订阅）项下。
   + `$aws/things/mySimulatedThing/shadow/name/simShadow1/delete/accepted`
   + `$aws/things/mySimulatedThing/shadow/name/simShadow1/delete/rejected`
   + `$aws/things/mySimulatedThing/shadow/name/simShadow1/get/accepted`
   + `$aws/things/mySimulatedThing/shadow/name/simShadow1/get/rejected`
   + `$aws/things/mySimulatedThing/shadow/name/simShadow1/update/accepted`
   + `$aws/things/mySimulatedThing/shadow/name/simShadow1/update/rejected`
   + `$aws/things/mySimulatedThing/shadow/name/simShadow1/update/delta`
   + `$aws/things/mySimulatedThing/shadow/name/simShadow1/update/documents`

   此时，在 AWS IoT发布主题时，模拟的设备已准备好接收这些主题。

**在 **MQTT client**（MQTT 客户端）中发布 MQTT 主题**  
在设备初始化自身并订阅响应主题后，它应查询支持的影子。此模拟仅支持一个阴影，即支持名为 *simShadow1 的事物对象的阴影*。*mySimulatedThing*

**从 **MQTT 客户端**中获取当前影子状态**

1. 在 **MQTT 客户端**中，选择**发布到主题**。

1. 在 **Publish**（发布）中，输入以下主题，并从输入主题下方的消息正文窗口中删除任何内容。然后，您可以选择 **Publish to topic**（发布主题）以发布请求。`$aws/things/mySimulatedThing/shadow/name/simShadow1/get`。

   如果您未创建命名影子 `simShadow1`，您将在 `$aws/things/mySimulatedThing/shadow/name/simShadow1/get/rejected` 主题中收到一条消息，并且 `code` 为 `404`（例如，在该示例中，由于尚未创建影子，因此我们接下来将进行创建）。

   ```
   {
     "code": 404,
     "message": "No shadow exists with name: 'simShadow1'"
   }
   ```

**使用设备的当前状态创建影子**

1. 在 **MQTT client**（MQTT 客户端）中，选择 **Publish to a topic**（发布主题），然后输入该主题。

   ```
   $aws/things/mySimulatedThing/shadow/name/simShadow1/update
   ```

1. 在消息正文窗口中，在您输入主题的位置下面输入该影子文档，以显示设备正在报告其 ID 并以 RGB 值形式报告其当前颜色。选择 **Publish**（发布）以发布请求。

   ```
   {
     "state": {
       "reported": {
         "ID": "SmartLamp21",
         "ColorRGB": [
           128,
           128,
           128
         ]
       }
     },
     "clientToken": "426bfd96-e720-46d3-95cd-014e3ef12bb6"
   }
   ```

如果您在主题中收到一条消息：
+ `$aws/things/mySimulatedThing/shadow/name/simShadow1/update/accepted`：表示创建了影子，并且消息正文包含当前影子文档。
+ `$aws/things/mySimulatedThing/shadow/name/simShadow1/update/rejected`：查看消息正文中的错误。
+ `$aws/things/mySimulatedThing/shadow/name/simShadow1/get/accepted`：影子已存在，并且消息正文包含当前影子状态，如示例中所示。通过使用该消息，您可以设置设备或确认它与影子状态匹配。

  ```
  {
    "state": {
      "reported": {
        "ID": "SmartLamp21",
        "ColorRGB": [
          128,
          128,
          128
        ]
      }
    },
    "metadata": {
      "reported": {
        "ID": {
          "timestamp": 1591140517
        },
        "ColorRGB": [
          {
            "timestamp": 1591140517
          },
          {
            "timestamp": 1591140517
          },
          {
            "timestamp": 1591140517
          }
        ]
      }
    },
    "version": 3,
    "timestamp": 1591140517,
    "clientToken": "426bfd96-e720-46d3-95cd-014e3ef12bb6"
  }
  ```

## 从应用程序中发送更新
<a name="using-device-shadows-app-update"></a>

本节使用 AWS CLI 来演示应用程序如何与影子交互。

**要获取阴影的当前状态，请使用 AWS CLI**  
从命令行中，输入以下命令。

```
aws iot-data get-thing-shadow --thing-name mySimulatedThing --shadow-name simShadow1 /dev/stdout
```

在 Windows 平台上，您可以使用 `con` 而不是 `/dev/stdout`。

```
aws iot-data get-thing-shadow --thing-name mySimulatedThing --shadow-name simShadow1 con
```

由于影子存在并且设备已将其初始化以反映其当前状态，因此，它应返回以下影子文档。

```
{
  "state": {
    "reported": {
      "ID": "SmartLamp21",
      "ColorRGB": [
        128,
        128,
        128
      ]
    }
  },
  "metadata": {
    "reported": {
      "ID": {
        "timestamp": 1591140517
      },
      "ColorRGB": [
        {
          "timestamp": 1591140517
        },
        {
          "timestamp": 1591140517
        },
        {
          "timestamp": 1591140517
        }
      ]
    }
  },
  "version": 3,
  "timestamp": 1591141111
}
```

应用程序可以使用该响应以初始化设备状态的表示形式。

如果应用程序更新状态（例如，在最终用户将智能灯泡的颜色更改为黄色时），应用程序将发送 **update-thing-shadow** 命令。该命令对应于 `UpdateThingShadow` REST API。

**从应用程序中更新影子**  
从命令行中，输入以下命令。

------
#### [ AWS CLI v2.x ]

```
aws iot-data update-thing-shadow --thing-name mySimulatedThing --shadow-name simShadow1 \
    --cli-binary-format raw-in-base64-out \
    --payload '{"state":{"desired":{"ColorRGB":[255,255,0]}},"clientToken":"21b21b21-bfd2-4279-8c65-e2f697ff4fab"}' /dev/stdout
```

------
#### [ AWS CLI v1.x ]

```
aws iot-data update-thing-shadow --thing-name mySimulatedThing --shadow-name simShadow1 \
    --payload '{"state":{"desired":{"ColorRGB":[255,255,0]}},"clientToken":"21b21b21-bfd2-4279-8c65-e2f697ff4fab"}' /dev/stdout
```

------

如果成功，该命令应返回以下影子文档。

```
{
  "state": {
    "desired": {
      "ColorRGB": [
        255,
        255,
        0
      ]
    }
  },
  "metadata": {
    "desired": {
      "ColorRGB": [
        {
          "timestamp": 1591141596
        },
        {
          "timestamp": 1591141596
        },
        {
          "timestamp": 1591141596
        }
      ]
    }
  },
  "version": 4,
  "timestamp": 1591141596,
  "clientToken": "21b21b21-bfd2-4279-8c65-e2f697ff4fab"
}
```

## 响应设备中的更新
<a name="using-device-shadows-device-update"></a>

返回 AWS 控制台中的 **MQTT 客户端**，您应该会看到为反映上一节中发出的更新命令而发布的消息。 AWS IoT 

**在 **MQTT 客户端**中查看更新消息**  
在 **MQTT 客户端**中，在 “**订阅**” 列aws/things/mySimulatedThing/shadow/name/simShadow1/update/delta中选择 **\$1**。如果主题名称被截断，您可以在其中暂停以查看完整主题。在本主题的主题日志中，您应该看到与此类似的 `/delta` 消息。

```
{
  "version": 4,
  "timestamp": 1591141596,
  "state": {
    "ColorRGB": [
      255,
      255,
      0
    ]
  },
  "metadata": {
    "ColorRGB": [
      {
        "timestamp": 1591141596
      },
      {
        "timestamp": 1591141596
      },
      {
        "timestamp": 1591141596
      }
    ]
  },
  "clientToken": "21b21b21-bfd2-4279-8c65-e2f697ff4fab"
}
```

设备将处理该消息的内容，以将设备状态设置为与消息中的 `desired` 状态匹配。

设备更新状态以匹配消息中的`desired`状态后，必须 AWS IoT 通过发布更新消息将新的报告状态发送回去。该流程在 **MQTT 客户端**中模拟这种情况。

**从设备中更新影子**

1. 在 **MQTT 客户端**中，选择**发布到主题**。

1. 在消息正文窗口中，在消息正文窗口上方的主题字段中，输入影子的主题，然后输入 `/update` 操作：`$aws/things/mySimulatedThing/shadow/name/simShadow1/update`，然后在消息正文中输入此更新的影子文档，该文档描述了设备的当前状态。选择 **Publish**（发布）以发布更新的设备状态。

   ```
   {
     "state": {
       "reported": {
         "ColorRGB": [255,255,0]
         }
     },
     "clientToken": "a4dc2227-9213-4c6a-a6a5-053304f60258"
   }
   ```

   如果成功收到消息 AWS IoT，则应在 **MQTT 客户端**的 **\$1 aws/things/mySimulatedThing/shadow/name/simShadow1/update/accepted** 消息日志中看到包含影子当前状态的新响应，例如此示例。

   ```
   {
     "state": {
       "reported": {
         "ColorRGB": [
           255,
           255,
           0
         ]
       }
     },
     "metadata": {
       "reported": {
         "ColorRGB": [
           {
             "timestamp": 1591142747
           },
           {
             "timestamp": 1591142747
           },
           {
             "timestamp": 1591142747
           }
         ]
       }
     },
     "version": 5,
     "timestamp": 1591142747,
     "clientToken": "a4dc2227-9213-4c6a-a6a5-053304f60258"
   }
   ```

成功更新设备报告的状态还会导致 AWS IoT 在消息中向`update/documents`主题发送有关影子状态的全面描述，例如该消息正文是由设备在前面的过程中执行的影子更新而生成的消息正文。

```
{
  "previous": {
    "state": {
      "desired": {
        "ColorRGB": [
          255,
          255,
          0
        ]
      },
      "reported": {
        "ID": "SmartLamp21",
        "ColorRGB": [
          128,
          128,
          128
        ]
      }
    },
    "metadata": {
      "desired": {
        "ColorRGB": [
          {
            "timestamp": 1591141596
          },
          {
            "timestamp": 1591141596
          },
          {
            "timestamp": 1591141596
          }
        ]
      },
      "reported": {
        "ID": {
          "timestamp": 1591140517
        },
        "ColorRGB": [
          {
            "timestamp": 1591140517
          },
          {
            "timestamp": 1591140517
          },
          {
            "timestamp": 1591140517
          }
        ]
      }
    },
    "version": 4
  },
  "current": {
    "state": {
      "desired": {
        "ColorRGB": [
          255,
          255,
          0
        ]
      },
      "reported": {
        "ID": "SmartLamp21",
        "ColorRGB": [
          255,
          255,
          0
        ]
      }
    },
    "metadata": {
      "desired": {
        "ColorRGB": [
          {
            "timestamp": 1591141596
          },
          {
            "timestamp": 1591141596
          },
          {
            "timestamp": 1591141596
          }
        ]
      },
      "reported": {
        "ID": {
          "timestamp": 1591140517
        },
        "ColorRGB": [
          {
            "timestamp": 1591142747
          },
          {
            "timestamp": 1591142747
          },
          {
            "timestamp": 1591142747
          }
        ]
      }
    },
    "version": 5
  },
  "timestamp": 1591142747,
  "clientToken": "a4dc2227-9213-4c6a-a6a5-053304f60258"
}
```

## 观察应用程序中的更新
<a name="using-device-shadows-view-result"></a>

应用程序现在可以查询影子以获取设备报告的当前状态。

**要获取阴影的当前状态，请使用 AWS CLI**

1. 从命令行中，输入以下命令。

   ```
   aws iot-data get-thing-shadow --thing-name mySimulatedThing --shadow-name simShadow1 /dev/stdout
   ```

   在 Windows 平台上，您可以使用 `con` 而不是 `/dev/stdout`。

   ```
   aws iot-data get-thing-shadow --thing-name mySimulatedThing --shadow-name simShadow1 con
   ```

1. 由于设备刚刚更新了影子以反映其当前状态，因此，它应返回以下影子文档。

   ```
   {
     "state": {
       "desired": {
         "ColorRGB": [
           255,
           255,
           0
         ]
       },
       "reported": {
         "ID": "SmartLamp21",
         "ColorRGB": [
           255,
           255,
           0
         ]
       }
     },
     "metadata": {
       "desired": {
         "ColorRGB": [
           {
             "timestamp": 1591141596
           },
           {
             "timestamp": 1591141596
           },
           {
             "timestamp": 1591141596
           }
         ]
       },
       "reported": {
         "ID": {
           "timestamp": 1591140517
         },
         "ColorRGB": [
           {
             "timestamp": 1591142747
           },
           {
             "timestamp": 1591142747
           },
           {
             "timestamp": 1591142747
           }
         ]
       }
     },
     "version": 5,
     "timestamp": 1591143269
   }
   ```

## 模拟补充内容
<a name="using-device-shadows-next-steps"></a>

试验 AWS CLI （表示应用程序）和控制台（表示设备）之间的交互以模拟您的物联网解决方案。