

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

# AWS IoT 教程
<a name="iot-tutorials"></a>

这些 AWS IoT 教程分为两种学习路径，以支持两个不同的目标。为您的目标选择最佳的学习路径。
+ 

**你想构建一个 proof-of-concept来测试或演示 AWS IoT 解决方案创意**  
要在设备上使用 AWS IoT 设备客户端演示常见的物联网任务和应用程序，请按照[使用 AWS IoT 设备客户端构建演示](iot-tutorials-dc-intro.md)学习路径进行操作。De AWS IoT vice Client 提供了设备软件，您可以使用这些软件应用自己的云资源来演示开发最少的 end-to-end解决方案。

  有关 AWS IoT 设备客户端的信息，请参阅[AWS IoT 设备客户端](https://github.com/awslabs/aws-iot-device-client#readme)。
+ 

**您想学习如何构建生产软件来部署解决方案**  
要使用 AWS IoT 设备 SDK 创建符合您特定要求的自己的解决方案软件，请遵循[使用 AWS IoT 设备构建解决方案 SDKs](iot-tutorials-sdk-intro.md)学习路径。

  有关可用 AWS IoT 设备的信息 SDKs，请参阅[AWS IoT Device SDK](iot-sdks.md#iot-device-sdks)。有关信息 AWS SDKs，请参阅[构建工具 AWS](https://aws.amazon.com/tools/)。

**Topics**
+ [使用 AWS IoT 设备客户端构建演示](iot-tutorials-dc-intro.md)
+ [使用 AWS IoT 设备构建解决方案 SDKs](iot-tutorials-sdk-intro.md)

# 使用 AWS IoT 设备客户端构建演示
<a name="iot-tutorials-dc-intro"></a>

本学习路径中的教程将引导您完成使用 AWS IoT 设备客户端开发演示软件的步骤。 AWS IoT 设备客户端提供在您的物联网设备上运行的软件，用于测试和演示基于物联网解决方案的各个方面 AWS IoT。

这些教程的目标是促进探索和实验，以便在开发设备软件之前，您可以放心地 AWS IoT 支持您的解决方案。

**您将在本教程中学到的内容：**
+ 如何准备 Raspberry Pi 以用作物联网设备 AWS IoT
+ 如何在设备上使用 AWS IoT 设备客户端来演示 AWS IoT 功能

在本学习路径中，你将在自己的 Raspberry Pi 上安装 AWS IoT 设备客户端，并在云端创建 AWS IoT 资源来演示物联网解决方案创意。尽管此学习路径中的教程通过使用 Raspberry Pi 演示功能，也讲解了帮助您适应其他设备的目标和程序。

## 使用 AWS IoT 设备客户端制作演示的先决条件
<a name="iot-dc-tutorial-overview"></a>

本节介绍在此学习路径中的教程开始之前需要了解的内容。

**要完成此学习路径中的教程，您需要：**
+ 

**一个 AWS 账户**  
如果有的话 AWS 账户，您可以使用现有角色或权限，但可能需要添加其他角色或权限才能使用这些教程使用的 AWS IoT 功能。

  如果您需要创建新的 AWS 账户，请参阅[设置 AWS 账户](setting-up.md)。
+ 

**Raspberry Pi 或兼容的物联网设备**  
由于因数不同，这些教程使用 [Raspberry Pi](https://www.raspberrypi.org/)，这是一种常用的演示色斑，成本相对较低。已在 [Raspberry Pi 3 Model B\$1](https://www.raspberrypi.com/products/raspberry-pi-3-model-b-plus/)、[Raspberry Pi 4 Model B](https://www.raspberrypi.com/products/raspberry-pi-4-model-b/) 以及运行 Ubuntu Server 20.04 LTS（HVM）的 Amazon EC2 实例上测试了教程。要使用 AWS CLI 和运行命令，我们建议您使用最新版本的 Raspberry Pi 操作系统[（64 位）或 O](https://www.raspberrypi.com/software/operating-systems/) S Lite）。早期版本的操作系统可能有用，但我们还没有测试过。
**注意**  
这些教程解释了每个步骤的目标，帮助您适应我们没有尝试过的物联网硬件；但是，没有具体描述如何适用于其他设备。
+ 

**熟悉物联网设备的操作系统**  
这些教程中的步骤假设您熟悉使用 Raspberry Pi 支持的命令行界面中的基本 Linux 命令和操作。如果您不熟悉这些操作，可能需要给自己更多的时间来完成教程。

  要完成这些教程，您应已经了解下列操作：
  + 安全地执行基本的设备操作，例如组装和连接组件、将设备连接到所需的电源以及安装和卸载存储卡。
  + 将系统软件和文件上传并下载到设备。如果您的设备不使用可移动存储设备，例如 microSD 卡，您需要知道如何连接到设备以及如何将系统软件和文件上传并下载到设备。
  + 将您的设备连接到计划使用的网络。
  + 用 SSH 终端或类似程序从另一台计算机连接到您的设备。
  + 用命令行界面在设备上创建、复制、移动、重命名和设置文件和目录的权限。
  + 在设备上安装新程序。
  + 使用 FTP 或 SCP 等工具在设备之间传输文件。
+ 

**IoT 解决方案的开发和测试环境**  
教程描述了所需的软件和硬件；然而，教程假设您能够执行可能没有明确描述的操作。此类硬件和操作的示例包括：
  + 

**下载并存储文件的本地主机**  
对于 Raspberry Pi 而言，通常是可以读写 microSD 存储卡的个人计算机或笔记本电脑。本地主机必须：
    + 连接到互联网。
    + 已经安装并配置 [AWS CLI](https://aws.amazon.com//cli/)。
    + 使用支持 AWS 控制台的 Web 浏览器。
  + 

**能够将本地主机连接到设备进行通信、输入命令以及传输文件**  
在 Raspberry Pi 上，通常是使用本地主机上的 SSH 和 SCP 完成的。
  + 

**连接到物联网设备上的显示器和键盘**  
这些可能会有所帮助，但并不是完成教程的必需内容。
  + 

**您本地主机和物联网设备能够连接到互联网**  
这可能是连接到互联网的路由器或网关的有线网络连接或无线网络连接。本地主机还必须能够连接到 Raspberry Pi。这可能需要它们在同一个局域网上。这些教程无法向您展示如何针对特定设备或设备配置进行设置，但说明了如何测试连通性。
  + 

**访问局域网的路由器查看连接的设备**  
要完成此学习路径中的教程，您需要能够找到物联网设备的 IP 地址。

    在局域网上，可以通过访问设备连接到的网络路由器的管理界面来完成此操作。如果您可以在路由器中为设备分配固定 IP 地址，可以在设备每次重新启动后简化重新连接。

    如果键盘和显示器连接到设备上，**ifconfig** 可以显示设备的 IP 地址。

    如果没有使用上述设备，需要在每次重启设备后找到一种方法来识别设备的 IP 地址。

获得所有资料之后，继续 [教程：为设备客户端准备 AWS IoT 设备](iot-dc-prepare-device.md)。

**Topics**
+ [使用 AWS IoT 设备客户端制作演示的先决条件](#iot-dc-tutorial-overview)
+ [教程：为设备客户端准备 AWS IoT 设备](iot-dc-prepare-device.md)
+ [教程：安装和配置 AWS IoT 设备客户端](iot-dc-install-dc.md)
+ [教程：演示与 AWS IoT 设备客户端的 MQTT 消息通信](iot-dc-testconn.md)
+ [教程：使用 AWS IoT 设备客户端演示远程操作（作业）](iot-dc-runjobs.md)
+ [教程：运行 AWS IoT 设备客户端教程后进行清理](iot-dc-cleanup.md)

# 教程：为设备客户端准备 AWS IoT 设备
<a name="iot-dc-prepare-device"></a>

本教程将引导您完成 Raspberry Pi 的初始化，为此学习路径中的后续教程做好准备。

本教程的目标是安装当前版本的设备操作系统，确保您可以在开发环境中与设备进行通信。

**先决条件**  
开始学习本教程之前，请确保您具有 [使用 AWS IoT 设备客户端制作演示的先决条件](iot-tutorials-dc-intro.md#iot-dc-tutorial-overview) 中所列的条目，并准备开始使用。

完成本教程需要大约 90 分钟。

**在本教程中，您将：**
+ 安装并更新设备的操作系统。
+ 安装并验证运行教程所需的任何其他软件。
+ 测试设备的连接并安装所需的证书。

完成本教程后，下一个教程将为使用设备客户端的演示做好 AWS IoT 设备准备。

**Topics**
+ [安装并更新设备的操作系统](iot-dc-prepare-device-sys.md)
+ [在设备上安装并验证所需的软件](iot-dc-prepare-device-sw.md)
+ [测试您的设备并保存 Amazon CA 证书](iot-dc-prepare-device-test.md)

# 安装并更新设备的操作系统
<a name="iot-dc-prepare-device-sys"></a>

本节中的步骤介绍了如何初始化 Raspberry Pi 用于系统驱动器的 microSD 卡。Raspberry Pi 的 microSD 卡包含其操作系统（OS）软件和应用程序文件存储空间。如果您没有使用 Raspberry Pi，请按照设备的说明安装和更新设备的操作系统软件。

完成本部分后，您应能够启动物联网设备并从本地主机上的终端程序进行连接。

**所需的设备：**
+ 您的本地开发和测试环境 
+ 可以连接到互联网的 Raspberry Pi 或您的物联网设备
+ 至少 8 GB 或足够空间的 microSD 存储卡，用于存储操作系统和所需的软件。
**注意**  
在选择 microSD 卡进行练习时，请选择一张存储量较小的卡。  
小容量 SD 卡的备份和更新速度会更快。在 Raspberry Pi 上，这些教程中使用的 microSD 卡容量不需要超过 8 GB。如果您需要更大的存储量用于特定的应用程序，在这些教程中保存的较小的图片文件可以调整存储量较大卡上的文件系统大小，使用所选卡的所有支持空间。

**可选设备：**
+ 连接到 Raspberry Pi 的 USB 键盘
+ 用于将显示器连接到 Raspberry Pi 的 HDMI 显示器和电缆

**Topics**
+ [将设备的操作系统加载到 microSD 卡内](#iot-dc-prepare-device-sys-step1)
+ [用新的操作系统启动物联网设备](#iot-dc-prepare-device-sys-step2)
+ [将您的本地主机连接到设备上](#iot-dc-prepare-device-sys-step3)

## 将设备的操作系统加载到 microSD 卡内
<a name="iot-dc-prepare-device-sys-step1"></a>

此一步骤使用本地主机将设备的操作系统加载到 microSD 卡内。

**注意**  
如果您的设备没有用于操作系统的可移动存储设备，请使用该设备的过程安装操作系统，然后继续 [用新的操作系统启动物联网设备](#iot-dc-prepare-device-sys-step2)。

**要在 Raspberry Pi 上安装操作系统**

1. 在本地主机上，下载并解压缩要使用的 Raspberry Pi 操作系统映像。最新版本可从[ https://www.raspberrypi.com/software/操作系统/](https://www.raspberrypi.com/software/operating-systems/) 

**选择 Raspberry Pi OS 版本**  
本教程使用 **Raspberry Pi OS Lite** 版本，因为它是在此学习路径中支持这些教程的最小版本。这个版本的 Raspberry Pi 操作系统只有命令行界面，没有图形用户界面。带图形用户界面的最新版本 Raspberry Pi 操作系统也可以使用这些教程；但是，本学习路径中描述的步骤仅使用命令行界面对 Raspberry Pi 执行操作。

1. 将 microSD 卡插到您的计算机上。

1. 使用 SD 卡成像工具，将解压缩的操作系统映像文件写入 microSD 卡。

1. 将 Raspberry Pi OS 映像写入 microSD 卡之后：

   1. 在命令行窗口或文件资源管理器窗口中打开 microSD 卡上的 BOOT 分区。

   1. 在 microSD 卡的 BOOT 分区中的根目录下，创建一个名为 `ssh`的空文件，没有文件扩展名也没有内容。在首次开机时会告知 Raspberry Pi 启用 SSH 通信。

1. 弹出 microSD 卡并从本地主机上安全取出卡片。

您的 microSD 卡已经准备好 [用新的操作系统启动物联网设备](#iot-dc-prepare-device-sys-step2)。

## 用新的操作系统启动物联网设备
<a name="iot-dc-prepare-device-sys-step2"></a>

此过程安装 microSD 卡并使用下载的操作系统首次启动 Raspberry Pi。

**用新的操作系统启动物联网设备**

1. 从设备断开电源的情况下，插入上一步中的 microSD 卡，[将设备的操作系统加载到 microSD 卡内](#iot-dc-prepare-device-sys-step1)，进入 Raspberry Pi。

1. 将设备连接到有线网络。

1. 这些教程将使用 SSH 终端从本地主机与 Raspberry Pi 进行交互。

   如果还想直接与设备交互，您可以：

   1. 将本地主机上的终端窗口 Connect 到 Raspberry Pi 之前，将 HDMI 显示器连接到Raspberry Pi 观看 Raspberry Pi 的控制台消息。

   1. 如果想直接与 Raspberry Pi 交互，请将 USB 键盘连接。

1. 将电源连接到 Raspberry Pi 上，等待大约一分钟后才能初始化。

   如果您的显示器连接到 Raspberry Pi 上，那您可以在显示器上查看启动过程。

1. 

   找出设备的 IP 地址：
   + 如果您将 HDMI 显示器连接到 Raspberry Pi 上，IP 地址将出现在显示器上的消息中 
   + 如果您可以访问 Raspberry Pi 连接的路由器，可以在路由器的管理界面中看到它的地址。

获得 Raspberry Pi IP 地址后，您可以进行 [将您的本地主机连接到设备上](#iot-dc-prepare-device-sys-step3)。

## 将您的本地主机连接到设备上
<a name="iot-dc-prepare-device-sys-step3"></a>

此过程使用本地主机上的终端程序连接到 Raspberry Pi 上并更改原定设置密码。

**要将您的本地主机连接到设备上**

1. 

   在本地主机上打开 SSH 终端程序：
   + Windows：`PuTTY`
   + Linux/macOS：`Terminal`
**注意**  
在 Windows 上没有自动安装 PuTTY。如果计算机上没有，可能需要下载并安装它。

1. 将终端程序连接到 Raspberry Pi 的 IP 地址，然后使用原定设置凭据登录。

   ```
   username: pi
   password: raspberry
   ```

1. 登录 Raspberry Pi 后，请更改 `pi` 用户的密码。

   ```
   passwd
   ```

   按照提示更改密码。

   ```
   Changing password for pi.
   Current password: raspberry
   New password: YourNewPassword
   Retype new password: YourNewPassword
   passwd: password updated successfully
   ```

在终端窗口中有 Raspberry Pi 的命令行提示符并更改密码后，可以继续 [在设备上安装并验证所需的软件](iot-dc-prepare-device-sw.md)。

# 在设备上安装并验证所需的软件
<a name="iot-dc-prepare-device-sw"></a>

本节中的步骤从[上一节](iot-dc-prepare-device-sys.md)继续，以更新您的 Raspberry Pi 的操作系统，并将软件安装在 Raspberry Pi 上，下一节将使用该软件来构建和安装 AWS IoT 设备客户端。

完成本节后，您的 Raspberry Pi 将拥有 up-to-date操作系统、本学习路径中教程所需的软件，并将根据您的位置进行配置。

**所需的设备：**
+ [上一节](iot-dc-prepare-device-sys.md)中您的本地开发和测试环境
+ [上一节](iot-dc-prepare-device-sys.md)中您使用 的Raspberry Pi
+ [上一节](iot-dc-prepare-device-sys.md)中的 microSD 存储卡

**注意**  
Raspberry Pi Model 3\$1 和 Raspberry Pi Model 4 可以执行此学习路径中描述的所有命令。如果您的物联网设备无法编译软件或无法运行 AWS Command Line Interface，则可能需要在本地主机上安装所需的编译器来构建软件，然后将其传输到您的物联网设备。有关如何为设备安装和构建软件的更多信息，请参阅设备软件的文档。

**Topics**
+ [更新操作系统软件](#iot-dc-prepare-device-sw-step1)
+ [安装所需的应用程序和库](#iot-dc-prepare-device-sw-step2)
+ [（可选）保存 microSD 卡映像](#iot-dc-prepare-device-sw-step3)

## 更新操作系统软件
<a name="iot-dc-prepare-device-sw-step1"></a>

这一步骤会更新操作系统软件。

**要更新 Raspberry Pi 上的操作系统软件**

在本地主机的终端窗口中执行这些步骤。

1. 输入以下命令在您的 Raspberry Pi 上更新系统软件。

   ```
   sudo apt-get -y update
   sudo apt-get -y upgrade
   sudo apt-get -y autoremove
   ```

1. 更新 Raspberry Pi 的区域设置和时区设置（可选）。

   输入此命令可以更新设备的区域设置和时区设置。

   ```
   sudo raspi-config
   ```

   1. 要设置设备的区域：

      1. 在 **Raspberry Pi Software Configuration Tool（raspi-config）**（Raspberry Pi 软件配置工具（raspi-config））屏幕上，选择选项 **5**。

         **`5 Localisation Options Configure language and regional settings`**

         使用 Tab键移动到 **<Select>**，然后按 space bar。

      1. 在本地化选项菜单中，选择选项**L1**。

         **`L1 Locale Configure language and regional settings`**

         使用 Tab键移动到 **<Select>**，然后按 space bar。

      1. 在区域设置选项列表中，使用箭头键滚动并选择要在 Raspberry Pi 上安装的语言环境 space bar来标记您想要的选项。

         在美国，**`en_US.UTF-8`** 是一个很好的选择。

      1. 为设备选择语言环境后，请使用 Tab 键来选择**<OK>**，然后按 space bar 显示**配置区域设置**的确认页面。

   1. 要设置设备的时区：

      1. 在 **aspi-config** 屏幕，选择选项 **5**。

         **`5 Localisation Options Configure language and regional settings`**

         使用 Tab键移动到 **<Select>**，然后按 space bar。

      1. 在本地化选项菜单中，使用箭头键选择选项 **L2**：

         **`L2 time zone Configure time zone`**

         使用 Tab键移动到 **<Select>**，然后按 space bar。

      1. 在**配置 tzdata**菜单中，从列表中选择您的地理区域。

         使用 Tab 键移动到 **<OK>**，然后按 space bar。

      1. 在城市列表中，使用箭头键选择时区内的城市。

         使要设置时区，用 Tab 键移动到 **<OK>**，然后按 space bar。

   1. 更新完设置后，用 Tab 键移动到**<Finish>**，然后按 space bar 关闭 **aspi-config**应用程序。

1. 输入此命令可重启您的 Raspberry Pi。

   ```
   sudo shutdown -r 0
   ```

1. 等您的 Raspberry Pi 重启。

1. 重新启动 Raspberry Pi 后，将本地主机上的终端窗口重新连接到 Raspberry Pi。

您的 Raspberry Pi 系统软件现已配置完毕，您已准备好继续 [安装所需的应用程序和库](#iot-dc-prepare-device-sw-step2)。

## 安装所需的应用程序和库
<a name="iot-dc-prepare-device-sw-step2"></a>

此过程将安装后续教程使用的应用程序软件和库。

如果您使用的是 Raspberry Pi，或可以在物联网设备上编译所需的软件，请在本地主机上的终端窗口中执行以下步骤。如果必须在本地主机上为物联网设备编译软件，请查看物联网设备的软件文档，了解有关如何在设备上执行这些步骤的信息。

**在 Raspberry Pi 上安装应用程序软件和库**

1. 输入此命令安装应用程序软件和库。

   ```
   sudo apt-get -y install build-essential libssl-dev cmake unzip git python3-pip
   ```

1. 输入这些命令来确认安装了正确版本的软件。

   ```
   gcc --version
   cmake --version
   openssl version
   git --version
   ```

1. 

   确认已安装以下版本的应用程序软件：
   + `gcc`：9.3.0 或更高版本
   + `cmake`：3.10.x 或更高版本
   + `OpenSSL`：1.1.1 或更高版本
   + `git`：2.20.1 或更高版本

如果您的Raspberry Pi拥有所需应用程序软件的可接受版本，您准备好继续 [（可选）保存 microSD 卡映像](#iot-dc-prepare-device-sw-step3)。

## （可选）保存 microSD 卡映像
<a name="iot-dc-prepare-device-sw-step3"></a>

在本学习路径中的整个教程中，您会遇到这些过程，将 Raspberry Pi 的 microSD 卡映像的副本保存到本地主机上的文件中。尽管鼓励这样做，但不是必需的任务。通过在建议的位置保存 microSD 卡映像，您可以跳过此学习路径中保存点之前的过程，如果发现需要重试某些内容，这可以节省时间。不定期保存 microSD 卡映像的后果是，如果 microSD 卡损坏或者不小心配置了应用程序或其设置错误，可能必须从头开始重新启动学习路径中的教程。

此时，Raspberry Pi 的 microSD 卡具有更新的操作系统和基本的应用程序软件加载。现在，您可以通过将 microSD 卡的内容保存到文件中来节省完成上述步骤所花的时间。采用拥有设备 microSD 卡映像的当前映像，您可以从这一点开始继续或重试教程或程序，无需从头开始安装和更新软件。

**要将 microSD 卡映像保存到文件中**

1. 输入此命令关闭 Raspberry Pi。

   ```
   sudo shutdown -h 0
   ```

1. Raspberry Pi 完全关闭后，请移除电源。

1. 从 Raspberry Pi 中取出 microSD 卡。

1. 在本地主机上：

   1. 插入 microSD 卡。

   1. 使用 SD 卡成像工具，将 microSD 卡映像保存到文件中。

   1. 保存 microSD 卡映像后，从本地主机上弹出该卡。

1. 从 Raspberry Pi 断开电源后，将 microSD 卡插入 Raspberry Pi。

1. 给 Raspberry Pi 供电。

1. 等待大约一分钟后，在本地主机上重新连接已连接到 Raspberry Pi 的本地主机上的终端窗口，然后登录 Raspberry Pi。

# 测试您的设备并保存 Amazon CA 证书
<a name="iot-dc-prepare-device-test"></a>

本节中的步骤从[上一节](iot-dc-prepare-device-sw.md)继续，安装 AWS Command Line Interface 和用于对连接进行身份验证的证书颁发机构证书 AWS IoT Core。

完成本节后，您将知道您的 Raspberry Pi 拥有安装 AWS IoT 设备客户端所需的系统软件，并且可以正常连接到互联网。

**所需的设备：**
+ [上一节](iot-dc-prepare-device-sw.md)中您的本地开发和测试环境
+ [上一节](iot-dc-prepare-device-sw.md)中您使用 的Raspberry Pi
+ [上一节](iot-dc-prepare-device-sw.md)中的 microSD 存储卡

**Topics**
+ [安装 AWS Command Line Interface](#iot-dc-prepare-device-test-step1)
+ [配置您的 AWS 账户 凭证](#iot-dc-prepare-device-test-step2)
+ [下载 Amazon Root CA 证书](#iot-dc-prepare-device-test-step3)
+ [（可选）保存 microSD 卡映像](#iot-dc-prepare-device-test-step4)

## 安装 AWS Command Line Interface
<a name="iot-dc-prepare-device-test-step1"></a>

此过程将安装 AWS CLI 到您的 Raspberry Pi 上。

如果您使用的是 Raspberry Pi 或者可以在物联网设备上编译软件，请在本地主机上的终端窗口中执行以下步骤。如果必须在本地主机上为物联网设备编译软件，请查看物联网设备的软件文档，了解所需库的信息。

**要在你的 Raspberry Pi AWS CLI 上安装**

1. 运行以下命令下载和并按照安装 AWS CLI。

   ```
   export PATH=$PATH:~/.local/bin # configures the path to include the directory with the AWS CLI
   git clone https://github.com/aws/aws-cli.git # download the AWS CLI code from GitHub
   cd aws-cli && git checkout v2 # go to the directory with the repo and checkout version 2
   pip3 install -r requirements.txt # install the prerequisite software
   ```

1. 运行此命令来安装 AWS CLI。完成此命令可能最多需要 15 分钟。

   ```
   pip3 install . # install the AWS CLI 
   ```

1. 运行此命令以确认安装的版本是否正确。 AWS CLI 

   ```
   aws --version
   ```

   的版本 AWS CLI 应为 2.2 或更高版本。

如果 AWS CLI 显示的是当前版本，则表示您已准备好继续[配置您的 AWS 账户 凭证](#iot-dc-prepare-device-test-step2)。

## 配置您的 AWS 账户 凭证
<a name="iot-dc-prepare-device-test-step2"></a>

在此过程中，您将获取 AWS 账户 凭证并将其添加到 Raspberry Pi 上使用。

**将您的 AWS 账户 凭证添加到您的设备**

1. 从您那里获取**访问密钥 ID** 和**私有访问密钥** AWS 账户 ，以便 AWS CLI 在您的设备上对其进行身份验证。

   如果您不熟悉 AWS IAM，Kn [ https://aws.amazon.com/premiumsupport/owledge-centercreate-access-key/](https://aws.amazon.com/premiumsupport/knowledge-center/create-access-key/)将介绍在 AWS 控制台中运行的创建要在设备上使用 AWS 的 IAM 证书的过程。

1. 在连接到 Raspberry Pi 的本地主机上的终端窗口中。并使用设备的**访问密钥 ID** 和**密钥访问密钥**凭据：

   1. 使用以下命令运行 AWS 配置应用程序：

      ```
      aws configure
      ```

   1. 出现提示时，输入您的 凭据和配置信息：

      ```
      AWS Access Key ID: your Access Key ID
      AWS Secret Access Key: your Secret Access Key
      Default region name: your AWS 区域 code
      Default output format: json
      ```

1. 运行此命令以测试您的设备对您的 AWS 账户 和 AWS IoT Core 端点的访问权限。

   ```
   aws iot describe-endpoint --endpoint-type iot:Data-ATS
   ```

   它应该返回您的 AWS 账户特定 AWS IoT 数据端点，例如以下示例：

   ```
   {
       "endpointAddress": "a3EXAMPLEffp-ats.iot.us-west-2.amazonaws.com"
   }
   ```

如果您看到自己的 AWS 账户特定 AWS IoT 数据端点，则表示您的 Raspberry Pi 具有继续[下载 Amazon Root CA 证书](#iot-dc-prepare-device-test-step3)访问的连接和权限。

**重要**  
你的 AWS 账户 凭证现在存储在 Raspberry Pi 的 microSD 卡上。虽然这使你将来可以 AWS 轻松地与你在这些教程中创建的软件进行交互，但默认情况下，它们也将被保存并复制到你在此步骤之后制作的任何 microSD 卡图像中。  
为了保护 AWS 账户 凭证的安全，在保存更多 microSD 卡映像之前，请考虑`aws configure`重新运行并输入访问密**钥 ID 和**私有访问密**钥**的随机字符来擦除凭证，以防止您的 AWS 账户 凭据被泄露。  
如果您发现自己无意中保存了 AWS 账户 证书，则可以在 IAM 控制台中将其停用。 AWS 

## 下载 Amazon Root CA 证书
<a name="iot-dc-prepare-device-test-step3"></a>

此过程下载并保存 Amazon Root 证书颁发机构（CA）的证书副本。下载此证书可保存以供后续教程中使用，还可测试设备与 AWS 服务的连接。

**要下载并保存 Amazon Root CA 证书**

1. 运行以下命令为证书创建一个目录。

   ```
   mkdir ~/certs
   ```

1. 运行此命令下载 Amazon Root CA 证书。

   ```
   curl -o ~/certs/AmazonRootCA1.pem https://www.amazontrust.com/repository/AmazonRootCA1.pem
   ```

1. 运行这些命令设置对证书目录及其文件的访问权限。

   ```
   chmod 745 ~
   chmod 700 ~/certs
   chmod 644 ~/certs/AmazonRootCA1.pem
   ```

1. 运行此命令查看新目录中的 CA 证书文件。

   ```
   ls -l ~/certs
   ```

   您会看到如下条目。日期和时间会有所不同；但是，文件大小和所有其他信息应与此处显示的相同。

   ```
   -rw-r--r-- 1 pi pi 1188 Oct 28 13:02 AmazonRootCA1.pem
   ```

   如果文件大小不是 `1188`，检查 **curl** 命令参数。您可能下载了错误的文件。

## （可选）保存 microSD 卡映像
<a name="iot-dc-prepare-device-test-step4"></a>

此时，Raspberry Pi 的 microSD 卡具有更新的操作系统和基本的应用程序软件加载。

**要将 microSD 卡映像保存到文件中**

1. 在本地主机上的终端窗口中，清除 AWS 凭证。

   1. 使用以下命令运行 AWS 配置应用程序：

      ```
      aws configure
      ```

   1. 出现提示时，替换凭证。您可以离开**原定设置区域名称**和**原定设置输出格式**，因为它们是通过按**Enter**（输入）。

      ```
      AWS Access Key ID [****************YT2H]: XYXYXYXYX
      AWS Secret Access Key [****************9plH]: XYXYXYXYX
      Default region name [us-west-2]: 
      Default output format [json]:
      ```

1. 输入此命令关闭 Raspberry Pi。

   ```
   sudo shutdown -h 0
   ```

1. Raspberry Pi 完全关闭后，卸下其电源接头。

1. 从设备中取出 microSD 卡。

1. 在本地主机上：

   1. 插入 microSD 卡。

   1. 使用 SD 卡成像工具，将 microSD 卡映像保存到文件中。

   1. 保存 microSD 卡映像后，从本地主机上弹出该卡。

1. 从 Raspberry Pi 断开电源后，将 microSD 卡插入 Raspberry Pi。

1. 对设备供电。

1. 大约一分钟后，在本地主机上重新启动终端窗口会话并登录到设备。

   **暂时不要重新输入您的 AWS 账户 凭证。**

重新启动并登录 Raspberry Pi 之后，您准备好继续 [教程：安装和配置 AWS IoT 设备客户端](iot-dc-install-dc.md)。

# 教程：安装和配置 AWS IoT 设备客户端
<a name="iot-dc-install-dc"></a>

本教程将引导您完成 AWS IoT 设备客户端的安装和配置，以及创建将在本演示和其他演示中使用的 AWS IoT 资源。

**要开始本教程：**
+ 准备好您的本地主机和[上一教程](iot-dc-prepare-device.md)中的 Raspberry Pi。

完成本教程需要大约 90 分钟。

**完成本主题后：**
+ 您的物联网设备将准备好在其他 AWS IoT 设备客户端演示中使用。
+ 您将在中配置您的物联网设备。 AWS IoT Core
+ 您将在设备上下载并安装 AWS IoT 设备客户端。
+ 您将保存设备 microSD 卡的映像，可在后续教程中使用。

**所需的设备：**
+ [上一节](iot-dc-prepare-device-test.md)中您的本地开发和测试环境
+ [上一节](iot-dc-prepare-device-test.md)中您使用 的Raspberry Pi
+ [上一节](iot-dc-prepare-device-test.md)中您使用的 Raspberry Pi microSD 记忆卡

**Topics**
+ [下载并保存 AWS IoT 设备客户端](iot-dc-install-download.md)
+ [在中配置你的树莓派 AWS IoT](iot-dc-install-provision.md)
+ [配置 AWS IoT 设备客户端以测试连通性](iot-dc-install-configure.md)

# 下载并保存 AWS IoT 设备客户端
<a name="iot-dc-install-download"></a>

本节中的步骤下载 AWS IoT 设备客户端，对其进行编译，然后将其安装到您的 Raspberry Pi 上。测试安装后，您可以保存 Raspberry Pi的 microSD卡映像，以便以后需要再次尝试教程时使用。

**Topics**
+ [下载并构建 AWS IoT 设备客户端](#iot-dc-install-dc-download)
+ [创建教程使用的目录](#iot-dc-install-dc-files)
+ [（可选）保存 microSD 卡映像](#iot-dc-install-dc-save)

## 下载并构建 AWS IoT 设备客户端
<a name="iot-dc-install-dc-download"></a>

此过程将 AWS IoT 设备客户端安装到您的 Raspberry Pi 上。

在连接到 Raspberry Pi 的本地主机上的终端窗口中执行这些命令。

**在 Raspberry Pi 上安装 AWS IoT 设备客户端**

1. 输入这些命令在 Raspberry Pi 上下载和构建 AWS IoT 设备客户端。

   ```
   cd ~
   git clone https://github.com/awslabs/aws-iot-device-client aws-iot-device-client
   mkdir ~/aws-iot-device-client/build && cd ~/aws-iot-device-client/build
   cmake ../
   ```

1. 运行此命令来构建 AWS IoT 设备客户端。完成此命令可能最多需要 15 分钟。

   ```
   cmake --build . --target aws-iot-device-client
   ```

   可以忽略 AWS IoT 设备客户端编译时显示的警告消息。

   这些教程已在 2021 年 10 月 30 日的 Raspberry Pi 操作系统（buster）版本上**gcc**使用内置的 AWS IoT 设备客户端（Raspbian 10.2.1-6\$1rpi1）10.2.1 20210110 进行了测试，版本为（Raspbian 8.3.0-6\$1rpi1）8.3.0。**gcc**

1.  AWS IoT 设备客户端构建完成后，通过运行此命令对其进行测试。

   ```
   ./aws-iot-device-client --help
   ```

如果您看到 AWS IoT 设备客户端的命令行帮助，则 AWS IoT 表示设备客户端已成功构建并可供您使用。

## 创建教程使用的目录
<a name="iot-dc-install-dc-files"></a>

此过程将在 Raspberry Pi 上创建目录，用于存储教程在此学习路径中使用的文件。

**要在此学习路径中创建教程使用的目录，请执行以下操作：**

1. 运行这些命令创建所需的目录。

   ```
   mkdir ~/dc-configs
   mkdir ~/policies
   mkdir ~/messages
   mkdir ~/certs/testconn
   mkdir ~/certs/pubsub
   mkdir ~/certs/jobs
   ```

1. 运行这些命令设置新目录的权限。

   ```
   chmod 745 ~
   chmod 700 ~/certs/testconn
   chmod 700 ~/certs/pubsub
   chmod 700 ~/certs/jobs
   ```

创建这些目录并设置权限后，请继续 [（可选）保存 microSD 卡映像](#iot-dc-install-dc-save)。

## （可选）保存 microSD 卡映像
<a name="iot-dc-install-dc-save"></a>

此时，你的 Raspberry Pi 的 microSD 卡已经更新了操作系统、基本应用软件和 AWS IoT 设备客户端。

如果您想再次尝试这些练习和教程，可以跳过前面的步骤，使用此步骤保存的 microSD 卡映像写入新的 microSD 卡，然后在 [在中配置你的树莓派 AWS IoT](iot-dc-install-provision.md) 中继续教程。

**要将 microSD 卡映像保存到文件中，请执行以下操作：**

在连接到 Raspberry Pi 的本地主机的终端窗口中：

1. 确认您的 AWS 账户 凭证尚未存储。

   1. 使用以下命令运行 AWS 配置应用程序：

      ```
      aws configure
      ```

   1. 如果您的凭据已存储（如果出现在提示中），输入 **XYXYXYXYX** 字符串在提示时，如下所示。保持**原定设置区域名称**和**原定设置输出格式**空白。

      ```
      AWS Access Key ID [****************YXYX]: XYXYXYXYX
      AWS Secret Access Key [****************YXYX]: XYXYXYXYX
      Default region name: 
      Default output format:
      ```

1. 输入此命令关闭 Raspberry Pi。

   ```
   sudo shutdown -h 0
   ```

1. Raspberry Pi 完全关闭后，卸下其电源接头。

1. 从设备中取出 microSD 卡。

1. 在本地主机上：

   1. 插入 microSD 卡。

   1. 使用 SD 卡成像工具，将 microSD 卡映像保存到文件中。

   1. 保存 microSD 卡的映像后，从本地主机上弹出该卡。

您可以继续使用这张 microSD 卡在 [在中配置你的树莓派 AWS IoT](iot-dc-install-provision.md) 中操作。

# 在中配置你的树莓派 AWS IoT
<a name="iot-dc-install-provision"></a>

本节中的步骤从安装了 AWS CLI 和 AWS IoT 设备客户端的保存的 microSD 映像开始，然后创建用于配置 Raspberry Pi 的 AWS IoT 资源和设备证书。 AWS IoT

## 在您的 Raspberry Pi 中安装 microSD 卡
<a name="iot-dc-install-dc-restore"></a>

此过程将 microSD 卡安装在 Raspberry Pi 中已加载和配置的必要软件，并对其进行配置， AWS 账户 以便您可以继续学习本学习路径中的教程。

使用来自 [（可选）保存 microSD 卡映像](iot-dc-install-download.md#iot-dc-install-dc-save) 的 microSD 卡，其中有这个学习路径中进行练习和教程的必要软件。

**要在您的 Raspberry Pi 中安装 microSD 卡**

1. 从 Raspberry Pi 断电后，将 microSD 卡插入 Raspberry Pi。

1. 给 Raspberry Pi 供电。

1. 大约一分钟后，在本地主机上重新启动终端窗口会话并登录 Raspberry Pi。

1. 在本地主机上、终端窗口中以及**访问密钥 ID**和您的 Raspberry Pi 上的**密钥访问密钥**凭证：

   1. 使用以下命令运行 AWS 配置应用程序：

      ```
      aws configure
      ```

   1. 出现提示时，输入您的 AWS 账户 凭据和配置信息：

      ```
      AWS Access Key ID [****************YXYX]: your Access Key ID
      AWS Secret Access Key [****************YXYX]: your Secret Access Key
      Default region name [us-west-2]: your AWS 区域 code
      Default output format [json]: json
      ```

恢复 AWS 账户 凭证后，就可以继续操作了[在中配置您的设备 AWS IoT Core](#iot-dc-install-dc-provision)。

## 在中配置您的设备 AWS IoT Core
<a name="iot-dc-install-dc-provision"></a>

本节中的步骤创建了在中配置 Raspberry Pi 的 AWS IoT 资源 AWS IoT。创建这些资源时，系统将要求您记录各种信息。 AWS IoT 设备客户端配置将在下一个步骤中使用此信息。

要使用你的 Raspberry Pi AWS IoT，必须对其进行配置。配置是创建和配置支持你的 Raspberry Pi 作为物联网设备所需的 AWS IoT 资源的过程。

启动并重新启动 Raspberry Pi 后，将本地主机上的终端窗口连接到 Raspberry Pi 上并完成这些步骤。

**Topics**
+ [创建并下载设备证书文件](#iot-dc-install-dc-provision-certs)
+ [创建 AWS IoT 资源](#iot-dc-install-dc-provision-resources)

### 创建并下载设备证书文件
<a name="iot-dc-install-dc-provision-certs"></a>

此过程为此演示创建设备证书文件。

**要为 Raspberry Pi 创建和下载设备证书文件**

1. 在本地主机的终端窗口中，输入这些命令为您的设备创建设备证书文件。

   ```
   mkdir ~/certs/testconn
   aws iot create-keys-and-certificate \
   --set-as-active \
   --certificate-pem-outfile "~/certs/testconn/device.pem.crt" \
   --public-key-outfile "~/certs/testconn/public.pem.key" \
   --private-key-outfile "~/certs/testconn/private.pem.key"
   ```

   此命令会返回类似以下内容的响应。记录 `certificateArn`值以供将来使用。

   ```
   {
       "certificateArn": "arn:aws:iot:us-west-2:57EXAMPLE833:cert/76e7e4edb3e52f52334be2f387a06145b2aa4c7fcd810f3aea2d92abc227d269",
       "certificateId": "76e7e4edb3e52f5233EXAMPLE7a06145b2aa4c7fcd810f3aea2d92abc227d269",
       "certificatePem": "-----BEGIN CERTIFICATE-----\nMIIDWTCCAkGgAwIBAgI_SHORTENED_FOR_EXAMPLE_Lgn4jfgtS\n-----END CERTIFICATE-----\n",
       "keyPair": {
           "PublicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BA_SHORTENED_FOR_EXAMPLE_ImwIDAQAB\n-----END PUBLIC KEY-----\n",
           "PrivateKey": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQE_SHORTENED_FOR_EXAMPLE_T9RoDiukY\n-----END RSA PRIVATE KEY-----\n"
       }
   }
   ```

1. 输入以下命令设置证书目录及其文件的权限。

   ```
   chmod 745 ~
   chmod 700 ~/certs/testconn
   chmod 644 ~/certs/testconn/*
   chmod 600 ~/certs/testconn/private.pem.key
   ```

1. 运行此命令可查看证书目录和文件的权限。

   ```
   ls -l ~/certs/testconn
   ```

   命令的输出应与您在此处看到的内容相同，但文件日期和时间会有所不同。

   ```
   -rw-r--r-- 1 pi pi 1220 Oct 28 13:02 device.pem.crt
   -rw------- 1 pi pi 1675 Oct 28 13:02 private.pem.key
   -rw-r--r-- 1 pi pi  451 Oct 28 13:02 public.pem.key
   ```

此时，您已经在 Raspberry Pi 上安装了设备证书文件，可以继续 [创建 AWS IoT 资源](#iot-dc-install-dc-provision-resources)。

### 创建 AWS IoT 资源
<a name="iot-dc-install-dc-provision-resources"></a>

此过程 AWS IoT 通过创建设备访问 AWS IoT 功能和服务所需的资源来配置您的设备。

**要在中配置您的设备 AWS IoT**

1. 在本地主机的终端窗口中，输入以下命令获取您的 AWS 账户设备数据端点的地址。

   ```
   aws iot describe-endpoint --endpoint-type IoT:Data-ATS
   ```

   上面步骤的命令会返回类似以下内容的响应。记录 `endpointAddress`值以供将来使用。

   ```
   {
       "endpointAddress": "a3qjEXAMPLEffp-ats.iot.us-west-2.amazonaws.com"
   }
   ```

1. 输入此命令为您的 Raspberry Pi 创建 AWS IoT 事物资源。

   ```
   aws iot create-thing --thing-name "DevCliTestThing"
   ```

   如果您的 AWS IoT 事物资源已创建，则该命令会返回这样的响应。

   ```
   {
       "thingName": "DevCliTestThing",
       "thingArn": "arn:aws:iot:us-west-2:57EXAMPLE833:thing/DevCliTestThing",
       "thingId": "8ea78707-32c3-4f8a-9232-14bEXAMPLEfd"
   }
   ```

1. 在终端窗口中：

   1. 打开文本编辑器，例如 `nano`。

   1. 复制此 JSON 策略文档并将其粘贴到打开的文本编辑器中。  
****  

      ```
      {
          "Version":"2012-10-17",		 	 	 
          "Statement": [
              {
                  "Effect": "Allow",
                  "Action": [
                      "iot:Publish",
                      "iot:Subscribe",
                      "iot:Receive",
                      "iot:Connect"
                  ],
                  "Resource": [
                      "*"
                  ]
              }
          ]
      }
      ```
**注意**  
本策略文档慷慨授予每个资源连接、接收、发布和订阅的权限。通常，策略仅向特定资源授予权限执行特定操作。但是，对于初始设备连通性测试，这种过于笼统和宽容的策略用于尽量减少测试期间出现访问问题的可能性。在随后的教程中，将使用范围更窄的策略文档来展示策略设计中的更好做法。

   1. 将文本编辑器中的文件保存为 **\$1/policies/dev\$1cli\$1test\$1thing\$1policy.json**。

1. 运行此命令使用前面步骤中的策略文档来创建 AWS IoT 策略。

   ```
   aws iot create-policy \
   --policy-name "DevCliTestThingPolicy" \
   --policy-document "file://~/policies/dev_cli_test_thing_policy.json"
   ```

   如果创建策略，该命令将返回类似此类的响应。

   ```
   {
       "policyName": "DevCliTestThingPolicy",
       "policyArn": "arn:aws:iot:us-west-2:57EXAMPLE833:policy/DevCliTestThingPolicy",
       "policyDocument": "{\n    \"Version\": \"2012-10-17\",		 	 	 \n    \"Statement\": [\n        {\n            \"Effect\": \"Allow\",\n            \"Action\": [\n                \"iot:Publish\",\n                \"iot:Subscribe\",\n                \"iot:Receive\",\n                \"iot:Connect\"\n            ],\n            \"Resource\": [\n                \"*\"\n            ]\n        }\n    ]\n}\n",
       "policyVersionId": "1"
   }
   ```

1. 运行此命令将策略附加到设备证书。将 `certificateArn`替换为 您之前保存的 `certificateArn`值。

   ```
   aws iot attach-policy \
   --policy-name "DevCliTestThingPolicy" \
   --target "certificateArn"
   ```

   如果成功，该命令不返回任何内容。

1. 运行此命令将设备证书附加到 AWS IoT 事物资源。将 `certificateArn`替换为 您之前保存的 `certificateArn`值。

   ```
   aws iot attach-thing-principal \
   --thing-name "DevCliTestThing" \
   --principal "certificateArn"
   ```

   如果成功，该命令不返回任何内容。

在中成功配置设备后 AWS IoT，就可以继续[配置 AWS IoT 设备客户端以测试连通性](iot-dc-install-configure.md)操作了。

# 配置 AWS IoT 设备客户端以测试连通性
<a name="iot-dc-install-configure"></a>

本节中的步骤将 AWS IoT 设备客户端配置为从您的 Raspberry Pi 发布 MQTT 消息。

**Topics**
+ [创建配置文件](#iot-dc-install-dc-configure-step1)
+ [打开 MQTT 测试客户端](#iot-dc-install-dc-configure-step2)
+ [运行 AWS IoT 设备客户端](#iot-dc-install-dc-configure-step3)

## 创建配置文件
<a name="iot-dc-install-dc-configure-step1"></a>

此过程创建配置文件来测试 AWS IoT 设备客户端。

**创建用于测试 AWS IoT 设备客户端的配置文件**
+ 在连接到 Raspberry Pi 的本地主机的终端窗口中：

  1. 输入这些命令为配置文件创建目录并设置对该目录的权限：

     ```
     mkdir ~/dc-configs
     chmod 745 ~/dc-configs
     ```

  1. 打开文本编辑器，例如 `nano`。

  1. 复制此 JSON 文档并将其粘贴到打开的文本编辑器中。

     ```
     {
       "endpoint": "a3qEXAMPLEaffp-ats.iot.us-west-2.amazonaws.com",
       "cert": "~/certs/testconn/device.pem.crt",
       "key": "~/certs/testconn/private.pem.key",
       "root-ca": "~/certs/AmazonRootCA1.pem",
       "thing-name": "DevCliTestThing",
       "logging": {
         "enable-sdk-logging": true,
         "level": "DEBUG",
         "type": "STDOUT",
         "file": ""
       },
       "jobs": {
         "enabled": false,
         "handler-directory": ""
       },
       "tunneling": {
         "enabled": false
       },
       "device-defender": {
         "enabled": false,
         "interval": 300
       },
       "fleet-provisioning": {
         "enabled": false,
         "template-name": "",
         "template-parameters": "",
         "csr-file": "",
         "device-key": ""
       },
       "samples": {
         "pub-sub": {
           "enabled": true,
           "publish-topic": "test/dc/pubtopic",
           "publish-file": "",
           "subscribe-topic": "test/dc/subtopic",
           "subscribe-file": ""
         }
       },
       "config-shadow": {
         "enabled": false
       },
       "sample-shadow": {
         "enabled": false,
         "shadow-name": "",
         "shadow-input-file": "",
         "shadow-output-file": ""
       }
     }
     ```

  1. 将该*endpoint*值替换为您在中找到的设备数据端点[在中配置您的设备 AWS IoT Core](iot-dc-install-provision.md#iot-dc-install-dc-provision)。 AWS 账户 

  1. 将文本编辑器中的文件保存为 **\$1/dc-configs/dc-testconn-config.json**。

  1. 运行这个命令在新文件上设置权限

     ```
     chmod 644 ~/dc-configs/dc-testconn-config.json
     ```

保存文件后，您已准备就绪继续 [打开 MQTT 测试客户端](#iot-dc-install-dc-configure-step2)。

## 打开 MQTT 测试客户端
<a name="iot-dc-install-dc-configure-step2"></a>

此过程使 AWS IoT 控制台中的 **MQTT 测试客户端**做好订阅 AWS IoT 设备客户端运行时发布的 MQTT 消息的准备。

**准备 **MQTT 测试客户端**订阅所有 MQTT 消息**

1. 在本地主机上，在[AWS IoT 控制台](https://console.aws.amazon.com//iot/home#/test)，选择**MQTT 测试客户端**。

1. 在**订阅主题**选项卡的**主题筛选条件**中输入 **\$1**（单个井号），然后选择**订阅**来订阅每个 MQTT 主题。

1. 在**订阅**标签下，确认您看见 **\$1**（单个井号）。

让窗口的 **MQTT 测试客户端** 保持打开，继续 [运行 AWS IoT 设备客户端](#iot-dc-install-dc-configure-step3)。

## 运行 AWS IoT 设备客户端
<a name="iot-dc-install-dc-configure-step3"></a>

此过程运行 AWS IoT 设备客户端，以便它发布一条 MQTT **测试客户端接收并显示的 MQTT** 消息。

**从 AWS IoT 设备客户端发送 MQTT 消息**

1. 在执行此步骤时，确保连接到 Raspberry Pi 的终端窗口和带 **MQTT 测试客户端**可见。

1. 在终端窗口中，输入这些命令以使用中创建的配置文件运行 AWS IoT 设备客户端[创建配置文件](#iot-dc-install-dc-configure-step1)。

   ```
   cd ~/aws-iot-device-client/build
   ./aws-iot-device-client --config-file ~/dc-configs/dc-testconn-config.json
   ```

   在终端窗口中， AWS IoT 设备客户端显示信息消息以及运行时出现的任何错误。

   如果终端窗口中没有显示错误，请查看 **MQTT 测试客户端**。

1. 在 **MQTT 测试客户端**的“订阅”窗口中，查看发送到 `test/dc/pubtopic` 消息主题的 *Hello World\$1* 消息。

1. 如果 AWS IoT 设备客户端没有显示任何错误并且你看到 *Hello World！* 发送到 **MQTT 测试客户端**中的`test/dc/pubtopic`消息时，您已演示连接成功。

1. 在终端窗口中，输入 **^C** (Ctrl-C) 以停止 AWS IoT 设备客户端。

在您证明 AWS IoT 设备客户端在 Raspberry Pi 上运行正常，并且可以与之通信之后 AWS IoT，您可以继续[教程：演示与 AWS IoT 设备客户端的 MQTT 消息通信](iot-dc-testconn.md)。

# 教程：演示与 AWS IoT 设备客户端的 MQTT 消息通信
<a name="iot-dc-testconn"></a>

本教程演示 AWS IoT 设备客户端如何订阅和发布物联网解决方案中常用的 MQTT 消息。

**要开始本教程：**
+ 将本地主机和 Raspberry Pi 配置为在[上一节](iot-dc-install-dc.md)使用。

  如果您在安装 AWS IoT 设备客户端后保存了 microSD 卡映像，则可以将带有该图像的 microSD 卡与 Raspberry Pi 一起使用。
+ 如果您之前运行过此演示，[第 2 步：使用 AWS IoT 设备客户端 AWS 账户 在构建演示之后清理你的](iot-dc-cleanup.md#iot-dc-cleanup-cloud)请查看删除您在之前运行中创建的所有 AWS IoT 资源，以避免出现重复的资源错误。

完成本教程需要大约 45 分钟。

**完成本主题后：**
+ 您将演示物联网设备订阅 MQTT 消息 AWS IoT 并向其发布 MQTT 消息的不同方式。 AWS IoT

**所需的设备：**
+ [上一节](iot-dc-install-dc.md)中您的本地开发和测试环境
+ [上一节](iot-dc-install-dc.md)中您使用 的Raspberry Pi
+ [上一节](iot-dc-install-dc.md)中您使用的 Raspberry Pi microSD 记忆卡

**Topics**
+ [准备 Raspberry Pi 来演示 MQTT 消息通信](iot-dc-testconn-provision.md)
+ [演示使用 AWS IoT 设备客户端发布消息](iot-dc-testconn-publish.md)
+ [演示使用 AWS IoT 设备客户端订阅消息](iot-dc-testconn-subscribe.md)

# 准备 Raspberry Pi 来演示 MQTT 消息通信
<a name="iot-dc-testconn-provision"></a>

此过程在 Raspberry Pi 中 AWS IoT 和中创建资源，以演示使用 AWS IoT 设备客户端进行 MQTT 消息通信。

**Topics**
+ [创建证书文件演示 MQTT 通信](#iot-dc-testconn-provision-certs)
+ [预调配您的设备演示 MQTT 通信](#iot-dc-testconn-provision-aws)
+ [配置 AWS IoT 设备客户端配置文件和 MQTT 测试客户端，演示 MQTT 通信](#iot-dc-testconn-provision-dc-config)

## 创建证书文件演示 MQTT 通信
<a name="iot-dc-testconn-provision-certs"></a>

此过程为此演示创建设备证书文件。

**要为 Raspberry Pi 创建和下载设备证书文件**



1. 在本地主机的终端窗口中，输入以下命令为您的设备创建设备证书文件。

   ```
   mkdir ~/certs/pubsub
   aws iot create-keys-and-certificate \
   --set-as-active \
   --certificate-pem-outfile "~/certs/pubsub/device.pem.crt" \
   --public-key-outfile "~/certs/pubsub/public.pem.key" \
   --private-key-outfile "~/certs/pubsub/private.pem.key"
   ```

   此命令会返回类似以下内容的响应。保存 `certificateArn`值供稍后使用。

   ```
   {
   "certificateArn": "arn:aws:iot:us-west-2:57EXAMPLE833:cert/76e7e4edb3e52f52334be2f387a06145b2aa4c7fcd810f3aea2d92abc227d269",
   "certificateId": "76e7e4edb3e52f5233EXAMPLE7a06145b2aa4c7fcd810f3aea2d92abc227d269",
   "certificatePem": "-----BEGIN CERTIFICATE-----\nMIIDWTCCAkGgAwIBAgI_SHORTENED_FOR_EXAMPLE_Lgn4jfgtS\n-----END CERTIFICATE-----\n",
   "keyPair": {
       "PublicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BA_SHORTENED_FOR_EXAMPLE_ImwIDAQAB\n-----END PUBLIC KEY-----\n",
       "PrivateKey": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQE_SHORTENED_FOR_EXAMPLE_T9RoDiukY\n-----END RSA PRIVATE KEY-----\n"
   }
   }
   ```

1. 输入以下命令设置证书目录及其文件的权限。

   ```
   chmod 700 ~/certs/pubsub
   chmod 644 ~/certs/pubsub/*
   chmod 600 ~/certs/pubsub/private.pem.key
   ```

1. 运行此命令可查看证书目录和文件的权限。

   ```
   ls -l ~/certs/pubsub
   ```

   命令的输出应与您在此处看到的内容相同，但文件日期和时间会有所不同。

   ```
   -rw-r--r-- 1 pi pi 1220 Oct 28 13:02 device.pem.crt
   -rw------- 1 pi pi 1675 Oct 28 13:02 private.pem.key
   -rw-r--r-- 1 pi pi  451 Oct 28 13:02 public.pem.key
   ```

1. 输入这些命令创建日志文件的目录。

   ```
   mkdir ~/.aws-iot-device-client
   mkdir ~/.aws-iot-device-client/log
   chmod 745 ~/.aws-iot-device-client/log
   echo " " > ~/.aws-iot-device-client/log/aws-iot-device-client.log
   echo " " > ~/.aws-iot-device-client/log/pubsub_rx_msgs.log
   chmod 600 ~/.aws-iot-device-client/log/*
   ```

## 预调配您的设备演示 MQTT 通信
<a name="iot-dc-testconn-provision-aws"></a>

本节创建了在中配置 Raspberry Pi 的 AWS IoT 资源 AWS IoT。

**在 AWS IoT中预置您的设备：**

1. 在本地主机的终端窗口中，输入以下命令获取您的 AWS 账户设备数据端点的地址。

   ```
   aws iot describe-endpoint --endpoint-type IoT:Data-ATS
   ```

   自从您为上一教程运行此命令以来，端点值一直没有更改。再次在此处运行命令是为了方便地查找数据端点值并将其粘贴到本教程中使用的配置文件中。

   上面步骤的命令会返回类似以下内容的响应。记录 `endpointAddress`值以供将来使用。

   ```
   {
   "endpointAddress": "a3qjEXAMPLEffp-ats.iot.us-west-2.amazonaws.com"
   }
   ```

1. 输入此命令为您的 Raspberry Pi 创建新 AWS IoT 事物资源。

   ```
   aws iot create-thing --thing-name "PubSubTestThing"
   ```

   由于 AWS IoT 事物资源是您的设备在云中的*虚拟*表示，因此我们可以创建多个事物资源 AWS IoT 以用于不同的目的。它们都可以由同一物理 IoT 设备使用来表示设备的不同方面。

   这些教程一次只能使用一个事物资源来表示 Raspberry Pi。这样，在这些教程中，它们代表了不同的演示，因此在为演示创建 AWS IoT 资源之后，您可以返回并使用专门为每个演示创建的资源重复演示。

   如果您的 AWS IoT 事物资源已创建，则该命令会返回类似这样的响应。

   ```
   {
   "thingName": "PubSubTestThing",
   "thingArn": "arn:aws:iot:us-west-2:57EXAMPLE833:thing/PubSubTestThing",
   "thingId": "8ea78707-32c3-4f8a-9232-14bEXAMPLEfd"
   }
   ```

1. 在终端窗口中：

   1. 打开文本编辑器，例如 `nano`。

   1. 复制此 JSON 文档并将其粘贴到打开的文本编辑器中。  
****  

      ```
      {
          "Version":"2012-10-17",		 	 	 
          "Statement": [
              {
                  "Effect": "Allow",
                  "Action": [
                      "iot:Connect"
                  ],
                  "Resource": [
                      "arn:aws:iot:us-west-2:123456789012:client/PubSubTestThing"
                  ]
              },
              {
                  "Effect": "Allow",
                  "Action": [
                      "iot:Publish"
                  ],
                  "Resource": [
                      "arn:aws:iot:us-west-2:123456789012:topic/test/dc/pubtopic"
                  ]
              },
              {
                  "Effect": "Allow",
                  "Action": [
                      "iot:Subscribe"
                  ],
                  "Resource": [
                      "arn:aws:iot:us-west-2:123456789012:topicfilter/test/dc/subtopic"
                  ]
              },
              {
                  "Effect": "Allow",
                  "Action": [
                      "iot:Receive"
                  ],
                  "Resource": [
                      "arn:aws:iot:us-west-2:123456789012:topic/test/dc/subtopic"
                  ]
              }
          ]
      }
      ```

   1. 在编辑器中，在政策文档的每个`Resource`部分中，*us-west-2:57EXAMPLE833*用您 AWS 区域的、冒号字符 (:) 和您的 12 位 AWS 账户 数字替换。

   1. 将文本编辑器中的文件保存为 **\$1/policies/pubsub\$1test\$1thing\$1policy.json**。

1. 运行此命令使用前面步骤中的策略文档来创建 AWS IoT 策略。

   ```
   aws iot create-policy \
   --policy-name "PubSubTestThingPolicy" \
   --policy-document "file://~/policies/pubsub_test_thing_policy.json"
   ```

   如果创建策略，该命令将返回类似此类的响应。

   ```
   {
                                       "policyName": "PubSubTestThingPolicy",
                                       "policyArn": "arn:aws:iot:us-west-2:57EXAMPLE833:policy/PubSubTestThingPolicy",
                                       "policyDocument": "{\n\"Version\": \"2012-10-17\",		 	 	 \n\"Statement\": [\n{\n\"Effect\": \"Allow\",\n\"Action\": [\n\"iot:Connect\"\n],\n\"Resource\": [\n\"arn:aws:iot:us-west-2:57EXAMPLE833:client/PubSubTestThing\"\n]\n},\n{\n\"Effect\": \"Allow\",\n\"Action\": [\n\"iot:Publish\"\n],\n\"Resource\": [\n\"arn:aws:iot:us-west-2:57EXAMPLE833:topic/test/dc/pubtopic\"\n]\n},\n{\n\"Effect\": \"Allow\",\n\"Action\": [\n\"iot:Subscribe\"\n],\n\"Resource\": [\n\"arn:aws:iot:us-west-2:57EXAMPLE833:topicfilter/test/dc/subtopic\"\n]\n},\n{\n\"Effect\": \"Allow\",\n\"Action\": [\n\"iot:Receive\"\n],\n\"Resource\": [\n\"arn:aws:iot:us-west-2:57EXAMPLE833:topic/test/dc/*\"\n]\n}\n]\n}\n",
                                       "policyVersionId": "1"
                                       }
   ```

1. 运行此命令将策略附加到设备证书。将 `certificateArn`替换为您之前在本部分保存的 `certificateArn`值。

   ```
   aws iot attach-policy \
   --policy-name "PubSubTestThingPolicy" \
   --target "certificateArn"
   ```

   如果成功，该命令不返回任何内容。

1. 运行此命令将设备证书附加到 AWS IoT 事物资源。将 `certificateArn`替换为您之前在本部分保存的 `certificateArn`值。

   ```
   aws iot attach-thing-principal \
   --thing-name "PubSubTestThing" \
   --principal "certificateArn"
   ```

   如果成功，该命令不返回任何内容。

在中成功配置设备后 AWS IoT，就可以继续操作了[配置 AWS IoT 设备客户端配置文件和 MQTT 测试客户端，演示 MQTT 通信](#iot-dc-testconn-provision-dc-config)。

## 配置 AWS IoT 设备客户端配置文件和 MQTT 测试客户端，演示 MQTT 通信
<a name="iot-dc-testconn-provision-dc-config"></a>

此过程创建一个配置文件来测试 AWS IoT 设备客户端。

**创建用于测试 AWS IoT 设备客户端的配置文件**

1. 在连接到 Raspberry Pi 的本地主机的终端窗口中：

   1. 打开文本编辑器，例如 `nano`。

   1. 复制此 JSON 文档并将其粘贴到打开的文本编辑器中。

      ```
      {
        "endpoint": "a3qEXAMPLEaffp-ats.iot.us-west-2.amazonaws.com",
        "cert": "~/certs/pubsub/device.pem.crt",
        "key": "~/certs/pubsub/private.pem.key",
        "root-ca": "~/certs/AmazonRootCA1.pem",
        "thing-name": "PubSubTestThing",
        "logging": {
          "enable-sdk-logging": true,
          "level": "DEBUG",
          "type": "STDOUT",
          "file": ""
        },
        "jobs": {
          "enabled": false,
          "handler-directory": ""
        },
        "tunneling": {
          "enabled": false
        },
        "device-defender": {
          "enabled": false,
          "interval": 300
        },
        "fleet-provisioning": {
          "enabled": false,
          "template-name": "",
          "template-parameters": "",
          "csr-file": "",
          "device-key": ""
        },
        "samples": {
          "pub-sub": {
            "enabled": true,
            "publish-topic": "test/dc/pubtopic",
            "publish-file": "",
            "subscribe-topic": "test/dc/subtopic",
            "subscribe-file": "~/.aws-iot-device-client/log/pubsub_rx_msgs.log"
          }
        },
        "config-shadow": {
          "enabled": false
        },
        "sample-shadow": {
          "enabled": false,
          "shadow-name": "",
          "shadow-input-file": "",
          "shadow-output-file": ""
        }
      }
      ```

   1. 将该*endpoint*值替换为您在中找到的设备数据端点[在中配置您的设备 AWS IoT Core](iot-dc-install-provision.md#iot-dc-install-dc-provision)。 AWS 账户 

   1. 将文本编辑器中的文件保存为 **\$1/dc-configs/dc-pubsub-config.json**。

   1. 运行这个命令在新文件上设置权限

      ```
      chmod 644 ~/dc-configs/dc-pubsub-config.json
      ```

1. 准备 **MQTT 测试客户端**订阅所有 MQTT 消息：

   1. 在本地主机上，在[AWS IoT 控制台](https://console.aws.amazon.com//iot/home#/test)，选择**MQTT 测试客户端**。

   1. 在**订阅主题**选项卡上，在**主题筛选条件**中，输入 **\$1**（单个井号），然后选择**订阅**。

   1. 在**订阅**标签下，确认您看见 **\$1**（单独英镑符号）。

   继续此教程时，让窗口的 **MQTT 测试客户端** 保持打开。

保存文件并配置 **MQTT 测试客户端**后，您便可以继续 [演示使用 AWS IoT 设备客户端发布消息](iot-dc-testconn-publish.md)。

# 演示使用 AWS IoT 设备客户端发布消息
<a name="iot-dc-testconn-publish"></a>

本节中的过程演示 AWS IoT 设备客户端如何发送默认和自定义 MQTT 消息。

在上一步中为这些练习创建的策略中的以下策略声明授予 Raspberry Pi 执行以下操作的权限：
+ 

**`iot:Connect`**  
让名`PubSubTestThing`为的客户端（运行 AWS IoT 设备客户端的 Raspberry Pi）进行连接。

  ```
      {
        "Effect": "Allow",
        "Action": [
          "iot:Connect"
        ],
        "Resource": [
          "arn:aws:iot:us-west-2:57EXAMPLE833:client/PubSubTestThing"
        ]
      }
  ```
+ 

**`iot:Publish`**  
授予 Raspberry Pi 用 `test/dc/pubtopic` MQTT 主题发布消息的全效。

  ```
      {
        "Effect": "Allow",
        "Action": [
          "iot:Publish"
        ],
        "Resource": [
          "arn:aws:iot:us-west-2:57EXAMPLE833:topic/test/dc/pubtopic"
        ]
      }
  ```

  `iot:Publish` 操作提供发布到资源数组中列出的 MQTT 主题权限。那些消息的*内容*不受策略声明的控制。

## 使用 AWS IoT 设备客户端发布默认消息
<a name="iot-dc-testconn-publish-default"></a>

此过程运行 AWS IoT 设备客户端，以便它发布一条默认 MQTT 消息，MQT **T 测试客户端**会收到并显示该消息。

**从 AWS IoT 设备客户端发送默认 MQTT 消息**

1. 执行此过程时，请确保连接到 Raspberry Pi 的本地主机上的终端窗口和使用 **MQTT测试客户端**的窗口都可见。

1. 在终端窗口中，输入这些命令以使用中创建的配置文件运行 AWS IoT 设备客户端[创建配置文件](iot-dc-install-configure.md#iot-dc-install-dc-configure-step1)。

   ```
   cd ~/aws-iot-device-client/build
   ./aws-iot-device-client --config-file ~/dc-configs/dc-pubsub-config.json
   ```

   在终端窗口中， AWS IoT 设备客户端显示信息消息以及运行时出现的任何错误。

   如果终端窗口中没有显示错误，请查看 **MQTT 测试客户端**。

1. 在 **MQTT 测试客户端**的**订阅**窗口中，查看发送到 `test/dc/pubtopic` 消息主题的 *Hello World\$1* 消息。

1. 如果 AWS IoT 设备客户端没有显示任何错误并且你看到 *Hello World！* 发送到 **MQTT 测试客户端**中的`test/dc/pubtopic`消息时，您已演示连接成功。

1. 在终端窗口中，输入 **^C** (Ctrl-C) 以停止 AWS IoT 设备客户端。

在您演示 AWS IoT 设备客户端发布了默认 MQTT 消息之后，您可以继续。[使用 AWS IoT 设备客户端发布自定义消息](#iot-dc-testconn-publish-custom)

## 使用 AWS IoT 设备客户端发布自定义消息
<a name="iot-dc-testconn-publish-custom"></a>

本节中的步骤创建一条自定义 MQTT 消息，然后运行 AWS IoT Device Client，以便将自定义 MQTT 消息发布一次，以便 **MQTT 测试客户端**接收和显示。

### 为 AWS IoT 设备客户端创建自定义 MQTT 消息
<a name="iot-dc-testconn-publish-custom-create"></a>

在连接到 Raspberry Pi 的本地主机上的终端窗口中执行以下步骤。

**创建自定义消息供 AWS IoT 设备客户端发布**

1. 在终端窗口中，打开文本编辑器，例如 `nano`。

1. 在文本编辑器中，复制并粘贴以下 JSON 文档。这将是 AWS IoT 设备客户端发布的 MQTT 消息有效负载。

   ```
   {
     "temperature": 28,
     "humidity": 80,
     "barometer": 1013,
     "wind": {
       "velocity": 22,
       "bearing": 255
     }
   }
   ```

1. 将文本编辑器的内容另存为 **\$1/messages/sample-ws-message.json**。

1. 输入以下命令设置刚才创建的消息文件的权限。

   ```
   chmod 600 ~/messages/*
   ```

**为 AWS IoT 设备客户端创建用于发送自定义消息的配置文件**

1. 在终端窗口中，在文本编辑器（例如）中`nano`，打开现有的 AWS IoT 设备客户端配置文件：**\$1/dc-configs/dc-pubsub-config.json**。

1. 编辑 `samples` 对象如下所示。此文件的其他部分不需要更改。

   ```
     "samples": {
       "pub-sub": {
         "enabled": true,
         "publish-topic": "test/dc/pubtopic",
         "publish-file": "~/messages/sample-ws-message.json",
         "subscribe-topic": "test/dc/subtopic",
         "subscribe-file": "~/.aws-iot-device-client/log/pubsub_rx_msgs.log"
   ```

1. 将文本编辑器的内容另存为 **\$1/dc-configs/dc-pubsub-custom-config.json**。

1. 运行这个命令在新文件上设置权限

   ```
   chmod 644 ~/dc-configs/dc-pubsub-custom-config.json
   ```

### 使用 AWS IoT 设备客户端发布自定义 MQTT 消息
<a name="iot-dc-testconn-publish-custom-publish"></a>

此更改仅影响 MQTT 消息有效载荷的*内容*，因此当前策略将继续工作。但是，如果*MQTT 主题*（由 `~/dc-configs/dc-pubsub-custom-config.json` 红的 `publish-topic` 值定义) 已更改，还需要修改策略语句 `iot::Publish`，允许 Raspberry Pi 发布到新的 MQTT 主题。

**从 AWS IoT 设备客户端发送 MQTT 消息**

1. 在执行此过程时，确保终端窗口和窗口都有 **MQTT 测试客户端**可见。此外，请确保 **MQTT 测试客户端**仍订阅为**\$1**主题筛选条件。如果没有订阅，请再次订阅**\$1**筛选条件主题。

1. 在终端窗口中，输入这些命令以使用在 AWS IoT 中创建的配置文件运行 [创建配置文件](iot-dc-install-configure.md#iot-dc-install-dc-configure-step1)Device Client。

   ```
   cd ~/aws-iot-device-client/build
   ./aws-iot-device-client --config-file ~/dc-configs/dc-pubsub-custom-config.json
   ```

   在终端窗口中， AWS IoT 设备客户端显示信息消息以及运行时出现的任何错误。

   如果终端窗口中没有显示错误，请查看 MQTT 测试客户端。

1. 在 **MQTT 测试客户端**中，在**订阅窗口**中，请参阅发送到 `test/dc/pubtopic` 消息主题的自定义消息有效载荷。

1. 如果 AWS IoT 设备客户端未显示任何错误，并且您看到在 **MQTT 测试客户端**中发布到`test/dc/pubtopic`消息的自定义消息负载，则表示您已成功发布自定义消息。

1. 在终端窗口中，输入 **^C** (Ctrl-C) 以停止 AWS IoT 设备客户端。

在您证明 AWS IoT 设备客户端发布了自定义消息负载之后，您可以继续[演示使用 AWS IoT 设备客户端订阅消息](iot-dc-testconn-subscribe.md)。

# 演示使用 AWS IoT 设备客户端订阅消息
<a name="iot-dc-testconn-subscribe"></a>

在本节中，您将演示两种类型的消息订阅：
+ 单独订阅主题
+ 通配符主题订阅

为这些练习创建的策略中的策略语句授予 Raspberry Pi 执行这些操作的权限：
+ 

**`iot:Receive`**  
授予 AWS IoT 设备客户端接收与`Resource`对象中命名主题相匹配的 MQTT 主题的权限。

  ```
      {
        "Effect": "Allow",
        "Action": [
          "iot:Receive"
        ],
        "Resource": [
          "arn:aws:iot:us-west-2:57EXAMPLE833:topic/test/dc/subtopic"
        ]
      }
  ```
+ 

**`iot:Subscribe`**  
向 AWS IoT 设备客户端授予订阅与`Resource`对象中命名的过滤器相匹配的 MQTT 主题过滤器的权限。

  ```
      {
        "Effect": "Allow",
        "Action": [
          "iot:Subscribe"
        ],
        "Resource": [
          "arn:aws:iot:us-west-2:57EXAMPLE833:topicfilter/test/dc/subtopic"
        ]
      }
  ```

## 订阅单个 MQTT 消息主题
<a name="iot-dc-testconn-subscribe-simple-topic"></a>

此过程演示 AWS IoT 设备客户端如何订阅和记录 MQTT 消息。

在连接到 Raspberry Pi 的本地主机上的终端窗口中，列出 **\$1/dc-configs/dc-pubsub-custom-config.json** 的内容或者在文本编辑器中打开该文件查看内容。定位 `samples` 对象，应如下所示。

```
  "samples": {
    "pub-sub": {
      "enabled": true,
      "publish-topic": "test/dc/pubtopic",
      "publish-file": "~/messages/sample-ws-message.json",
      "subscribe-topic": "test/dc/subtopic",
      "subscribe-file": "~/.aws-iot-device-client/log/pubsub_rx_msgs.log"
```

注意 `subscribe-topic` 值是 AWS IoT Device Client 将在运行时订阅的 MQTT 主题。 AWS IoT 设备客户端将其从此订阅中收到的消息负载写入`subscribe-file`值中命名的文件。

**从 AWS IoT 设备客户端订阅 MQTT 消息主题**

1. 在执行此过程时，确保终端窗口和窗口都有 MQTT 测试客户端可见。此外，请确保 **MQTT 测试客户端**仍订阅为**\$1**主题筛选条件。如果没有订阅，请再次订阅**\$1**筛选条件主题。

1. 在终端窗口中，输入这些命令以使用中创建的配置文件运行 AWS IoT 设备客户端[创建配置文件](iot-dc-install-configure.md#iot-dc-install-dc-configure-step1)。

   ```
   cd ~/aws-iot-device-client/build
   ./aws-iot-device-client --config-file ~/dc-configs/dc-pubsub-custom-config.json
   ```

   在终端窗口中， AWS IoT 设备客户端显示信息消息以及运行时出现的任何错误。

   如果终端窗口中未显示错误，请在 AWS IoT 控制台继续。

1. 在 AWS IoT 控制台的 **MQTT 测试客户端**中，选择**发布到主题**选项卡。

1. 在 **主题名称**中，输入 **test/dc/subtopic**。

1. 在**消息有效载荷**中，查看消息内容。

1. 选择 **Publish**（发布）发布 MQTT 消息。

1. 在终端窗口中，注意从 AWS IoT 设备客户端*收到的如下所示的消息*条目。

   ```
   2021-11-10T16:02:20.890Z [DEBUG] {samples/PubSubFeature.cpp}: Message received on subscribe topic, size: 45 bytes
   ```

1. 看到显示*已收到消息的消息*条目后，输入 **^C** (Ctrl-C) 停止 AWS IoT 设备客户端。

1. 输入此命令可查看消息日志文件的末尾并查看您从 **MQTT 测试客户端**发布的信息

   ```
   tail ~/.aws-iot-device-client/log/pubsub_rx_msgs.log
   ```

通过查看日志文件中的消息，您已经演示了 AWS IoT Device Client 收到了您从 MQTT 测试客户端发布的消息。

## 使用通配符订阅多个 MQTT 消息主题
<a name="iot-dc-testconn-subscribe-wild-topic"></a>

这些过程演示了 AWS IoT 设备客户端如何使用通配符订阅和记录 MQTT 消息。要做到这一点，您将：

1. 更新 AWS IoT 设备客户端用于订阅 MQTT 主题的主题筛选器。

1. 更新设备使用的策略允许新订阅。

1. 运行 AWS IoT 设备客户端并从 MQTT 测试控制台发布消息。

**使用通配符 MQTT 主题筛选条件创建配置文件订阅多个 MQTT 消息主题**

1. 在连接到 Raspberry Pi 的本地主机上的终端窗口中，打开 **\$1/dc-configs/dc-pubsub-custom-config.json** 进行编辑并定位 `samples` 对象。

1. 在文本编辑器中，定位 `samples` 对象并更新 `subscribe-topic` 值如下所示。

   ```
     "samples": {
       "pub-sub": {
         "enabled": true,
         "publish-topic": "test/dc/pubtopic",
         "publish-file": "~/messages/sample-ws-message.json",
         "subscribe-topic": "test/dc/#",
         "subscribe-file": "~/.aws-iot-device-client/log/pubsub_rx_msgs.log"
   ```

   新 `subscribe-topic`值是 [MQTT 主题筛选条件](topics.md#topicfilters)，其末尾带有 MQTT 通配符。这描述了以 `test/dc/`开始的所有 MQTT 主题的订阅。 AWS IoT 设备客户端将其从此订阅中收到的消息负载写入中`subscribe-file`名为的文件。

1. 将修改后的配置文件另存为 **\$1/dc-configs/dc-pubsub-wild-config.json**，然后退出编辑器。

**修改 Raspberry Pi 使用的策略允许订阅和接收多个 MQTT 消息主题**

1. 在连接到 Raspberry Pi 的本地主机上的终端窗口中，在您最喜欢的文本编辑器中打开 **\$1/policies/pubsub\$1test\$1thing\$1policy.json** 进行编辑，然后定位 `iot::Subscribe` 和 `iot::Receive` 文件中的策略语句。

1. 在`iot::Subscribe`策略语句中更新 Resource 对象中的字符串用 `*`替换 `subtopic`，如下所示。

   ```
       {
         "Effect": "Allow",
         "Action": [
           "iot:Subscribe"
         ],
         "Resource": [
           "arn:aws:iot:us-west-2:57EXAMPLE833:topicfilter/test/dc/*"
         ]
       }
   ```
**注意**  
[MQTT 主题筛选条件通配符](topics.md#topicfilters) 是 `+`（加号）和 `#`（磅符号）。结尾带有 `#` 的订阅请求订阅以字符前面的字符串开头的 `#` 所有主题（例如，在本使用案例中为 `test/dc/`）。  
但是，授权此订阅的策略语句中的资源值必须在主题筛选条件ARN中使用 `*`（星号）代替 `#`（磅号）。这是因为策略处理器使用的通配符不同于 MQTT 使用的通配符。  
有关在策略中为主题和主题筛选条件使用通配符的详细信息，请参阅 [在 MQTT 和策略中使用通配符 AWS IoT Core](pub-sub-policy.md#pub-sub-policy-cert)。

1. 在 `iot::Receive`策略语句中更新 Resource 对象中的字符串用 `subtopic`替换 `*`，如下所示。

   ```
       {
         "Effect": "Allow",
         "Action": [
           "iot:Receive"
         ],
         "Resource": [
           "arn:aws:iot:us-west-2:57EXAMPLE833:topic/test/dc/*"
         ]
       }
   ```

1. 将更新后的策略文档另存为 **\$1/policies/pubsub\$1wild\$1test\$1thing\$1policy.json**，然后退出编辑器。

1. 输入此命令可更新本教程的策略使用新的资源定义。

   ```
   aws iot create-policy-version \
   --set-as-default \
   --policy-name "PubSubTestThingPolicy" \
   --policy-document "file://~/policies/pubsub_wild_test_thing_policy.json"
   ```

   如果命令成功，将返回类似于此类的响应。请注意，`policyVersionId` 现在是 `2`，表示这是此策略的第二个版本。

   如果成功更新策略，可以继续下一个过程。

   ```
   {
       "policyArn": "arn:aws:iot:us-west-2:57EXAMPLE833:policy/PubSubTestThingPolicy",
       "policyDocument": "{\n  \"Version\": \"2012-10-17\",		 	 	 \n  \"Statement\": [\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"iot:Connect\"\n      ],\n      \"Resource\": [\n        \"arn:aws:iot:us-west-2:57EXAMPLE833:client/PubSubTestThing\"\n      ]\n    },\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"iot:Publish\"\n      ],\n      \"Resource\": [\n        \"arn:aws:iot:us-west-2:57EXAMPLE833:topic/test/dc/pubtopic\"\n      ]\n    },\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"iot:Subscribe\"\n      ],\n      \"Resource\": [\n        \"arn:aws:iot:us-west-2:57EXAMPLE833:topicfilter/test/dc/*\"\n      ]\n    },\n    {\n      \"Effect\": \"Allow\",\n      \"Action\": [\n        \"iot:Receive\"\n      ],\n      \"Resource\": [\n        \"arn:aws:iot:us-west-2:57EXAMPLE833:topic/test/dc/*\"\n      ]\n    }\n  ]\n}\n",
       "policyVersionId": "2",
       "isDefaultVersion": true
   }
   ```

   如果您收到有太多策略版本无法保存新版本的错误，请输入此命令列出策略的当前版本。查看此命令返回的列表查找可以删除的策略版本。

   ```
   aws iot list-policy-versions --policy-name "PubSubTestThingPolicy"
   ```

   输入此命令删除不再需要的版本。请注意，您无法删除原定设置策略版本。原定设置策略版本为具有 `true` 的 `isDefaultVersion` 值。

   ```
   aws iot delete-policy-version \
   --policy-name "PubSubTestThingPolicy" \
   --policy-version-id policyId
   ```

   删除策略版本后，请重试此步骤。

有了更新的配置文件和策略，您就可以通过 AWS IoT 设备客户端演示通配符订阅了。

**演示 AWS IoT 设备客户端如何订阅和接收多个 MQTT 消息主题**

1. 在 **MQTT 测试客户端**，检查订阅。如果已在 **\$1** 主题筛选条件中订阅了 **MQTT 测试客户端**，请继续执行下一步。如果没有订阅，在 **MQTT 测试客户端**，在**订阅主题**选项卡的**主题筛选条件**中，输入 **\$1**（井号），然后选择**订阅**以进行订阅。

1. 在连接到 Raspberry Pi 的本地主机上的终端窗口中，输入这些命令启动 AWS IoT Device Client。

   ```
   cd ~/aws-iot-device-client/build
   ./aws-iot-device-client --config-file ~/dc-configs/dc-pubsub-wild-config.json
   ```

1. 在本地主机的终端窗口中观看 AWS IoT 设备客户端输出时，返回 **MQTT 测试客户端**。在**发布主题**选项卡中，**主题名称**，输入 **test/dc/subtopic**，然后选择**发布**。

1. 在终端窗口中，通过查找以下消息确认已收到消息，例如：

   ```
   2021-11-10T16:34:20.101Z [DEBUG] {samples/PubSubFeature.cpp}: Message received on subscribe topic, size: 76 bytes
   ```

1. 在本地主机的终端窗口中观看 AWS IoT 设备客户端输出时，返回 **MQTT 测试客户端**。在**发布主题**选项卡中，**主题名称**，输入 **test/dc/subtopic2**，然后选择**发布**。

1. 在终端窗口中，通过查找以下消息确认已收到消息，例如：

   ```
   2021-11-10T16:34:32.078Z [DEBUG] {samples/PubSubFeature.cpp}: Message received on subscribe topic, size: 77 bytes
   ```

1. 看到确认收到两条消息的消息后，输入 **^C** (Ctrl-C) 停止 AWS IoT 设备客户端。

1. 输入此命令可查看消息日志文件的末尾并查看您从 **MQTT 测试客户端**发布的信息

   ```
   tail -n 20 ~/.aws-iot-device-client/log/pubsub_rx_msgs.log
   ```
**注意**  
该日志文件仅包含消息有效载荷。消息主题不会记录在收到的消息日志文件中。  
您还可能在收到的日志中看到 AWS IoT 设备客户端发布的消息。这是因为通配符主题筛选条件包含该消息主题，有时候，在发布的消息发送给订阅者之前，消息代理可以处理订阅请求。

日志文件中的条目表明已收到消息。您可以使用其他主题名称重复此过程。主题名称以 `test/dc/` 开头的所有消息应该接收并记录。主题名称以任何其他文本开头的消息将被忽略。

演示 AWS IoT 设备客户端如何发布和订阅 MQTT 消息后，请继续。[教程：使用 AWS IoT 设备客户端演示远程操作（作业）](iot-dc-runjobs.md)

# 教程：使用 AWS IoT 设备客户端演示远程操作（作业）
<a name="iot-dc-runjobs"></a>

在这些教程中，您将配置任务并将其部署到 Raspberry Pi，演示如何向物联网设备发送远程操作。

**要开始本教程：**
+ 将本地主机和 Raspberry Pi 配置为在[上一节](iot-dc-testconn.md)使用。
+ 如果您尚未完成上一节中的教程，则可以使用 Raspberry Pi 和 microSD 卡来尝试本教程，该卡上有您在安装 AWS IoT 设备客户端后保存的图像。[（可选）保存 microSD 卡映像](iot-dc-install-download.md#iot-dc-install-dc-save)
+ 如果您之前运行过此演示，[第 2 步：使用 AWS IoT 设备客户端 AWS 账户 在构建演示之后清理你的](iot-dc-cleanup.md#iot-dc-cleanup-cloud)请查看删除您在之前运行中创建的所有 AWS IoT 资源，以避免出现重复的资源错误。

完成本教程需要大约 45 分钟。

**完成本主题后：**
+ 您将演示物联网设备使用不同的方式 AWS IoT Core 来运行由管理的远程操作 AWS IoT 。

**所需的设备：**
+ 您在[上一节](iot-dc-install-dc.md)中测试的本地开发和测试环境
+ 您在[上一节](iot-dc-install-dc.md)中测试的 Raspberry Pi
+ 您在[上一节](iot-dc-install-dc.md)中测试的来自Raspberry Pi 的 microSD 存储卡

**Topics**
+ [准备 Raspberry Pi 运行任务](iot-dc-runjobs-prepare.md)
+ [使用 AWS IoT 设备客户端创建和运行作业 AWS IoT](iot-dc-runjobs-prepare-define.md)

# 准备 Raspberry Pi 运行任务
<a name="iot-dc-runjobs-prepare"></a>

本节中的过程介绍如何使用 AWS IoT 设备客户端让 Raspberry Pi 做好运行作业的准备。

**注意**  
这些过程是特定于设备的。如果要同时对多个设备执行本节中的步骤，每个设备将需要自己的策略和唯一的、特定于设备的证书和设备名称。要为每台设备提供独特的资源，请对每台设备执行一次此过程，同时按照过程中所述更改特定于设备的元素。

**Topics**
+ [提供您的 Raspberry Pi 来演示任务](#iot-dc-runjobs-prepare-provision)
+ [将 AWS IoT 设备客户端配置为运行作业代理](#iot-dc-runjobs-prepare-config)

## 提供您的 Raspberry Pi 来演示任务
<a name="iot-dc-runjobs-prepare-provision"></a>

本节中的过程通过为树莓派创建 AWS IoT 资源和设备证书 AWS IoT 来配置 Raspberry Pi。

**Topics**
+ [创建和下载设备证书文件以演示 AWS IoT 作业](#iot-dc-runjobs-prepare-cert)
+ [创建 AWS IoT 资源来演示 AWS IoT 工作](#iot-dc-runjobs-prepare-iot)

### 创建和下载设备证书文件以演示 AWS IoT 作业
<a name="iot-dc-runjobs-prepare-cert"></a>

此过程为此演示创建设备证书文件。

如果准备了多台设备，必须在每台设备上执行此过程。

**要为 Raspberry Pi 创建和下载设备证书文件，请执行以下操作：**

在连接到 Raspberry Pi 的本地主机上的终端窗口中，输入以下命令。

1. 输入以下命令为您的设备创建设备证书文件。

   ```
   aws iot create-keys-and-certificate \
   --set-as-active \
   --certificate-pem-outfile "~/certs/jobs/device.pem.crt" \
   --public-key-outfile "~/certs/jobs/public.pem.key" \
   --private-key-outfile "~/certs/jobs/private.pem.key"
   ```

   此命令会返回类似以下内容的响应。保存 `certificateArn`值供稍后使用。

   ```
   {
   "certificateArn": "arn:aws:iot:us-west-2:57EXAMPLE833:cert/76e7e4edb3e52f52334be2f387a06145b2aa4c7fcd810f3aea2d92abc227d269",
   "certificateId": "76e7e4edb3e52f5233EXAMPLE7a06145b2aa4c7fcd810f3aea2d92abc227d269",
   "certificatePem": "-----BEGIN CERTIFICATE-----\nMIIDWTCCAkGgAwIBAgI_SHORTENED_FOR_EXAMPLE_Lgn4jfgtS\n-----END CERTIFICATE-----\n",
   "keyPair": {
       "PublicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BA_SHORTENED_FOR_EXAMPLE_ImwIDAQAB\n-----END PUBLIC KEY-----\n",
       "PrivateKey": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQE_SHORTENED_FOR_EXAMPLE_T9RoDiukY\n-----END RSA PRIVATE KEY-----\n"
   }
   }
   ```

1. 输入以下命令设置证书目录及其文件的权限。

   ```
   chmod 700 ~/certs/jobs
   chmod 644 ~/certs/jobs/*
   chmod 600 ~/certs/jobs/private.pem.key
   ```

1. 运行此命令可查看证书目录和文件的权限。

   ```
   ls -l ~/certs/jobs
   ```

   命令的输出应与您在此处看到的内容相同，但文件日期和时间会有所不同。

   ```
   -rw-r--r-- 1 pi pi 1220 Oct 28 13:02 device.pem.crt
   -rw------- 1 pi pi 1675 Oct 28 13:02 private.pem.key
   -rw-r--r-- 1 pi pi  451 Oct 28 13:02 public.pem.key
   ```

将设备证书文件下载到 Raspberry Pi 之后，您准备好继续 [提供您的 Raspberry Pi 来演示任务](#iot-dc-runjobs-prepare-provision)。

### 创建 AWS IoT 资源来演示 AWS IoT 工作
<a name="iot-dc-runjobs-prepare-iot"></a>

为此设备创建 AWS IoT 资源。

如果准备了多台设备，必须在每台设备上执行此过程。



**在 AWS IoT中预调配您的设备：**

在连接到 Raspberry Pi 的本地主机的终端窗口中：

1. 输入以下命令获取您的设备数据端点的地址： AWS 账户。

   ```
   aws iot describe-endpoint --endpoint-type IoT:Data-ATS
   ```

   自上次运行此命令以来，端点值未发生更改。再次在此处运行该命令可以轻松查找数据端点值并将其粘贴到本教程中使用的配置文件中。

   此 **describe-endpoint** 命令会返回类似以下内容的响应：记录 `endpointAddress`值以供将来使用。

   ```
   {
   "endpointAddress": "a3qjEXAMPLEffp-ats.iot.us-west-2.amazonaws.com"
   }
   ```

1. *uniqueThingName*替换为设备的唯一名称。如果要使用多台设备执行本教程，请为每台设备指定自己的名称。例如，**TestDevice01**、**TestDevice02** 等等。

   输入此命令为您的 Raspberry Pi 创建新 AWS IoT 事物资源。

   ```
   aws iot create-thing --thing-name "uniqueThingName"
   ```

   由于 AWS IoT 事物资源是您的设备在云中的*虚拟*表示，因此我们可以创建多个事物资源 AWS IoT 以用于不同的目的。它们都可以由同一物理 IoT 设备使用来表示设备的不同方面。
**注意**  
当您想要保护多台设备的策略时，可以使用 `${iot:Thing.ThingName}` 而不是静态事物名称 `uniqueThingName`。

   这些教程每台设备一次只能使用一件事资源。这样，在这些教程中，它们代表了不同的演示，因此在为演示创建 AWS IoT 资源之后，您可以使用专门为每个演示创建的资源返回并重复演示。

   如果您的 AWS IoT 事物资源已创建，则该命令会返回这样的响应。记录 `thingArn` 值以供稍后创建要在此设备上运行的任务时使用。

   ```
   {
   "thingName": "uniqueThingName",
   "thingArn": "arn:aws:iot:us-west-2:57EXAMPLE833:thing/uniqueThingName",
   "thingId": "8ea78707-32c3-4f8a-9232-14bEXAMPLEfd"
   }
   ```

1. 在终端窗口中：

   1. 打开文本编辑器，例如 `nano`。

   1. 复制此 JSON 文档并将其粘贴到打开的文本编辑器中。  
****  

      ```
      {
          "Version":"2012-10-17",		 	 	 
          "Statement": [
              {
                  "Effect": "Allow",
                  "Action": [
                      "iot:Connect"
                  ],
                  "Resource": [
                      "arn:aws:iot:us-west-2:123456789012:client/uniqueThingName"
                  ]
              },
              {
                  "Effect": "Allow",
                  "Action": [
                      "iot:Publish"
                  ],
                  "Resource": [
                      "arn:aws:iot:us-west-2:123456789012:topic/test/dc/pubtopic",
                      "arn:aws:iot:us-west-2:123456789012:topic/$aws/events/job/*",
                      "arn:aws:iot:us-west-2:123456789012:topic/$aws/events/jobExecution/*",
                      "arn:aws:iot:us-west-2:123456789012:topic/$aws/things/uniqueThingName/jobs/*"
                  ]
              },
              {
                  "Effect": "Allow",
                  "Action": [
                      "iot:Subscribe"
                  ],
                  "Resource": [
                      "arn:aws:iot:us-west-2:123456789012:topicfilter/test/dc/subtopic",
                      "arn:aws:iot:us-west-2:123456789012:topic/$aws/events/jobExecution/*",
                      "arn:aws:iot:us-west-2:123456789012:topicfilter/$aws/things/uniqueThingName/jobs/*"
                  ]
              },
              {
                  "Effect": "Allow",
                  "Action": [
                      "iot:Receive"
                  ],
                  "Resource": [
                      "arn:aws:iot:us-west-2:123456789012:topic/test/dc/subtopic",
                      "arn:aws:iot:us-west-2:123456789012:topic/$aws/things/uniqueThingName/jobs/*"
                  ]
              },
              {
                  "Effect": "Allow",
                  "Action": [
                      "iot:DescribeJobExecution",
                      "iot:GetPendingJobExecutions",
                      "iot:StartNextPendingJobExecution",
                      "iot:UpdateJobExecution"
                  ],
                  "Resource": [
                      "arn:aws:iot:us-west-2:123456789012:topic/$aws/things/uniqueThingName"
                  ]
              }
          ]
      }
      ```

   1. 在编辑器中，在每份政策声明的`Resource`部分中，*us-west-2:57EXAMPLE833*用您的 AWS 区域、冒号字符 (:) 和您的 12 位 AWS 账户 数字替换。

   1. 在编辑器中，在每份策略声明中，*uniqueThingName*用你为该事物资源提供的事物名称替换。

   1. 将文本编辑器中的文件保存为 **\$1/policies/jobs\$1test\$1thing\$1policy.json**。

      如果要为多台设备运行此过程，请将文件保存为每台设备上的此文件名。

1. *uniqueThingName*替换为设备的事物名称，然后运行此命令来创建针对该设备量身定制的 AWS IoT 策略。

   ```
   aws iot create-policy \
   --policy-name "JobTestPolicyForuniqueThingName" \
   --policy-document "file://~/policies/jobs_test_thing_policy.json"
   ```

   如果创建策略，该命令将返回类似此类的响应。  
****  

   ```
   {
       "policyName": "JobTestPolicyForuniqueThingName",
       "policyArn": "arn:aws:iot:us-west-2:57EXAMPLE833:policy/JobTestPolicyForuniqueThingName",
       "policyDocument": "{\n\"Version\": \"2012-10-17\",\n\"Statement\": [\n{\n\"Effect\": \"Allow\",\n\"Action\": [\n\"iot:Connect\"\n],\n\"Resource\": [\n\"arn:aws:iot:us-west-2:57EXAMPLE833:client/PubSubTestThing\"\n]\n},\n{\n\"Effect\": \"Allow\",\n\"Action\": [\n\"iot:Publish\"\n],\n\"Resource\": [\n\"arn:aws:iot:us-west-2:57EXAMPLE833:topic/test/dc/pubtopic\"\n]\n},\n{\n\"Effect\": \"Allow\",\n\"Action\": [\n\"iot:Subscribe\"\n],\n\"Resource\": [\n\"arn:aws:iot:us-west-2:57EXAMPLE833:topicfilter/test/dc/subtopic\"\n]\n},\n{\n\"Effect\": \"Allow\",\n\"Action\": [\n\"iot:Receive\"\n],\n\"Resource\": [\n\"arn:aws:iot:us-west-2:57EXAMPLE833:topic/test/dc/*\"\n]\n}\n]\n}\n",
       "policyVersionId": "1"
   }
   ```

1. *uniqueThingName*替换为设备的事物`certificateArn`名称以及您在本节前面为该设备保存的`certificateArn`值，然后运行此命令将策略附加到设备证书。

   ```
   aws iot attach-policy \
   --policy-name "JobTestPolicyForuniqueThingName" \
   --target "certificateArn"
   ```

   如果成功，该命令不返回任何内容。

1.  *uniqueThingName*替换为设备的事物名称，`certificateArn`替换为本节前面部分中保存的`certificateArn`值，然后运行此命令将设备证书附加到 AWS IoT 事物资源。

   ```
   aws iot attach-thing-principal \
   --thing-name "uniqueThingName" \
   --principal "certificateArn"
   ```

   如果成功，该命令不返回任何内容。

成功预调配 Raspberry Pi 之后，您可以在测试中为另一个 Raspberry Pi 重复此部分，或者，如果所有设备均已预调配，请继续 [将 AWS IoT 设备客户端配置为运行作业代理](#iot-dc-runjobs-prepare-config)。

## 将 AWS IoT 设备客户端配置为运行作业代理
<a name="iot-dc-runjobs-prepare-config"></a>

此过程为 AWS IoT 设备客户端创建一个配置文件以运行作业代理:.

注意：如果准备多台设备，必须在每台设备上执行此过程。

**要创建用于测试 AWS IoT 设备客户端的配置文件，请执行以下操作：**

1. 在连接到 Raspberry Pi 的本地主机的终端窗口中：

   1. 打开文本编辑器，例如 `nano`。

   1. 复制此 JSON 文档并将其粘贴到打开的文本编辑器中。

      ```
      {
        "endpoint": "a3qEXAMPLEaffp-ats.iot.us-west-2.amazonaws.com",
        "cert": "~/certs/jobs/device.pem.crt",
        "key": "~/certs/jobs/private.pem.key",
        "root-ca": "~/certs/AmazonRootCA1.pem",
        "thing-name": "uniqueThingName",
        "logging": {
          "enable-sdk-logging": true,
          "level": "DEBUG",
          "type": "STDOUT",
          "file": ""
        },
        "jobs": {
          "enabled": true,
          "handler-directory": ""
        },
        "tunneling": {
          "enabled": false
        },
        "device-defender": {
          "enabled": false,
          "interval": 300
        },
        "fleet-provisioning": {
          "enabled": false,
          "template-name": "",
          "template-parameters": "",
          "csr-file": "",
          "device-key": ""
        },
        "samples": {
          "pub-sub": {
            "enabled": false,
            "publish-topic": "",
            "publish-file": "",
            "subscribe-topic": "",
            "subscribe-file": ""
          }
        },
        "config-shadow": {
          "enabled": false
        },
        "sample-shadow": {
          "enabled": false,
          "shadow-name": "",
          "shadow-input-file": "",
          "shadow-output-file": ""
        }
      }
      ```

   1. 将该*endpoint*值替换为您在中找到的设备数据端点值[在中配置您的设备 AWS IoT Core](iot-dc-install-provision.md#iot-dc-install-dc-provision)。 AWS 账户 

   1. *uniqueThingName*替换为您用于此设备的事物名称。

   1. 将文本编辑器中的文件保存为 **\$1/dc-configs/dc-jobs-config.json**。

1. 运行此命令设置新配置文件的文件权限。

   ```
   chmod 644 ~/dc-configs/dc-jobs-config.json
   ```

此测试没有使用 **MQTT 测试客户端**。虽然设备将与交换与作业相关的 MQTT 消息 AWS IoT，但任务进度消息仅与运行任务的设备交换。由于任务进度消息仅与运行任务的设备交换，因此您无法从其他设备（例如 AWS IoT 控制台）订阅它们。

保存配置文件后，您已准备继续 [使用 AWS IoT 设备客户端创建和运行作业 AWS IoT](iot-dc-runjobs-prepare-define.md)。

# 使用 AWS IoT 设备客户端创建和运行作业 AWS IoT
<a name="iot-dc-runjobs-prepare-define"></a>

本节中的过程将创建作业文档和 AWS IoT 作业资源。创建作业资源后， AWS IoT 将作业文档发送到指定的作业目标，作业代理会将作业文档应用到设备或客户端。

**Topics**
+ [创建并存储物联网任务的任务文档](#iot-dc-runjobs-prepare-define-jobdoc)
+ [AWS IoT 为一台 IoT 设备运行作业](#iot-dc-runjobs-prepare-define-job)

## 创建并存储物联网任务的任务文档
<a name="iot-dc-runjobs-prepare-define-jobdoc"></a>

此过程创建一个要包含在作业资源中的简单 AWS IoT 作业文档。这份任务文档显示“Hello world\$1” 在任务目标上。

**要创建和存储任务文档：**

1. 选择要将任务文档保存到的 Amazon S3 存储桶。如果您没有现有 Amazon S3 存储桶可用，需要创建一个。有关如何创建 Amazon S3 存储桶的信息，请参阅 [Amazon S3 入门](https://docs.aws.amazon.com//AmazonS3/latest/userguide/GetStartedWithS3.html)中的主题。

1. 为此任务创建并保存任务文档

   1. 在本地主机上，打开文本编辑器。

   1. 复制此文本并粘贴到编辑器中。

      ```
      {
          "operation": "echo",
          "args": ["Hello world!"]
      }
      ```

   1. 在本地主机上，将编辑器内容保存到名为 **hello-world-job.json**的文件中。

   1. 确认文件已正确保存。一些文本编辑器会自动追加 `.txt` 用户保存文本文件时的文件名。如果您的编辑器附加 `.txt` 在文件名中，在继续之前更正文件名。

1. 将替换为路径**hello-world-job.json**，如果它不在您的当前目录中，则将其*s3\$1bucket\$1name*替换为您所选存储桶的 Amazon S3 存储桶路径，然后运行此命令将您的任务文档放入 Amazon S3 存储桶。*path\$1to\$1file*

   ```
   aws s3api put-object \
   --key hello-world-job.json \
   --body path_to_file/hello-world-job.json --bucket s3_bucket_name
   ```

   用于标识您存储在 Amazon S3 中的任务文档的任务文档 URL 是通过替换以下 URL *AWS\$1region* 中的*s3\$1bucket\$1name*和来确定的。记录生成的 URL 以备日后用作 *job\$1document\$1path*

   ```
   https://s3_bucket_name.s3.AWS_Region.amazonaws.com/hello-world-job.json
   ```
**注意**  
AWS 安全性可防止您在外部打开此 URL AWS 账户，例如使用浏览器。默认情况下， AWS IoT 作业引擎使用此 URL，该引擎有权访问该文件。在生产环境中，您需要确保 AWS IoT 服务有权访问存储在 Amazon S3 中的任务文档。

保存任务文档的 URL 后，继续 [AWS IoT 为一台 IoT 设备运行作业](#iot-dc-runjobs-prepare-define-job)。

## AWS IoT 为一台 IoT 设备运行作业
<a name="iot-dc-runjobs-prepare-define-job"></a>

本节中的步骤在 Raspberry Pi 上启动 AWS IoT 设备客户端，在设备上运行作业代理，等待作业运行。它还会在中创建任务资源 AWS IoT，该资源会将任务发送到您的物联网设备并在您的物联网设备上运行。

**注意**  
此过程仅在一台设备上运行任务。

**要在 Raspberry Pi 上启动任务代理：**

1. 在连接到 Raspberry Pi 的本地主机的终端窗口中，运行此命令启动 AWS IoT 设备客户端。

   ```
   cd ~/aws-iot-device-client/build
   ./aws-iot-device-client --config-file ~/dc-configs/dc-jobs-config.json
   ```

1. 在终端窗口中，确认 AWS IoT 设备客户端和显示这些消息

   ```
   2021-11-15T18:45:56.708Z [INFO]  {Main.cpp}: Jobs is enabled
                         .
                         .
                         .
   2021-11-15T18:45:56.708Z [INFO]  {Main.cpp}: Client base has been notified that Jobs has started
   2021-11-15T18:45:56.708Z [INFO]  {JobsFeature.cpp}: Running Jobs!
   2021-11-15T18:45:56.708Z [DEBUG] {JobsFeature.cpp}: Attempting to subscribe to startNextPendingJobExecution accepted and rejected
   2021-11-15T18:45:56.708Z [DEBUG] {JobsFeature.cpp}: Attempting to subscribe to nextJobChanged events
   2021-11-15T18:45:56.708Z [DEBUG] {JobsFeature.cpp}: Attempting to subscribe to updateJobExecutionStatusAccepted for jobId +
   2021-11-15T18:45:56.738Z [DEBUG] {JobsFeature.cpp}: Ack received for SubscribeToUpdateJobExecutionAccepted with code {0}
   2021-11-15T18:45:56.739Z [DEBUG] {JobsFeature.cpp}: Attempting to subscribe to updateJobExecutionStatusRejected for jobId +
   2021-11-15T18:45:56.753Z [DEBUG] {JobsFeature.cpp}: Ack received for SubscribeToNextJobChanged with code {0}
   2021-11-15T18:45:56.760Z [DEBUG] {JobsFeature.cpp}: Ack received for SubscribeToStartNextJobRejected with code {0}
   2021-11-15T18:45:56.776Z [DEBUG] {JobsFeature.cpp}: Ack received for SubscribeToStartNextJobAccepted with code {0}
   2021-11-15T18:45:56.776Z [DEBUG] {JobsFeature.cpp}: Ack received for SubscribeToUpdateJobExecutionRejected with code {0}
   2021-11-15T18:45:56.777Z [DEBUG] {JobsFeature.cpp}: Publishing startNextPendingJobExecutionRequest
   2021-11-15T18:45:56.785Z [DEBUG] {JobsFeature.cpp}: Ack received for StartNextPendingJobPub with code {0}
   2021-11-15T18:45:56.785Z [INFO]  {JobsFeature.cpp}: No pending jobs are scheduled, waiting for the next incoming job
   ```

1. 在终端窗口中，看到此消息后，继续下一步并创建任务资源。请注意，它可能不是列表中的最后一个条目。

   ```
   2021-11-15T18:45:56.785Z [INFO]  {JobsFeature.cpp}: No pending jobs are scheduled, waiting for the next incoming job
   ```

**创建 AWS IoT 任务资源**

1. 在本地主机上：

   1. *job\$1document\$1url*替换为来自的作业文档 URL [创建并存储物联网任务的任务文档](#iot-dc-runjobs-prepare-define-jobdoc)。

   1. *thing\$1arn*替换为您为设备创建的事物资源的 ARN，然后运行此命令。

      ```
      aws iot create-job \
      --job-id hello-world-job-1 \
      --document-source "job_document_url" \
      --targets "thing_arn" \
      --target-selection SNAPSHOT
      ```

      如果成功，该命令将返回类似此结果。

      ```
      {
        "jobArn": "arn:aws:iot:us-west-2:57EXAMPLE833:job/hello-world-job-1",
        "jobId": "hello-world-job-1"
      }
      ```

1. 在终端窗口中，您应该看到 AWS IoT 设备客户端的输出如下所示。

   ```
   2021-11-15T18:02:26.688Z [INFO]  {JobsFeature.cpp}: No pending jobs are scheduled, waiting for the next incoming job
   2021-11-15T18:10:24.890Z [DEBUG] {JobsFeature.cpp}: Job ids differ
   2021-11-15T18:10:24.890Z [INFO]  {JobsFeature.cpp}: Executing job: hello-world-job-1
   2021-11-15T18:10:24.890Z [DEBUG] {JobsFeature.cpp}: Attempting to update job execution status!
   2021-11-15T18:10:24.890Z [DEBUG] {JobsFeature.cpp}: Not including stdout with the status details
   2021-11-15T18:10:24.890Z [DEBUG] {JobsFeature.cpp}: Not including stderr with the status details
   2021-11-15T18:10:24.890Z [DEBUG] {JobsFeature.cpp}: Assuming executable is in PATH
   2021-11-15T18:10:24.890Z [INFO]  {JobsFeature.cpp}: About to execute: echo Hello world!
   2021-11-15T18:10:24.890Z [DEBUG] {Retry.cpp}: Retryable function starting, it will retry until success
   2021-11-15T18:10:24.890Z [DEBUG] {JobsFeature.cpp}: Created EphermalPromise for ClientToken 3TEWba9Xj6 in the updateJobExecution promises map
   2021-11-15T18:10:24.890Z [DEBUG] {JobEngine.cpp}: Child process now running
   2021-11-15T18:10:24.890Z [DEBUG] {JobEngine.cpp}: Child process about to call execvp
   2021-11-15T18:10:24.890Z [DEBUG] {JobEngine.cpp}: Parent process now running, child PID is 16737
   2021-11-15T18:10:24.891Z [DEBUG] {16737}: Hello world!
   2021-11-15T18:10:24.891Z [DEBUG] {JobEngine.cpp}: JobEngine finished waiting for child process, returning 0
   2021-11-15T18:10:24.891Z [INFO]  {JobsFeature.cpp}: Job exited with status: 0
   2021-11-15T18:10:24.891Z [INFO]  {JobsFeature.cpp}: Job executed successfully!
   2021-11-15T18:10:24.891Z [DEBUG] {JobsFeature.cpp}: Attempting to update job execution status!
   2021-11-15T18:10:24.891Z [DEBUG] {JobsFeature.cpp}: Not including stdout with the status details
   2021-11-15T18:10:24.891Z [DEBUG] {JobsFeature.cpp}: Not including stderr with the status details
   2021-11-15T18:10:24.892Z [DEBUG] {Retry.cpp}: Retryable function starting, it will retry until success
   2021-11-15T18:10:24.892Z [DEBUG] {JobsFeature.cpp}: Created EphermalPromise for ClientToken GmQ0HTzWGg in the updateJobExecution promises map
   2021-11-15T18:10:24.905Z [DEBUG] {JobsFeature.cpp}: Ack received for PublishUpdateJobExecutionStatus with code {0}
   2021-11-15T18:10:24.905Z [DEBUG] {JobsFeature.cpp}: Removing ClientToken 3TEWba9Xj6 from the updateJobExecution promises map
   2021-11-15T18:10:24.905Z [DEBUG] {JobsFeature.cpp}: Success response after UpdateJobExecution for job hello-world-job-1
   2021-11-15T18:10:24.917Z [DEBUG] {JobsFeature.cpp}: Ack received for PublishUpdateJobExecutionStatus with code {0}
   2021-11-15T18:10:24.918Z [DEBUG] {JobsFeature.cpp}: Removing ClientToken GmQ0HTzWGg from the updateJobExecution promises map
   2021-11-15T18:10:24.918Z [DEBUG] {JobsFeature.cpp}: Success response after UpdateJobExecution for job hello-world-job-1
   2021-11-15T18:10:25.861Z [INFO]  {JobsFeature.cpp}: No pending jobs are scheduled, waiting for the next incoming job
   ```

1. 当 AWS IoT 设备客户端运行并等待任务时，您可以通过更改`job-id`值并重新运行步骤 1 中的值来提交另一个作业。**create-job**

运行完任务后，在终端窗口中输入 ^C (Control-C) 以停止 AWS IoT 设备客户端。

# 教程：运行 AWS IoT 设备客户端教程后进行清理
<a name="iot-dc-cleanup"></a>

本教程中的过程将指导您在完成本学习路径中的教程时删除创建的文件和资源。

**Topics**
+ [步骤 1：使用设备客户端制作演示后清理 AWS IoT 设备](#iot-dc-cleanup-devices)
+ [第 2 步：使用 AWS IoT 设备客户端 AWS 账户 在构建演示之后清理你的](#iot-dc-cleanup-cloud)

## 步骤 1：使用设备客户端制作演示后清理 AWS IoT 设备
<a name="iot-dc-cleanup-devices"></a>

本教程介绍了在此学习路径中构建演示后如何清理 microSD 卡的两个选项。选择提供所需安全级别的选项。

请注意，清理设备的 microSD 卡并不会移除您 AWS IoT 创建的任何资源。要在清理设备的 microSD 卡后清理 AWS IoT 资源，您应该查看上面的教程。[第 2 步：使用 AWS IoT 设备客户端 AWS 账户 在构建演示之后清理你的](#iot-dc-cleanup-cloud)

### 选项 1：通过重写 microSD 卡进行清理
<a name="iot-dc-cleanup-devices-flash"></a>

在完成本学习路径中的教程之后，清理 microSD 卡最简单、最彻底的方法是用您在首次准备设备时创建的保存图像文件覆盖 microSD 卡。

此过程使用本地主机将保存的 microSD 卡映像写入 microSD 卡。

**注意**  
如果您的设备没有将可移动存储介质用于操作系统，请参阅该设备的步骤。

**要向 microSD 卡写入一个新映像**

1. 在本地主机上，找到要写入 microSD 卡的已保存 microSD 卡映像。

1. 将 microSD 卡插到您的计算机上。

1. 使用 SD 卡成像工具，将选定的图像文件写入 microSD 卡。

1. 将 Raspberry Pi 操作系统映像写入 microSD 卡后，弹出 microSD 卡并将其从本地主机安全地移除。

您的 microSD 卡已准备就绪，可供使用。

### 选项 2：通过删除用户目录进行清理
<a name="iot-dc-cleanup-devices-dirs"></a>

要在完成教程后清理 microSD 卡而不重写 microSD 卡映像，可以单独删除用户目录。这并不像从保存的图像中重写 microSD 卡那么彻底，因为它不会删除可能已安装的任何系统文件。

如果删除用户目录足以满足您的需要，可以按照此步骤操作。

**从设备中删除此学习路径的用户目录**

1. 运行这些命令可以在连接到设备的终端窗口中删除在此学习路径中创建的用户目录、子目录及其所有文件。
**注意**  
删除这些目录和文件后，如果不再完成教程，您将无法运行演示。

   ```
   rm -Rf ~/dc-configs
   rm -Rf ~/policies
   rm -Rf ~/messages
   rm -Rf ~/certs
   rm -Rf ~/.aws-iot-device-client
   ```

1. 在连接到设备的终端窗口中，运行这些命令删除应用程序源目录和文件。
**注意**  
这些命令不会卸载任何程序。他们只删除用于构建和安装它们的源文件。删除这些文件后， AWS CLI 和 AWS IoT 设备客户端可能无法运行。

   ```
   rm -Rf ~/aws-cli
   rm -Rf ~/aws
   rm -Rf ~/aws-iot-device-client
   ```

## 第 2 步：使用 AWS IoT 设备客户端 AWS 账户 在构建演示之后清理你的
<a name="iot-dc-cleanup-cloud"></a>

这些过程可帮助您识别和删除您在完成本学习路径中的教程时创建的 AWS 资源。

### 清理 AWS IoT 资源
<a name="iot-dc-cleanup-cloud-iot"></a>

此过程可帮助您识别和删除您在完成本学习路径中的教程时创建的 AWS IoT 资源。


**AWS IoT 在此学习路径中创建的资源**  

| 教程 | 事物资源 | 策略资源 | 
| --- | --- | --- | 
|  [教程：安装和配置 AWS IoT 设备客户端](iot-dc-install-dc.md)  |  **DevCliTestThing**  | DevCliTestThingPolicy | 
|  [教程：演示与 AWS IoT 设备客户端的 MQTT 消息通信](iot-dc-testconn.md)  |  **PubSubTestThing**  | PubSubTestThingPolicy | 
|  [教程：使用 AWS IoT 设备客户端演示远程操作（作业）](iot-dc-runjobs.md)  | 定义的用户（可能有不止一个） |  *定义的用户*（可能有不止一个）  | 

**要删除 AWS IoT 资源，请针对您创建的每个事物资源执行以下步骤**

1. 将 `thing_name` 替换为要删除的对象资源的名称，然后运行此命令列出从本地主机附加到对象资源的证书。

   ```
   aws iot list-thing-principals --thing-name thing_name
   ```

   此命令返回类似这样的响应，其中列出了附加到 `thing_name`的证书。在大多数情况下，列表中只有一个证书。

   ```
   {
       "principals": [
           "arn:aws:iot:us-west-2:57EXAMPLE833:cert/23853eea3cf0edc7f8a69c74abeafa27b2b52823cab5b3e156295e94b26ae8ac"
       ]
   }
   ```

1. 对于上一个命令列出的每个证书：

   1. 将 `certificate_ID`替换为上一个命令中的证书 ID。证书ID是上一个命令返回的 ARN 中遵循 `cert/`的字母数字字符。然后运行此命令以停用证书。

      ```
      aws iot update-certificate --new-status INACTIVE --certificate-id certificate_ID
      ```

      如果成功，该命令不返回任何内容。

   1. 将 `certificate_ARN` 替换为之前返回的证书列表中的证书 ARN，然后运行此命令列出附加到此证书的策略。

      ```
      aws iot list-attached-policies --target certificate_ARN
      ```

      此命令返回类似这样的响应，其中列出了附加到证书的策略。在大多数情况下，列表中只有一个策略。

      ```
      {
          "policies": [
              {
                  "policyName": "DevCliTestThingPolicy",
                  "policyArn": "arn:aws:iot:us-west-2:57EXAMPLE833:policy/DevCliTestThingPolicy"
              }
          ]
      }
      ```

   1. 对于附加到该证书的每个策略。

      1. 将 `policy_name` 替换为上一个命令中的 `policyName` 值，将 `certificate_ARN` 替换为证书的 ARN，然后运行此命令将策略与证书分离。

         ```
         aws iot detach-policy --policy-name policy_name --target certificate_ARN
         ```

         如果成功，该命令不返回任何内容。

      1. 将 `policy_name` 替换为 `policyName` 值，然后运行此命令查看策略是否附加到其他证书。

         ```
         aws iot list-targets-for-policy --policy-name policy_name
         ```

         如果该命令返回这样的空列表，该策略不会附加到任何证书，您将继续列出策略版本。如果还有附加到策略的证书，请继续 **detach-thing-principal** 步骤。

         ```
         {
             "targets": []
         }
         ```

      1. 将 `policy_name` 替换为 `policyName` 值，然后运行此命令检查策略版本。要删除策略，它必须只有一个版本。

         ```
         aws iot list-policy-versions --policy-name policy_name
         ```

         如果策略只有一个版本（如此示例），则可以跳至步骤 **delete-policy** 立即删除策略。

         ```
         {
             "policyVersions": [
                 {
                     "versionId": "1",
                     "isDefaultVersion": true,
                     "createDate": "2021-11-18T01:02:46.778000+00:00"
                 }
             ]
         }
         ```

         如果策略有多个版本，如本例所示，则必须先删除 `false` 值为 `isDefaultVersion` 的策略版本，然后才能删除策略。

         ```
         {
             "policyVersions": [
                 {
                     "versionId": "2",
                     "isDefaultVersion": true,
                     "createDate": "2021-11-18T01:52:04.423000+00:00"
                 },
                 {
                     "versionId": "1",
                     "isDefaultVersion": false,
                     "createDate": "2021-11-18T01:30:18.083000+00:00"
                 }
             ]
         }
         ```

         如果您需要删除策略版本，将 `policy_name` 替换为 `policyName` 值，将 `version_ID` 替换为来自上一个命令的 `versionId`值，然后运行此命令删除策略版本。

         ```
         aws iot delete-policy-version --policy-name policy_name --policy-version-id version_ID
         ```

         如果成功，该命令不返回任何内容。

         删除策略版本后，请重复此步骤，直到该策略只有一个策略版本。

      1. 将 `policy_name`替换为 `policyName` 值，然后运行此命令删除策略。

         ```
         aws iot delete-policy --policy-name policy_name
         ```

   1. 将 `thing_name` 替换为事物名称，将 `certificate_ARN` 替换为证书的 ARN，然后运行此命令将证书与事物资源分离。

      ```
      aws iot detach-thing-principal --thing-name thing_name --principal certificate_ARN
      ```

      如果成功，该命令不返回任何内容。

   1. 将 `certificate_ID`替换为上一个命令中的证书 ID。证书 ID 是上一个命令返回的 ARN 中遵循 `cert/`的字母数字字符。运行这个命令删除证书资源。

      ```
      aws iot delete-certificate --certificate-id certificate_ID
      ```

      如果成功，该命令不返回任何内容。

1. 将 `thing_name`替换为事物名称，然后运行此命令删除该事物。

   ```
   aws iot delete-thing --thing-name thing_name
   ```

   如果成功，该命令不返回任何内容。

### 清理 AWS 资源
<a name="iot-dc-cleanup-cloud-aws"></a>

此过程可帮助您识别和删除您在完成本学习路径中的教程时创建的其他 AWS 资源。


**在此学习路径中创建的其他 AWS 资源**  

| 教程 | 资源类型 | 资源名称或 ID | 
| --- | --- | --- | 
|  [教程：使用 AWS IoT 设备客户端演示远程操作（作业）](iot-dc-runjobs.md)  | Amazon S3 对象 | hello-world-job.json | 
|  [教程：使用 AWS IoT 设备客户端演示远程操作（作业）](iot-dc-runjobs.md)  |  AWS IoT 工作资源  | 定义的用户 | 

**删除在此学习路径中创建的 AWS 资源**

1. 要删除在此学习路径中创建的职位

   1. 运行此命令列出您的中的作业 AWS 账户。

      ```
      aws iot list-jobs
      ```

      该命令会返回你的 AWS IoT 任务列表 AWS 账户 AWS 区域 ，如下所示。

      ```
      {
          "jobs": [
              {
                  "jobArn": "arn:aws:iot:us-west-2:57EXAMPLE833:job/hello-world-job-2",
                  "jobId": "hello-world-job-2",
                  "targetSelection": "SNAPSHOT",
                  "status": "COMPLETED",
                  "createdAt": "2021-11-16T23:40:36.825000+00:00",
                  "lastUpdatedAt": "2021-11-16T23:40:41.375000+00:00",
                  "completedAt": "2021-11-16T23:40:41.375000+00:00"
              },
              {
                  "jobArn": "arn:aws:iot:us-west-2:57EXAMPLE833:job/hello-world-job-1",
                  "jobId": "hello-world-job-1",
                  "targetSelection": "SNAPSHOT",
                  "status": "COMPLETED",
                  "createdAt": "2021-11-16T23:35:26.381000+00:00",
                  "lastUpdatedAt": "2021-11-16T23:35:29.239000+00:00",
                  "completedAt": "2021-11-16T23:35:29.239000+00:00"
              }
          ]
      }
      ```

   1. 对于您从列表中识别为在此学习路径中创建的作业的每项作业，请`jobId`替换为要删除的作业的`jobId`值，然后运行此命令删除 AWS IoT 作业。

      ```
      aws iot delete-job --job-id jobId
      ```

      如果命令成功，该命令不返回任何内容。

1. 要删除您在此学习路径中存储在 Amazon S3 存储桶中的任务文档。

   1. 将 `bucket`替换为您使用的存储桶名称，然后运行此命令列出您使用的 Amazon S3 存储桶中的对象。

      ```
      aws s3api list-objects --bucket bucket
      ```

      该命令返回存储桶中 Amazon S3 对象的列表，该列表如下所示。

      ```
      {
          "Contents": [
              {
                  "Key": "hello-world-job.json",
                  "LastModified": "2021-11-18T03:02:12+00:00",
                  "ETag": "\"868c8bc3f56b5787964764d4b18ed5ef\"",
                  "Size": 54,
                  "StorageClass": "STANDARD",
                  "Owner": {
                      "DisplayName": "EXAMPLE",
                      "ID": "e9e3d6ec1EXAMPLEf5bfb5e6bd0a2b6ed03884d1ed392a82ad011c144736a4ee"
                  }
              },
              {
                  "Key": "iot_job_firmware_update.json",
                  "LastModified": "2021-04-13T21:57:07+00:00",
                  "ETag": "\"7c68c591949391791ecf625253658c61\"",
                  "Size": 66,
                  "StorageClass": "STANDARD",
                  "Owner": {
                      "DisplayName": "EXAMPLE",
                      "ID": "e9e3d6ec1EXAMPLEf5bfb5e6bd0a2b6ed03884d1ed392a82ad011c144736a4ee"
                  }
              },
              {
                  "Key": "order66.json",
                  "LastModified": "2021-04-13T21:57:07+00:00",
                  "ETag": "\"bca60d5380b88e1a70cc27d321caba72\"",
                  "Size": 29,
                  "StorageClass": "STANDARD",
                  "Owner": {
                      "DisplayName": "EXAMPLE",
                      "ID": "e9e3d6ec1EXAMPLEf5bfb5e6bd0a2b6ed03884d1ed392a82ad011c144736a4ee"
                  }
              }
          ]
      }
      ```

   1. 对于从列表中识别为在此学习路径中创建的对象的每个对象，将 `bucket` 替换为要删除的对象的存储桶名称，将 `key` 替换为密钥值，然后运行此命令删除 Amazon S3 对象。

      ```
       aws s3api delete-object --bucket bucket --key key
      ```

      如果命令成功，该命令不返回任何内容。

删除完成此学习路径时创建的所有 AWS 资源和对象后，您可以重新开始并重复这些教程。

# 使用 AWS IoT 设备构建解决方案 SDKs
<a name="iot-tutorials-sdk-intro"></a>

本节中的教程将引导您完成开发可使用部署到生产环境的 IoT 解决方案的步骤 AWS IoT。

与上一节中的教程相比，这些教程可能需要更多时间才能完成，[使用 AWS IoT 设备客户端构建演示](iot-tutorials-dc-intro.md)因为它们使用 AWS IoT 设备 SDKs 并更详细地解释了正在应用的概念，以帮助您创建安全可靠的解决方案。

## 开始使用 AWS IoT 设备构建解决方案 SDKs
<a name="iot-sdk-tutorial-overview"></a>

这些教程将引导您了解不同的 AWS IoT 场景。在适当情况下，教程会使用 AWS IoT 设备 SDKs。

**Topics**
+ [开始使用 AWS IoT 设备构建解决方案 SDKs](#iot-sdk-tutorial-overview)
+ [教程：使用设备 SDK 将 AWS IoT 设备连接到 AWS IoT Core](sdk-tutorials.md)
+ [创建将设备数据路由到其他服务的 AWS IoT 规则](iot-rules-tutorial.md)
+ [在设备处于离线状态时使用设备影子保持设备状态](iot-shadows-tutorial.md)
+ [教程：为创建自定义授权方 AWS IoT Core](custom-auth-tutorial.md)
+ [教程：使用 AWS IoT 和 Raspberry Pi 监测土壤湿度](iot-moisture-tutorial.md)

# 教程：使用设备 SDK 将 AWS IoT 设备连接到 AWS IoT Core
<a name="sdk-tutorials"></a>

本教程演示了如何将设备连接起来， AWS IoT Core 以便它可以向和从设备发送和接收数据 AWS IoT。完成本教程后，您的设备将被配置为连接，您将了解设备是如何与之通信的 AWS IoT。 AWS IoT Core 

**Topics**
+ [先决条件](#sdk-tutorials-prereq)
+ [为设备做好准备 AWS IoT](#sdk-tutorials-prepare)
+ [查看 MQTT 协议](#sdk-tutorials-mqtt-review)
+ [查看 pubsub.py Device SDK 示例应用程序](#sdk-tutorials-explore-sample)
+ [连接您的设备并与之通信 AWS IoT Core](#sdk-tutorials-experiment)
+ [查看结果](#sdk-tutorials-conclusion)
+ [教程：使用 AWS IoT Device SDK for Embedded C](iot-embedded-c-sdk.md)

## 先决条件
<a name="sdk-tutorials-prereq"></a>

在开始本教程之前，请确保您具有：
+ 

**已完成 [AWS IoT Core 教程入门](iot-gs.md)**  
在本教程中，您必须在某部分 [配置您的设备](configure-device.md)，请为您的设备选择 [连接 Raspberry Pi 或其他设备](connecting-to-existing-device.md)选项，然后使用 Python 语言选项来配置设备。
**注意**  
在该教程中使用的终端窗口保持开启，因为您还将在本教程中使用它。
+ 

**可以运行适用于 Python 的 AWS IoT 设备 SDK v2 的设备。**  
本教程介绍如何使用 Python 代码示例将设备连接到 AWS IoT Core 设备，这需要相对强大的设备。如果您使用的是资源受限的设备，则这些代码示例可能无法适用于这些设备。在这种情况下，使用 [教程：使用 AWS IoT Device SDK for Embedded C](iot-embedded-c-sdk.md) 教程可能会更成功。
+ 

**获取连接到设备所需的信息**  
要将设备连接到 AWS IoT，您必须拥有有关事物名称、主机名和端口号的信息。
**注意**  
您也可以使用自定义身份验证将设备连接到 AWS IoT Core。您传递给授权方 Lambda 函数的连接数据取决于您使用的协议。
  + **事物名称**：您要连接 AWS IoT 的事物的名称。你一定已经注册为你的设备 AWS IoT 了。有关更多信息，请参阅 [使用管理设备 AWS IoT](iot-thing-management.md)。
  + **主机名**：特定于账户的物联网端点的主机名。
  + **端口号**：要连接到的端口号。

  您可以使用 AWS IoT Python SDK 中的`configureEndpoint`方法来配置主机名和端口号。

  ```
  myAWSIoTMQTTClient.configureEndpoint("random.iot.region.amazonaws.com", 8883)
  ```

## 为设备做好准备 AWS IoT
<a name="sdk-tutorials-prepare"></a>

在 [AWS IoT Core 教程入门](iot-gs.md)，您已准备好您的设备以及 AWS 账户，所以它们能够进行通信。本节概述了该准备工作中适用于任何与之连接的设备的各个方面 AWS IoT Core。

对于要连接到 AWS IoT Core的设备：

1. 您必须具有 **AWS 账户**。

   中的过程[设置 AWS 账户](setting-up.md)介绍了如何创建一个（ AWS 账户 如果您还没有）。

1. 在该账户中，您必须为自己 AWS 账户 和地区的设备定义以下**AWS IoT 资源**。

   [创建 AWS IoT 资源](create-iot-resources.md) 中的流程介绍了如何为您的 AWS 账户 和区域中的设备创建这些资源。
   + 使用 AWS IoT 注册并激活以验证设备的**设备证书**。

     该证书通常使用 **AWS IoT 事物对象**创建并随附其上。虽然设备不需要事物对象即可连接 AWS IoT，但它为设备提供了其他 AWS IoT 功能。
   + 附加到设备证书的**策略**，授权其连接 AWS IoT Core 并执行您想要的所有操作。

1. 能够访问您的 AWS 账户的设备端点的**互联网连接**。

   设备端点在控制台的设置页面中[AWS IoT 设备数据和服务端点](iot-connect-devices.md#iot-connect-device-endpoints)进行了描述，也可以在[AWS IoT 控制台的设置页面](https://console.aws.amazon.com/iot/home#/settings)中看到。

1. 诸如 AWS IoT 设备之类的@@ **通信软件** SDKs 提供。本教程使用 [AWS IoT Device SDK v2 for Python](https://github.com/aws/aws-iot-device-sdk-python-v2#aws-iot-device-sdk-v2-for-python)。

## 查看 MQTT 协议
<a name="sdk-tutorials-mqtt-review"></a>

在我们讨论示例应用程序之前，它能有助于了解 MQTT 协议。与其它网络通信协议（如 HTTP）相比，MQTT 协议具有一些优势，这使得它成为了物联网设备的常用选择。本部分回顾的是适用于本教程的 MQTT 的主要方面。有关如何将 MQTT 与 HTTP 进行比较的信息，请参阅 [为设备通信选择应用程序协议](protocols.md#protocol-selection)。

**MQTT 使用 publish/subscribe 通信模型**  
MQTT 协议使用与其主机的 publish/subscribe 通信模型。此模型不同于 HTTP 使用的 request/response 模型。借助 MQTT，设备可以与由唯一客户端 ID 标识的主机建立会话。要发送数据，设备会将主题标识的消息发布到主机中的消息代理上。要接收来自消息代理的消息，设备通过在订阅请求中向消息代理发送主题筛选条件，来订阅主题。

**MQTT 支持持久会话**  
消息代理接收来自设备的消息，并将消息发布到已订阅消息的设备。借助[持久会话](mqtt.md#mqtt-persistent-sessions)（即使在初始设备断开连接时，仍能保持活动状态的会话），设备可以检索在断开连接时发布的消息。在设备端，MQTT 支持服务质量级别（[QoS](mqtt.md#mqtt-qos)），以确保主机接收设备发送的消息。

## 查看 pubsub.py Device SDK 示例应用程序
<a name="sdk-tutorials-explore-sample"></a>

本部分将回顾本教程中适用的来自 **AWS IoT Device SDK v2 for Python** 中的 `pubsub.py`示例应用程序。在这里，我们将回顾它如何 AWS IoT Core 连接到发布和订阅 MQTT 消息。下一节将介绍一些练习，以帮助您探索设备如何连接和通 AWS IoT Core信。

**该`pubsub.py`示例应用程序演示了 MQTT 连接的 AWS IoT Core以下方面：**
+ [通信协议](#sdk-tutorials-explore-protocols)
+ [持久会话](#sdk-tutorials-explore-persistent)
+ [服务质量](#sdk-tutorials-explore-qos)
+ [消息发布](#sdk-tutorials-explore-publish)
+ [消息订阅](#sdk-tutorials-explore-subscribe)
+ [设备断开和重新连接](#sdk-tutorials-explore-connect)

### 通信协议
<a name="sdk-tutorials-explore-protocols"></a>

`pubsub.py` 示例演示了使用 MQTT 和 MQTT over WSS 协议进行的 MQTT 连接。[AWS 通用运行时 (AWS CRT)](https://github.com/awslabs/aws-crt-python#aws-crt-python) 库提供低级通信协议支持，包含在适用于 Python 的 AWS IoT 设备 SDK v2 中。

#### MQTT
<a name="sdk-tutorials-explore-mqtt"></a>

中的`pubsub.py`示例调用`mtls_from_path`（如图所示）使用 MQTT 协议与 AWS IoT Core 之建立连接。[https://github.com/awslabs/aws-crt-python/blob/89207bcf1387177034e02fe29e8e469ca45e39b7/awscrt/awsiot_mqtt_connection_builder.py](https://github.com/awslabs/aws-crt-python/blob/89207bcf1387177034e02fe29e8e469ca45e39b7/awscrt/awsiot_mqtt_connection_builder.py) `mtls_from_path`使用 X.509 证书和 TLS v1.2 对设备进行身份验证。 AWS CRT 库处理该连接的较低级别细节。

```
mqtt_connection = mqtt_connection_builder.mtls_from_path(
    endpoint=args.endpoint,
    cert_filepath=args.cert,
    pri_key_filepath=args.key,
    ca_filepath=args.ca_file,
    client_bootstrap=client_bootstrap,
    on_connection_interrupted=on_connection_interrupted,
    on_connection_resumed=on_connection_resumed,
    client_id=args.client_id,
    clean_session=False,
    keep_alive_secs=6
)
```

`endpoint`  
您的物 AWS 账户联网设备端点  
在示例应用程序中，此值将从命令行传入。

`cert_filepath`  
设备证书文件的路径。  
在示例应用程序中，此值将从命令行传入。

`pri_key_filepath`  
使用其证书文件创建的设备私有密钥文件的路径  
在示例应用程序中，此值将从命令行传入。

`ca_filepath`  
Root CA 文件的路径。仅当 MQTT 服务器使用信任存储中尚未存在的证书时才需要此项。  
在示例应用程序中，此值将从命令行传入。

`client_bootstrap`  
处理套接字通信活动的通用运行时对象  
在示例应用程序中，此对象会在调用 `mqtt_connection_builder.mtls_from_path`前实例化。

`on_connection_interrupted``on_connection_resumed`  
当设备连接中断和恢复时调用的回调函数

`client_id`  
在 AWS 区域中唯一标识此设备的 ID  
在示例应用程序中，此值将从命令行传入。

`clean_session`  
启动新的持久会话，或者（如果会话已存在）重新连接到现有会话

`keep_alive_secs`  
保持活动状态值（以秒为单位），在 `CONNECT`请求中发送。在此时间间隔内将自动发送 ping。如果服务器在此值的 1.5 倍之后没有收到 ping，假定连接丢失。

#### 基于 WSS 的 MQTT
<a name="sdk-tutorials-explore-mqtt-wss"></a>

`pubsub.py` 示例在 [https://github.com/awslabs/aws-crt-python/blob/89207bcf1387177034e02fe29e8e469ca45e39b7/awscrt/awsiot_mqtt_connection_builder.py](https://github.com/awslabs/aws-crt-python/blob/89207bcf1387177034e02fe29e8e469ca45e39b7/awscrt/awsiot_mqtt_connection_builder.py) 中调用 `websockets_with_default_aws_signing`（此处显示）以使用借助 WSS 的 MQTT 协议建立与 AWS IoT Core 的连接。`websockets_with_default_aws_signing` 使用 [Signature V4](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html) 通过 WSS 创建 MQTT 连接对设备进行身份验证。

```
mqtt_connection = mqtt_connection_builder.websockets_with_default_aws_signing(
    endpoint=args.endpoint,
    client_bootstrap=client_bootstrap,
    region=args.signing_region,
    credentials_provider=credentials_provider,
    websocket_proxy_options=proxy_options,
    ca_filepath=args.ca_file,
    on_connection_interrupted=on_connection_interrupted,
    on_connection_resumed=on_connection_resumed,
    client_id=args.client_id,
    clean_session=False,
    keep_alive_secs=6
)
```

`endpoint`  
您的物 AWS 账户联网设备端点  
在示例应用程序中，此值将从命令行传入。

`client_bootstrap`  
处理套接字通信活动的通用运行时对象  
在示例应用程序中，此对象会在调用 `mqtt_connection_builder.websockets_with_default_aws_signing`前实例化。

`region`  
 AWS 签名 V4 身份验证使用的签名区域。在 `pubsub.py` 中，它将在命令行中传递输入的参数。  
在示例应用程序中，此值将从命令行传入。

`credentials_provider`  
提供的用于身份验证的 AWS 凭证  
在示例应用程序中，此对象会在调用 `mqtt_connection_builder.websockets_with_default_aws_signing`前实例化。

`websocket_proxy_options`  
HTTP 代理选项（如果使用代理主机）  
在示例应用程序中，此值在调用 `mqtt_connection_builder.websockets_with_default_aws_signing` 前初始化。

`ca_filepath`  
Root CA 文件的路径。仅当 MQTT 服务器使用信任存储中尚未存在的证书时才需要此项。  
在示例应用程序中，此值将从命令行传入。

`on_connection_interrupted``on_connection_resumed`  
当设备连接中断和恢复时调用的回调函数

`client_id`  
在 AWS 区域中唯一标识此设备的 ID。  
在示例应用程序中，此值将从命令行传入。

`clean_session`  
启动新的持久会话，或者（如果会话已存在）重新连接到现有会话

`keep_alive_secs`  
保持活动状态值（以秒为单位），在 `CONNECT`请求中发送。在此时间间隔内将自动发送 ping。如果服务器在此值的 1.5 倍之后没有收到 ping，则假定连接丢失。

#### HTTPS
<a name="sdk-tutorials-explore-https"></a>

那么 HTTPS 呢？ AWS IoT Core 支持发布 HTTPS 请求的设备。从编程的角度来看，设备会像其它应用程序一样将 HTTPS 请求发送到 AWS IoT Core 。有关从设备发送 HTTP 消息的 Python 程序示例，请参阅使用 Python 的 `requests`库的 [HTTPS 代码示例](http.md#codeexample)。此示例 AWS IoT Core 使用 HTTPS 向发送一条消息，从而将其 AWS IoT Core 解释为 MQTT 消息。

虽然 AWS IoT Core 支持来自设备的 HTTPS 请求，但请务必查看相关信息，[为设备通信选择应用程序协议](protocols.md#protocol-selection)以便您可以就使用哪种协议进行设备通信做出明智的决定。

### 持久会话
<a name="sdk-tutorials-explore-persistent"></a>

在示例应用程序中，将 `clean_session` 参数设置为 `False` 即表示连接应该是持久连接。实际上，这意味着此调用打开的连接将重新连接到现有持久会话（如果存在）。否则，它会创建并连接到新的持久会话。

对于持久会话，如果设备未连接，则发送到设备的消息将由消息代理存储。当设备重新连接到持久会话时，消息代理会向设备发送它已订阅的所有已存储的消息。

如果没有持久会话，设备将不会接收设备未连接时发送的消息。使用哪个选项取决于您的应用程序，以及是否必须传达设备未连接时发生的消息。有关更多信息，请参阅 [MQTT 持久会话](mqtt.md#mqtt-persistent-sessions)。

### 服务质量
<a name="sdk-tutorials-explore-qos"></a>

当设备发布和订阅消息时，可以设置首选服务质量 (QoS)。 AWS IoT 支持发布和订阅操作的 QoS 级别 0 和 1。有关中 QoS 级别的更多信息 AWS IoT，请参阅。[MQTT 服务质量（QoS）选项](mqtt.md#mqtt-qos)

Python 的 AWS CRT 运行时为其支持的 QoS 级别定义了以下常量：


**Python QoS 级别**  

| MQTT QoS 级别 | SDK 使用的 Python 符号值 | 说明 | 
| --- | --- | --- | 
| QoS 级别 0 | mqtt.QoS.AT\$1MOST\$1ONCE | 无论是否收到消息，均只会尝试发送一次消息。如果出现诸如设备未连接或存在网络错误的情况，则消息可能根本不会发送。 | 
| QoS 级别 1 | mqtt.QoS.AT\$1LEAST\$1ONCE | 消息将重复发送，直至收到 PUBACK 确认。 | 

在示例应用程序中，发布和订阅请求的 QoS 级别为 1 (`mqtt.QoS.AT_LEAST_ONCE`)。
+ 

**发布时的 QoS**  
当设备发布 QoS 级别为 1 的消息时，它会重复发送消息，直至从消息代理收到 `PUBACK` 响应。如果设备未连接，消息将在重新连接后排队等待发送。
+ 

**订阅时的 QoS**  
当设备订阅 QoS 级别为 1 的消息时，消息代理会保存设备订阅的消息，直到这些消息可以发送到设备。消息代理会重新发送消息，直至收到设备发出的 `PUBACK`响应。

### 消息发布
<a name="sdk-tutorials-explore-publish"></a>

成功建立与的连接后 AWS IoT Core，设备可以发布消息。`pubsub.py` 示例通过调用 `mqtt_connection` 对象的 `publish` 操作来完成此操作。

```
mqtt_connection.publish(
    topic=args.topic,
    payload=message,
    qos=mqtt.QoS.AT_LEAST_ONCE
)
```

`topic`  
标识消息的消息主题名称  
在示例应用程序中，这是从命令行传入的。

`payload`  
格式化为字符串的消息有效载荷（例如，JSON 文档）  
在示例应用程序中，这是从命令行传入的。  
JSON 文档是一种常见的负载格式，可以被其他 AWS IoT 服务识别；但是，消息负载的数据格式可以是发布者和订阅者同意的任何格式。但在某些情况下，对于大多数操作来说，其它 AWS IoT 服务只能识别 JSON 和 CBOR。

`qos`  
此消息的 QoS 级别

### 消息订阅
<a name="sdk-tutorials-explore-subscribe"></a>

要接收来自其他 AWS IoT 服务和设备的消息，设备需要按主题名称订阅这些消息。设备可以通过指定[主题名称](topics.md#topicnames)来订阅单个消息，也可以通过指定[主题筛选条件](topics.md#topicfilters)来订阅一组消息（筛选条件中可以包含通配符）。`pubsub.py` 示例使用此处显示的代码订阅消息并注册回调函数，以便在收到消息后处理消息。

```
subscribe_future, packet_id = mqtt_connection.subscribe(
    topic=args.topic,
    qos=mqtt.QoS.AT_LEAST_ONCE,
    callback=on_message_received
)
subscribe_result = subscribe_future.result()
```

`topic`  
要订阅的主题。这可以是主题名称或主题筛选条件。  
在示例应用程序中，这是从命令行传入的。

`qos`  
在设备断开连接时，消息代理是否应该存储这些消息。  
`mqtt.QoS.AT_LEAST_ONCE` 的值（QoS 级别 1），创建连接时需要指定持久会话 (`clean_session=False`)。

`callback`  
要调用以处理已订阅消息的函数。

`mqtt_connection.subscribe` 函数返回未来和数据包 ID。如果订阅请求成功初始化，则返回的数据包 ID 大于 0。要确保消息代理已接收并注册订阅，您必须等待异步操作的结果返回，如代码示例所示。

**回调函数**  
`pubsub.py` 示例中的回调函数会在设备接收订阅的消息时处理这些消息。

```
def on_message_received(topic, payload, **kwargs):
    print("Received message from topic '{}': {}".format(topic, payload))
    global received_count
    received_count += 1
    if received_count == args.count:
        received_all_event.set()
```

`topic`  
消息的主题  
这是收到的消息的特定主题名称，即使您订阅了主题筛选条件也是如此。

`payload`  
消息有效载荷  
此格式是特定于应用程序的格式。

`kwargs`  
可能的其它实际参数，如 [https://awslabs.github.io/aws-crt-python/api/mqtt.html#awscrt.mqtt.Connection.subscribe](https://awslabs.github.io/aws-crt-python/api/mqtt.html#awscrt.mqtt.Connection.subscribe)中所述。

在 `pubsub.py` 示例中，`on_message_received` 仅显示主题及其有效载荷。它还会计算在达到限制后收到的结束程序的消息。

您的应用程序将评估主题和有效载荷，以确定要执行的操作。

### 设备断开和重新连接
<a name="sdk-tutorials-explore-connect"></a>

`pubsub.py` 示例包括在设备断开连接和重新建立连接时调用的回调函数。您的设备对这些事件采取的操作是特定于应用程序的。

当设备首次连接时，它必须订阅主题才能接收。如果设备在重新连接时存在会话，则会恢复其订阅，并在设备重新连接后，将来自这些订阅的所有存储消息发送到设备。

如果设备的会话在重新连接时不再存在，则必须重新订阅其订阅。持久会话的生命周期有限，当设备断开连接太长时间时，可能会过期。

## 连接您的设备并与之通信 AWS IoT Core
<a name="sdk-tutorials-experiment"></a>

本部分介绍了一些练习，可帮助您探索将设备连接到 AWS IoT Core的不同方面。在这些练习中，您将使用 AWS IoT 控制台中的 [MQTT 测试客户端](https://console.aws.amazon.com/iot/home#/test)查看您的设备发布的内容，并将消息发布到您的设备。这些练习使用来自 [AWS IoT Device SDK v2 for Python](https://github.com/aws/aws-iot-device-sdk-python-v2/tree/master/samples#sample-apps-for-the-aws-iot-device-sdk-v2-for-python) 的 [https://github.com/aws/aws-iot-device-sdk-python-v2/blob/master/samples/pubsub.py](https://github.com/aws/aws-iot-device-sdk-python-v2/blob/master/samples/pubsub.py) 示例并根据您在 [AWS IoT Core 教程入门](iot-gs.md) 教程中的经验构建。

**Topics**
+ [订阅通配符主题筛选条件](#sdk-tutorials-experiment-wild)
+ [处理主题筛选条件订阅](#sdk-tutorials-experiment-process)
+ [从您的设备发布消息](#sdk-tutorials-experiment-publish)

对于这些练习，您将从 `pubsub.py` 示例程序开始操作。

**注意**  
这些练习假定您已完成 [AWS IoT Core 教程入门](iot-gs.md) 教程并使用该教程中的设备终端窗口。

### 订阅通配符主题筛选条件
<a name="sdk-tutorials-experiment-wild"></a>

在本练习中，您将修改用于调用 `pubsub.py` 的命令行以订阅通配符主题筛选条件，并根据消息主题处理收到的消息。

#### 练习流程
<a name="sdk-tutorials-experiment-wild-steps"></a>

在本练习中，假设您的设备包含温度控制和光控。它使用这些主题名称来标识有关的消息。

1. 在开始练习之前，请尝试根据 [AWS IoT Core 教程入门](iot-gs.md) 教程在您的设备上运行此命令，确保一切都准备就绪，可正常进行练习。

   ```
   cd ~/aws-iot-device-sdk-python-v2/samples
   python3 pubsub.py --topic topic_1 --ca_file ~/certs/Amazon-root-CA-1.pem --cert ~/certs/device.pem.crt --key ~/certs/private.pem.key --endpoint your-iot-endpoint
   ```

   您看到的输出应该与您在[入门教程](connecting-to-existing-device.md#gs-device-node-app-run)看到的一样。

1. 在本练习中，请更改这些命令行参数。    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/iot/latest/developerguide/sdk-tutorials.html)

   对初始命令行进行这些更改将得到此命令行。在设备的终端窗口中输入此命令。

   ```
   python3 pubsub.py --message "" --count 2 --topic device/+/details --ca_file ~/certs/Amazon-root-CA-1.pem --cert ~/certs/device.pem.crt --key ~/certs/private.pem.key --endpoint your-iot-endpoint
   ```

   程序应该类似如下所示：

   ```
   Connecting to a3qexamplesffp-ats.iot.us-west-2.amazonaws.com with client ID 'test-24d7cdcc-cc01-458c-8488-2d05849691e1'...
   Connected!
   Subscribing to topic 'device/+/details'...
   Subscribed with QoS.AT_LEAST_ONCE
   Waiting for all messages to be received...
   ```

   如果您在终端上看到类似的内容，则表示您的设备已准备就绪，并侦听主题名称以 `device` 开始并以结束 `/detail` 的消息。所以，让我们来测试吧。

1. 以下是您的设备可能会收到的几条消息。    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/iot/latest/developerguide/sdk-tutorials.html)

1. 使用 AWS IoT 控制台中的 MQTT 测试客户端，将上一步中所述的消息发送到您的设备。

   1. 在 AWS IoT 控制台中打开 [MQTT 测试客户端](https://console.aws.amazon.com/iot/home#/test)。

   1. 在**订阅主题**中，在**订阅主题字段**输入主题筛选条件：**device/\$1/details**，然后选择**订阅主题**。

   1. 在 MQTT 测试客户端中的**订阅**列中，选择 **device/\$1/details**。

   1. 对于上表中的每个主题，请在 MQTT 测试客户端中执行以下操作：

      1. 在**发布**中，在表中输入**主题名称**列的值。

      1. 在主题名称下方的消息有效载荷字段中，在表中输入**消息有效载荷**列的值。

      1. 观看 `pubsub.py` 运行所在的终端窗口，并在 MQTT 测试客户端中选择**发布到主题**。

      您应该看到该消息是由终端窗口中的 `pubsub.py`接收的。

#### 练习结果
<a name="sdk-tutorials-experiment-wild-result"></a>

有了这个，`pubsub.py`，使用通配符主题筛选条件订阅消息，接收消息并在终端窗口中显示这些消息。请注意您如何订阅单个主题筛选条件，并调用回调函数来处理具有两个不同主题的消息。

### 处理主题筛选条件订阅
<a name="sdk-tutorials-experiment-process"></a>

在上一练习的基础上，修改 `pubsub.py` 示例应用程序以评估消息主题并根据主题处理订阅的消息。

#### 练习流程
<a name="sdk-tutorials-experiment-process-steps"></a>

**评估消息主题**

1. 将 `pubsub.py` 复制到 `pubsub2.py`。

1. 在您常用的文本编辑器或 IDE 中打开 `pubsub2.py`。

1. 在 `pubsub2.py` 中，查找 `on_message_received` 函数。

1. 在 `on_message_received` 中，在以 `print("Received message` 开头的行之后和在以 `global received_count` 开头的行之前插入以下代码。

   ```
       topic_parsed = False
       if "/" in topic:
           parsed_topic = topic.split("/")
           if len(parsed_topic) == 3:
               # this topic has the correct format
               if (parsed_topic[0] == 'device') and (parsed_topic[2] == 'details'):
                   # this is a topic we care about, so check the 2nd element
                   if (parsed_topic[1] == 'temp'):
                       print("Received temperature request: {}".format(payload))
                       topic_parsed = True
                   if (parsed_topic[1] == 'light'):
                       print("Received light request: {}".format(payload))
                       topic_parsed = True
       if not topic_parsed:
           print("Unrecognized message topic.")
   ```

1. 保存更改并使用此命令行运行修改后的程序。

   ```
   python3 pubsub2.py --message "" --count 2 --topic device/+/details --ca_file ~/certs/Amazon-root-CA-1.pem --cert ~/certs/device.pem.crt --key ~/certs/private.pem.key --endpoint your-iot-endpoint
   ```

1. 在 AWS IoT 控制台中，打开 [MQTT 测试客户端](https://console.aws.amazon.com/iot/home#/test)。

1. 在**订阅主题**中，在**订阅主题字段**输入主题筛选条件：**device/\$1/details**，然后选择**订阅主题**。

1. 在 MQTT 测试客户端中的 **Subscriptions**（订阅）列中，选择**device/\$1/details**。

1. 对于此表中的每个主题，请在 MQTT 测试客户端中执行以下操作：    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/iot/latest/developerguide/sdk-tutorials.html)

   1. 在 **Publish**（发布）中，在表中输入 **Topic name**（主题名称）列的值。

   1. 在主题名称下方的消息有效载荷字段中，在表中输入**消息有效载荷**列的值。

   1. 观看 `pubsub.py` 运行所在的终端窗口，并在 MQTT 测试客户端中选择**发布到主题**。

   您应该看到该消息是由终端窗口中的 `pubsub.py`接收的。

您应在终端窗口中看到类似的内容。

```
Connecting to a3qexamplesffp-ats.iot.us-west-2.amazonaws.com with client ID 'test-af794be0-7542-45a0-b0af-0b0ea7474517'...
Connected!
Subscribing to topic 'device/+/details'...
Subscribed with QoS.AT_LEAST_ONCE
Waiting for all messages to be received...
Received message from topic 'device/light/details': b'{ "desiredLight": 100, "currentLight": 50 }'
Received light request: b'{ "desiredLight": 100, "currentLight": 50 }'
Received message from topic 'device/temp/details': b'{ "desiredTemp": 20, "currentTemp": 15 }'
Received temperature request: b'{ "desiredTemp": 20, "currentTemp": 15 }'
2 message(s) received.
Disconnecting...
Disconnected!
```

#### 练习结果
<a name="sdk-tutorials-experiment-process-result"></a>

在本练习中，您添加了代码，以便示例应用程序能够识别并处理回调函数中的多条消息。有了这个，您的设备便可以接收消息并对它们采取行动。

您的设备接收和处理多条消息的另一种方式是单独订阅不同的消息，并将每个订阅分配给自己的回调函数。

### 从您的设备发布消息
<a name="sdk-tutorials-experiment-publish"></a>

您可以使用 pubsub.py 示例应用程序从您的设备发布消息。虽然它会按原样发布消息，但消息不能作为 JSON 文档读取。本练习修改了示例应用程序，使其能够在消息负载中发布 JSON 文档，供 AWS IoT Core其读取。

#### 练习流程
<a name="sdk-tutorials-experiment-publish-steps"></a>

在本练习中，以下消息将以 `device/data` 主题发布。

```
{
    "timestamp": 1601048303,
    "sensorId": 28,
    "sensorData": [
        {
        "sensorName": "Wind speed",
        "sensorValue": 34.2211224
        }
    ]
}
```

**准备 MQTT 测试客户端以监控本练习中的消息**

1. 在 **Subscribe to topic**（订阅主题）中，在 **Subscription topic field**（订阅主题字段）输入主题筛选条件：**device/data**，然后选择 **Subscribe to topic**（订阅主题）。

1. 在 **Subscriptions**（订阅）列中，选择 **device/data**（设备/数据）。

1. 将 MQTT 测试客户端窗口保持打开状态，等待来自设备的消息。

**使用 pubsub.py 示例应用程序发送 JSON 文档**

1. 在您的设备上，将 `pubsub.py` 复制到 `pubsub3.py`。

1. 编辑 `pubsub3.py` 来更改其所发布消息的格式。

   1. 在文本编辑器中打开 `pubsub3.py`。

   1. 查找此代码行：

      `message = "{} [{}]".format(message_string, publish_count)`

   1. 将其更改为：

      `message = "{}".format(message_string)`

   1. 查找此代码行：

      `message_json = json.dumps(message)`

   1. 将其更改为：

      `message = "{}".json.dumps(json.loads(message))`

   1. 保存更改。

1. 在您的设备上运行此命令以发送消息两次。

   ```
   python3 pubsub3.py  --ca_file ~/certs/Amazon-root-CA-1.pem  --cert ~/certs/device.pem.crt  --key ~/certs/private.pem.key  --topic device/data  --count 2 --message '{"timestamp":1601048303,"sensorId":28,"sensorData":[{"sensorName":"Wind speed","sensorValue":34.2211224}]}'  --endpoint your-iot-endpoint
   ```

1. 在 MQTT 测试客户端中，检查它是否已解释并格式化了消息有效载荷中的 JSON 文档，如下所示：  
![\[该图显示了如何在 AWS IoT 控制台的 MQTT 客户端中显示 JSON 消息负载。\]](http://docs.aws.amazon.com/zh_cn/iot/latest/developerguide/images/mqtt-test-client-output.png)

预设情况下，`pubsub3.py` 也会订阅它发送的消息。您应该看到它在应用程序的输出中收到了消息。终端窗口应类似如下所示。

```
Connecting to a3qEXAMPLEsffp-ats.iot.us-west-2.amazonaws.com with client ID 'test-5cff18ae-1e92-4c38-a9d4-7b9771afc52f'...
Connected!
Subscribing to topic 'device/data'...
Subscribed with QoS.AT_LEAST_ONCE
Sending 2 message(s)
Publishing message to topic 'device/data': {"timestamp":1601048303,"sensorId":28,"sensorData":[{"sensorName":"Wind speed","sensorValue":34.2211224}]}
Received message from topic 'device/data': b'{"timestamp":1601048303,"sensorId":28,"sensorData":[{"sensorName":"Wind speed","sensorValue":34.2211224}]}'
Publishing message to topic 'device/data': {"timestamp":1601048303,"sensorId":28,"sensorData":[{"sensorName":"Wind speed","sensorValue":34.2211224}]}
Received message from topic 'device/data': b'{"timestamp":1601048303,"sensorId":28,"sensorData":[{"sensorName":"Wind speed","sensorValue":34.2211224}]}'
2 message(s) received.
Disconnecting...
Disconnected!
```

#### 练习结果
<a name="sdk-tutorials-experiment-publish-result"></a>

这样，您的设备就可以生成要发送的消息 AWS IoT Core 以测试基本连接，并提供设备消息 AWS IoT Core 以供处理。例如，您可以使用此应用程序将测试数据从您的设备发送到测试 AWS IoT 规则操作。

## 查看结果
<a name="sdk-tutorials-conclusion"></a>

本教程中的示例让你亲身体验了设备如何与之通信的基础知识， AWS IoT Core这是 AWS IoT 解决方案的基本组成部分。当您的设备能够与之通信时 AWS IoT Core，它们可以将消息传递给 AWS 服务和其他可以操作的设备。同样， AWS 服务和其他设备可以处理信息，从而将消息发送回您的设备。

当您准备好 AWS IoT Core 进一步探索时，请尝试以下教程：
+ [教程：发送 Amazon SNS 通知](iot-sns-rule.md)
+ [教程：将设备数据存储在 DynamoDB 表中](iot-ddb-rule.md)
+ [教程：使用 AWS Lambda 函数格式化通知](iot-lambda-rule.md)

# 教程：使用 AWS IoT Device SDK for Embedded C
<a name="iot-embedded-c-sdk"></a>

此部分描述如何运行 AWS IoT Device SDK for Embedded C。

**Topics**
+ [步骤 1：安装 AWS IoT Device SDK for Embedded C](#install-embedded-c-sdk)
+ [步骤 2：配置示例应用](#iot-c-sdk-app-config)
+ [步骤 3：构建并运行示例应用程序](#iot-c-sdk-app-run)

## 步骤 1：安装 AWS IoT Device SDK for Embedded C
<a name="install-embedded-c-sdk"></a>

AWS IoT Device SDK for Embedded C通常面向需要优化的 C 语言运行时的资源受限设备。您可以在任何操作系统上使用此 SDK，并将其托管在任何类型的处理器（例如 MCU 和 MPU）上。如果您有更多的可用内存和处理资源，我们建议您使用更高级的 AWS IoT设备和移动 SDK 之一（例如，C\$1\$1、Java、JavaScript 和 Python）。

一般而言，AWS IoT Device SDK for Embedded C适用于以下系统：这些系统使用 MCU 或运行嵌入式操作系统的低端 MPU。对于本部分中的编程示例，我们假定您的设备使用 Linux。

**Example**  

1. 从 [GitHub](https://github.com/aws/aws-iot-device-sdk-embedded-C) 将 AWS IoT Device SDK for Embedded C下载到您的设备。

   ```
   git clone https://github.com/aws/aws-iot-device-sdk-embedded-c.git --recurse-submodules
   ```

   这将在当前目录中创建一个名为 `aws-iot-device-sdk-embedded-c`的目录。

1. 前往到该目录并签出最新版本。请参阅 [github.com/aws/aws-iot-device-sdk-embedded-C/tags](https://github.com/aws/aws-iot-device-sdk-embedded-C/tags) 以获取最新版本标签。

   ```
   cd aws-iot-device-sdk-embedded-c
   git checkout latest-release-tag
   ```

1. 安装 OpenSSL 1.1.0 或更高版本。当通过软件包管理器安装时，OpenSSL 开发库通常被称为“libssl-dev”或“openssl-devel”。

   ```
   sudo apt-get install libssl-dev
   ```

## 步骤 2：配置示例应用
<a name="iot-c-sdk-app-config"></a>

AWS IoT Device SDK for Embedded C 包含供您试用的示例应用程序。为了简单起见，本教程使用的是 `mqtt_demo_mutual_auth`应用程序，此应用程序演示如何连接到 AWS IoT Core消息代理并订阅和发布到 MQTT 主题。

1. 将您在 [AWS IoT Core 教程入门](iot-gs.md)中创建的证书和私有密钥复制到 `build/bin/certificates`目录中。
**注意**  
设备和根 CA 证书可能会过期或被吊销。如果您的证书过期或被吊销，则您必须将新的 CA 证书或私有密钥和设备证书复制到您的设备上。

1. 您必须使用个人 AWS IoT Core终端节点、私有密钥、证书和根 CA 证书配置示例。导航到 `aws-iot-device-sdk-embedded-c/demos/mqtt/mqtt_demo_mutual_auth`目录。

   如果您已安装 AWS CLI，则可使用此命令查找您的账户端点 URL。

   ```
   aws iot describe-endpoint --endpoint-type iot:Data-ATS
   ```

   如果您尚未安装 AWS CLI，请打开 [AWS IoT控制台](https://console.aws.amazon.com/iot/home)。在导航窗格中，依次选择 **Manage (管理)** 和 **Things (事物)**。为您的设备选择 IoT 事物，然后选择 **Interact**（交互）。您的终端节点显示在事物详细信息页面的 **HTTPS** 部分中。

1. 打开 `demo_config.h`文件并更新以下各项的值：  
AWS\$1IOT\$1ENDPOINT  
您的私有终端节点。  
CLIENT\$1CERT\$1PATH  
您的证书文件路径，例如 `certificates/device.pem.crt"`。  
CLIENT\$1PRIVATE\$1KEY\$1PATH  
您的私有密钥文件名，例如 `certificates/private.pem.key`。

   例如：

   ```
   // Get from demo_config.h
   // =================================================
   #define AWS_IOT_ENDPOINT               "my-endpoint-ats.iot.us-east-1.amazonaws.com"
   #define AWS_MQTT_PORT                  8883
   #define CLIENT_IDENTIFIER              "testclient"
   #define ROOT_CA_CERT_PATH              "certificates/AmazonRootCA1.crt"
   #define CLIENT_CERT_PATH               "certificates/my-device-cert.pem.crt"
   #define CLIENT_PRIVATE_KEY_PATH        "certificates/my-device-private-key.pem.key"
   // =================================================
   ```

1. 使用此命令检查您的设备上是否安装了 CMake。

   ```
   cmake --version
   ```

   如果您看到编译器的版本信息，则可以继续下一部分。

   如果出现错误或看不到任何信息，则需要使用此命令安装 cmake 软件包。

   ```
   sudo apt-get install cmake
   ```

   再次运行 **cmake --version**命令，确认 CMake 已安装并且您已准备好继续操作。

1. 使用此命令检查您的设备上是否安装了开发工具。

   ```
   gcc --version
   ```

   如果您看到编译器的版本信息，则可以继续下一部分。

   如果出现错误或看不到任何编译器信息，则需要使用此命令安装 `build-essential`软件包。

   ```
   sudo apt-get install build-essential
   ```

   再次运行 **gcc --version**命令，确认构建工具已安装并且您已准备好继续操作。

## 步骤 3：构建并运行示例应用程序
<a name="iot-c-sdk-app-run"></a>

此步骤介绍如何在您的设备上生成 `mqtt_demo_mutual_auth` 应用程序并使用 AWS IoT Device SDK for Embedded C 将其连接到 [AWS IoT 控制台](https://console.aws.amazon.com/iot/home)。

**运行 AWS IoT Device SDK for Embedded C示例应用程序**

1. 导航到 `aws-iot-device-sdk-embedded-c`并创建目录。

   ```
   mkdir build && cd build
   ```

1. 输入以下 CMake 命令以生成 Makefiles 构建所需的文件。

   ```
   cmake ..  
   ```

1. 输入以下命令以构建可执行应用程序文件。

   ```
   make
   ```

1. 使用此命令运行 `mqtt_demo_mutual_auth`应用程序。

   ```
   cd bin
   ./mqtt_demo_mutual_auth
   ```

   您应该可以看到类似于如下所示的输出内容：  
![\[运行 AWS IoT Device SDK for Embedded C 示例应用程序的命令行输出。\]](http://docs.aws.amazon.com/zh_cn/iot/latest/developerguide/images/successful-run2.png)

设备现已使用 AWS IoT Device SDK for Embedded C连接到 AWS IoT。

您还可以使用 AWS IoT控制台查看示例应用程序正在发布的 MQTT 消息。有关如何在 [AWS IoT控制台](https://console.aws.amazon.com/iot/home)中使用 MQTT 客户端的信息，请参阅[使用 MQTT 客户端查看 AWS IoT MQTT 消息](view-mqtt-messages.md)。

# 创建将设备数据路由到其他服务的 AWS IoT 规则
<a name="iot-rules-tutorial"></a>

这些教程向您展示了如何使用一些更常见的 AWS IoT 规则操作来创建和测试规则。

AWS IoT 规则将数据从您的设备发送到其他 AWS 服务。它们侦听特定的 MQTT 消息，格式化消息有效载荷中的数据，并将结果发送到其它 AWS 服务。

我们建议您按照这里显示的顺序尝试这些功能，即使您的目标是使用 Lambda 或更复杂的函数创建一个规则。这些教程是按照从基本到复杂的顺序提供的。它们以递增方式呈现新概念，从而帮助您了解可用于创建没有特定教程的规则操作的概念。

**注意**  
AWS IoT 规则可帮助您将物联网设备中的数据发送到其他 AWS 服务。但是，要成功完成此操作，您需要了解要向其发送数据的其它服务的工作知识。虽然这些教程提供了完成任务所需的信息，但您可能会发现在解决方案中使用数据之前，了解有关要向其发送数据的服务的详细信息会很有帮助。对其他 AWS 服务的详细说明不在这些教程的范围之内。

**教程场景概览**  
这些教程的场景是定期发布数据的天气传感器设备。在这个虚构系统中有许多这样的传感器设备。但是，本部分中的教程侧重于单个设备，同时展示了如何容纳多个传感器。

本节中的教程向您展示如何使用 AWS IoT 规则对这个虚构的天气传感器设备系统执行以下任务。
+ 

**[教程：重新发布 MQTT 消息](iot-repub-rule.md)**  
本教程介绍如何将从天气传感器收到的 MQTT 消息重新发布为仅包含传感器 ID 和温度值的消息。它只使用 AWS IoT Core 服务，并演示简单 SQL 查询以及如何使用 MQTT 客户端来测试您的规则。
+ 

**[教程：发送 Amazon SNS 通知](iot-sns-rule.md)**  
本教程介绍如何在天气传感器设备的值超过特定值时发送 SNS 消息。它以上一教程中介绍的概念为基础，并添加了如何使用另一项 AWS 服务，即[亚马逊简单通知服务](https://docs.aws.amazon.com//sns/latest/dg/welcome.html) (Amazon SNS)。

  如果您是 Amazon SNS 的新用户，请查看其[入门](https://docs.aws.amazon.com//sns/latest/dg/sns-getting-started.html)练习，然后再开始本教程。
+ 

**[教程：将设备数据存储在 DynamoDB 表中](iot-ddb-rule.md)**  
本教程介绍如何将来自气象传感器设备的数据存储在数据库表中。它使用规则查询语句和替代模板来设置目标服务的消息数据的格式，[Amazon DynamoDB](https://docs.aws.amazon.com//amazondynamodb/latest/developerguide/Introduction.html)。

  如果您是的 DynamoDB 用户，请查看其[入门](https://docs.aws.amazon.com//amazondynamodb/latest/developerguide/GettingStartedDynamoDB.html)练习，然后再开始本教程。
+ 

**[教程：使用 AWS Lambda 函数格式化通知](iot-lambda-rule.md)**  
本教程介绍如何调用 Lambda 函数来重新格式化设备数据，然后将其作为文本消息发送。它在函数中添加了 Python 脚本和 AWS SDK [AWS Lambda](https://docs.aws.amazon.com//lambda/latest/dg/welcome.html)函数，以便使用来自天气传感器设备的消息有效载荷数据进行格式化并发送短信。

  如果您是 Lambda 的新用户，请查看 Lambda 的[入门](https://docs.aws.amazon.com//lambda/latest/dg/getting-started.html)练习，然后再开始本教程。

**AWS IoT 规则概述**  
所有这些教程都创建了 AWS IoT 规则。

对于将数据从设备发送到其他 AWS 服务的 AWS IoT 规则，它使用：


+ 规则查询语句，由以下内容组成：
  + 一个 SQL SELECT 子句，用于从消息有效载荷中选择数据并设置其格式
  + 标识要使用的消息的主题筛选条件（规则查询语句中的 FROM 对象）
  + 可选条件语句（SQL WHERE 子句），用于指定执行操作的特定条件
+ 至少一个规则操作

设备会向主题发布 MQTT 消息。SQL SELECT 语句中的主题筛选条件标识要应用规则的 MQTT 主题。SQL SELECT 语句中指定的字段将来自传入 MQTT 消息有效载荷的数据格式化，以供规则的操作使用。有关规则操作的完整列表，请参阅 [AWS IoT 规则操作](iot-rule-actions.md)。

**Topics**
+ [教程：重新发布 MQTT 消息](iot-repub-rule.md)
+ [教程：发送 Amazon SNS 通知](iot-sns-rule.md)
+ [教程：将设备数据存储在 DynamoDB 表中](iot-ddb-rule.md)
+ [教程：使用 AWS Lambda 函数格式化通知](iot-lambda-rule.md)

# 教程：重新发布 MQTT 消息
<a name="iot-repub-rule"></a>

本教程演示如何创建在收到指定的 MQTT 消息时发布 MQTT 消息的 AWS IoT 规则。可以在发布之前通过规则修改传入的消息有效载荷。这样就可以创建针对特定应用程序量身定制的消息，而无需更改设备或固件。您还可以使用规则的筛选功能仅在满足特定条件时发布消息。

通过规则重新发布的消息就像任何其他 AWS IoT 设备或客户端发送的消息一样。设备可以订阅重新发布的消息，就像订阅任何其它 MQTT 消息主题一样。

**您将在本教程中学到的内容：**
+ 如何在规则查询语句中使用简单的 SQL 查询和函数
+ 如何使用 MQTT 客户端测试规则 AWS IoT 

完成本教程需要大约 30 分钟。

**Topics**
+ [查看 MQTT 主题和规则 AWS IoT](#iot-repub-rule-mqtt)
+ [步骤 1：创建 AWS IoT 规则以重新发布 MQTT 消息](#iot-repub-rule-define)
+ [步骤 2：测试您的新规则](#iot-repub-rule-test)
+ [步骤 3：查看结果和后续步骤](#iot-repub-rule-review)

**在开始本教程之前，请确保您具有：**
+ 

**[设置 AWS 账户](setting-up.md)**  
你需要你的 AWS 账户 和 AWS IoT 主机才能完成本教程。
+ 

**审核 [使用 MQTT 客户端查看 AWS IoT MQTT 消息](view-mqtt-messages.md)**  
请确保您可以使用 MQTT 客户端订阅和发布主题。您将使用 MQTT 客户端在此流程中测试新规则。

## 查看 MQTT 主题和规则 AWS IoT
<a name="iot-repub-rule-mqtt"></a>

在讨论 AWS IoT 规则之前，先了解 MQTT 协议会有所帮助。在物联网解决方案中，MQTT 协议相比于其它网络通信协议（如 HTTP）更具优势，这使得它成为物联网设备使用的常用选择。本部分回顾了 MQTT 的关键方面，因为它们适用于本教程。有关如何将 MQTT 与 HTTP 进行比较的信息，请参阅 [为设备通信选择应用程序协议](protocols.md#protocol-selection)。

**MQTT 协议**  
MQTT 协议使用与其主机的 publish/subscribe 通信模型。为了发送数据，设备会向消息代理发布由主题标识的 AWS IoT 消息。要接收来自消息代理的消息，设备通过在订阅请求中向消息代理发送主题筛选条件，来订阅其将接收的主题。 AWS IoT 规则引擎从消息代理接收 MQTT 消息。

**AWS IoT 规则**  
AWS IoT 规则由规则查询语句和一个或多个规则操作组成。当 AWS IoT 规则引擎接收 MQTT 消息，则这些元素将按如下方式操作消息。
+ 

**规则查询语句**  
规则的查询语句描述了要使用的 MQTT 主题，解释消息有效载荷中的数据，并按类似于常用 SQL 数据库使用的语句的 SQL 语句的描述设置数据的格式。查询语句的结果是发送到规则操作的数据。
+ 

**规则操作**  
规则中的每个规则操作都对规则的查询语句生成的数据起作用。 AWS IoT 支持[许多规则操作](iot-rule-actions.md)。但是，在本教程中，您将专注于 [重新发布](republish-rule-action.md) 规则操作，该操作将查询语句的结果发布为带有特定主题的 MQTT 消息。

## 步骤 1：创建 AWS IoT 规则以重新发布 MQTT 消息
<a name="iot-repub-rule-define"></a>

您将在本教程中创建的 AWS IoT 规则订阅了 `device/device_id/data` MQTT 主题，其中*device\$1id*是发送消息的设备的 ID。这些主题由[主题筛选条件](topics.md#topicfilters)描述为 `device/+/data`，其中，`+` 是匹配两个正斜杠字符之间的任何字符串的通配符。

当规则收到来自匹配主题的消息时，它会重新发布 `device_id` 和 `temperature` 的值，以 `device/data/temp` 主题发布为新的 MQTT 消息。

例如，具有 `device/22/data` 主题的 MQTT 消息有效载荷如下所示：

```
{
  "temperature": 28,
  "humidity": 80,
  "barometer": 1013,
  "wind": {
    "velocity": 22,
    "bearing": 255
  }
}
```

该规则将 `temperature` 值从消息有效载荷中取出，将 `device_id` 从主题中取出，并将其作为 MQTT 消息以 `device/data/temp` 为主题和类似下面这样的消息有效载荷重新发布：

```
{
  "device_id": "22",
  "temperature": 28
}
```

使用此规则，只需要设备 ID 和温度数据的设备会订阅 `device/data/temp` 主题以仅接收该信息。

**创建重新发布 MQTT 消息的规则**

1. 打开[AWS IoT 控制台的 “**规则**” 中心](https://console.aws.amazon.com//iot/home#/rulehub)。

1. 在 **Rules**（规则）中，选择 **Create**（创建）并开始创建新规则。

1. 在**创建规则**顶部：

   1. 在 **Name**（名称）下，输入规则的名称。在本教程中，将其命名为 **republish\$1temp**。

      请记住，规则名称在您的账户和区域中必须唯一，并且不能包含任何空格。我们在此名称中使用了下划线字符来分隔规则名称中的两个单词。

   1.  在**说明**中，描述规则。

      有意义的描述可以帮助您记住此规则的作用以及您创建它的原因。描述可以根据需要延长，因此请尽可能详细。

1. 在**创建规则**的**规则查询语句**中：

   1.  在**使用 SQL 版本**中，选择 **2016-03-23**。

   1. 在**规则查询语句**编辑框中，输入语句：

      ```
      SELECT topic(2) as device_id, temperature FROM 'device/+/data'
      ```

      本语句：
      + 侦听主题符合 `device/+/data`主题筛选条件的 MQTT 消息。
      + 从主题字符串中选择第二个元素，并将其分配给 `device_id`字段。
      + 从消息负载中选择 `temperature`字段的值，并将其分配给 `temperature`字段。

1. 在**设置一个或多个操作**中：

   1. 要打开此规则的规则操作列表，请选择**添加操作**。

   1. 在 **“选择操作**” 中，选择 “将**消息重新发布到 AWS IoT 主题**”。

   1. 在操作列表底部，选择 **Configure action**（配置操作）以打开选定操作的配置页面。

1. 在**配置操作**中：

   1.  在 **Topic**（主题）中输入 **device/data/temp**。这是此规则将发布的消息 MQTT 主题。

   1.  在 **Quality of Service**（服务质量）中，选择 **0 - The message is delivered zero or more times**（0-消息传递零次或多次）。

   1.  在**选择或创建角色以授予执行此操作的 AWS IoT 访问权限**中：

      1.  选择**创建角色**。**Create a new role**（创建新角色）对话框打开。

      1. 输入描述新角色的名称。在本教程中，请使用 **republish\$1role**。

         创建新角色时，将创建用于执行规则操作的正确策略并将其附加到新角色。如果更改此规则操作的主题或在其它规则操作中使用此角色，则必须更新该角色的策略以授权新主题或操作。要更新现有角色，请在本部分中选择 **Update role**（更新角色）。

      1. 选择 **Create Role**（创建角色）以创建角色并关闭对话框。

   1. 选择 **Add action**（添加操作）将操作添加到规则并返回到 **Create a rule**（创建规则）页。

1. “将**消息重新发布到 AWS IoT 主题**” 操作现在列在 **“设置一个或多个操作**” 中。

   在新动作的磁贴中，在**将消息重新发布至 AWS IoT 主题**下，您可以看到重新发布操作将发布到的主题。

   这是您将添加到此规则的唯一规则操作。

1. 在 **Create a rule**（创建规则）中，向下滚动到底部，然后选择 **Create rule**（创建规则）以创建规则并完成此步骤。

## 步骤 2：测试您的新规则
<a name="iot-repub-rule-test"></a>

要测试新规则，您将使用 MQTT 客户端发布和订阅此规则所使用的 MQTT 消息。

在新窗口中打开 [AWS IoT 控制台中的 MQTT 客户端](https://console.aws.amazon.com//iot/home#/test)。这将允许您在不丢失 MQTT 客户端配置的情况下编辑规则。如果您让其转到控制台中的其它页面，MQTT 客户端不会保留任何订阅或消息日志。

**如需使用 MQTT 客户端来测试您的规则**

1. 在 [AWS IoT 控制台中的 MQTT 客户端](https://console.aws.amazon.com//iot/home#/test)中，订阅输入主题，在本例中为 `device/+/data`。

   1. 在 MQTT 客户端中，在**订阅**下，选择**订阅主题**。

   1. 在**订阅主题**中，输入输入主题筛选条件的主题，**device/\$1/data**。

   1. 将其它字段保留为默认设置。

   1. 选择**订阅主题**。

      在**订阅**栏，在**发布到主题**项下，将会显示 **device/\$1/data**。

1. 订阅您的规则将发布的主题：`device/data/temp`。

   1. 在 **Subscriptions**（订阅）中，再次选择 **Subscribe to a topic**（订阅主题），并在 **Subscription topic**（订阅主题）中，输入重新发布消息的主题，**device/data/temp**。

   1. 将其它字段保留为默认设置。

   1. 选择 **Subscribe to topic**（订阅主题）。

      在 **Subscriptions**（订阅）栏，在 **device/\$1/data** 下，将会显示 **device/data/temp**。

1. 使用特定设备 ID **device/22/data**向输入主题发布消息。您无法发布到包含通配符的 MQTT 主题。

   1. 在 MQTT 客户端中，在**订阅**下，选择**订阅主题**。

   1. 在**发布**字段中，输入输入主题名称，**device/22/data**。

   1. 复制此处显示的示例数据，然后在主题名称下方的编辑框中粘贴示例数据。

      ```
      {
        "temperature": 28,
        "humidity": 80,
        "barometer": 1013,
        "wind": {
          "velocity": 22,
          "bearing": 255
        }
      }
      ```

   1. 要发送您的 MQTT 消息，请选择**发布到主题**。

1. 查看已发送的消息。

   1. 在 MQTT 客户端中，在 **Subscriptions**（订阅）项下，您之前订阅的两个主题旁边有一个绿点。

      绿色圆点表示自您上次查看它们以来已收到一条或多条新消息。

   1. 在**订阅**下，选择 **device/\$1/data** 来检查消息有效载荷是否与刚刚发布的内容匹配，如下所示：

      ```
      {
        "temperature": 28,
        "humidity": 80,
        "barometer": 1013,
        "wind": {
          "velocity": 22,
          "bearing": 255
        }
      }
      ```

   1. 在 “**订阅**” 下 **device/data/temp**，选择检查重新发布的消息有效负载是否如下所示：

      ```
      {
        "device_id": "22",  
        "temperature": 28
      }
      ```

      请注意，`device_id` 值是一个带引号的字符串，`temperature` 值为数字。这是因为 [https://docs.aws.amazon.com//iot/latest/developerguide/iot-sql-functions.html#iot-function-topic](https://docs.aws.amazon.com//iot/latest/developerguide/iot-sql-functions.html#iot-function-topic)函数从输入消息的主题名称中提取字符串，而 `temperature`值使用输入消息负载中的数值。

      如果您想使 `device_id`值为数值，请在规则查询语句中将 `topic(2)`替换为：

      ```
      cast(topic(2) AS DECIMAL)
      ```

      请注意，将 `topic(2)`值设置为数字值仅在主题的该部分仅包含数字字符时才起作用。

1. 如果您看到已向该**device/data/temp**主题发布了正确的消息，则说明您的规则起作用了。请在下一部分中了解有关“重新发布规则”操作的更多信息。

   如果您没有看到正确的消息已发布到**设备/\$1/data** 或**device/data/temp**主题，请查看疑难解答提示。

### 重新发布消息规则疑难解答
<a name="iot-repub-rule-trouble"></a>

如果您没有看到期望的结果，可检查以下事项。
+ 

**您收到了一个错误的广告条**  
如果在您发布输入消息时出现错误，请先更正该错误。以下步骤可帮助您更正此错误。
+ 

**您未在 MQTT 客户端中看到输入消息**  
每次将输入消息发布到 `device/22/data`主题时，如果您如流程中所述订阅了 `device/+/data`主题筛选条件，则消息应当会在 MQTT 客户端中显示。

**要检查的事项**
  + 

**检查您订阅的主题筛选条件**  
如果您如流程中所述订阅了输入消息主题，则每次发布输入消息时都应看到该输入消息的副本。

    如果没有看到该消息，请检查您订阅的主题名称，并将其与您发布的主题进行比较。主题名称区分大小写，您订阅的主题必须与发布消息负载的主题相同。
  + 

**检查消息发布函数**  
在 MQTT 客户端中，在**订阅**下，选择 **device/\$1/data**，检查发布消息的主题，然后选择**发布到主题**。您应该会看到来自主题下方编辑框中的消息负载出现在消息列表中。
+ 

**您未在 MQTT 客户端中看到您的重新发布的消息**  
要使规则起作用，规则必须具有授权其接收和重新发布消息的正确策略，并且必须接收消息。

**要检查的事项**
  + 

**检查您 AWS 区域 的 MQTT 客户端和您创建的规则**  
您在其中运行 MQTT 客户端的控制台必须位于您所创建规则的同一 AWS 区域。
  + 

**检查规则查询语句中的输入消息主题**  
要使规则起作用，它必须收到一条消息，消息主题名称应与规则查询语句 FROM 子句中的主题筛选条件相匹配。

    检查规则查询语句中主题筛选条件的拼写与 MQTT 客户端中主题的拼写。主题名称区分大小写，消息的主题必须与规则查询语句中的主题筛选条件匹配。
  + 

**检查输入消息负载的内容**  
要使规则起作用，则必须在 SELECT 语句中声明的消息负载中找到数据字段。

    检查规则查询语句 `temperature`字段中的拼写与 MQTT 客户端中消息负载的拼写。字段名称区分大小写，规则查询语句中 `temperature`字段必须与消息负载中的 `temperature`字段相同。

    确保消息负载中的 JSON 文档格式正确。如果 JSON 有任何错误（例如缺少逗号），则规则将无法读取它。
  + 

**在规则操作中检查重新发布的消息主题**  
重新发布规则操作向其发布新消息的主题必须与您在 MQTT 客户端中订阅的主题匹配。

    在控制台中打开您创建的规则，然后检查规则操作将重新发布消息的主题。
  + 

**检查规则所使用的角色**  
规则操作必须具有接收原始主题和发布新主题的权限。

    授权规则接收消息数据并重新发布的策略特定于所使用的主题。如果更改用于重新发布消息数据的主题，则必须更新规则操作的角色，以更新其策略来匹配当前主题。

    如果怀疑这里出现了问题，请编辑“重新发布”规则操作并创建新角色。规则操作创建的新角色将接收执行这些操作所需的授权。

## 步骤 3：查看结果和后续步骤
<a name="iot-repub-rule-review"></a>

**在本教程中：**
+ 您在规则查询语句中使用了一个简单的 SQL 查询和几个函数来生成新的 MQTT 消息。
+ 您创建了重新发布该新消息的规则。
+ 您使用 MQTT 客户端来测试您的 AWS IoT 规则。

**后续步骤**  
使用此规则重新发布几条消息后，请尝试使用该规则进行实验，以了解更改教程的某些方面如何影响重新发布的消息。以下想法可以帮助您开始操作。
+ *device\$1id*在输入消息的主题中更改并观察重新发布的消息有效负载中的效果。
+ 更改规则查询语句中选定的字段，并观察重新发布的消息有效载荷中的效果。
+ 尝试本系列中的下一个教程，了解如何 [教程：发送 Amazon SNS 通知](iot-sns-rule.md)。

本教程中使用的“重新发布规则”操作也可以帮助您调试规则查询语句。例如，您可以将此操作添加到规则中，以查看其规则查询语句如何设置规则操作所使用的数据的格式。

# 教程：发送 Amazon SNS 通知
<a name="iot-sns-rule"></a>

本教程演示如何创建一条 AWS IoT 规则，将 MQTT 消息数据发送到 Amazon SNS 主题，以便可以将其作为 SMS 短信发送。

在本教程中，您将创建一条规则，以在温度超过规则中设置的值时将消息数据从天气传感器发送到 Amazon SNS 主题的所有订阅者。当报告的温度超过规则设置的值时，规则会检测到，并创建一个新的消息有效载荷，其中仅包含设备 ID、报告的温度和超出的温度限制。规则将新消息有效载荷作为 JSON 文档发送到 SNS 主题，该主题会通知 SNS 主题的所有订阅者。

**您将在本教程中学到的内容：**
+ 如何创建和测试 Amazon SNS 通知
+ 如何根据规则调用 Amazon SNS 通知 AWS IoT 
+ 如何在规则查询语句中使用简单的 SQL 查询和函数
+ 如何使用 MQTT 客户端测试规则 AWS IoT 

完成本教程需要大约 30 分钟。

**Topics**
+ [步骤 1：创建 Amazon SNS 主题，发送 SMS 文本消息](#iot-sns-rule-create-sns-topic)
+ [步骤 2：创建发送短信的 AWS IoT 规则](#iot-sns-rule-create-rule)
+ [第 3 步：测试 AWS IoT 规则和 Amazon SNS 通知](#iot-sns-rule-test-rule)
+ [步骤 4：查看结果和后续步骤](#iot-sns-rule-review-results)

**在开始本教程之前，请确保您具有：**
+ 

**[设置 AWS 账户](setting-up.md)**  
你需要你的 AWS 账户 和 AWS IoT 主机才能完成本教程。
+ 

**审核 [使用 MQTT 客户端查看 AWS IoT MQTT 消息](view-mqtt-messages.md)**  
请确保您可以使用 MQTT 客户端订阅和发布主题。您将使用 MQTT 客户端在此流程中测试新规则。
+ 

**审核 [Amazon Simple Notification Service](https://docs.aws.amazon.com//sns/latest/dg/welcome.html)**  
如果您以前未使用过 Amazon SNS，请查看 [设置 Amazon SNS 的访问权限](https://docs.aws.amazon.com//sns/latest/dg/sns-setting-up.html)。如果您已经完成了其他 AWS IoT 教程，则 AWS 账户 应该已经正确配置了您的教程。

## 步骤 1：创建 Amazon SNS 主题，发送 SMS 文本消息
<a name="iot-sns-rule-create-sns-topic"></a>

此步骤说明如何创建您的天气传感器可以向其发送消息数据的 Amazon SNS 主题。然后，Amazon SNS 主题将通过 SMS 文本消息通知所有订阅者已超过温度限制。

**创建发送 SMS 文本消息的 Amazon SNS 主题**

1. **创建 Amazon SNS 主题。**

   1. 登录 [Amazon SNS 控制台](https://console.aws.amazon.com//sns/home)。

   1. 在左侧导航窗格中，选择**主题**。

   1. 在 **Topics**（主题）页面上，选择 **Create topic**（创建主题）。

   1. 在 **Details**（详细信息）中，选择 **Standard**（标准）类型。默认情况下，控制台会创建 FIFO 主题。

   1. 在 **Name**（名称）中，输入 SNS 主题名称。在本教程中，请输入 **high\$1temp\$1notice**。

   1. 滚动到页面底部，然后选择 **Create topic**（创建主题）。

      控制台会打开新主题的**详细信息**页面。

1. **创建 Amazon SNS 订阅。**
**注意**  
您将在本教程中发送的消息可能会使您在此订阅中使用的电话号码产生短信费用。

   1. 在 **high\$1temp\$1notice** 主题详细信息页面上，选择 **Create subscription**（创建订阅）。

   1. 在 **Create subscripition**（创建订阅），在 **Details**（详细信息）部分中，在 **Protocol**（协议）列表中，选择 **SMS**。

   1. 在 **Endpoint**（端点）中，输入可接收文本消息的电话号码。请务必输入号码，以 `+` 开头，包含国家和地区代码，并且不包括任何其它标点符号字符。

   1. 选择 **Create subscription**（创建订阅）。

1. **测试 Amazon SNS 通知。**

   1. 在 [Amazon SNS 控制台](https://console.aws.amazon.com//sns/home)中，左侧导航窗格内，选择 **Topics**（主题）。

   1. 要打开主题的详细信息页面，请在 **Topics**（主题），在主题列表中，选择 **high\$1temp\$1notice**。

   1. 打开 **Publish message to topic**（将消息发布到主题）页面中的 **high\$1temp\$1notice**详细信息页面，选择 **Publish message**（发布消息）。

   1. 在 **Publish message to topic**（将消息发布到主题），在 **Message body**（消息正文）部分，**Message body to send to the endpoint**（要发送到端点的消息正文）中，输入一条简短的消息。

   1. 滚动到页面底部并选择 **Publish message**（发布消息）。

   1. 在使用您之前创建订阅时使用的号码的电话上，确认已收到消息。

   如果您没有收到测试消息，请仔细检查电话号码和手机的设置。

   确保您可以从 [Amazon SNS 控制台](https://console.aws.amazon.com//sns/home)发布测试消息，然后继续本教程。

## 步骤 2：创建发送短信的 AWS IoT 规则
<a name="iot-sns-rule-create-rule"></a>

您将在本教程中创建的 AWS IoT 规则订阅了 `device/device_id/data` MQTT 主题，其中`device_id`是发送消息的设备的 ID。这些主题在主题筛选条件中描述为 `device/+/data`，其中，`+` 是匹配两个正斜杠字符之间的任何字符串的通配符。此规则还测试消息有效载荷中的 `temperature` 字段值。

当规则收到来自匹配主题的消息时，它会从主题名称中取 `device_id`，从消息有效载荷中取 `temperature` 值，并为正在测试的限制添加一个常量值，并将这些值作为 JSON 文档发送到 Amazon SNS 通知主题。

 例如，来自气象传感器设备编号 32 的 MQTT 消息使用 `device/32/data` 主题，并具有如下所示的消息有效载荷：

```
{
  "temperature": 38,
  "humidity": 80,
  "barometer": 1013,
  "wind": {
    "velocity": 22,
    "bearing": 255
  }
}
```

规则的规则查询语句从消息有效载荷中取 `temperature` 值，从主题名称中取 `device_id`，并添加常量 `max_temperature` 值以向 Amazon SNS 主题发送类似于以下内容的消息有效载荷：

```
{
  "device_id": "32",
  "reported_temperature": 38,
  "max_temperature": 30
}
```

**创建用于检测超限温度值的 AWS IoT 规则并创建要发送至 Amazon SNS 主题的数据**

1. 打开[AWS IoT 控制台的 “**规则**” 中心](https://console.aws.amazon.com//iot/home#/rulehub)。

1. 如果这是您的第一条规则，请选择 **Create**（创建），或者 **Create a rule**（创建规则）。

1. 在 **Create a rule**（创建规则）中：

   1. 在 **Name**（名称）中，输入 **temp\$1limit\$1notify**。

      请记住，规则名称在您的 AWS 账户 和区域内必须是唯一的，并且不能有任何空格。我们在此名称中使用了下划线字符来分隔规则名称中的单词。

   1. 在 **Description**（说明）中，描述规则。

      有意义的描述可以更容易地记住此规则的作用以及您创建它的原因。描述可以根据需要延长，因此请尽可能详细。

1. 在 **Create a rule**（创建规则）的 **Rule query statement**（规则查询语句）中：

   1.  在 **Using SQL version**（使用 SQL 版本）中，选择 **2016-03-23**。

   1. 在 **Rule query statement**（规则查询语句）编辑框中，输入语句：

      ```
      SELECT topic(2) as device_id, 
          temperature as reported_temperature, 
          30 as max_temperature 
        FROM 'device/+/data' 
        WHERE temperature > 30
      ```

      本语句：
      + 侦听主题与 `device/+/data`主题筛选条件相符，并且 `temperature`值大于 30 的 MQTT 消息。
      + 从主题字符串中选择第二个元素，并将其分配给 `device_id`字段。
      + 从消息负载中选择 `temperature`字段的值，并将其分配给 `reported_temperature`字段。
      + 创建常数值 `30` 来表示限制值，并将其赋值给 `max_temperature` 字段。

1. 要打开此规则的规则操作列表，请在 **Set one or more actions**（设置一个或多个操作）中，选择 **Add action**（添加操作）。

1. 在 **Select an action**（选择操作）页面上，选择 **Send a message as an SNS push notification**（将消息发送为 SNS 推送通知）。

1. 要打开选定操作的配置页面，请在操作列表底部选择**配置操作**。

1. 在 **Configure action**（配置操作）中：

   1. 在 **SNS target**（SNS target）中，选择 **Select**（选择），找到您名为 **high\$1temp\$1notice** 的 SNS 主题，然后选择 **Select**（选择）。

   1. 对于 **Message format**（消息格式），请选择 **RAW**。

   1. 在**选择或创建角色以授予执行此操作的 AWS IoT 访问权限**中，选择**创建角色**。

   1. 在 **Create a new role**（创建新角色）中，**Name**（名称）项下，输入新角色的唯一名称。在本教程中，请使用 **sns\$1rule\$1role**。

   1. 选择**创建角色**。

   如果要重复本教程或重复使用现有角色，请选择 **Update role**（更新角色）然后再继续。这将更新角色的策略文档，以便与 SNS 目标配合使用。

1. 选择 **Add action**（添加操作），然后返回到 **Create a rule**（创建规则）页。

   在新操作的磁贴中，在 **Send a message as an SNS push notification**（将消息作为 SNS 推送通知发送）项下，您可以看到规则将调用的 SNS 主题。

   这是您将添加到此规则的唯一规则操作。

1. 要创建规则并完成此步骤，请在 **Create a rule**（创建规则）中，向下滚动到底部，然后选择 **Create rule**（创建规则）。

## 第 3 步：测试 AWS IoT 规则和 Amazon SNS 通知
<a name="iot-sns-rule-test-rule"></a>

要测试新规则，您将使用 MQTT 客户端发布和订阅此规则所使用的 MQTT 消息。

在新窗口中打开 [AWS IoT 控制台中的 MQTT 客户端](https://console.aws.amazon.com//iot/home#/test)。这将允许您在不丢失 MQTT 客户端配置的情况下编辑规则。如果您让 MQTT 客户端转到控制台中的其它页面，它将不会保留任何订阅或消息日志。

**如需使用 MQTT 客户端来测试您的规则**

1. 在 [AWS IoT 控制台中的 MQTT 客户端](https://console.aws.amazon.com//iot/home#/test)中，订阅输入主题，在本例中为 `device/+/data`。

   1. 在 MQTT 客户端中，在**订阅**下，选择**订阅主题**。

   1. 在**订阅主题**中，输入输入主题筛选条件的主题，**device/\$1/data**。

   1. 将其它字段保留为默认设置。

   1. 选择**订阅主题**。

      在 **Subscriptions**（订阅）栏，在 **Publish to a topic**（发布到主题）项下，将会显示 **device/\$1/data**。

1. 使用特定设备 ID **device/32/data**向输入主题发布消息。您无法发布到包含通配符的 MQTT 主题。

   1. 在 MQTT 客户端中，在**订阅**下，选择**订阅主题**。

   1. 在**发布**字段中，输入输入主题名称，**device/32/data**。

   1. 复制此处显示的示例数据，然后在主题名称下方的编辑框中粘贴示例数据。

      ```
      {
        "temperature": 38,
        "humidity": 80,
        "barometer": 1013,
        "wind": {
          "velocity": 22,
          "bearing": 255
        }
      }
      ```

   1. 选择 **Publish to topic**（发布到主题）以发布您的 MQTT 消息。

1. 确认文本消息已发送。

   1. 在 MQTT 客户端的**订阅**下，您之前订阅的主题旁边会有一个绿色圆点。

      绿色圆点表示自上次查看消息以来已收到一条或多条新消息。

   1. 在 **Subscriptions**（订阅）中，选择 **device/\$1/data** 来检查消息负载是否与刚刚发布的内容匹配，如下所示：

      ```
      {
        "temperature": 38,
        "humidity": 80,
        "barometer": 1013,
        "wind": {
          "velocity": 22,
          "bearing": 255
        }
      }
      ```

   1. 检查您用于订阅 SNS 主题的电话，并确认消息负载的内容，如下所示：

      ```
      {"device_id":"32","reported_temperature":38,"max_temperature":30}
      ```

      请注意，`device_id` 值是一个带引号的字符串，`temperature` 值为数字。这是因为 [https://docs.aws.amazon.com//iot/latest/developerguide/iot-sql-functions.html#iot-function-topic](https://docs.aws.amazon.com//iot/latest/developerguide/iot-sql-functions.html#iot-function-topic)函数从输入消息的主题名称中提取字符串，而 `temperature`值使用输入消息负载中的数值。

      如果您想使 `device_id`值为数值，请在规则查询语句中将 `topic(2)`替换为：

      ```
      cast(topic(2) AS DECIMAL)
      ```

      请注意，将 `topic(2)` 值设置为数字，`DECIMAL` 值仅在主题的该部分仅包含数字字符时才起作用。

1. 尝试发送温度未超过限制的 MQTT 消息。

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

   1. 在**发布**字段中，输入输入主题名称，**device/33/data**。

   1. 复制此处显示的示例数据，然后在主题名称下方的编辑框中粘贴示例数据。

      ```
      {
        "temperature": 28,
        "humidity": 80,
        "barometer": 1013,
        "wind": {
          "velocity": 22,
          "bearing": 255
        }
      }
      ```

   1. 要发送您的 MQTT 消息，请选择**发布到主题**。

   您应该会看到您在 **device/\$1/data** 订阅中发送的消息。但是，由于温度值低于规则查询语句中的最大温度，因此您应无法收到文本消息。

   如果您未看到正确的行为，请检查故障排除提示。

### 对 SNS 消息规则进行故障排除
<a name="iot-sns-rule-trouble"></a>

如果您没有看到期望的结果，可以检查以下事项。
+ 

**您收到了一个错误的广告条**  
如果在您发布输入消息时出现错误，请先更正该错误。以下步骤可帮助您更正此错误。
+ 

**您未在 MQTT 客户端中看到输入消息**  
每次将输入消息发布到 `device/22/data`主题时，如果您如流程中所述订阅了 `device/+/data`主题筛选条件，则消息应当会在 MQTT 客户端中显示。

**要检查的事项**
  + 

**检查您订阅的主题筛选条件**  
如果您如流程中所述订阅了输入消息主题，则每次发布输入消息时都应看到该输入消息的副本。

    如果没有看到该消息，请检查您订阅的主题名称，并将其与您发布的主题进行比较。主题名称区分大小写，您订阅的主题必须与发布消息负载的主题相同。
  + 

**检查消息发布函数**  
在 MQTT 客户端中，在**订阅**下，选择 **device/\$1/data**，检查发布消息的主题，然后选择**发布到主题**。您应该会看到来自主题下方编辑框中的消息负载出现在消息列表中。
+ 

**您没有收到 SMS 消息**  
要使规则起作用，规则必须具有授权其接收消息和发送 SNS 通知的正确策略，并且必须接收消息。

**要检查的事项**
  + 

**检查您 AWS 区域 的 MQTT 客户端和您创建的规则**  
您在其中运行 MQTT 客户端的控制台必须位于您所创建规则的同一 AWS 区域。
  + 

**检查消息负载中的温度值是否超过测试阈值**  
如果温度值小于或等于 30（如规则查询语句中定义），则规则将不会执行其任何操作。
  + 

**检查规则查询语句中的输入消息主题**  
要使规则起作用，它必须收到一条消息，消息主题名称应与规则查询语句 FROM 子句中的主题筛选条件相匹配。

    检查规则查询语句中主题筛选条件的拼写与 MQTT 客户端中主题的拼写。主题名称区分大小写，消息的主题必须与规则查询语句中的主题筛选条件匹配。
  + 

**检查输入消息负载的内容**  
要使规则起作用，则必须在 SELECT 语句中声明的消息负载中找到数据字段。

    检查规则查询语句 `temperature`字段中的拼写与 MQTT 客户端中消息负载的拼写。字段名称区分大小写，规则查询语句中 `temperature`字段必须与消息负载中的 `temperature`字段相同。

    确保消息负载中的 JSON 文档格式正确。如果 JSON 有任何错误（例如缺少逗号），则规则将无法读取它。
  + 

**在规则操作中检查重新发布的消息主题**  
重新发布规则操作向其发布新消息的主题必须与您在 MQTT 客户端中订阅的主题匹配。

    在控制台中打开您创建的规则，然后检查规则操作将重新发布消息的主题。
  + 

**检查规则所使用的角色**  
规则操作必须具有接收原始主题和发布新主题的权限。

    授权规则接收消息数据并重新发布的策略特定于所使用的主题。如果更改用于重新发布消息数据的主题，则必须更新规则操作的角色，以更新其策略来匹配当前主题。

    如果怀疑这里出现了问题，请编辑“重新发布”规则操作并创建新角色。规则操作创建的新角色将接收执行这些操作所需的授权。

## 步骤 4：查看结果和后续步骤
<a name="iot-sns-rule-review-results"></a>

**在本教程中：**
+ 您创建并测试了 Amazon SNS 通知主题和订阅。
+ 您在规则查询语句中使用了简单 SQL 查询和函数来为您的通知创建新消息。
+ 您创建了使用您的自定义消息负载发送 Amazon SNS 通知的 AWS IoT 规则。
+ 您使用 MQTT 客户端来测试您的 AWS IoT 规则。

**后续步骤**  
使用此规则发送了几条文本消息后，请尝试使用它来了解更改教程的某些方面如何影响消息以及发送消息的时间。以下想法可以帮助您开始操作。
+ 更改输入消息主题*device\$1id*中的内容，并观察短信内容中的效果。
+ 更改规则查询语句中选定的字段，并观察文本消息内容中的效果。
+ 将规则查询语句中的测试更改为测试最低温度而不是最高温度。记得更改 `max_temperature` 名称！
+ 添加重新发布规则操作，以便在发送 SNS 通知时发送 MQTT 消息。
+ 尝试本系列中的下一个教程，了解如何 [教程：将设备数据存储在 DynamoDB 表中](iot-ddb-rule.md)。

# 教程：将设备数据存储在 DynamoDB 表中
<a name="iot-ddb-rule"></a>

本教程演示如何创建将消息数据发送到 DynamoDB 表的 AWS IoT 规则。

在本教程中，您将创建一条规则来将消息数据从假想气象传感器设备发送到 DynamoDB 表。该规则将为来自许多气象传感器的数据设置格式，以便将其添加到单个数据库表中。

**在本教程中您将学到**
+ 如何创建 DynamoDB 表
+ 如何通过规则向 DynamoDB 表发送消息数据 AWS IoT 
+ 如何在 AWS IoT 规则中使用替换模板
+ 如何在规则查询语句中使用简单的 SQL 查询和函数
+ 如何使用 MQTT 客户端测试规则 AWS IoT 

完成本教程需要大约 30 分钟。

**Topics**
+ [步骤 1：为本教程创建 DynamoDB 表](#iot-ddb-rule-ddb-table)
+ [步骤 2：创建向 DynamoDB 表发送数据的 AWS IoT 规则](#iot-ddb-rule-topic-rule)
+ [步骤 3：测试 AWS IoT 规则和 DynamoDB 表](#iot-ddb-rule-test)
+ [步骤 4：查看结果和后续步骤](#iot-ddb-rule-review)

**在开始本教程之前，请确保您具有：**
+ 

**[设置 AWS 账户](setting-up.md)**  
你需要你的 AWS 账户 和 AWS IoT 主机才能完成本教程。
+ 

**审核 [使用 MQTT 客户端查看 AWS IoT MQTT 消息](view-mqtt-messages.md)**  
请确保您可以使用 MQTT 客户端订阅和发布主题。您将使用 MQTT 客户端在此流程中测试新规则。
+ 

**审核 [Amazon DynamoDB](https://docs.aws.amazon.com//amazondynamodb/latest/developerguide/Introduction.html) 概览**  
如果您之前没有使用过 DynamoDB，请查看 [DynamoDB 入门](https://docs.aws.amazon.com//amazondynamodb/latest/developerguide/GettingStartedDynamoDB.html)来熟悉 DynamoDB 的基本概念和操作。

## 步骤 1：为本教程创建 DynamoDB 表
<a name="iot-ddb-rule-ddb-table"></a>

在本教程中，您将创建一个具有以下属性的 DynamoDB 表，以记录来自虚拟气象传感器设备的数据：
+ `sample_time` 是主键，描述了记录样本的时间。
+ `device_id` 是排序键，描述了提供示例的设备 
+ `device_data` 是从设备接收并由规则查询语句格式化的数据

**如需为本教程创建 DynamoDB 表**

1. 打开 [DynamoDB 控制台](https://console.aws.amazon.com//dynamodb/home)，然后选择 **Create table**（创建表格）。

1. 在 **Create table**（创建表）中：

   1.  在 **Table name**（表名称）框中输入表名：**wx\$1data**。

   1. 在 **Partition key**（分区键）中，输入 **sample\$1time**，然后在字段旁边的选项列表中，选择 **Number**。

   1. 在 **Sort key**（排序键）中，输入 **device\$1id**，然后在字段旁边的选项列表中，选择 **Number**。

   1. 在页面底部，选择 **Create**（创建）。

您将在稍后定义 `device_data`，即您配置 DynamoDB 规则操作时。

## 步骤 2：创建向 DynamoDB 表发送数据的 AWS IoT 规则
<a name="iot-ddb-rule-topic-rule"></a>

在此步骤中，您将使用规则查询语句格式化来自虚拟气象传感器设备的数据，以便写入数据库表。

从天气传感器设备接收的示例消息有效载荷如下所示：

```
{
  "temperature": 28,
  "humidity": 80,
  "barometer": 1013,
  "wind": {
    "velocity": 22,
    "bearing": 255
  }
}
```

对于数据库条目，您将使用规则查询语句将消息有效载荷的结构展平如下：

```
{
  "temperature": 28,
  "humidity": 80,
  "barometer": 1013,
  "wind_velocity": 22,
  "wind_bearing": 255
}
```

在这个规则中，您还将使用几个 [替换模板](iot-substitution-templates.md)。替代模板是用于从函数和消息数据中插入动态值的表达式。

**创建向 DynamoDB 表发送数据的 AWS IoT 规则**

1. 打开 [AWS IoT 控制台的 Rules（规则）中心](https://console.aws.amazon.com//iot/home#/rulehub)。或者，您可以在中打开 AWS IoT 主页 AWS 管理控制台 并导航到 “**消息路由” > “规则”。**

1. 要开始在 **Rules**（规则）中创建新规则，请选择 **Create rule**（创建规则）。

1. 在 **Rule properties**（规则属性）中：

   1. 在 **Rule name**（规则名称）中，输入 **wx\$1data\$1ddb**。

      请记住，规则名称在您的 AWS 账户 和区域内必须是唯一的，并且不能有任何空格。我们在此名称中使用了下划线字符来分隔规则名称中的两个单词。

   1. 在 **Rule description**（规则描述）中，描述规则。

      有意义的描述可以更容易地记住此规则的作用以及您创建它的原因。描述可以根据需要延长，因此请尽可能详细。

1. 选择**下一步**以继续。

1. 在 **SQL statement**（SQL 语句）中：

   1. 在 **SQL version**（SQL 版本）中，选择 **2016-03-23**。

   1. 在 **SQL statement**（SQL 语句）编辑框中，输入语句：

      ```
      SELECT temperature, humidity, barometer,
        wind.velocity as wind_velocity,
        wind.bearing as wind_bearing,
      FROM 'device/+/data'
      ```

      本语句：
      + 侦听主题符合 `device/+/data`主题筛选条件的 MQTT 消息。
      + 将 `wind` 属性的元素格式化为单个属性。
      + 传递 `temperature`、`humidity`、`barometer` 属性，使其保持不变。

1. 选择**下一步**以继续。

1. 在 **Rule actions**（规则操作）中：

   1. 要打开此规则的规则操作列表，请在 **Action 1**（操作 1）中，选择 **DynamoDB**。
**注意**  
请务必选择 DynamoDB 而不是 Dyn DBv2 amo 作为规则操作。

   1. 在 **Table name**（表名称）中，选择在上一步中创建的 DynamoDB 表的名称：**wx\$1data**。

      **Partition key type**（分区键类型）和 **Sort key type**（排序键类型）字段将使用 DynamoDB 表中的值填充。

   1. 在**分区键**中，输入 **sample\$1time**。

   1. 在**分区键值**中，输入 **\$1\$1timestamp()\$1**。

      这是您将在此规则中使用第一个 [替换模板](iot-substitution-templates.md)。它将使用 timestamp 函数返回的值，而不是消息有效载荷中的值。要了解更多信息，请参阅*《AWS IoT Core 开发人员指南》*中的[时间戳](iot-sql-functions.md#iot-function-timestamp)。

   1. 在 **Sort key**（排序键）中，输入 **device\$1id**。

   1. 在**排序键值**中，输入 **\$1\$1cast(topic(2) AS DECIMAL)\$1**。

      这是您将在此规则中使用的第二个 [替换模板](iot-substitution-templates.md)。它将第二个元素的值插入到主题名称，即设备的 ID，后面其将投射为十进制值以匹配密钥的数字格式。要了解有关主题的更多信息，请参阅*《AWS IoT Core 开发人员指南》*中的[主题](iot-sql-functions.md#iot-function-topic)。或者，要了解有关强制转换的更多信息，请参阅*《AWS IoT Core 开发人员指南》*中的[强制转换](iot-sql-functions.md#iot-sql-function-cast)。

   1. 在**将消息数据写入到此列**中，输入 **device\$1data**。

      这将在 DynamoDB 表中创建 `device_data` 列。

   1. 将**操作**留空。

   1. 在 **IAM Role**（IAM 角色）中，选择 **Create new role**（创建新角色）。

   1. 在 **Create role**（创建角色）对话框中，为 **Role name**（角色名称）输入 **wx\$1ddb\$1role**。这个新角色将自动包含前缀为 “aws-iot-rule” 的策略，该策略将允许该**wx\$1data\$1ddb**规则将数据发送到您创建的 D **wx\$1data** ynamoDB 表。

   1. 在 **IAM role**（IAM 角色）中，选择 **wx\$1ddb\$1role**。

   1. 在页面底部，选择**下一步**。

1. 在 **Review and create**（审核和创建）页面的底部，选择 **Create**（创建）以创建规则。

## 步骤 3：测试 AWS IoT 规则和 DynamoDB 表
<a name="iot-ddb-rule-test"></a>

要测试新规则，您将使用 MQTT 客户端发布和订阅此测试中使用的 MQTT 消息。

在新窗口中打开 [AWS IoT 控制台中的 MQTT 客户端](https://console.aws.amazon.com//iot/home#/test)。这将允许您在不丢失 MQTT 客户端配置的情况下编辑规则。如果您让其转到控制台中的其它页面，MQTT 客户端不会保留任何订阅或消息日志。您还需要在控制台的 D [ynamoDB 表中心打开一个单独的控制台窗口 AWS IoT ，](https://console.aws.amazon.com//dynamodb/home#tables:)以查看您的规则发送的新条目。

**如需使用 MQTT 客户端来测试您的规则**

1. 在 [AWS IoT 控制台中的 MQTT 客户端](https://console.aws.amazon.com//iot/home#/test)中，订阅输入主题，`device/+/data`。

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

   1. 对于 **Topic filter**（主题筛选条件）中，输入输入主题筛选条件的主题，**device/\$1/data**。

   1. 选择**订阅**。

1. 现在，使用特定设备 ID **device/22/data** 向输入主题发布消息。您无法发布到包含通配符的 MQTT 主题。

   1. 在 MQTT 客户端中，选择 **Publish to a topic**（发布到主题）。

   1. 对于 **Topic name**（主题名称），输入输入主题名称 **device/22/data**。

   1. 对于**消息有效载荷**，输入以下示例数据。

      ```
      {
        "temperature": 28,
        "humidity": 80,
        "barometer": 1013,
        "wind": {
          "velocity": 22,
          "bearing": 255
        }
      }
      ```

   1. 要发布 MQTT 消息，请选择 **Publish**（发布）。

   1. 现在，在 MQTT 客户端中，选择 **Subscribe to a topic**（订阅主题）。在**订阅**栏中，选择 **device/\$1/data** 订阅。确认上一步骤中的示例数据是否显示在此处。

1. 检查以查看您的规则创建的 DynamoDB 表中的行。

   1. **在控制台的 D [ynamoDB 表中心中 AWS IoT](https://console.aws.amazon.com//dynamodb/home#tables:)，**选择 wx\$1data，然后选择**项目选项卡。**

      如果您已经在 **Items**（项目）选项卡上，则可能需要通过选择表格标题右上角的刷新图标来刷新显示。

   1. 请注意，表中的 **sample\$1time** 值是链接，请打开一个。如果您刚刚发送了第一条消息，那么这将是列表中唯一的消息。

      此链接显示表的该行中所有的数据。

   1. 展开 **device\$1data** 条目以查看规则查询语句生成的数据。

   1. 浏览此显示中可用数据的不同表示形式。您也可以编辑此显示中的数据。

   1. 查看完此行数据后，要保存所做的任何更改，请选择 **Save**（保存），或者要退出而不保存任何更改，请选择 **Cancel**（取消）。

如果您未看到正确的行为，请检查故障排除提示。

### 故障排除 DynamoDB 规则
<a name="iot-ddb-rule-trouble"></a>

如果您没有看到期望的结果，可检查以下事项。
+ 

**您收到了一个错误的广告条**  
如果在您发布输入消息时出现错误，请先更正该错误。以下步骤可帮助您更正此错误。
+ 

**您未在 MQTT 客户端中看到输入消息**  
每次将输入消息发布到 `device/22/data`主题时，如果您如流程中所述订阅了 `device/+/data`主题筛选条件，则消息应当会在 MQTT 客户端中显示。

**要检查的事项**
  + 

**检查您订阅的主题筛选条件**  
如果您如流程中所述订阅了输入消息主题，则每次发布输入消息时都应看到该输入消息的副本。

    如果没有看到该消息，请检查您订阅的主题名称，并将其与您发布的主题进行比较。主题名称区分大小写，您订阅的主题必须与发布消息负载的主题相同。
  + 

**检查消息发布函数**  
在 MQTT 客户端中，在**订阅**下，选择 **device/\$1/data**，检查发布消息的主题，然后选择**发布到主题**。您应该会看到来自主题下方编辑框中的消息负载出现在消息列表中。
+ 

**您在 DynamoDB 表中看不到您的数据**  
要做的第一件事是通过选择表格标题右上角的刷新图标来刷新显示。如果没有显示您要查找的数据，请检查以下内容。

**要检查的事项**
  + 

**检查您 AWS 区域 的 MQTT 客户端和您创建的规则**  
您在其中运行 MQTT 客户端的控制台必须位于您所创建规则的同一 AWS 区域。
  + 

**检查规则查询语句中的输入消息主题**  
要使规则起作用，它必须收到一条消息，消息主题名称应与规则查询语句 FROM 子句中的主题筛选条件相匹配。

    检查规则查询语句中主题筛选条件的拼写与 MQTT 客户端中主题的拼写。主题名称区分大小写，消息的主题必须与规则查询语句中的主题筛选条件匹配。
  + 

**检查输入消息负载的内容**  
要使规则起作用，则必须在 SELECT 语句中声明的消息负载中找到数据字段。

    检查规则查询语句 `temperature`字段中的拼写与 MQTT 客户端中消息负载的拼写。字段名称区分大小写，规则查询语句中 `temperature`字段必须与消息负载中的 `temperature`字段相同。

    确保消息负载中的 JSON 文档格式正确。如果 JSON 有任何错误（例如缺少逗号），则规则将无法读取它。
  + 

**检查规则操作中使用的键名和字段名称**  
主题规则中使用的字段名称必须与已发布消息的 JSON 消息有效载荷中找到的字段名称匹配。

    打开在控制台中创建的规则，并检查规则操作配置中的字段名称与 MQTT 客户端中使用的字段名称。
  + 

**检查规则所使用的角色**  
规则操作必须具有接收原始主题和发布新主题的权限。

    授权规则接收消息数据和更新 DynamoDB 表的策略特定于所使用的主题。如果更改规则使用的主题或 DynamoDB 表名称，则必须更新规则操作的角色以更新其策略来匹配。

    如果您怀疑存在问题，请编辑规则操作并创建新角色。规则操作创建的新角色将接收执行这些操作所需的授权。

## 步骤 4：查看结果和后续步骤
<a name="iot-ddb-rule-review"></a>

使用此规则向 DynamoDB 表发送几条消息后，请尝试对其进行试验，以了解更改教程中的某些方面如何影响写入表的数据。以下想法可以帮助您开始操作。
+ 更改输入消息主题*device\$1id*中的并观察其对数据的影响。您可以使用它来模拟从多个气象传感器接收数据。
+ 更改规则查询语句中选定的字段，并观察对数据的影响。您可以使用它筛选存储在表中的数据。
+ 添加重新发布规则操作，以便为添加到表中的每一行发送 MQTT 消息。您可以使用它进行调试。

完成本教程后，检查 [教程：使用 AWS Lambda 函数格式化通知](iot-lambda-rule.md)。

# 教程：使用 AWS Lambda 函数格式化通知
<a name="iot-lambda-rule"></a>

本教程演示如何将 MQTT 消息数据发送到 AWS Lambda 操作以进行格式化并发送到其他 AWS 服务。在本教程中， AWS Lambda 操作使用 AWS 软件开发工具包将格式化的消息发送到您在教程中创建的有关如何操作的 Amazon SNS 主题。[教程：发送 Amazon SNS 通知](iot-sns-rule.md)

在有关如何 [教程：发送 Amazon SNS 通知](iot-sns-rule.md) 的教程中，则由规则的查询语句生成的 JSON 文档将作为文本消息的正文发送。结果是一条文本消息，示例如下：

```
{"device_id":"32","reported_temperature":38,"max_temperature":30}
```

在本教程中，您将使用 AWS Lambda 规则操作来调用一个 AWS Lambda 函数，该函数将规则查询语句中的数据格式化为更友好的格式，例如以下示例：

```
Device 32 reports a temperature of 38, which exceeds the limit of 30.
```

您将在本教程中创建的 AWS Lambda 函数使用规则查询语句中的数据格式化消息字符串，并调用 [S AWS DK 的 SNS 发布](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sns.html#SNS.Client.publish)函数来创建通知。

**在本教程中您将学到**
+ 如何创建和测试 AWS Lambda 函数
+ 如何在 AWS Lambda 函数中使用 AWS 软件开发工具包发布 Amazon SNS 通知
+ 如何在规则查询语句中使用简单的 SQL 查询和函数
+ 如何使用 MQTT 客户端测试规则 AWS IoT 

完成本教程需要大约 45 分钟。

**Topics**
+ [步骤 1：创建发送短信的 AWS Lambda 函数](#iot-lambda-rule-create-lambda)
+ [步骤 2：使用 AWS IoT 规则操作创建 AWS Lambda 规则](#iot-lambda-rule-create-rule)
+ [步骤 3：测试 AWS IoT 规则和 AWS Lambda 规则操作](#iot-lambda-rule-test-rule)
+ [步骤 4：查看结果和后续步骤](#iot-lambda-rule-next-steps)

**在开始本教程之前，请确保您具有：**
+ 

**[设置 AWS 账户](setting-up.md)**  
你需要你的 AWS 账户 和 AWS IoT 主机才能完成本教程。
+ 

**审核 [使用 MQTT 客户端查看 AWS IoT MQTT 消息](view-mqtt-messages.md)**  
请确保您可以使用 MQTT 客户端订阅和发布主题。您将使用 MQTT 客户端在此流程中测试新规则。
+ 

**完成本部分中的其它规则教程**  
本教程需要您在如何 [教程：发送 Amazon SNS 通知](iot-sns-rule.md) 的教程中创建的 SNS 通知主题。本教程还假定您已完成本部分中其它与规则相关的教程。
+ 

**审核 [AWS Lambda](https://docs.aws.amazon.com//lambda/latest/dg/welcome.html)概览**  
如果您 AWS Lambda 以前从未使用过，请查看[AWS Lambda](https://docs.aws.amazon.com//lambda/latest/dg/welcome.html)并[开始使用 Lambda](https://docs.aws.amazon.com//lambda/latest/dg/getting-started.html)，以了解其术语和概念。

## 步骤 1：创建发送短信的 AWS Lambda 函数
<a name="iot-lambda-rule-create-lambda"></a>

本教程中的 AWS Lambda 函数接收规则查询语句的结果，将元素插入文本字符串，然后将生成的字符串作为通知中的消息发送到 Amazon SNS。

与使用 AWS IoT 规则操作发送通知的操作方法教程不同，本教程使用软件开发工具包的函数从 Lambda 函数发送通知。[教程：发送 Amazon SNS 通知](iot-sns-rule.md) AWS 但是，本教程中使用的实际 Amazon SNS 通知主题与您在有关如何 [教程：发送 Amazon SNS 通知](iot-sns-rule.md) 的教程中使用的主题相同。

**创建发送短信的 AWS Lambda 函数**

1. 创建新 AWS Lambda 函数。

   1. 在 [AWS Lambda 控制台](https://console.aws.amazon.com//lambda/home)中，选择 **Create function**（创建函数）。

   1. 在 **Create function**（创建函数）中，选择 **Use a blueprint**（使用蓝图）。

      搜索并选择 **hello-world-python** 蓝图，然后选择**配置**。

   1. 在 **Basic information**（基本信息）中：

      1. 在 **Function name**（函数名称）中，输入函数的名称，**format-high-temp-notification**。

      1. 在**执行角色**中，选择**从 AWS 策略模板创建新角色**。

      1. 在 Role name（角色名称）中，为新角色输入名称，**format-high-temp-notification-role**。

      1. 在**策略模板 - *可选***中，搜索并选择 **Amazon SNS 发布策略**。

      1. 选择 **Create function**（创建函数）。

1. 修改蓝图代码以格式化并发送 Amazon SNS 通知。

   1. 创建函数后，您应该会看到**format-high-temp-notification**详细信息页面。如果您不这样做，请从 [Lambda **Functions**](https://console.aws.amazon.com//lambda/home#/functions)（Lambda 函数）页打开它。

   1. 在**format-high-temp-notification**详细信息页面中，选择**配置**选项卡，然后滚动到**函数代码**面板。

   1. 在 **Function code**（函数代码）窗口中的 **Environment**（环境）窗格中，选择 Python 文件，`lambda_function.py`。

   1. 在 **Function code**（函数代码）窗口中，从蓝图中删除所有原始程序代码，并将其替换为此代码。

      ```
      import boto3
      #
      #   expects event parameter to contain:
      #   {
      #       "device_id": "32",
      #       "reported_temperature": 38,
      #       "max_temperature": 30,
      #       "notify_topic_arn": "arn:aws:sns:us-east-1:57EXAMPLE833:high_temp_notice"
      #   }
      # 
      #   sends a plain text string to be used in a text message
      #
      #      "Device {0} reports a temperature of {1}, which exceeds the limit of {2}."
      #   
      #   where:
      #       {0} is the device_id value
      #       {1} is the reported_temperature value
      #       {2} is the max_temperature value
      #
      def lambda_handler(event, context):
      
          # Create an SNS client to send notification
          sns = boto3.client('sns')
      
          # Format text message from data
          message_text = "Device {0} reports a temperature of {1}, which exceeds the limit of {2}.".format(
                  str(event['device_id']),
                  str(event['reported_temperature']),
                  str(event['max_temperature'])
              )
      
          # Publish the formatted message
          response = sns.publish(
                  TopicArn = event['notify_topic_arn'],
                  Message = message_text
              )
      
          return response
      ```

   1. 选择 **Deploy**（部署）。

1. 在新窗口中，从关于如何 [教程：发送 Amazon SNS 通知](iot-sns-rule.md) 的教程中查找 Amazon SNS 主题的 Amazon 资源名称（ARN）。

   1. 在新窗口中，打开 [Topics page of the Amazon SNS console](https://console.aws.amazon.com//sns/v3/home#/topics)（Amazon SNS 控制台主题页面）。

   1. 在**主题**页面上，在 Amazon SNS 主题列表中找到 **high\$1temp\$1notice** 通知主题。

   1. 查找 **high\$1temp\$1notice** 通知主题的 **ARN**，以在下一步中使用。

1. 为您的 Lambda 函数创建一个测试使用案例。

   1. 在控制台的 [Lambda F **un**](https://console.aws.amazon.com//lambda/home#/functions) ctions 页面的**format-high-temp-notification**详细信息页面上，**选择页面右上角的选择测试事件**（尽管它看起来已禁用），然后选择**配置测试**事件。

   1. 在 **Configure test event**（配置测试事件）中，选择 **Create new test event**（创建新测试事件）。

   1. 在 **Event name**（事件名称）中，输入 **SampleRuleOutput**。

   1. 在 **Event name**（事件名称）下方的 JSON 编辑器中，请粘贴此示例 JSON 文档。这是您的 AWS IoT 规则将向 Lambda 函数发送的内容的示例。

      ```
      {
        "device_id": "32",
        "reported_temperature": 38,
        "max_temperature": 30,
        "notify_topic_arn": "arn:aws:sns:us-east-1:57EXAMPLE833:high_temp_notice"
      }
      ```

   1. 请参阅具有 **high\$1temp\$1notice**通知主题的 **ARN** 的窗口并复制 ARN 值。

   1. 在 JSON 编辑器中将 `notify_topic_arn` 值替换成您通知主题中的 ARN。

      保持此窗口打开状态，以便在创建 AWS IoT 规则时再次使用该 ARN 值。

   1. 选择 **Choose**（创建）。

1. 使用示例数据测试函数。

   1. 在页面右上角的**format-high-temp-notification**详细信息页面中，确认**SampleRuleOutput**显示在 “**测试**” 按钮旁边。如果没有，请从可用测试事件列表中选择它。

   1. 要将示例规则输出消息发送到您的函数，请选择 **Test**（测试）。

如果函数和通知都有效，您将在订阅通知的手机上收到一条文本消息。

如果您在手机上没有收到文本消息，请检查操作结果。在 **Function code**（函数代码）面板中的 **Execution result**（执行结果）选项卡上，查看响应以查找发生的任何错误。请勿继续执行下一步，直到您的函数可以将通知发送到您的手机。

## 步骤 2：使用 AWS IoT 规则操作创建 AWS Lambda 规则
<a name="iot-lambda-rule-create-rule"></a>

在此步骤中，您将使用规则查询语句格式化来自虚拟气象传感器设备的数据，以发送到 Lambda 函数，该函数将格式化并发送文本消息。

从天气设备接收的示例消息有效载荷如下所示：

```
{
  "temperature": 28,
  "humidity": 80,
  "barometer": 1013,
  "wind": {
    "velocity": 22,
    "bearing": 255
  }
}
```

在此规则中，您将使用规则查询语句为 Lambda 函数创建消息有效载荷，如下所示：

```
{
  "device_id": "32",
  "reported_temperature": 38,
  "max_temperature": 30,
  "notify_topic_arn": "arn:aws:sns:us-east-1:57EXAMPLE833:high_temp_notice"
}
```

这包含 Lambda 函数格式化和发送正确文本消息所需的所有信息。

**创建调用 Lambda 函数的 AWS IoT 规则**

1. 打开[AWS IoT 控制台的 “**规则**” 中心](https://console.aws.amazon.com//iot/home#/rulehub)。

1. 要在 **Rule**（规则）中创建新规则，请选择 **Create**（创建）。

1. 在 **Create a rule**（创建规则）顶部：

   1. 在 **Name**（名称）中，输入规则的名称，**wx\$1friendly\$1text**。

      请记住，规则名称在您的 AWS 账户 和区域内必须是唯一的，并且不能有任何空格。我们在此名称中使用了下划线字符来分隔规则名称中的两个单词。

   1.  在 **Description**（说明）中，描述规则。

      有意义的描述可以更容易地记住此规则的作用以及您创建它的原因。描述可以根据需要延长，因此请尽可能详细。

1. 在**创建规则**的**规则查询语句**中：

   1.  在**使用 SQL 版本**中，选择 **2016-03-23**。

   1. 在**规则查询语句**编辑框中，输入语句：

      ```
      SELECT 
        cast(topic(2) AS DECIMAL) as device_id, 
        temperature as reported_temperature,
        30 as max_temperature,
        'arn:aws:sns:us-east-1:57EXAMPLE833:high_temp_notice' as notify_topic_arn
      FROM 'device/+/data' WHERE temperature > 30
      ```

      本语句：
      + 侦听主题与 `device/+/data`主题筛选条件相符，并且 `temperature`值大于 30 的 MQTT 消息。
      + 从主题字符串中选择第二个元素，将其转换为十进制数，然后将其分配给 `device_id` 字段。
      + 从消息有效载荷中选择 `temperature` 字段的值，并将其分配给 `reported_temperature` 字段。
      + 创建常数值 `30` 来表示限制值，并将其赋值给 `max_temperature` 字段。
      + 为 `notify_topic_arn` 字段创建常数值。

   1. 请参阅具有 **high\$1temp\$1notice** 通知主题的 **ARN** 的窗口并复制 ARN 值。

   1. 将规则查询语句编辑器中的 ARN 值 (*arn:aws:sns:us-east-1:57EXAMPLE833:high\$1temp\$1notice*) 替换为通知主题的 ARN。

1. 在**设置一个或多个操作**中：

   1. 要打开此规则的规则操作列表，请选择 **Add action**（添加操作）。

   1. 在 **Select an action**（选择操作）中，选择 **Send a message to a Lambda function**（向 Lambda 函数发送消息）。

   1. 要打开选定操作的配置页面，请在操作列表底部选择 **Configure action**（配置操作）。

1. 在 **Configure action**（配置操作）中：

   1. 在 **Function name**（函数名称）中，选择 **Select**（选择）。

   1. 选择 **format-high-temp-notification**。

   1. 在 **Configure action**（配置操作）底部，选择 **Add action**（添加操作）。

   1. 要创建规则，请在 **Create a rule**（创建一条规则）底部，选择 **Create rule**（创建规则）。

## 步骤 3：测试 AWS IoT 规则和 AWS Lambda 规则操作
<a name="iot-lambda-rule-test-rule"></a>

要测试新规则，您将使用 MQTT 客户端发布和订阅此规则所使用的 MQTT 消息。

在新窗口中打开 [AWS IoT 控制台中的 MQTT 客户端](https://console.aws.amazon.com//iot/home#/test)。现在，您可以在不丢失 MQTT 客户端配置的情况下编辑规则。如果您离开 MQTT 客户端并转到控制台中的其它页面，则将丢失您的订阅或消息日志。

**如需使用 MQTT 客户端来测试您的规则**

1. 在 [AWS IoT 控制台中的 MQTT 客户端](https://console.aws.amazon.com//iot/home#/test)中，订阅输入主题，在本例中为 `device/+/data`。

   1. 在 MQTT 客户端中，在**订阅**下，选择**订阅主题**。

   1. 在**订阅主题**中，输入输入主题筛选条件的主题，**device/\$1/data**。

   1. 将其它字段保留为默认设置。

   1. 选择**订阅主题**。

      在 **Subscriptions**（订阅）栏，在 **Publish to a topic**（发布到主题）项下，将会显示 **device/\$1/data**。

1. 使用特定设备 ID **device/32/data**向输入主题发布消息。您无法发布到包含通配符的 MQTT 主题。

   1. 在 MQTT 客户端中，在**订阅**下，选择**订阅主题**。

   1. 在**发布**字段中，输入输入主题名称，**device/32/data**。

   1. 复制此处显示的示例数据，然后在主题名称下方的编辑框中粘贴示例数据。

      ```
      {
        "temperature": 38,
        "humidity": 80,
        "barometer": 1013,
        "wind": {
          "velocity": 22,
          "bearing": 255
        }
      }
      ```

   1. 如需发布 MQTT 消息，请选择 **Publish to topic**（发布到主题）。

1. 确认文本消息已发送。

   1. 在 MQTT 客户端的**订阅**下，您之前订阅的主题旁边会有一个绿色圆点。

      绿色圆点表示自上次查看消息以来已收到一条或多条新消息。

   1. 在 **Subscriptions**（订阅）中，选择 **device/\$1/data** 来检查消息负载是否与刚刚发布的内容匹配，如下所示：

      ```
      {
        "temperature": 38,
        "humidity": 80,
        "barometer": 1013,
        "wind": {
          "velocity": 22,
          "bearing": 255
        }
      }
      ```

   1. 检查您用于订阅 SNS 主题的电话，并确认消息负载的内容，如下所示：

      ```
      Device 32 reports a temperature of 38, which exceeds the limit of 30.
      ```

      如果您更改消息主题中的主题 ID 元素，请记住，将 `topic(2)` 值投射为数字值仅在消息主题中的元素仅包含数字字符时才起作用。

1. 尝试发送温度未超过限制的 MQTT 消息。

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

   1. 在**发布**字段中，输入输入主题名称，**device/33/data**。

   1. 复制此处显示的示例数据，然后在主题名称下方的编辑框中粘贴示例数据。

      ```
      {
        "temperature": 28,
        "humidity": 80,
        "barometer": 1013,
        "wind": {
          "velocity": 22,
          "bearing": 255
        }
      }
      ```

   1. 要发送您的 MQTT 消息，请选择 **Publish to topic**（发布到主题）。

   您应在 **device/\$1/data** 订阅中看到您发送的消息；但是，由于温度值低于规则查询语句中的最大温度，因此您不应收到文本消息。

   如果您未看到正确的行为，请检查故障排除提示。

### 对您的 AWS Lambda 规则和通知进行故障排除
<a name="iot-lambda-rule-troubleshoot"></a>

如果您没有看到期望的结果，可以检查以下事项。
+ 

**您收到了一个错误的广告条**  
如果在您发布输入消息时出现错误，请先更正该错误。以下步骤可帮助您更正此错误。
+ 

**您未在 MQTT 客户端中看到输入消息**  
每次将输入消息发布到 `device/32/data`主题时，如果您如流程中所述订阅了 `device/+/data`主题筛选条件，则消息应当会在 MQTT 客户端中显示。

**要检查的事项**
  + 

**检查您订阅的主题筛选条件**  
如果您如流程中所述订阅了输入消息主题，则每次发布输入消息时都应看到该输入消息的副本。

    如果没有看到该消息，请检查您订阅的主题名称，并将其与您发布的主题进行比较。主题名称区分大小写，您订阅的主题必须与发布消息负载的主题相同。
  + 

**检查消息发布函数**  
在 MQTT 客户端中，在**订阅**下，选择 **device/\$1/data**，检查发布消息的主题，然后选择**发布到主题**。您应该会看到来自主题下方编辑框中的消息负载出现在消息列表中。
+ 

**您没有收到 SMS 消息**  
要使规则起作用，规则必须具有授权其接收消息和发送 SNS 通知的正确策略，并且必须接收消息。

**要检查的事项**
  + 

**检查您 AWS 区域 的 MQTT 客户端和您创建的规则**  
您在其中运行 MQTT 客户端的控制台必须位于您所创建规则的同一 AWS 区域。
  + 

**检查消息负载中的温度值是否超过测试阈值**  
如果温度值小于或等于 30（如规则查询语句中定义），则规则将不会执行其任何操作。
  + 

**检查规则查询语句中的输入消息主题**  
要使规则起作用，它必须收到一条消息，消息主题名称应与规则查询语句 FROM 子句中的主题筛选条件相匹配。

    检查规则查询语句中主题筛选条件的拼写与 MQTT 客户端中主题的拼写。主题名称区分大小写，消息的主题必须与规则查询语句中的主题筛选条件匹配。
  + 

**检查输入消息负载的内容**  
要使规则起作用，则必须在 SELECT 语句中声明的消息负载中找到数据字段。

    检查规则查询语句 `temperature`字段中的拼写与 MQTT 客户端中消息负载的拼写。字段名称区分大小写，规则查询语句中 `temperature`字段必须与消息负载中的 `temperature`字段相同。

    确保消息负载中的 JSON 文档格式正确。如果 JSON 有任何错误（例如缺少逗号），则规则将无法读取它。
  + 

**查看 Amazon SNS 通知**  
在 [步骤 1：创建 Amazon SNS 主题，发送 SMS 文本消息](iot-sns-rule.md#iot-sns-rule-create-sns-topic)中，请参阅步骤 3，该步骤介绍如何测试 Amazon SNS 通知并测试通知以确保通知有效。
  + 

**检查 Lambda 函数**  
在 [步骤 1：创建发送短信的 AWS Lambda 函数](#iot-lambda-rule-create-lambda) 中，请参阅步骤 5，该步骤介绍如何使用测试数据测试 Lambda 函数并测试 Lambda 函数。
  + 

**检查规则所使用的角色**  
规则操作必须具有接收原始主题和发布新主题的权限。

    授权规则接收消息数据并重新发布的策略特定于所使用的主题。如果更改用于重新发布消息数据的主题，则必须更新规则操作的角色，以更新其策略来匹配当前主题。

    如果怀疑这里出现了问题，请编辑“重新发布”规则操作并创建新角色。规则操作创建的新角色将接收执行这些操作所需的授权。

## 步骤 4：查看结果和后续步骤
<a name="iot-lambda-rule-next-steps"></a>

**在本教程中：**
+ 您创建了一 AWS IoT 条规则来调用 Lambda 函数，该函数使用您的自定义消息负载发送了 Amazon SNS 通知。
+ 您在规则查询语句中使用了简单的 SQL 查询和函数来为 Lambda 函数创建新的消息有效载荷。
+ 您使用 MQTT 客户端来测试您的 AWS IoT 规则。

**后续步骤**  
使用此规则发送了几条文本消息后，请尝试使用它来了解更改教程的某些方面如何影响消息以及发送消息的时间。以下想法可以帮助您开始操作。
+ 更改输入消息主题*device\$1id*中的内容，并观察短信内容中的效果。
+ 更改规则查询语句中选定的字段，更新 Lambda 函数以在新消息中使用这些字段，并观察文本消息内容中的效果。
+ 将规则查询语句中的测试更改为测试最低温度而不是最高温度。更新 Lambda 函数以格式化新消息，并记得更改 `max_temperature` 名称。
+ 要详细了解如何查找在开发和使用 AWS IoT 规则时可能出现的错误，请参阅[监控 AWS IoT](monitoring_overview.md)。

# 在设备处于离线状态时使用设备影子保持设备状态
<a name="iot-shadows-tutorial"></a>

这些教程向您展示了 AWS IoT 如何使用 Device Shadow 服务来存储和更新设备的状态信息。影子文档是 JSON 文档，根据设备、本地应用程序或服务发布的消息显示设备状态的更改。在本教程中，影子文档将显示灯泡颜色的变化。这些教程还显示影子如何存储此信息，即使设备与互联网断开连接，并在设备重新联机并请求此信息时将最新状态信息传递回设备。

我们建议您按照这里显示的顺序尝试这些教程，从需要创建的 AWS IoT 资源以及必要的硬件设置开始，这也有助于您逐步学习这些概念。这些教程展示了如何配置和连接 Raspberry Pi 设备以供使用 AWS IoT。如果您没有所需的硬件，您可以按照这些教程将它们适配于您选择的设备或[使用 Amazon EC2 创建虚拟设备](creating-a-virtual-thing.md)。

**教程场景概览**  
这些教程的场景是一个本地应用程序或服务，该应用程序或服务可更改灯泡的颜色，并将其数据发布到预留的影子主题。这些教程类似于[交互式入门教程](interactive-demo.md)中描述的 Device Shadow 功能，并在Raspberry Pi设备上实现。本部分中的教程侧重于单个经典影子，同时将展示如何容纳已命名的影子或多个设备。

以下教程将帮助您学习如何使用 Dev AWS IoT ice Shadow 服务。
+ 

**[教程：准备 Raspberry Pi 运行影子应用程序](create-resources-shadow.md)**  
本教程介绍如何设置 Raspberry Pi 设备以进行连接 AWS IoT。您还将创建 AWS IoT 策略文档和事物资源，下载证书，然后将策略附加到该事物资源。完成本教程需要大约 30 分钟。
+ 

**[教程：安装设备软件开发包并运行 Device Shadow 示例应用程序](lightbulb-shadow-application.md)**  
本教程介绍如何安装所需的工具、软件和适用于 Python 的 AWS IoT 设备 SDK，然后运行示例影子应用程序。本教程基于 [连接 Raspberry Pi 或其他设备](connecting-to-existing-device.md) 中介绍的概念所打造，完成需要 20 分钟。
+ 

**[教程：示例应用程序及 MQTT 测试客户端与 Device Shadow 交互](interact-lights-device-shadows.md)**  
本教程展示了如何使用`shadow.py`示例应用程序和**AWS IoT 控制台**来观察 AWS IoT 设备阴影与灯泡状态变化之间的相互作用。本教程还介绍了如何将 MQTT 消息发送到 Device Shadow 的预留主题。完成本教程需要大约 45 分钟。

**AWS IoT Device Shadow 概述**  
Device Shadow 是设备的永久虚拟表示形式，由您在 AWS IoT 注册表中创建[的事物资源](iot-thing-management.md)管理。Shadow 文档是一个 JSON 或 JavaScript 符号文档，用于存储和检索设备的当前状态信息。无论设备是否已连接到互联网，您都可以使用 shadow 通过 MQTT 主题或 HTTP RES APIs T 获取和设置设备的状态。

影子文档包含一个 `state` 属性，以描述设备状态的以下方面。
+ `desired`：应用程序更新 `desired` 对象以指定设备属性的所需状态。
+ `reported`：设备在 `reported` 对象中报告其当前状态。
+ `delta`： AWS IoT 报告`delta`对象中所需状态和报告状态之间的差异。

以下为示例影子状态文档：

```
{
  "state": {
    "desired": {
      "color": "green"
      },
    "reported": {
      "color": "blue"
      },
    "delta": {
      "color": "green"
      }
   }
}
```

要更新设备的 Shadow 文档，您可以使用[保留的 MQTT 主题](reserved-topics.md#reserved-topics-shadow)、支持、、HTTP `DELETE` 操作 APIs的 Device Shado [w RES](device-shadow-rest-api.md) T 以及 [AWS IoT CLI](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/iot-data/index.html)。`GET` `UPDATE`

在前面的示例中，假设您希望将 `desired` 颜色改为 `yellow`。要执行此操作，请将请求发送到 [UpdateThingShadow](device-shadow-rest-api.md#API_UpdateThingShadow) API 或将消息发布到[更新](device-shadow-mqtt.md#update-pub-sub-topic)主题，`$aws/things/THING_NAME/shadow/update`。

```
{
  "state": {
    "desired": {
      "color": yellow
    }
  }
}
```

更新仅影响请求中指定的字段。成功更新 Device Shadow 后，将新`desired`状态 AWS IoT 发布到`delta`主题`$aws/things/THING_NAME/shadow/delta`。在这种情况下，影子文档如下所示：

```
{
  "state": {
    "desired": {
      "color": yellow
    },
    "reported": {
      "color": green
    },
    "delta": {
      "color": yellow
      }
  }
}
```

然后，使用`$aws/things/THING_NAME/shadow/update`带有以下 JSON 消息的`Update`主题向 Dev AWS IoT ice Shadow 报告新状态：

```
{
  "state": {
    "reported": {
      "color": yellow
    }
  }
}
```

如果要获取当前状态信息，请将请求发送至 [GetThingShadow](device-shadow-rest-api.md#API_GetThingShadow) API 或将 MQTT 消息发布到 [Get](device-shadow-mqtt.md#get-pub-sub-topic)（获取）主题，`$aws/things/THING_NAME/shadow/get`。

有关使用 Device Shadow 服务的更多信息，请参阅 [AWS IoT Device Shadow 服务](iot-device-shadows.md)。

有关在设备、应用程序和服务中使用 Device Shadow 的更多信息，请参阅 [在设备中使用影子](device-shadow-comms-device.md) 和 [在应用程序和服务中使用影子](device-shadow-comms-app.md)。

有关与 AWS IoT 阴影交互的信息，请参见[与影子交互](device-shadow-data-flow.md)。

有关 MQTT 保留主题和 HTTP REST 的信息 APIs，请参阅[Device Shadow MQTT 主题](device-shadow-mqtt.md)和。[Device Shadow REST API](device-shadow-rest-api.md)

# 教程：准备 Raspberry Pi 运行影子应用程序
<a name="create-resources-shadow"></a>

本教程演示如何设置和配置 Raspberry Pi 设备，以及如何创建设备连接和交换 MQTT 消息所需的 AWS IoT 资源。

**注意**  
如果您计划 [使用 Amazon EC2 创建虚拟设备](creating-a-virtual-thing.md)，您可以跳过此页面并继续执行 [配置您的设备](configure-device.md)。创建虚拟事物时，您将创建这些资源。如果您想使用不同的设备，而不是 Raspberry Pi，可以尝试按照这些教程进行操作，将它们调整到您选择的设备。

**在本教程中，您将学习如何：**
+ 设置 Raspberry Pi 设备并将其配置为与一起使用 AWS IoT。
+ 创建 AWS IoT 策略文档，授权您的设备与 AWS IoT 服务进行交互。
+ 在 X.509 设备证书 AWS IoT 中创建事物资源，然后附加策略文档。

  事物是您的设备在 AWS IoT 注册表中的虚拟展示。证书用于向 C AWS IoT ore 对您的设备进行身份验证，策略文档授权您的设备与之交互。 AWS IoT

**如何运行本教程？**  
要为 Device Shadow 运行 `shadow.py` 示例应用程序，您将需要一个连接到 AWS IoT的 Raspberry Pi 设备。我们建议您按照此处显示的顺序遵循本教程，首先设置 Raspberry Pi 及其配件，然后创建策略并将策略附加到您创建的事物资源。然后，您可以使用 Raspberry Pi 支持的图形用户界面 (GUI) 在设备的 Web 浏览器上打开 AWS IoT 控制台，从而更轻松地将证书直接下载到 Raspberry Pi 进行连接 AWS IoT。

**在开始本教程之前，请确保您具有：**
+ 一个 AWS 账户。如果您没有账户，请完成 [设置 AWS 账户](setting-up.md)中介绍的步骤然后继续操作。你需要你的 AWS 账户 和 AWS IoT 主机才能完成本教程。
+ Raspberry Pi 及其必要的配件。您将需要：
  + [Raspberry Pi 3 Model B](https://www.raspberrypi.com/products/) 或更新型号。本教程可能适用于早期版本的 Raspberry Pi，但我们还没有测试过。
  + [Raspberry Pi OS (32 位)](https://www.raspberrypi.com/software/operating-systems/)或更高版本。我们始终建议使用最新版本的 Raspberry Pi OS。早期版本的操作系统可能有用，但我们还没有测试过。
  + 以太网或 Wi-Fi 连接。
  + 键盘、鼠标、显示器、电缆和电源。

完成本教程需要大约 30 分钟。

## 步骤 1：设置和配置 Raspberry Pi 设备
<a name="setup-device-shadow"></a>

在本节中，我们将配置一台 Raspberry Pi 设备与一起使用 AWS IoT。

**重要**  
将这些指令用于其它设备和操作系统可能会非常困难。您需要充分了解您的设备，以便能够解释这些说明并将它们应用到您的设备上。如果遇到困难，可以尝试使用其它设备选项之一作为替代方案，例如 [使用 Amazon EC2 创建虚拟设备](creating-a-virtual-thing.md) 或者 [使用你的 Windows、Linux 电脑或 Mac 作为 AWS IoT 设备](using-laptop-as-device.md)。

您需要配置您的 Raspberry Pi，以便它可以启动操作系统（OS），连接到互联网，并允许您在命令行界面与它进行交互。您也可以使用 Raspberry Pi 支持的图形用户界面 (GUI) 打开 AWS IoT 控制台并运行本教程的其余部分。

**要设置 Raspberry Pi**

1. 将 SD 卡插入 Raspberry Pi 上的 MicroSD 卡槽。有些 SD 卡预装了一个安装管理器，将为您显示在启动主板后安装操作系统的菜单。您还可以使用 Raspberry Pi 在您的卡上安装操作系统。

1. 将 HDMI TV 或显示器 Connect 到 HDMI 电缆，然后连接到 Raspberry Pi 的 HDMI 端口。

1. 将键盘和鼠标连接到 Raspberry Pi 的 USB 端口，然后插入电源适配器以启动主板。

Raspberry Pi 启动后，如果 SD 卡预先加载了安装管理器，则会出现一个菜单来帮助您安装操作系统。如果您在安装操作系统时遇到问题，请尝试以下步骤。有关设置 Raspberry Pi 的更多信息，请参阅[设置您的 Raspberry Pi](https://projects.raspberrypi.org/en/projects/raspberry-pi-setting-up/)。

**如果您在设置 Raspberry Pi 时遇到问题：**
+ 在启动主板之前，请检查是否插入了 SD 卡。如果在启动主板后插入 SD 卡，则可能不会显示安装菜单。
+ 确保电视或显示器已打开，并且选择了正确的输入信号源。
+ 确保您使用的是兼容 Raspberry Pi 的软件。

安装并配置 Raspberry Pi 操作系统后，打开 Raspberry Pi 的 Web 浏览器并导航到 AWS IoT Core 控制台，继续本教程中的其余步骤。

如果你能打开 AWS IoT Core 主机，那么 Raspberry Pi 就准备好了，你可以继续[教程：在中配置您的设备 AWS IoT](shadow-provision-cloud.md)。

如果您遇到问题或需要其它帮助，请参阅[为您的 Raspberry Pi 获取帮助](https://projects.raspberrypi.org/en/projects/raspberry-pi-setting-up/5)。

# 教程：在中配置您的设备 AWS IoT
<a name="shadow-provision-cloud"></a>

本节创建了您的教程将使用的 AWS IoT Core 资源。

**Topics**
+ [步骤 1：为 Device Shadow 创建 AWS IoT 策略](#create-policy-shadow)
+ [步骤 2：创建事物资源并将策略附加到事物](#create-thing-shadow)
+ [步骤 3：查看结果和后续步骤](#resources-shadow-review)

## 步骤 1：为 Device Shadow 创建 AWS IoT 策略
<a name="create-policy-shadow"></a>

X.509 证书用于对您的设备进行身份验证。 AWS IoT Core AWS IoT 策略附加到证书，允许设备执行 AWS IoT 操作，例如订阅或发布到 Device Shadow 服务使用的 MQTT 保留主题。您的设备在连接并向其发送消息时会出示其证书 AWS IoT Core。

在此流程中，您将创建一个策略以允许您的设备执行运行示例程序所必要的 AWS IoT 操作。建议您创建一个策略以仅授予执行任务所需的许可。您首先创建 AWS IoT 策略，然后将其附加到稍后创建的设备证书。

**创建 AWS IoT 策略**

1. 在左侧菜单中，选择 **Secure**（安全），然后选 **Policies**（策略）。如果您的账户已有策略，请选择 **Create**（创建），否则，在 **You don’t have a policy yet**（您还没有策略）页面上，选择 **Create a policy**（创建策略）。

1. 在 **Create a policy**（创建策略）页面上：

   1. 在 **Name**（名称）字段，输入策略的名称（例如 **My\$1Device\$1Shadow\$1policy**）。请勿在策略名称中使用个人身份信息。

   1. 在策略文档中，您描述了授予设备发布和订阅 MQTT 保留主题权限的连接、订阅、接收和发布操作。

      复制以下策略并将其粘贴到策略文档中。`thingname`替换为您要创建的事物的名称（例如`My_light_bulb`）、`region`您正在使用服务的 AWS IoT 地区以及`account`您的 AWS 账户 电话号码。有关 AWS IoT 策略的更多信息，请参阅[AWS IoT Core 政策](iot-policies.md)。  
****  

      ```
      {
          "Version":"2012-10-17",		 	 	 
          "Statement": [
              {
                  "Effect": "Allow",
                  "Action": [
                      "iot:Publish"
                  ],
                  "Resource": [
                      "arn:aws:iot:us-east-1:123456789012:topic/$aws/things/thingname/shadow/get",
                      "arn:aws:iot:us-east-1:123456789012:topic/$aws/things/thingname/shadow/update"
                  ]
              },
              {
                  "Effect": "Allow",
                  "Action": [
                      "iot:Receive"
                  ],
                  "Resource": [
                      "arn:aws:iot:us-east-1:123456789012:topic/$aws/things/thingname/shadow/get/accepted",
                      "arn:aws:iot:us-east-1:123456789012:topic/$aws/things/thingname/shadow/get/rejected",
                      "arn:aws:iot:us-east-1:123456789012:topic/$aws/things/thingname/shadow/update/accepted",
                      "arn:aws:iot:us-east-1:123456789012:topic/$aws/things/thingname/shadow/update/rejected",
                      "arn:aws:iot:us-east-1:123456789012:topic/$aws/things/thingname/shadow/update/delta"
                  ]
              },
              {
                  "Effect": "Allow",
                  "Action": [
                      "iot:Subscribe"
                  ],
                  "Resource": [
                      "arn:aws:iot:us-east-1:123456789012:topicfilter/$aws/things/thingname/shadow/get/accepted",
                      "arn:aws:iot:us-east-1:123456789012:topicfilter/$aws/things/thingname/shadow/get/rejected",
                      "arn:aws:iot:us-east-1:123456789012:topicfilter/$aws/things/thingname/shadow/update/accepted",
                      "arn:aws:iot:us-east-1:123456789012:topicfilter/$aws/things/thingname/shadow/update/rejected",
                      "arn:aws:iot:us-east-1:123456789012:topicfilter/$aws/things/thingname/shadow/update/delta"
                  ]
              },
              {
                  "Effect": "Allow",
                  "Action": "iot:Connect",
                  "Resource": "arn:aws:iot:us-east-1:123456789012:client/test-*"
              }
          ]
      }
      ```

## 步骤 2：创建事物资源并将策略附加到事物
<a name="create-thing-shadow"></a>

连接的设备 AWS IoT 可以用 AWS IoT 注册表中的*事物资源*表示。*事物资源*表示特定设备或逻辑实体，如本教程中的灯泡。

要学习如何在中创建事物 AWS IoT，请按照中所述的步骤进行操作[创建一个事物对象](create-iot-resources.md#create-aws-thing)。以下是您在遵循该教程中的步骤时需要注意的几个关键事项：

1. 选择**创建单个事物**，并在**名称**字段中，输入与您在之前创建策略时指定的 `thingname` 相同的事物名称（例如，`My_light_bulb`)。

   事物名称一旦创建，便不可更改。如果您给它一个不同于 `thingname` 的名字，请以 `thingname` 为名称创建新的事物，并删除旧的事物。
**注意**  
请勿在事物名称中使用个人身份信息。事物名称可以出现在未加密的通信和报告中。

1. 我们建议您将 **Certificate created\$1**（已创建证书！）页面的每个证书文件下载到您可以轻松找到的位置。您需要安装这些文件才能运行示例应用程序。

   建议您将文件下载到 Raspberry Pi 中您的 `home` 目录下的 `certs` 子目录中，并使用一个更简单的名称命名各个文件，如下表所示。  
**证书文件名**    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/iot/latest/developerguide/shadow-provision-cloud.html)

1. 激活证书以启用与之连接后 AWS IoT，选择**附加策略**，并确保将之前创建的策略（例如**My\$1Device\$1Shadow\$1policy**）附加到该事物。

   创建事物后，您可以看到您的事物资源显示在 AWS IoT 控制台的事物列表中。

## 步骤 3：查看结果和后续步骤
<a name="resources-shadow-review"></a>

**在本教程中，您学习了如何：**
+ 设置和配置 Raspberry Pi 设备。
+ 创建授权您的设备与 AWS IoT 服务交互的 AWS IoT 策略文档。
+ 创建事物资源和关联的 X.509 设备证书，并将策略文档附加到其中。

**后续步骤**  
现在，你可以安装适用于 Python 的 AWS IoT 设备 SDK，运行`shadow.py`示例应用程序，并使用设备影子来控制状态。有关如何使用该教程的更多信息，请参阅 [教程：安装设备软件开发包并运行 Device Shadow 示例应用程序](lightbulb-shadow-application.md)。

# 教程：安装设备软件开发包并运行 Device Shadow 示例应用程序
<a name="lightbulb-shadow-application"></a>

本节介绍如何安装所需的软件和适用于 Python 的 AWS IoT 设备 SDK，以及如何运行`shadow.py`示例应用程序来编辑 Shadow 文档和控制阴影的状态。

**在本教程中，您将学习如何：**
+ 使用已安装的软件和适用于 Python 的 AWS IoT 设备 SDK 来运行示例应用程序。
+ 了解使用示例应用程序输入值如何在 AWS IoT 控制台发布预期的值。
+ 查看 `shadow.py` 示例应用程序以及它如何使用 MQTT 协议来更新影子的状态。

**在运行本教程之前：**  
您必须已设置好自己的 Raspberry Pi 设备，并创建了授予设备发布和订阅 Device Shadow 服务的 MQTT 保留主题的权限 AWS IoT 的事物和策略。 AWS 账户有关更多信息，请参阅 [教程：准备 Raspberry Pi 运行影子应用程序](create-resources-shadow.md)。

你还必须安装了 Git、Python 和适用于 Python 的 AWS IoT 设备 SDK。本教程基于教程 [连接 Raspberry Pi 或其他设备](connecting-to-existing-device.md) 中介绍的概念执行。如果您尚未尝试该教程，我们建议您按照该教程中描述的步骤安装证书文件和 Device SDK，然后返回本教程运行 `shadow.py` 示例应用程序。

**Topics**
+ [步骤 1：运行 shadow.py 示例应用程序](#run-sample-application-shadows)
+ [步骤 2：查看 shadow.py 设备软件开发包示例应用](#review-shadow-sample-code)
+ [步骤 3：借助 `shadow.py`示例应用程序排除问题](#shadow-sample-app-troubleshoot)
+ [步骤 4：查看结果和后续步骤](#sample-app-shadow-review)

完成本教程需要大约 20 分钟。

## 步骤 1：运行 shadow.py 示例应用程序
<a name="run-sample-application-shadows"></a>

在运行 `shadow.py` 示例应用程序前，除了安装的证书文件的名称和位置之外，还需要以下信息。


**应用程序参数值**  

|  参数  |  在何处查找值  | 
| --- | --- | 
| your-iot-thing-name |  您之前在中创建 AWS IoT 的事物的名称[步骤 2：创建事物资源并将策略附加到事物](shadow-provision-cloud.md#create-thing-shadow)。 要查找此值，请在 [AWS IoT 控制台](https://console.aws.amazon.com/iot/home)中，选择 **Manage**（管理），然后选择 **Things**（事物）。  | 
| your-iot-endpoint |   该*your-iot-endpoint*值的格式为:`endpoint_id-ats.iot.region.amazonaws.com`，例如`a3qj468EXAMPLE-ats.iot.us-west-2.amazonaws.com`。要查找此值： [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/iot/latest/developerguide/lightbulb-shadow-application.html)  | 

**安装并运行示例应用程序**

1. 导航到示例应用程序目录。

   ```
   cd ~/aws-iot-device-sdk-python-v2/samples/service-clients
   ```

1. 在命令行窗口中，*your-iot-thing-name*按照指示替换*your-iot-endpoint*和并运行此命令。

   ```
   python3 shadow.py --ca_file ~/certs/Amazon-root-CA-1.pem --cert ~/certs/device.pem.crt --key ~/certs/private.pem.key --endpoint your-iot-endpoint --thing_name your-iot-thing-name
   ```

1. 观察示例应用程序：

   1. 连接到您账户的 AWS IoT 服务。

   1. 订阅 `Delta` 事件和 `Update` 及 `Get` 响应。

   1. 提示您在终端中输入所需的值。

   1. 输出类似于以下内容：

   ```
   Connecting to a3qEXAMPLEffp-ats.iot.us-west-2.amazonaws.com with client ID 'test-0c8ae2ff-cc87-49d2-a82a-ae7ba1d0ca5a'...
   Connected!
   Subscribing to Delta events...
   Subscribing to Update responses...
   Subscribing to Get responses...
   Requesting current shadow state...
   Launching thread to read user input...
   Finished getting initial shadow state.
   Shadow contains reported value 'off'.
   Enter desired value:
   ```

**注意**  
如果您在运行 `shadow.py` 示例应用程序时遇到问题，请查看 [步骤 3：借助 `shadow.py`示例应用程序排除问题](#shadow-sample-app-troubleshoot)。若要获取可能帮助您更正此问题的其它信息，请将 `--verbosity debug` 参数添加到命令行，以便示例应用程序显示有关其正在执行的操作的详细消息。

**在影子文档中输入值并观察更新**  
您可以在终端中输入值来指定 `desired` 值，该值还会更新 `reported` 值。假设您在终端中输入颜色 `yellow`。`reported` 值也会更新为颜色 `yellow`。下面显示了终端中显示的消息：

```
Enter desired value:
yellow
Changed local shadow value to 'yellow'.
Updating reported shadow value to 'yellow'...
Update request published.
Finished updating reported shadow value to 'yellow'.
```

当您发布此更新请求时， AWS IoT 会为事物资源创建一个默认的经典影子。您可以通过查看您创建的事物资源（例如`My_light_bulb`）的 Shadow 文档来观察您发布到 AWS IoT 控制台中的`reported`和`desired`值的更新请求。要查看影子文档中的更新：

1. 在 AWS IoT 控制台中，选择 “**管理**”，然后选择 “**事物**”。

1. 在显示的事物列表中，选择您创建的事物，选择 **Shadows**（影子），然后选择 **Classic Shadow**（经典影子）。

影子文档应类似于以下内容，显示为颜色 `yellow` 设置的 `reported` 和 `desired` 值。您可以在文档的 **Shadow state**（影子状态）部分看到这些值。

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

您还可以看到 **Metadata**（元数据）部分，其中包含请求的时间戳信息和版本号。

您可以使用状态文档版本来确保正在更新的设备影子文档为最新版本。如果您发送另一个更新请求，则版本号将增加 1。当您为更新请求提供版本时，如果状态文档的当前版本与提供的版本不符，该服务将显示 HTTP 409 冲突响应代码并拒绝请求。

```
{
"metadata": {
  "desired": {
    "welcome": {
      "timestamp": 1620156892
    },
    "color": {
      "timestamp": 1620156893
    }
  },
  "reported": {
    "welcome": {
      "timestamp": 1620156892
    },
    "color": {
      "timestamp": 1620156893
    }
  }
},
"version": 10
}
```

要了解有关影子文档的详细信息并观察状态信息的更改，请继续阅读下一教程 [教程：示例应用程序及 MQTT 测试客户端与 Device Shadow 交互](interact-lights-device-shadows.md)，如本教程的 [步骤 4：查看结果和后续步骤](#sample-app-shadow-review) 部分所述。或者，您也可以在下一部分中了解 `shadow.py` 示例代码以及它如何使用 MQTT 协议。

## 步骤 2：查看 shadow.py 设备软件开发包示例应用
<a name="review-shadow-sample-code"></a>

本部分将回顾本教程中适用的来自 **AWS IoT Device SDK v2 for Python** 中的 `shadow.py`示例应用程序。在这里，我们将回顾一下它如何使用基于 WSS AWS IoT Core 的 MQTT 和 MQTT 协议进行连接。[AWS 通用运行时 (AWS-CRT)](https://github.com/awslabs/aws-crt-python#aws-crt-python) 库提供低级通信协议支持，并包含在适用于 Python 的 AWS IoT 设备 SDK v2 中。

虽然本教程使用基于 WSS 的 MQTT 和 MQTT，但 AWS IoT 支持发布 HTTPS 请求的设备。有关从设备发送 HTTP 消息的 Python 程序示例，请参阅使用 Python 的 `requests`库的 [HTTPS 代码示例](http.md#codeexample)。

有关如何对设备通信使用何种协议作出明智决定的信息，请查看 [为设备通信选择应用程序协议](protocols.md#protocol-selection)。

**MQTT**  
`shadow.py` 示例在 [https://github.com/awslabs/aws-crt-python/blob/89207bcf1387177034e02fe29e8e469ca45e39b7/awscrt/awsiot_mqtt_connection_builder.py](https://github.com/awslabs/aws-crt-python/blob/89207bcf1387177034e02fe29e8e469ca45e39b7/awscrt/awsiot_mqtt_connection_builder.py) 中调用 `mtls_from_path`（此处显示）以使用 MQTT 协议建立与 AWS IoT Core 的连接。`mtls_from_path` 使用 X.509 证书和 TLS v1.2 对设备进行身份验证。 AWS-CRT 库处理该连接的较低级别细节。

```
mqtt_connection = mqtt_connection_builder.mtls_from_path(
  endpoint=args.endpoint,
  cert_filepath=args.cert,
  pri_key_filepath=args.key,
  ca_filepath=args.ca_file,
  client_bootstrap=client_bootstrap,
  on_connection_interrupted=on_connection_interrupted,
  on_connection_resumed=on_connection_resumed,
  client_id=args.client_id,
  clean_session=False,
  keep_alive_secs=6
)
```
+ `endpoint`是您从命令行传入的 AWS IoT 终端节点，`client_id`也是在中唯一标识此设备的 ID AWS 区域。
+ `cert_filepath`、`pri_key_filepath` 和 `ca_filepath` 是指向设备证书和私钥文件以及根 CA 文件的路径。
+ `client_bootstrap` 是处理套接字通信活动的通用运行时对象，并在调用 `mqtt_connection_builder.mtls_from_path` 前实例化。
+ `on_connection_interrupted` 和 `on_connection_resumed` 是在设备连接中断和恢复时调用的回调函数。
+ `clean_session` 表示是否启动新的持久会话，或者如果会话已存在，则重新连接到现有会话。`keep_alive_secs` 是保持活动状态的值（以秒为单位），以发送到 `CONNECT` 请求中。在此时间间隔内将自动发送 ping。如果服务器在此值的 1.5 倍之后没有收到 ping，则假定连接丢失。

`shadow.py` 示例还调用 [https://github.com/awslabs/aws-crt-python/blob/89207bcf1387177034e02fe29e8e469ca45e39b7/awscrt/awsiot_mqtt_connection_builder.py](https://github.com/awslabs/aws-crt-python/blob/89207bcf1387177034e02fe29e8e469ca45e39b7/awscrt/awsiot_mqtt_connection_builder.py) 中的 `websockets_with_default_aws_signing` 以使用采用 WSS 的 MQTT 协议与 AWS IoT Core 建立连接。采用 WSS 的 MQTT 也使用与 MQTT 相同的参数，并采用以下附加参数：
+ `region`是 Signature V4 身份验证使用的签名区域，`credentials_provider`也是提供用于身份验证的 AWS 凭据。 AWS 区域是从命令行传递的，`credentials_provider` 对象在调用 `mqtt_connection_builder.websockets_with_default_aws_signing` 前进行实例化。
+ `websocket_proxy_options` 是 HTTP 代理选项（如果使用代理主机）。在 `shadow.py` 示例应用程序中，此值在调用 `mqtt_connection_builder.websockets_with_default_aws_signing` 前进行实例化。

**订阅影子主题和活动**  
`shadow.py` 示例尝试建立连接并等待完全连接。如果未连接，命令将排队。连接后，示例将订阅增量事件并更新和获取消息，并发布服务质量（QoS）级别为 1 的消息 (`mqtt.QoS.AT_LEAST_ONCE`)。

当设备订阅 QoS 级别 1 的消息时，消息代理会保存该设备订阅的消息，直到这些消息可以发送到设备。消息代理会重新发送消息，直至收到设备发出的 `PUBACK`响应。

有关 MQTT 协议的更多信息，请参阅 [查看 MQTT 协议](sdk-tutorials.md#sdk-tutorials-mqtt-review)和 [MQTT](mqtt.md)。

有关本教程中如何使用 MQTT、采用 WSS 的 MQTT、持久会话和 QoS 级别的详细信息，请参阅 [查看 pubsub.py Device SDK 示例应用程序](sdk-tutorials.md#sdk-tutorials-explore-sample)。

## 步骤 3：借助 `shadow.py`示例应用程序排除问题
<a name="shadow-sample-app-troubleshoot"></a>

当您运行 `shadow.py` 示例应用程序时，您应该看到终端中显示的一些消息以及输入 `desired` 值的提示。如果程序抛出错误，那么请调试以解决错误，您可以从检查系统是否运行了正确的命令开始。

在某些情况下，错误消息可能会指示连接问题，并且看起来类似于：`Host name was invalid for dns resolution` 或者 `Connection was closed unexpectedly`。在这种情况下，以下是您可以检查的几个事项：
+ 

**检查命令中的端点地址**  
查看您在命令中输入用来运行示例应用程序的 `endpoint` 参数（例如 `a3qEXAMPLEffp-ats.iot.us-west-2.amazonaws.com`），然后在 **AWS IoT 控制台**中检查此值。

  要检查是否使用了正确的值：

  1. 在 **AWS IoT 控制台**中，选择**管理**，然后选择**事物**。

  1. 选择您为示应用程序创建的事物（例如 **My\$1light\$1bulb**），然后选择 **Interact**（交互）。

  您的端点会显示在事物详细信息页面的 **HTTPS** 部分中。您还会看到一条消息，写着：`This thing already appears to be connected.`
+ 

**检查证书激活**  
证书用于对您的设备进行身份验证 AWS IoT Core。

  要检查您的证书是否处于活动状态：

  1. 在 **AWS IoT 控制台**中，选择 **Manage**（管理），然后选择 **Things**（事物）。

  1. 选择您为示应用程序创建的事物（例如 **My\$1light\$1bulb**），然后选择 **Security**（安全）。

  1. 选择证书，然后从证书的详细信息页面中选择 **Actions**（操作）。

  如果在下拉列表中 **Activate**（激活）不可用，且您只能选择 **Deactivate**（停用），则表示您的证书处于活动状态。如果并非如此，请选择 **Activate**（激活）并重新运行示例程序。

  如果程序仍未运行，请检查 `certs` 文件夹中的证书文件名。
+ 

**检查附加到事物资源的策略**  
在证书对您的设备进行身份验证的同时， AWS IoT 策略允许设备执行 AWS IoT 操作，例如订阅或发布 MQTT 保留主题。

  要检查是否附加了正确的策略：

  1. 查找如前所述的证书，然后选择 **Policies**（策略）。

  1. 选择显示的策略，并检查它是否描述 `connect`、`subscribe`、`receive` 和 `publish` 操作，授予设备发布和订阅 MQTT 预留主题的权限。

     如需了解示例策略，请参阅 [步骤 1：为 Device Shadow 创建 AWS IoT 策略](shadow-provision-cloud.md#create-policy-shadow)。

  如果您看到错误消息表明无法连接到该策略 AWS IoT，则可能是因为您正在使用策略的权限。如果是这样的话，我们建议您从提供对 AWS IoT 资源的完全访问权限的策略开始，然后重新运行示例程序。您可以编辑当前策略，也可以选择当前策略，选择 **Detach**（分离），然后创建另一个提供完全访问权限的策略并将其附加到您的事物资源。您可以稍后将策略限制为运行程序所需的操作和策略。  
****  

  ```
  {
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "iot:*"
            ],
            "Resource": "*"
        }
    ]
  }
  ```
+ 

**检查您的设备 Device SDK 安装**  
如果程序仍未运行，您可以重新安装 Device SDK 包以确保 SDK 安装完整且正确。

## 步骤 4：查看结果和后续步骤
<a name="sample-app-shadow-review"></a>

**在本教程中，您学习了如何：**
+ 安装所需的软件、工具和适用于 Python 的 AWS IoT 设备 SDK。
+ 了解示例应用程序 `shadow.py` 如何使用 MQTT 协议检索和更新影子的当前状态。
+ 运行 Device Shadows 的示例应用程序，并在 AWS IoT 控制台中观察 Shadow 文档的更新。您还学习了如何在运行程序时解决任何问题和修复错误。

**后续步骤**  
您现在可以运行 `shadow.py` 示例应用程序，并使用 Device Shadow 控制状态。您可以在 AWS IoT 控制台中观察并更新影子文档，并观察示例应用程序相应的增量事件。使用 MQTT 测试客户端，您可以订阅预留影子主题并在运行示例程序时观察主题收到的消息。有关如何使用该教程的更多信息，请参阅 [教程：示例应用程序及 MQTT 测试客户端与 Device Shadow 交互](interact-lights-device-shadows.md)。

# 教程：示例应用程序及 MQTT 测试客户端与 Device Shadow 交互
<a name="interact-lights-device-shadows"></a>

若要与 `shadow.py` 示例应用程序交互，请在终端中为 `desired` 值输入一个值。例如，您可以指定类似于交通信号灯的颜色，并 AWS IoT 响应请求并更新报告的值。

**在本教程中，您将学习如何：**
+ 使用 `shadow.py`示例应用程序来指定所需的状态并更新影子的当前状态。
+ 编辑影子文档以观察增量事件以及 `shadow.py`示例应用程序如何响应。
+ 使用 MQTT 测试客户端订阅影子主题并在运行示例程序时观察更新。

**运行本教程之前，您必须具有：**  
设置你的 AWS 账户，配置你的 Raspberry Pi 设备，并创建了 AWS IoT 事物和策略。您还必须安装了所需的软件、Device SDK、证书文件，并在终端中运行示例程序。有关更多信息，请参阅教程 [教程：准备 Raspberry Pi 运行影子应用程序](create-resources-shadow.md) 和 [步骤 1：运行 shadow.py 示例应用程序](lightbulb-shadow-application.md#run-sample-application-shadows)。如果您尚未完成这些教程，请先予完成。

**Topics**
+ [步骤 1：使用 `shadow.py` 示例应用程序更新所需值和报告值](#update-desired-shadow-sample)
+ [步骤 2：查看来自 `shadow.py` 中 MQTT 测试客户端中示例应用程序的消息](#shadow-sample-view-msg)
+ [步骤 3：排除 Device Shadow 交互中的错误](#shadow-observe-messages-troubleshoot)
+ [步骤 4：查看结果和后续步骤](#sample-shadow-review)

完成本教程需要大约 45 分钟。

## 步骤 1：使用 `shadow.py` 示例应用程序更新所需值和报告值
<a name="update-desired-shadow-sample"></a>

在上一教程中[步骤 1：运行 shadow.py 示例应用程序](lightbulb-shadow-application.md#run-sample-application-shadows)，您学习了如何在输入所需值时在 AWS IoT 控制台中观察发布到 Shadow 文档的消息（如本节所述）[教程：安装设备软件开发包并运行 Device Shadow 示例应用程序](lightbulb-shadow-application.md)。

在前面的示例中，我们将所需的颜色设置为 `yellow`。输入每个值后，终端将提示您输入另一个 `desired` 值。如果您再次输入相同的值 (`yellow`)，应用程序会识别这一点，并提示您输入一个新的 `desired` 值。

```
Enter desired value:
yellow
Local value is already 'yellow'.
Enter desired value:
```

现在，假设你输入了颜色`green`。 AWS IoT 响应请求并将`reported`值更新为`green`。这就是当 `desired` 状态不同于 `reported` 状态时产生更新的方式，从而导致增量。

**`shadow.py` 示例应用程序模拟 Device Shadow 交互：**

1. 在终端输入 `desired` 值（例如 `yellow`）来发布所需的状态。

1. 由于 `desired` 状态不同于 `reported` 状态（比如说颜色 `green`），则会产生增量，并且订阅增量的应用程序会收到此消息。

1. 应用程序响应消息并将其状态更新为 `desired` 值，`yellow`。

1. 然后，应用程序会发布一条更新消息，其中包含设备状态的新报告值，`yellow`。

下面显示了终端中显示的消息，其展示了更新申请是如何发布的。

```
Enter desired value:
green
Changed local shadow value to 'green'.
Updating reported shadow value to 'green'...
Update request published.
Finished updating reported shadow value to 'green'.
```

在 AWS IoT 控制台中，Shadow 文档将`reported`和`desired`字段`green`的更新值反映为，版本号以 1 为增量。例如，如果以前的版本号显示为 10，则当前版本号将显示为 11。

**注意**  
删除影子不会将版本号重置为 0。当您发布更新请求或创建另一个具有相同名称的影子时，您将看到影子版本递增 1。

**编辑影子文档以观察增量事件**  
`shadow.py` 示例应用程序也订阅 `delta` 事件，并在 `desired` 值出现更改时予以响应。例如，您可以将 `desired`值更改为颜色 `red`。为此，请在 AWS IoT 控制台中单击 “编辑” 来编辑 Shadow 文档，然后**在** JSON `red` 中将该`desired`值设置为，同时将该`reported`值保持为`green`。保存更改之前，请保持 Raspberry Pi 上的终端打开状态，因为当出现更改时，您会看到终端中显示的消息。

```
{
"desired": {
  "welcome": "aws-iot",
  "color": "red"
},
"reported": {
  "welcome": "aws-iot",
  "color": "green"
}
}
```

保存新值后，`shadow.py` 示例应用程序响应此更改，并在终端中显示指示增量的消息。然后，您应该看到以下消息出现在输入 `desired` 值的提示下方。

```
Enter desired value:
Received shadow delta event.
Delta reports that desired value is 'red'. Changing local value...
Changed local shadow value to 'red'.
Updating reported shadow value to 'red'...
Finished updating reported shadow value to 'red'.
Enter desired value:
Update request published.
Finished updating reported shadow value to 'red'.
```

## 步骤 2：查看来自 `shadow.py` 中 MQTT 测试客户端中示例应用程序的消息
<a name="shadow-sample-view-msg"></a>

您可以使用 **AWS IoT 控制台**中的 **MQTT 测试客户端**来监控传递在 AWS 账户中的 MQTT 消息。通过订阅 Device Shadow 服务使用的保留 MQTT 主题，您可以观察在运行示例应用程序时主题收到的消息。

如果尚未使用 MQTT 测试客户端，您可以查看 [使用 MQTT 客户端查看 AWS IoT MQTT 消息](view-mqtt-messages.md)。它可以帮助您了解如何使用 **AWS IoT 控制台**中的 **MQTT 测试客户端**来查看通过消息代理时的 MQTT 消息。

1. 

**打开 MQTT 测试客户端**

   打开 [AWS IoT 控制台中的 MQTT 测试客户端](https://console.aws.amazon.com//iot/home#/test)，以便您可以观察 MQTT 主题收到的消息，而不会丢失 MQTT 测试客户端的配置。如果您让 MQTT 测试客户端进入控制台中的其它页面，则 MQTT 测试客户端不会保留任何订阅或消息日志。在本教程的这一部分中，你可以让你的 AWS IoT 事物的 Shadow 文档和 MQTT 测试客户端在单独的窗口中打开，以便更轻松地观察与设备影子的交互情况。

1. 

**订阅 MQTT 预留的影子主题**

   您可以使用 MQTT 测试客户端输入 Device Shadow 的 MQTT 预留主题的名称，并在运行 `shadow.py` 示例应用程序时订阅它们以接收更新。要订阅主题：

   1. 在 **AWS IoT 控制台**的 **MQTT 测试客户端**中，选择**订阅主题**。

   1.  在**主题筛选器**部分，输入：**\$1aws/things/ /shadow/updat *thingname*** e/ \$1。在这里，`thingname` 是您之前创建的事物资源的名称（例如，`My_light_bulb`）。

   1. 保留附加配置设置的默认值，然后选择 **Subscribe**（订阅）。

   通过使用 **\$1** 通配符，您可以同时订阅多个 MQTT 主题，并在单个窗口中观察设备与其影子之间交换的所有消息。有关通配符及其用法的更多信息，请参阅 [MQTT 主题](topics.md)。

1. 

**运行 `shadow.py` 示例程序和观察消息**

   在 Raspberry Pi 的命令行窗口中，如果您已经断开程序的连接，请再次运行示例应用程序，并在 **AWS IoT 控制台**中的 **MQTT 测试客户端**观察消息。

   1. 运行以下命令以重新启动示程序。将*your-iot-thing-name*和*your-iot-endpoint*替换为您之前创建 AWS IoT 的事物的名称（例如`My_light_bulb`），以及要与设备交互的终端节点。

      ```
      cd ~/aws-iot-device-sdk-python-v2/samples/service-clients
      python3 shadow.py --ca_file ~/certs/Amazon-root-CA-1.pem --cert ~/certs/device.pem.crt --key ~/certs/private.pem.key --endpoint your-iot-endpoint --thing_name your-iot-thing-name
      ```

      `shadow.py` 示例应用程序随后会开始运行并检索当前影子状态。如果已删除影子或清除当前状态，程序会将当前值设置为 `off`，然后提示您输入 `desired` 值。

      ```
      Connecting to a3qEXAMPLEffp-ats.iot.us-west-2.amazonaws.com with client ID 'test-0c8ae2ff-cc87-49d2-a82a-ae7ba1d0ca5a'...
      Connected!
      Subscribing to Delta events...
      Subscribing to Update responses...
      Subscribing to Get responses...
      Requesting current shadow state...
      Launching thread to read user input...
      Finished getting initial shadow state.
      Shadow document lacks 'color' property. Setting defaults...
      Changed local shadow value to 'off'.
      Updating reported shadow value to 'off'...
      Update request published.
      Finished updating reported shadow value to 'off'...
      Enter desired value:
      ```

      另一方面，如果程序正在运行，并且您将程序重新启动，您将看到终端中报告的最新颜色值。**在 MQTT 测试客户端中，你会看到 \$1aws/things//shadow/get 和 **\$1aws/things// *thingname*** 主题的更新。*thingname* shadow/get/accepted**

      假设报告的最新颜色为 `green`。以下显示了 **\$1aws/things// *thingname*** JSON 文件的内容。shadow/get/accepted

      ```
      {
      "state": {
        "desired": {
          "welcome": "aws-iot",
          "color": "green"
        },
        "reported": {
          "welcome": "aws-iot",
          "color": "green"
        }
      },
      "metadata": {
        "desired": {
          "welcome": {
            "timestamp": 1620156892
          },
          "color": {
            "timestamp": 1620161643
          }
        },
        "reported": {
          "welcome": {
            "timestamp": 1620156892
          },
          "color": {
            "timestamp": 1620161643
          }
        }
      },
      "version": 10,
      "timestamp": 1620173908
      }
      ```

   1. 在终端中输入 `desired` 值，例如 `yellow`。`shadow.py` 示例应用程序响应并在终端中显示以下消息，这些消息显示了 `reported` 值变更为 `yellow`的情况。

      ```
      Enter desired value:
      yellow
      Changed local shadow value to 'yellow'.
      Updating reported shadow value to 'yellow'...
      Update request published.
      Finished updating reported shadow value to 'yellow'.
      ```

      在 **AWS IoT 控制台**的 **MQTT 测试客户端**中，在**订阅**下，您会看到以下主题收到一条消息：
      + **\$1aws/things/ *thingname* /shadow/update**：显示和值都`desired`变为颜色。`updated` `yellow`
      + **\$1aws/things*thingname*//shadow/update/accepted**：显示`desired`和`reported`状态的当前值及其元数据和版本信息。
      + **\$1aws/things*thingname*//shadow/update/documents**：显示和`reported`状态的先前`desired`和当前值及其元数据和版本信息。

      由于文档 **\$1aws/things/*thingname*/shadow/update/documents**也包含其他两个主题中包含的信息，因此我们可以查看它以查看状态信息。上一个状态显示报告的值设置为 `green`、其元数据和版本信息，而当前的状态显示报告的值更新为 `yellow`。

      ```
      {
      "previous": {
        "state": {
          "desired": {
            "welcome": "aws-iot",
            "color": "green"
          },
          "reported": {
            "welcome": "aws-iot",
            "color": "green"
          }
        },
        "metadata": {
          "desired": {
            "welcome": {
              "timestamp": 1617297888
            },
            "color": {
              "timestamp": 1617297898
            }
          },
          "reported": {
            "welcome": {
              "timestamp": 1617297888
            },
            "color": {
              "timestamp": 1617297898
            }
          }
        },
        "version": 10
      },
      "current": {
        "state": {
          "desired": {
            "welcome": "aws-iot",
            "color": "yellow"
          },
          "reported": {
            "welcome": "aws-iot",
            "color": "yellow"
          }
        },
        "metadata": {
          "desired": {
            "welcome": {
              "timestamp": 1617297888
            },
            "color": {
              "timestamp": 1617297904
            }
          },
          "reported": {
            "welcome": {
              "timestamp": 1617297888
            },
            "color": {
              "timestamp": 1617297904
            }
          }
        },
        "version": 11
      },
      "timestamp": 1617297904
      }
      ```

   1. 现在，如果您输入另一个 `desired` 值，您可以看到 `reported` 值的进一步更改和这些主题收到的消息更新。版本号也会增加 1。例如，如果您输入值 `green`，之前的状态会报告值 `yellow`，而当前状态报告值 `green`。

1. 

**编辑影子文档以观察增量事件**

   要观察对增量主题的更改，请在 AWS IoT 控制台编辑影子文档。例如，您可以将 `desired`值更改为颜色 `red`。为此，请在 AWS IoT 控制台中选择 **“编辑”，然后在** JSON 中将该`desired`值设置为红色，同时将该`reported`值设置为`green`。在保存更改之前，请保持终端处于开启状态，因为您将看到终端中报告的增量消息。

   ```
   {
   "desired": {
     "welcome": "aws-iot",
     "color": "red"
   },
   "reported": {
     "welcome": "aws-iot",
     "color": "green"
   }
   }
   ```

   `shadow.py` 示例应用程序响应此更改，并在终端中显示指示增量的消息。在 MQTT 测试客户端中，`update` 主题将收到一条消息，显示对 `desired` 和 `reported` 值的更改。

   你还会看到话题 **\$1aws/things/*thingname*/shadow/update/delta**收到了一条消息。要查看消息，请选择该主题，其列于 **Subscriptions**（订阅）下方。

   ```
   {
   "version": 13,
   "timestamp": 1617318480,
   "state": {
     "color": "red"
   },
   "metadata": {
     "color": {
       "timestamp": 1617318480
     }
   }
   }
   ```

## 步骤 3：排除 Device Shadow 交互中的错误
<a name="shadow-observe-messages-troubleshoot"></a>

运行影子示例应用程序时，在观察与 Device Shadow 服务的交互过程中可能会遇到问题。

如果程序运行成功并提示您输入 `desired` 值，您应该能够通过使用前述影子文档和 MQTT 测试客户端来观察 Device Shadow 交互。但是，如果您无法查看交互，可以检查以下事项：
+ 

**在 AWS IoT 控制台中检查事物名称及其阴影**  
如果您在影子文档中没有看到这些消息，请查看该命令，并确保它与 **AWS IoT 控制台** 中的事物名称相符。您还可以通过选择事物资源，然后选择 **Shadows**（影子）来查看您是否拥有经典影子。本教程主要侧重于与经典影子的交互。

   您还可以确认您使用的设备已连接到互联网。在 **AWS IoT 控制台**，选择您之前创建的事物，然后选择**交互**。在事物详细信息页面上，您应该会在此处看到一条消息：`This thing already appears to be connected.`
+ 

**检查您订阅的 MQTT 预留主题**  
如果在 MQTT 测试客户端中看不到消息，请检查您订阅的主题是否格式正确。MQTT Device Shadow 主题的格式为 **\$1aws/things/ *thingname* /shadow/**，可能有`update``get`、或`delete`关注它，具体取决于你要对影子执行的操作。**本教程使用主题 **\$1aws/things/ *thingname* /shadow/ \$1**，因此在测试客户端的 “主题筛选器” 部分订阅该主题时，请务必正确输入该主题。**

  输入主题名称时，请确保与之前创建 AWS IoT 的事物的名称相同。*thingname*您还可以订阅其它 MQTT 主题，以查看是否已成功执行更新。例如，您可以订阅主题 **\$1aws/things/*thingname*/**，shadow/update/rejected以便在更新请求失败时收到一条消息，以便您可以调试连接问题。有关预留主题的更多信息，请参阅 [影子主题](reserved-topics.md#reserved-topics-shadow) 和 [Device Shadow MQTT 主题](device-shadow-mqtt.md)。

## 步骤 4：查看结果和后续步骤
<a name="sample-shadow-review"></a>

**在本教程中，您学习了如何：**
+ 使用 `shadow.py`示例应用程序来指定所需的状态并更新影子的当前状态。
+ 编辑影子文档以观察增量事件以及 `shadow.py`示例应用程序如何响应。
+ 使用 MQTT 测试客户端订阅影子主题并在运行示例程序时观察更新。

**后续步骤**  
您可以订阅其它 MQTT 预留主题，以观察影子应用程序的更新。例如，如果您只订阅主题 **\$1aws/things/*thingname*/shadow/update/accepted**，则成功执行更新后，您将只能看到当前状态信息。

您还可以订阅其它影子主题以调试问题或了解有关 Device Shadow 交互的详细信息，还可以调试与 Device Shadow 交互有关的任何问题。有关更多信息，请参阅[影子主题](reserved-topics.md#reserved-topics-shadow)和[Device Shadow MQTT 主题](device-shadow-mqtt.md)。

您也可以选择使用命名阴影或使用与 Raspberry Pi 连接的其他硬件来扩展应用程序， LEDs 并使用终端发送的消息观察其状态的变化。

有关 Device Shadow 服务以及在设备、应用程序和服务中使用该服务的详细信息，请参阅 [AWS IoT Device Shadow 服务](iot-device-shadows.md)、[在设备中使用影子](device-shadow-comms-device.md) 和 [在应用程序和服务中使用影子](device-shadow-comms-app.md)。

# 教程：为创建自定义授权方 AWS IoT Core
<a name="custom-auth-tutorial"></a>

本教程演示了使用 AWS CLI创建、验证和使用自定义身份验证的步骤。或者，使用本教程，您可以借助 HTTP Publish API 使用 Postman 将数据发送到 AWS IoT Core 。

本教程介绍如何创建一个示例 Lambda 函数，该函数将在启用令牌签名的情况下，借助 **create-authorizer** 调用实现授权和身份验证逻辑。然后使用对授权方进行验证，最后**test-invoke-authorizer**，您可以使用 HTTP 发布 API 向测试 MQTT 主题发送数据。 AWS IoT Core 示例请求将使用标头指定要调用的授权方，并在请求`x-amz-customauthorizer-name`标头`x-amz-customauthorizer-signature`中传递 token-key-name和。

**您将在本教程中学到的内容：**
+ 如何创建一个 Lambda 函数作为自定义授权方处理程序
+ 如何在启用令牌签名的情况下使用创建自定义授权方 AWS CLI 
+ 如何使用 **test-invoke-authorizer**命令测试您的自定义授权方
+ 如何使用 [Postman](https://www.postman.com/) 发布 MQTT 主题并使用您的自定义授权方验证请求

完成本教程需要大约 60 分钟。

**Topics**
+ [步骤 1：为自定义授权方创建 Lambda 函数](#custom-auth-tutorial-define)
+ [步骤 2：为自定义授权方创建公有密钥和私有密钥对](#custom-auth-tutorial-keys)
+ [步骤 3：创建自定义授权方资源及其授权](#custom-auth-tutorial-authorizer)
+ [步骤 4：通过调用来测试授权者 test-invoke-authorizer](#custom-auth-tutorial-test)
+ [步骤 5：测试使用 Postman 发布 MQTT 消息](#custom-auth-tutorial-postman)
+ [步骤 6：在 MQTT 测试客户端中查看消息](#custom-auth-tutorial-testclient)
+ [步骤 7：查看结果和后续步骤](#custom-auth-tutorial-review)
+ [步骤 8：清除](#custom-auth-tutorial-cleanup)

**在开始本教程之前，请确保您具有：**
+ 

**[设置 AWS 账户](setting-up.md)**  
你需要你的 AWS 账户 和 AWS IoT 主机才能完成本教程。

  当您用于本教程的账户中至少包含这些 AWS 托管策略时，账户的效果最佳：
  + [https://console.aws.amazon.com//iam/home#/policies/arn:aws:iam::aws:policy/IAMFullAccess$jsonEditor](https://console.aws.amazon.com//iam/home#/policies/arn:aws:iam::aws:policy/IAMFullAccess$jsonEditor)
  + [https://console.aws.amazon.com//iam/home#/policies/arn:aws:iam::aws:policy/AWSIoTFullAccess$jsonEditor](https://console.aws.amazon.com//iam/home#/policies/arn:aws:iam::aws:policy/AWSIoTFullAccess$jsonEditor)
  + [https://console.aws.amazon.com//iam/home#/policies/arn:aws:iam::aws:policy/AWSLambda_FullAccess$jsonEditor](https://console.aws.amazon.com//iam/home#/policies/arn:aws:iam::aws:policy/AWSLambda_FullAccess$jsonEditor)
**重要**  
本教程中使用的 IAM 策略比您在生产实施中应遵循的更宽松。在生产环境中，请确保您的账户和资源策略仅授予必要的权限。  
在您为生产创建 IAM 策略时，请确定用户和角色需要的访问权限，然后设计允许他们仅执行这些任务的策略。  
有关更多信息，请参阅 [IAM 安全最佳实践](https://docs.aws.amazon.com//IAM/latest/UserGuide/best-practices.html)。
+ 

**安装了 AWS CLI**  
有关如何安装的信息 AWS CLI，请参阅[安装 AWS CLI](https://docs.aws.amazon.com//cli/latest/userguide/cli-chap-install.html)。本教程需要 AWS CLI 版本`aws-cli/2.1.3 Python/3.7.4 Darwin/18.7.0 exe/x86_64`或更高版本。
+ 

**OpenSSL 工具**  
本教程中的示例使用 [LibreSSL 2.6.5](https://www.libressl.org/)。您还可以在本教程中使用 [OpenSSL v1.1.1i](https://www.openssl.org/) 工具。
+ 

**查看 [AWS Lambda](https://docs.aws.amazon.com//lambda/latest/dg/welcome.html)概览**  
如果您 AWS Lambda 以前从未使用过，请查看[AWS Lambda](https://docs.aws.amazon.com//lambda/latest/dg/welcome.html)并[开始使用 Lambda](https://docs.aws.amazon.com//lambda/latest/dg/getting-started.html)，以了解其术语和概念。
+ 

**回顾了如何在 Postman 中构建请求**  
有关更多信息，请参阅[构建请求](https://learning.postman.com/docs/sending-requests/requests/)。
+ 

**从以前的教程中删除了自定义授权方**  
一次 AWS 账户 只能配置有限数量的自定义授权方。有关如何创建和删除自定义授权方的信息，请参阅 [步骤 8：清除](#custom-auth-tutorial-cleanup)。

## 步骤 1：为自定义授权方创建 Lambda 函数
<a name="custom-auth-tutorial-define"></a>

中的自定义身份验证 AWS IoT Core 使用您创建的[授权方资源](https://docs.aws.amazon.com//iot/latest/apireference/API_AuthorizerDescription.html)对客户端进行身份验证和授权。您将在本节中创建的函数在客户端连接和访问 AWS IoT 资源时对其进行身份验证 AWS IoT Core 和授权。

Lambda 函数执行以下操作：
+ 如果请求来自 **test-invoke-authorizer**，则它会返回一个带有 `Deny` 操作的 IAM 策略。
+ 如果请求来自使用 HTTP 的 Postman，且 `actionToken` 参数的值为 `allow`，则它会返回一个带有 `Allow` 操作的 IAM 策略。否则，它会返回带有 `Deny` 操作的 IAM 策略。

**要为自定义授权方创建 Lambda 函数：**

1. 在 [Lambda](https://console.aws.amazon.com//lambda/home#) 控制台，打开[函数](https://console.aws.amazon.com//lambda/home#/functions)。

1. 选择**创建函数**。

1. 确认 **Author from scratch**（从头开始编写）处于选中状态。

1. 在 **Basic information** 下：

   1. 在**函数名称**中，输入 **custom-auth-function**。

   1. 在**运行时系统**中，确认 **Node.js 18.x** 

1. 选择**创建函数**。

   Lambda 创建 Node.js 函数和[执行角色](https://docs.aws.amazon.com//lambda/latest/dg/lambda-intro-execution-role.html)，该角色将授予函数上载日志的权限。Lambda 函数在您调用函数时担任执行角色，并使用执行角色为 AWS SDK 创建凭证和从事件源读取数据。

1. 要在[AWS Cloud9](https://docs.aws.amazon.com/cloud9/latest/user-guide/welcome.html)编辑器中查看函数的代码和配置，请在设计器窗口**custom-auth-function**中选择，然后在编辑器的导航窗格中选择 **index.js**。

   对于脚本语言（如 Node.js），Lambda 包含返回成功响应的基本函数。您可以使用 [AWS Cloud9](https://docs.aws.amazon.com/cloud9/latest/user-guide/welcome.html) 编辑器来编辑您的函数，只要源码不超过 3MB 即可。

1. 在编辑器中使用以下代码替换 **index.js** 代码：

   ```
   // A simple Lambda function for an authorizer. It demonstrates
   // How to parse a CLI and Http password to generate a response.
   
   export const handler = async (event, context, callback) => {
   
       //Http parameter to initiate allow/deny request
       const HTTP_PARAM_NAME='actionToken';
       const ALLOW_ACTION = 'Allow';
       const DENY_ACTION = 'Deny';
   
       //Event data passed to Lambda function
       var event_str = JSON.stringify(event);
       console.log('Complete event :'+ event_str);
   
       //Read protocolData from the event json passed to Lambda function
       var protocolData = event.protocolData;
       console.log('protocolData value---> ' + protocolData);
   
       //Get the dynamic account ID from function's ARN to be used
       // as full resource for IAM policy
       var ACCOUNT_ID = context.invokedFunctionArn.split(":")[4];
       console.log("ACCOUNT_ID---"+ACCOUNT_ID);
   
       //Get the dynamic region from function's ARN to be used
       // as full resource for IAM policy
       var REGION = context.invokedFunctionArn.split(":")[3];
       console.log("REGION---"+REGION);
   
       //protocolData data will be undefined if testing is done via CLI.
       // This will help to test the set up.
       if (protocolData === undefined) {
   
           //If CLI testing, pass deny action as this is for testing purpose only.
           console.log('Using the test-invoke-authorizer cli for testing only');
           callback(null, generateAuthResponse(DENY_ACTION,ACCOUNT_ID,REGION));
   
       } else{
   
           //Http Testing from Postman
           //Get the query string from the request
           var queryString = event.protocolData.http.queryString;
           console.log('queryString values -- ' + queryString);
           /*         global URLSearchParams       */
           const params = new URLSearchParams(queryString);
           var action = params.get(HTTP_PARAM_NAME);
   
           if(action!=null && action.toLowerCase() === 'allow'){
   
               callback(null, generateAuthResponse(ALLOW_ACTION,ACCOUNT_ID,REGION));
   
           }else{
   
               callback(null, generateAuthResponse(DENY_ACTION,ACCOUNT_ID,REGION));
   
           }
   
       }
   
   };
   
   // Helper function to generate the authorization IAM response.
   var generateAuthResponse = function(effect,ACCOUNT_ID,REGION) {
   
       var full_resource = "arn:aws:iot:"+ REGION + ":" + ACCOUNT_ID + ":*";
       console.log("full_resource---"+full_resource);
   
       var authResponse = {};
       authResponse.isAuthenticated = true;
       authResponse.principalId = 'principalId';
   
       var policyDocument = {};
       policyDocument.Version = '2012-10-17';		 	 	 
       policyDocument.Statement = [];
       var statement = {};
       statement.Action = 'iot:*';
       statement.Effect = effect;
       statement.Resource = full_resource;
       policyDocument.Statement[0] = statement;
       authResponse.policyDocuments = [policyDocument];
       authResponse.disconnectAfterInSeconds = 3600;
       authResponse.refreshAfterInSeconds = 600;
   
       console.log('custom auth policy function called from http');
       console.log('authResponse --> ' + JSON.stringify(authResponse));
       console.log(authResponse.policyDocuments[0]);
   
       return authResponse;
   }
   ```

1. 选择**部署**。

1. 在 **Changes deployed**（更改已部署）出现在编辑器上方后：

   1. 滚动到编辑器上方的 **Function overview**（函数概览）部分。

   1. 复制 **Function ARN**（函数 ARN）并保存以在本教程稍后的部分中使用。

1. 测试 函数。

   1. 选择 **Test**（测试）选项卡。

   1. 使用默认测试设置，选择 **Invoke**（调用）。

   1. 如果测试成功，则在 **Execution results**（执行结果）下，打开 **Details**（详细信息）视图。您应该看到函数返回的策略文档。

      如果测试失败或没有看到策略文档，请查看代码以查找并更正错误。

## 步骤 2：为自定义授权方创建公有密钥和私有密钥对
<a name="custom-auth-tutorial-keys"></a>

您的自定义授权方需要公有密钥和私有密钥来对其进行身份验证。本部分中的命令使用 OpenSSL 工具来创建此密钥对。

**要为自定义授权方创建公有和私有密钥对，请执行以下操作**

1. 创建私有密钥文件。

   ```
   openssl genrsa -out private-key.pem 4096
   ```

1. 验证您刚创建的私有密钥文件。

   ```
   openssl rsa -check -in private-key.pem -noout
   ```

   如果命令未显示任何错误，则私有密钥文件是有效的。

1. 创建公有密钥文件。

   ```
   openssl rsa -in private-key.pem -pubout -out public-key.pem
   ```

1. 验证公有密钥文件。

   ```
   openssl pkey -inform PEM -pubin -in public-key.pem -noout
   ```

   如果命令未显示任何错误，则公有密钥文件是有效的。

## 步骤 3：创建自定义授权方资源及其授权
<a name="custom-auth-tutorial-authorizer"></a>

 AWS IoT 自定义授权器是将前面步骤中创建的所有元素联系在一起的资源。在本部分中，您将创建一个自定义授权方资源，并授予其运行您之前创建的 Lambda 函数的权限。您可以使用 AWS IoT 控制台、或 AWS API 创建自定义授权方 AWS CLI资源。

在本教程中，您只需要创建一个自定义授权方。本节介绍如何使用 AWS IoT 控制台和进行创建 AWS CLI，以便您可以使用最方便的方法。以两种方法创建的自定义授权方资源之间没有区别。

### 创建自定义授权方资源
<a name="custom-auth-tutorial-authorizer-resource"></a>

**选择以下选项之一以创建自定义授权方资源**
+ [使用控制台创建自定义授权方 AWS IoT](#create-custom-auth-in-console)
+ [使用 AWS CLI创建自定义授权方](#create-custom-auth-in-cli)

**要创建自定义授权方（控制台）**

1. 打开[AWS IoT 控制台的 “自定义授权者” 页面](https://console.aws.amazon.com//iot/home#/authorizerhub)，然后选择 “**创建授权**者”。

1. 在**创建授权方**中：

   1. 在**授权方名称**中，输入 **my-new-authorizer**。

   1. 在**授权者状态**中，选中**活动**。

   1. 在 **Authorizer function**（授权方函数）中，选择您之前创建的 Lambda 函数。

   1. 在**令牌验证 - 可选**中：

      1. 开启**令牌验证**。

      1. 在**令牌密钥名称**中，输入 **tokenKeyName**。

      1. 选择**添加密钥**。

      1. 在 **密钥名称**中，输入 **FirstKey**。

      1. 在**公有密钥**中，输入 `public-key.pem` 文件的内容。请务必包含文件中的行以及 `-----BEGIN PUBLIC KEY-----`和 `-----END PUBLIC KEY-----`，并且不要从文件内容中添加或删除任何换行符、回车符或其它字符。您输入的字符串应类似下面这个示例。

         ```
         -----BEGIN PUBLIC KEY-----
         MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvEBzOk4vhN+3LgslvEWt
         sLCqNmt5Damas3bmiTRvq2gjRJ6KXGTGQChqArAJwL1a9dkS9+maaXC3vc6xzx9z
         QPu/vQOe5tyzz1MsKdmtFGxMqQ3qjEXAMPLEOmqyUKPP5mff58k6ePSfXAnzBH0q
         lg2HioefrpU5OSAnpuRAjYKofKjbc2Vrn6N2G7hV+IfTBvCElf0csalS/Rk4phD5
         oa4Y0GHISRnevypg5C8n9Rrz91PWGqP6M/q5DNJJXjMyleG92hQgu1N696bn5Dw8
         FhedszFa6b2x6xrItZFzewNQkPMLMFhNrQIIyvshtT/F1LVCS5+v8AQ8UGGDfZmv
         QeqAMAF7WgagDMXcfgKSVU8yid2sIm56qsCLMvD2Sq8Lgzpey9N5ON1o1Cvldwvc
         KrJJtgwW6hVqRGuShnownLpgG86M6neZ5sRMbVNZO8OzcobLngJ0Ibw9KkcUdklW
         gvZ6HEJqBY2XE70iEXAMPLETPHzhqvK6Ei1HGxpHsXx6BNft582J1VpgYjXha8oa
         /NN7l7Zbj/euAb41IVtmX8JrD9z613d1iM5L8HluJlUzn62Q+VeNV2tdA7MfPfMC
         8btGYladFAnitThaz6+F0VSBJPu7pZQoLnqyEp5zLMtF+kFl2yOBmGAP0RBivRd9
         JWBUCG0bqcLQPeQyjbXSOfUCAwEAAQ==
         -----END PUBLIC KEY-----
         ```

1. 选择 **Create Authorizer**（创建授权方）。

1. 如果创建了自定义授权方资源，您将看到自定义授权方列表，并且您的新自定义授权方应显示在列表中，然后您便可以继续下一部分展开测试了。

   如果您看到错误，请检查错误并尝试再次创建自定义授权方，然后仔细检查条目。请注意，每个自定义授权方资源必须具有唯一的名称。

**要创建自定义授权方 (AWS CLI)**

1. 将您的值替换为 `authorizer-function-arn` 和 `token-signing-public-keys`，然后运行以下命令：

   ```
   aws iot create-authorizer \
   --authorizer-name "my-new-authorizer" \
   --token-key-name "tokenKeyName" \
   --status ACTIVE \
   --no-signing-disabled \
   --authorizer-function-arn "arn:aws:lambda:Region:57EXAMPLE833:function:custom-auth-function" \
   --token-signing-public-keys FirstKey="-----BEGIN PUBLIC KEY-----
   MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvEBzOk4vhN+3LgslvEWt
   sLCqNmt5Damas3bmiTRvq2gjRJ6KXGTGQChqArAJwL1a9dkS9+maaXC3vc6xzx9z
   QPu/vQOe5tyzz1MsKdmtFGxMqQ3qjEXAMPLEOmqyUKPP5mff58k6ePSfXAnzBH0q
   lg2HioefrpU5OSAnpuRAjYKofKjbc2Vrn6N2G7hV+IfTBvCElf0csalS/Rk4phD5
   oa4Y0GHISRnevypg5C8n9Rrz91PWGqP6M/q5DNJJXjMyleG92hQgu1N696bn5Dw8
   FhedszFa6b2x6xrItZFzewNQkPMLMFhNrQIIyvshtT/F1LVCS5+v8AQ8UGGDfZmv
   QeqAMAF7WgagDMXcfgKSVU8yid2sIm56qsCLMvD2Sq8Lgzpey9N5ON1o1Cvldwvc
   KrJJtgwW6hVqRGuShnownLpgG86M6neZ5sRMbVNZO8OzcobLngJ0Ibw9KkcUdklW
   gvZ6HEJqBY2XE70iEXAMPLETPHzhqvK6Ei1HGxpHsXx6BNft582J1VpgYjXha8oa
   /NN7l7Zbj/euAb41IVtmX8JrD9z613d1iM5L8HluJlUzn62Q+VeNV2tdA7MfPfMC
   8btGYladFAnitThaz6+F0VSBJPu7pZQoLnqyEp5zLMtF+kFl2yOBmGAP0RBivRd9
   JWBUCG0bqcLQPeQyjbXSOfUCAwEAAQ==
   -----END PUBLIC KEY-----"
   ```

**其中：**
   + `authorizer-function-arn` 值是您为自定义授权方创建的 Lambda 函数的 Amazon 资源名称（ARN）。
   + `token-signing-public-keys` 值包含密钥的名称、**FirstKey** 以及 `public-key.pem`文件的内容。请务必包含文件中的行以及 `-----BEGIN PUBLIC KEY-----`和 `-----END PUBLIC KEY-----`，并且不要从文件内容中添加或删除任何换行符、回车符或其它字符。

     注意：输入公有密钥时要非常小心，因为对公有密钥值的任何更改都会使其无法使用。

1. 如果创建了自定义授权方，则该命令将返回新资源的名称和 ARN，如下所示。

   ```
   {
       "authorizerName": "my-new-authorizer",
       "authorizerArn": "arn:aws:iot:Region:57EXAMPLE833:authorizer/my-new-authorizer"
   }
   ```

   保存 `authorizerArn` 值，以供下一步使用。

   请记住，每个自定义授权方资源必须具有唯一的名称。

### 授权自定义授权方资源
<a name="custom-auth-tutorial-authorizer-permission"></a>

在本节中，您将为您刚创建的自定义授权方资源授予运行 Lambda 函数的权限。要授予权限，您可以使用 [add-permission](https://docs.aws.amazon.com//cli/latest/reference/lambda/add-permission.html) CLI 命令。

**使用授予您的 Lambda 函数的权限 AWS CLI**

1. 插入您的值后，输入以下命令。请注意，`statement-id` 值必须唯一。如果您之前运行过本教程，或者如果您遇到了 `ResourceConflictException` 错误，请将 `Id-1234` 替换为另一个值。

   ```
   aws lambda add-permission  \
   --function-name "custom-auth-function" \
   --principal "iot.amazonaws.com" \
   --action "lambda:InvokeFunction" \
   --statement-id "Id-1234" \
   --source-arn authorizerArn
   ```

1. 如果命令成功，则返回一个权限语句，如本示例。您可以继续到下一部分来测试自定义授权方。

   ```
   {
       "Statement": "{\"Sid\":\"Id-1234\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"iot.amazonaws.com\"},\"Action\":\"lambda:InvokeFunction\",\"Resource\":\"arn:aws:lambda:Region:57EXAMPLE833:function:custom-auth-function\",\"Condition\":{\"ArnLike\":{\"AWS:SourceArn\":\"arn:aws:lambda:Region:57EXAMPLE833:function:custom-auth-function\"}}}"
   }
   ```

   如果命令不成功，则返回错误，如本示例。在继续操作之前，您需要查看并更正错误。

   ```
   An error occurred (AccessDeniedException) when calling the AddPermission operation: User: arn:aws:iam::57EXAMPLE833:user/EXAMPLE-1 is not authorized to perform: lambda:AddPer
   mission on resource: arn:aws:lambda:Region:57EXAMPLE833:function:custom-auth-function
   ```

## 步骤 4：通过调用来测试授权者 test-invoke-authorizer
<a name="custom-auth-tutorial-test"></a>

定义好所有资源后，在本节中，您将 test-invoke-authorizer从命令行调用以测试授权通行证。

请注意，在通过命令行调用授权方时，`protocolData` 并未定义，因此授权方将始终返回 DENY 文档。但是，此测试将确认您的自定义授权方和 Lambda 函数是否已正确配置，即使它并未完全测试 Lambda 函数。

**要测试您的自定义授权方及其 Lambda 函数，请使用 AWS CLI**

1. 在包含您在上一步中创建的 `private-key.pem` 文件的目录中，请运行以下命令。

   ```
   echo -n "tokenKeyValue" | openssl dgst -sha256 -sign private-key.pem | openssl base64 -A
   ```

   此命令将创建要在下一步中使用的签名字符串。签名字符串如下所示：

   ```
   dBwykzlb+fo+JmSGdwoGr8dyC2qB/IyLefJJr+rbCvmu9Jl4KHAA9DG+V+MMWu09YSA86+64Y3Gt4tOykpZqn9mn
   VB1wyxp+0bDZh8hmqUAUH3fwi3fPjBvCa4cwNuLQNqBZzbCvsluv7i2IMjEg+CPY0zrWt1jr9BikgGPDxWkjaeeh
   bQHHTo357TegKs9pP30Uf4TrxypNmFswA5k7QIc01n4bIyRTm90OyZ94R4bdJsHNig1JePgnuOBvMGCEFE09jGjj
   szEHfgAUAQIWXiVGQj16BU1xKpTGSiTAwheLKUjITOEXAMPLECK3aHKYKY+d1vTvdthKtYHBq8MjhzJ0kggbt29V
   QJCb8RilN/P5+vcVniSXWPplyB5jkYs9UvG08REoy64AtizfUhvSul/r/F3VV8ITtQp3aXiUtcspACi6ca+tsDuX
   f3LzCwQQF/YSUy02u5XkWn+sto6KCkpNlkD0wU8gl3+kOzxrthnQ8gEajd5Iylx230iqcXo3osjPha7JDyWM5o+K
   EWckTe91I1mokDr5sJ4JXixvnJTVSx1li49IalW4en1DAkc1a0s2U2UNm236EXAMPLELotyh7h+flFeloZlAWQFH
   xRlXsPqiVKS1ZIUClaZWprh/orDJplpiWfBgBIOgokJIDGP9gwhXIIk7zWrGmWpMK9o=
   ```

   复制此签名字符串以在下一步中使用。请注意，不要包含任何额外的字符或遗漏任何字符。

1. 在此命令中，将 `token-signature` 值替换为上一步中的签名字符串，并运行此命令来测试您的授权程序。

   ```
   aws iot test-invoke-authorizer \
   --authorizer-name my-new-authorizer \
   --token tokenKeyValue \
   --token-signature dBwykzlb+fo+JmSGdwoGr8dyC2qB/IyLefJJr+rbCvmu9Jl4KHAA9DG+V+MMWu09YSA86+64Y3Gt4tOykpZqn9mnVB1wyxp+0bDZh8hmqUAUH3fwi3fPjBvCa4cwNuLQNqBZzbCvsluv7i2IMjEg+CPY0zrWt1jr9BikgGPDxWkjaeehbQHHTo357TegKs9pP30Uf4TrxypNmFswA5k7QIc01n4bIyRTm90OyZ94R4bdJsHNig1JePgnuOBvMGCEFE09jGjjszEHfgAUAQIWXiVGQj16BU1xKpTGSiTAwheLKUjITOEXAMPLECK3aHKYKY+d1vTvdthKtYHBq8MjhzJ0kggbt29VQJCb8RilN/P5+vcVniSXWPplyB5jkYs9UvG08REoy64AtizfUhvSul/r/F3VV8ITtQp3aXiUtcspACi6ca+tsDuXf3LzCwQQF/YSUy02u5XkWn+sto6KCkpNlkD0wU8gl3+kOzxrthnQ8gEajd5Iylx230iqcXo3osjPha7JDyWM5o+KEWckTe91I1mokDr5sJ4JXixvnJTVSx1li49IalW4en1DAkc1a0s2U2UNm236EXAMPLELotyh7h+flFeloZlAWQFHxRlXsPqiVKS1ZIUClaZWprh/orDJplpiWfBgBIOgokJIDGP9gwhXIIk7zWrGmWpMK9o=
   ```

   如果命令成功，它将返回自定义授权方函数生成的信息，如此示例。

   ```
   {
       "isAuthenticated": true,
       "principalId": "principalId",
       "policyDocuments": [
           "{\"Version\":\"2012-10-17\",		 	 	 \"Statement\":[{\"Action\":\"iot:*\",\"Effect\":\"Deny\",\"Resource\":\"arn:aws:iot:Region:57EXAMPLE833:*\"}]}"
       ],
       "refreshAfterInSeconds": 600,
       "disconnectAfterInSeconds": 3600
   }
   ```

   如果命令返回错误，请查看错误并仔细检查您在本节中使用的命令。

## 步骤 5：测试使用 Postman 发布 MQTT 消息
<a name="custom-auth-tutorial-postman"></a>

1. 要从命令行获取设备数据端点，请如此处所示调用 [describe-endpoint](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/iot/describe-endpoint.html)

   ```
   aws iot describe-endpoint --output text --endpoint-type iot:Data-ATS
   ```

   保存此地址，以便*device\$1data\$1endpoint\$1address*在以后的步骤中使用。

1. 打开一个新的 Postman 窗口并创建一个新的 HTTP POST 请求。

   1. 在您的计算机中，打开 Postman 应用程序。

   1. 在 Postman 的 **File**（文件）菜单中，选择 **New…**（新建）。

   1. 在 **New**（新建）对话框中，选择 **Request**（请求）。

   1. 在“保存”请求中，

      1. 在 **Request name**（请求名称）中，输入 **Custom authorizer test request**。

      1. 在 **Select a collection or folder to save to:**（选择要保存到的收藏夹或文件夹：）中选择或创建要保存此请求的收藏夹。

      1. 选择 “**保存到” *collection\$1name***。

1. 创建 POST 请求以测试您的自定义授权方。

   1. 在 URL 字段旁边的请求方法选择器中，选择 **POST**。

   1. 在 URL 字段中，使用以下 URL 和上一步中的 desc [ribe-en *device\$1data\$1endpoint\$1address* dpoin](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/iot/describe-endpoint.html) t 命令来创建请求的网址。

      ```
      https://device_data_endpoint_address:443/topics/test/cust-auth/topic?qos=0&actionToken=allow
      ```

      请注意，此 URL 包含 `actionToken=allow` 查询参数，该参数将告诉您的 Lambda 函数返回允许访问 AWS IoT的策略文档。输入 URL 后，查询参数也会显示在 Postman 的 **Params**（参数）选项卡上。

   1. 在 **Auth**（身份验证）选项卡上的 **Type**（类型）字段中，选择 **No Auth**（无身份验证）。

   1. 在标头选项卡中：

      1. 如果选择了 **Host**（主机）密钥，请取消选中此项。

      1. 在标头列表的底部添加这些新标头并确认它们被选中。将该**Host**值替换为你的*device\$1data\$1endpoint\$1address*，将**x-amz-customauthorizer-signature**值替换为你在上一节中的**test-invoke-authorize**命令中使用的签名字符串。    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/iot/latest/developerguide/custom-auth-tutorial.html)

   1. 在“正文”选项卡中：

      1. 在数据格式选项框中，选择 **Raw**（原始）。

      1. 在数据类型列表中，选择**JavaScript**。

      1. 在文本字段中，为测试消息输入此 JSON 消息有效载荷：

         ```
         {
             "data_mode": "test",
             "vibration": 200,
             "temperature": 40
         }
         ```

1. 选择 **Send**（发送）以提交请求。

   如果请求成功，则返回：

   ```
   {
       "message": "OK",
       "traceId": "ff35c33f-409a-ea90-b06f-fbEXAMPLE25c"
   }
   ```

   成功的响应表示您的自定义授权方允许连接， AWS IoT 并且测试消息已传送给中 AWS IoT Core介服务器。

   如果它返回错误，请查看错误消息*device\$1data\$1endpoint\$1address*、、签名字符串和其他标头值。

将此请求保留在 Postman 中以供下一节使用。

## 步骤 6：在 MQTT 测试客户端中查看消息
<a name="custom-auth-tutorial-testclient"></a>

在上一步中，您使用 Postman 向发送 AWS IoT 了模拟设备消息。成功的响应表明您的自定义授权方允许与 AWS IoT 的连接并且测试消息已经传送到 AWS IoT Core中的代理处。在本节中，您将像其他设备和服务一样使用 AWS IoT 控制台中的 MQTT 测试客户端来查看该消息中的消息内容。

**要查看自定义授权方授权的测试消息**

1. 在 AWS IoT 控制台中，打开 [MQTT 测试客户端](https://console.aws.amazon.com//iot/home#/test)。

1. 在 **Subscribe to topic**（订阅主题）选项卡中的 **Topic filter**（主题筛选条件）中，输入 **test/cust-auth/topic**，这是前一节中 Postman 示例使用的消息主题。

1. 选择**订阅**。

   在下一步中，保持此窗口可见。

1. 在 Postman 中，在您为上一节创建的请求中，选择 **Send**（发送）。

   查看响应以确保响应成功。如果没有，请按照上一节所述对错误进行故障排除。

1. 在 **MQTT test client**（MQTT 测试客户端），您应该看到一个新条目，其中显示消息主题以及来自从 Postman 发送的请求（如果已展开）的消息有效载荷。

   如果您未在 **MQTT test client**（MQTT 测试客户端）中看到您的消息，可以检查以下事项：
   + 确保您的 Postman 请求成功返回。如果 AWS IoT 拒绝连接并返回错误，则请求中的消息不会传递给消息代理。
   + 确保 AWS 区域 用于打开 AWS IoT 控制台的 AWS 账户 和与你在 Postman URL 中使用的和相同。
   + 确保您为自定义授权方使用了适当的端点。默认的物联网端点可能不支持将自定义授权方与 Lambda 函数一起使用。相反，您可以使用域配置来定义新端点，然后为该自定义授权方指定该端点。
   + 请确保您已在 **MQTT test client**（MQTT 测试客户端）中正确输入主题。主题筛选条件区分大小写。如有疑问，您也可以订阅该**\$1**主题，该主题将订阅通过消息代理 AWS 账户 并 AWS 区域 用于打开控制台的所有 MQTT 消息。 AWS IoT 

## 步骤 7：查看结果和后续步骤
<a name="custom-auth-tutorial-review"></a>

**在本教程中：**
+ 您创建了一个 Lambda 函数作为自定义授权方处理程序
+ 您创建了启用令牌签名的自定义授权方
+ 您使用 **test-invoke-authorizer** 命令测试了自定义授权方
+ 您使用 [Postman](https://www.postman.com/) 发布了一个 MQTT 主题通过并使用您的自定义授权方验证请求
+ 您使用了 **MQTT test client**（MQTT 测试客户端）查看 Postman 测试发送的消息

**后续步骤**  
从 Postman 发送一些消息以验证自定义授权方是否正常工作后，请尝试试验以了解更改本教程的不同方面会对结果产生何种影响。以下是一些入门示例。
+ 更改签名字符串，使其不再有权查看未经授权的连接尝试的处理方式。您应该得到一个错误响应，如此所示，并且该消息不应出现在 **MQTT test client**（MQTT 测试客户端）中。

  ```
  {
      "message": "Forbidden",
      "traceId": "15969756-a4a4-917c-b47a-5433e25b1356"
  }
  ```
+ 要详细了解如何查找在开发和使用 AWS IoT 规则时可能出现的错误，请参阅[监控 AWS IoT](monitoring_overview.md)。

## 步骤 8：清除
<a name="custom-auth-tutorial-cleanup"></a>

如果您想重复本教程，可能需要删除一些自定义授权方。您 AWS 账户 一次只能配置有限数量的自定义授权方，当您尝试在不删除现有自定义授权方的情况下添加新的自定义授权方`LimitExceededException`时，可以获得。

**要删除自定义授权方（控制台）**

1. 打开[AWS IoT 控制台的自定义授权者页面](https://console.aws.amazon.com//iot/home#/authorizerhub)，在自定义授权者列表中，找到要移除的自定义授权者。

1. 打开“自定义授权方详细信息”页面，然后从 **Actions**（操作）菜单中，选择 **Edit**（编辑）。

1. 取消选中 **Activate authorizer**（激活授权方），然后选择 **Update**（更新）。

   您无法在自定义授权方处于活动状态时将其删除。

1. 在“自定义授权方详细信息”页面，打开 **Actions**（操作）菜单，然后选择 **Delete**（删除）。

**要删除自定义授权方 (AWS CLI)**

1. 列出您已安装的自定义授权方，并查找要删除的自定义授权方的名称。

   ```
   aws iot list-authorizers 
   ```

1. 在将 `Custom_Auth_Name` 替换为要删除的自定义授权方的 `authorizerName` 后，运行此命令，以将自定义授权方设置为 `inactive`。

   ```
   aws iot update-authorizer --status INACTIVE --authorizer-name Custom_Auth_Name
   ```

1. 在将 `Custom_Auth_Name` 替换为要删除的自定义授权方的 `authorizerName` 后，运行此命令，以删除自定义授权方。

   ```
   aws iot delete-authorizer --authorizer-name Custom_Auth_Name
   ```

# 教程：使用 AWS IoT 和 Raspberry Pi 监测土壤湿度
<a name="iot-moisture-tutorial"></a>

本教程向您展示如何使用 [Raspberry Pi](https://www.raspberrypi.org/)、湿度传感器，以及 AWS IoT 如何监测室内植物或花园的土壤湿度水平。Raspberry Pi 运行的代码从传感器读取湿度和温度，然后将数据发送到 AWS IoT。您可以在中创建一条规则 AWS IoT ，当水分含量低于阈值时，向订阅了 Amazon SNS 主题的地址发送一封电子邮件。

**注意**  
本教程可能不是最新版本。自本主题最初发布以来，一些参考文献可能已被取代。

**Contents**
+ [先决条件](#iot-moisture-prereqs)
+ [设置 AWS IoT](iot-moisture-setup.md)
  + [步骤 1：创建 AWS IoT 策略](iot-moisture-policy.md)
  + [第 2 步：创建 AWS IoT 事物、证书和私钥](iot-moisture-create-thing.md)
  + [步骤 3：创建 Amazon SNS 主题和订阅](iot-moisture-create-sns-topic.md)
  + [步骤 4：创建发送电子邮件的 AWS IoT 规则](iot-moisture-create-rule.md)
+ [设置您的 Raspberry Pi 和含水量传感器](iot-moisture-raspi-setup.md)

## 先决条件
<a name="iot-moisture-prereqs"></a>

要完成此教程，需要：
+ 一个 AWS 账户。
+ 具有管理员权限的 IAM 用户。
+ 运行 Windows、macOS、Linux 或 Unix 的开发计算机（用于访问 [AWS IoT 控制台](https://console.aws.amazon.com/iot/home)）。
+ 运行最新 [Raspberry Pi OS](https://www.raspberrypi.com/software/operating-systems/) 的 [Raspberry Pi 3B 或 4B](https://www.raspberrypi.com/products/)。有关安装说明，请参阅 Raspberry Pi 网站上的[安装操作系统](https://www.raspberrypi.com/documentation/computers/getting-started.html#installing-the-operating-system)。
+ 用于 Raspberry Pi 的显示器、键盘、鼠标和 Wi-Fi 网络或以太网连接。
+ 与 Raspberry Pi 兼容的含水量传感器。本教程中使用的传感器是 [Adafruit STEMMA I2C 电容式含水量传感器](https://www.adafruit.com/product/4026)，带有 [JST 4 针转母插座电缆接头](https://www.adafruit.com/product/3950)。

# 设置 AWS IoT
<a name="iot-moisture-setup"></a>

要完成本教程，您需要创建以下资源。要将设备连接到 AWS IoT，您需要创建物联网事物、设备证书和 AWS IoT 策略。
+ 一 AWS IoT 件事。

  事物代表物理设备（在本例中为 Raspberry Pi），包括有关该设备的静态元数据。
+ 设备证书。

  所有设备都必须拥有设备证书才能连接到 AWS IoT和通过其身份验证。
+ 一项 AWS IoT 政策。

  每个设备证书都有一个或多个与之关联的 AWS IoT 策略。这些策略决定了设备可以访问哪些 AWS IoT 资源。
+  AWS IoT 根 CA 证书。

  设备和其他客户端使用 AWS IoT 根 CA 证书对与之通信的 AWS IoT 服务器进行身份验证。有关更多信息，请参阅 [服务器身份验证](server-authentication.md)。
+ 一条 AWS IoT 规则。

  规则包含查询和一个或多个规则操作。查询从设备消息中提取数据，以确定是否应处理该消息数据。规则操作指定当数据与查询匹配时该做些什么。
+ 创建 Amazon SNS 主题和主题订阅。

  该规则侦听来自 Raspberry Pi 的含水量数据。如果该值低于阈值，它会向 Amazon SNS 主题发送消息。Amazon SNS 会将该消息发送到订阅该主题的所有电子邮件地址。

 



# 步骤 1：创建 AWS IoT 策略
<a name="iot-moisture-policy"></a>

创建允许你的 Raspberry Pi 连接和向其发送消息的 AWS IoT 策略 AWS IoT。

1. 在 [AWS IoT 控制台](https://console.aws.amazon.com/iot)中，如果显示**开始使用**按钮，请选择该按钮。否则，请在导航窗格中展开 **Secure**（安全），然后选择 **Policies**（策略）。

1. 如果显示**您还没有任何策略**对话框，请选择**创建策略**。否则，选择**创建**。

1. 输入 AWS IoT 策略的名称（例如，**MoistureSensorPolicy**）。

1. 在**添加声明**部分中，将现有策略替换为以下 JSON。*account*用你*region*的 and AWS 账户 编号替换 AWS 区域 和。  
****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": "iot:Connect",
               "Resource": "arn:aws:iot:us-east-1:123456789012:client/RaspberryPi"
           },
           {
               "Effect": "Allow",
               "Action": "iot:Publish",
               "Resource": [
                   "arn:aws:iot:us-east-1:123456789012:topic/$aws/things/RaspberryPi/shadow/update",
                   "arn:aws:iot:us-east-1:123456789012:topic/$aws/things/RaspberryPi/shadow/delete",
                   "arn:aws:iot:us-east-1:123456789012:topic/$aws/things/RaspberryPi/shadow/get"
               ]
           },
           {
               "Effect": "Allow",
               "Action": "iot:Receive",
               "Resource": [
                   "arn:aws:iot:us-east-1:123456789012:topic/$aws/things/RaspberryPi/shadow/update/accepted",
                   "arn:aws:iot:us-east-1:123456789012:topic/$aws/things/RaspberryPi/shadow/delete/accepted",
                   "arn:aws:iot:us-east-1:123456789012:topic/$aws/things/RaspberryPi/shadow/get/accepted",
                   "arn:aws:iot:us-east-1:123456789012:topic/$aws/things/RaspberryPi/shadow/update/rejected",
                   "arn:aws:iot:us-east-1:123456789012:topic/$aws/things/RaspberryPi/shadow/delete/rejected"
               ]
           },
           {
               "Effect": "Allow",
               "Action": "iot:Subscribe",
               "Resource": [
                   "arn:aws:iot:us-east-1:123456789012:topicfilter/$aws/things/RaspberryPi/shadow/update/accepted",
                   "arn:aws:iot:us-east-1:123456789012:topicfilter/$aws/things/RaspberryPi/shadow/delete/accepted",
                   "arn:aws:iot:us-east-1:123456789012:topicfilter/$aws/things/RaspberryPi/shadow/get/accepted",
                   "arn:aws:iot:us-east-1:123456789012:topicfilter/$aws/things/RaspberryPi/shadow/update/rejected",
                   "arn:aws:iot:us-east-1:123456789012:topicfilter/$aws/things/RaspberryPi/shadow/delete/rejected"
               ]
           },
           {
               "Effect": "Allow",
               "Action": [
                   "iot:GetThingShadow",
                   "iot:UpdateThingShadow",
                   "iot:DeleteThingShadow"
               ],
               "Resource": "arn:aws:iot:us-east-1:123456789012:thing/RaspberryPi"
           }
       ]
   }
   ```

1. 选择**创建**。

# 第 2 步：创建 AWS IoT 事物、证书和私钥
<a name="iot-moisture-create-thing"></a>

在 AWS IoT 注册表中创建一个代表你的 Raspberry Pi 的东西。

1. 在 [AWS IoT 控制台](https://console.aws.amazon.com/iot/home)的导航窗格中，依次选择**管理**和**事物**。

1. 如果显示**您还没有任何事物**对话框，请选择**注册事物**。否则，选择**创建**。

1. 在**创建 AWS IoT 事物**页面上，选择**创建单个事物**。

1. 在**将您的设备添加到设备注册表** 页面上，输入您的物联网事物的名称（例如 **RaspberryPi**），然后选择**下一步**。您无法在创建事物后更改其名称。要更改事物的名称，您必须创建一个新事物，为其指定新名称，然后删除旧事物。

1. 在**添加事物的证书**页面上，选择**创建证书**。

1. 选择**下载**链接以下载证书、私有密钥和根 CA 证书。
**重要**  
这是您下载证书和私有密钥的唯一机会。

1. 选择 **Activate**（激活）来激活您的证书。证书必须处于活动状态，设备才能连接到 AWS IoT。

1. 选择**附加策略**。

1. 在 “**为您的事物添加策略**” 中，选择 **MoistureSensorPolicy**，然后选择 “**注册事物**”。

# 步骤 3：创建 Amazon SNS 主题和订阅
<a name="iot-moisture-create-sns-topic"></a>

创建 Amazon SNS 主题和订阅。

1. 从 [AWS SNS 控制台](https://console.aws.amazon.com/sns/home)的导航窗格中，选择 **Topics**（主题），然后选择 **Create topic**（创建主题）。

1. 选择**标准**作为类型，然后输入主题的名称（例如 **MoistureSensorTopic**）。

1. 输入主题的显示名称（例如，**Moisture Sensor Topic**）。这是在 Amazon SNS 控制台中为您的主题显示的名称。

1. 选择**创建主题**。

1. 在 Amazon SNS 主题详细信息页面上，选择 **Create subscription**（创建订阅）。

1. 对于**协议**，选择**电子邮件**。

1. 对于**端点**，输入您的电子邮件地址。

1. 选择**创建订阅**。

1. 打开您的电子邮件客户端，查找主题为 **MoistureSensorTopic** 的消息。打开这封电子邮件，然后单击**确认订阅**链接。
**重要**  
在确认订阅之前，您不会收到来自该 Amazon SNS 主题的任何电子邮件告警。

您应该会收到一封电子邮件，其中包含您输入的文本。

# 步骤 4：创建发送电子邮件的 AWS IoT 规则
<a name="iot-moisture-create-rule"></a>

 AWS IoT 规则定义了从设备收到消息时要执行的查询和一项或多项操作。 AWS IoT 规则引擎监听设备发送的消息，并使用消息中的数据来确定是否应采取某些措施。有关更多信息，请参阅 [的规则 AWS IoT](iot-rules.md)。

在本教程中，您的 Raspberry Pi 在 `aws/things/RaspberryPi/shadow/update` 上发布消息。这是设备和 Thing Shadow 服务使用的内部 MQTT 主题。Raspberry Pi 发布具有以下形式的消息：

```
{
    "reported": {
        "moisture" : moisture-reading,
        "temp" : temperature-reading
    }
}
```

创建查询来从传入消息中提取含水量和温度数据。创建 Amazon SNS 操作来在含水量读数低于阈值时获取数据并将其发送给 Amazon SNS 主题订阅者。

**创建 Amazon SNS 规则**

1. 在 [AWS IoT 控制台](https://console.aws.amazon.com/iot/home)中，选择**消息路由**，然后选择**规则**。如果显示**您还没有任何规则**对话框，请选择**创建规则**。否则，请选择**创建规则**。

1. 在**规则属性**页面中，输入**规则名称**（例如 **MoistureSensorRule**），并提供简短的**规则描述**（例如 **Sends an alert when soil moisture level readings are too low**）。

1. 选择**下一步**并配置您的 SQL 语句。选择 **SQL 版本**为 **2016-03-23**，然后输入以下 AWS IoT SQL 查询语句：

   ```
   SELECT * FROM '$aws/things/RaspberryPi/shadow/update/accepted' WHERE state.reported.moisture < 400
   ```

   当 `moisture`读数小于 `400`时，该语句将触发规则操作。
**注意**  
您可能需要使用其它值。在 Raspberry Pi 上运行代码之后，您可以通过触摸传感器、将其放入水中或放入花盆中来查看从传感器获得的值。

1. 选择**下一步**并附加规则操作。对于**操作 1**，选择 **Simple Notification Service**。此规则操作的描述为**将消息作为 SNS 推送通知发送**。

1. 对于 **SNS 主题**，请选择您在[步骤 3：创建 Amazon SNS 主题和订阅](iot-moisture-create-sns-topic.md)、中创建的主题 **MoistureSensorTopic**，并将**消息格式**保留为 **RAW**。对于 **IAM 角色**，选择**创建新角色**。输入角色的名称（例如 **LowMoistureTopicRole**），然后选择**创建角色**。

1. 选择**下一步**进行查看，然后选择**创建**来创建规则。

# 设置您的 Raspberry Pi 和含水量传感器
<a name="iot-moisture-raspi-setup"></a>



将 Micro SD 卡插入 Raspberry Pi 中，连接显示器、键盘、鼠标以及以太网电缆（如果您未使用 Wi-Fi）。先不要连接电源线。

将 JST 跳线连接到含水量传感器。跳线的另一端有四根电线：
+ 绿色：I2C SCL
+ 白色：I2C SDA
+ 红色：电源 (3.5 V)
+ 黑色：接地

握住 Raspberry Pi（以太网插孔位于右侧）。以该方向握持时，可看到顶部有两排 GPIO 引脚。按照以下顺序将含水量传感器的电线连接到下排引脚。从最左侧的引脚开始，连接红色（电源）、白色（SDA）和绿色（SCL）电线。跳过一个引脚，然后连接黑色（接地）电线。有关更多信息，请参阅 [Python 计算机接线](https://learn.adafruit.com/adafruit-stemma-soil-sensor-i2c-capacitive-moisture-sensor/python-circuitpython-test)。

将电源线连接到 Raspberry Pi，然后将另一端插入墙壁插座以将其打开。

**配置您的 Raspberry Pi**

1. 在**欢迎使用 Raspberry Pi**页面上，选择**下一步**。

1. 选择您的国家/地区、语言、时区和键盘布局。选择**下一步**。

1. 输入 Raspberry Pi 的密码，然后选择**下一步**。

1. 选择您的 Wi-Fi 网络，然后选择**下一步**。如果不使用 Wi-Fi 网络，则选择**跳过**。

1. 选择**下一步**检查软件更新。完成更新后，选择**重启**以重启您的 Raspberry Pi。

在 Raspberry Pi 启动后，启用 I2C 接口。

1. 在 Raspbian 桌面的左上角，单击 Raspberry 图标，选择**首选项**，然后选择 **Raspberry Pi 配置**。

1. 在**接口**选项卡上，对于 **I2C**，选择**启用**。

1. 选择**确定**。

Adafruit STEMMA 湿度传感器的库是为之编写的。 CircuitPython要在 Raspberry Pi 上运行它们，需要安装最新版本的 Python 3。

1. 在命令提示符中运行以下命令来更新 Raspberry Pi 软件：

   `sudo apt-get update`

   `sudo apt-get upgrade`

1. 运行以下命令，更新您的 Python 3 安装：

   `sudo pip3 install --upgrade setuptools`

1. 运行以下命令，安装 Raspberry Pi GPIO 库：

   `pip3 install RPI.GPIO`

1. 运行以下命令，安装 Adafruit Blinka 库：

   `pip3 install adafruit-blinka`

   有关更多信息，请参阅[在 Raspberry Pi 上安装 CircuitPython 库](https://learn.adafruit.com/circuitpython-on-raspberrypi-linux/installing-circuitpython-on-raspberry-pi)。

1. 运行以下命令，安装 Adafruit Seesaw 库：

   `sudo pip3 install adafruit-circuitpython-seesaw`

1. 运行以下命令安装适用于 Python 的 AWS IoT 设备 SDK：

   `pip3 install AWSIoTPythonSDK`

Raspberry Pi 现已具备所有必需的库。创建一个名为 **moistureSensor.py** 的文件，并将以下 Python 代码复制到该文件中：

```
from adafruit_seesaw.seesaw import Seesaw
from AWSIoTPythonSDK.MQTTLib import AWSIoTMQTTShadowClient
from board import SCL, SDA

import logging
import time
import json
import argparse
import busio

# Shadow JSON schema:
#
# {
#   "state": {
#       "desired":{
#           "moisture":<INT VALUE>,
#           "temp":<INT VALUE>            
#       }
#   }
# }

# Function called when a shadow is updated
def customShadowCallback_Update(payload, responseStatus, token):

    # Display status and data from update request
    if responseStatus == "timeout":
        print("Update request " + token + " time out!")

    if responseStatus == "accepted":
        payloadDict = json.loads(payload)
        print("~~~~~~~~~~~~~~~~~~~~~~~")
        print("Update request with token: " + token + " accepted!")
        print("moisture: " + str(payloadDict["state"]["reported"]["moisture"]))
        print("temperature: " + str(payloadDict["state"]["reported"]["temp"]))
        print("~~~~~~~~~~~~~~~~~~~~~~~\n\n")

    if responseStatus == "rejected":
        print("Update request " + token + " rejected!")

# Function called when a shadow is deleted
def customShadowCallback_Delete(payload, responseStatus, token):

     # Display status and data from delete request
    if responseStatus == "timeout":
        print("Delete request " + token + " time out!")

    if responseStatus == "accepted":
        print("~~~~~~~~~~~~~~~~~~~~~~~")
        print("Delete request with token: " + token + " accepted!")
        print("~~~~~~~~~~~~~~~~~~~~~~~\n\n")

    if responseStatus == "rejected":
        print("Delete request " + token + " rejected!")


# Read in command-line parameters
def parseArgs():

    parser = argparse.ArgumentParser()
    parser.add_argument("-e", "--endpoint", action="store", required=True, dest="host", help="Your device data endpoint")
    parser.add_argument("-r", "--rootCA", action="store", required=True, dest="rootCAPath", help="Root CA file path")
    parser.add_argument("-c", "--cert", action="store", dest="certificatePath", help="Certificate file path")
    parser.add_argument("-k", "--key", action="store", dest="privateKeyPath", help="Private key file path")
    parser.add_argument("-p", "--port", action="store", dest="port", type=int, help="Port number override")
    parser.add_argument("-n", "--thingName", action="store", dest="thingName", default="Bot", help="Targeted thing name")
    parser.add_argument("-id", "--clientId", action="store", dest="clientId", default="basicShadowUpdater", help="Targeted client id")

    args = parser.parse_args()
    return args


# Configure logging
# AWSIoTMQTTShadowClient writes data to the log
def configureLogging():

    logger = logging.getLogger("AWSIoTPythonSDK.core")
    logger.setLevel(logging.DEBUG)
    streamHandler = logging.StreamHandler()
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    streamHandler.setFormatter(formatter)
    logger.addHandler(streamHandler)


# Parse command line arguments
args = parseArgs()

if not args.certificatePath or not args.privateKeyPath:
    parser.error("Missing credentials for authentication.")
    exit(2)

# If no --port argument is passed, default to 8883
if not args.port: 
    args.port = 8883


# Init AWSIoTMQTTShadowClient
myAWSIoTMQTTShadowClient = None
myAWSIoTMQTTShadowClient = AWSIoTMQTTShadowClient(args.clientId)
myAWSIoTMQTTShadowClient.configureEndpoint(args.host, args.port)
myAWSIoTMQTTShadowClient.configureCredentials(args.rootCAPath, args.privateKeyPath, args.certificatePath)

# AWSIoTMQTTShadowClient connection configuration
myAWSIoTMQTTShadowClient.configureAutoReconnectBackoffTime(1, 32, 20)
myAWSIoTMQTTShadowClient.configureConnectDisconnectTimeout(10) # 10 sec
myAWSIoTMQTTShadowClient.configureMQTTOperationTimeout(5) # 5 sec

# Initialize Raspberry Pi's I2C interface
i2c_bus = busio.I2C(SCL, SDA)

# Intialize SeeSaw, Adafruit's Circuit Python library
ss = Seesaw(i2c_bus, addr=0x36)

# Connect to AWS IoT
myAWSIoTMQTTShadowClient.connect()

# Create a device shadow handler, use this to update and delete shadow document
deviceShadowHandler = myAWSIoTMQTTShadowClient.createShadowHandlerWithName(args.thingName, True)

# Delete current shadow JSON doc
deviceShadowHandler.shadowDelete(customShadowCallback_Delete, 5)

# Read data from moisture sensor and update shadow
while True:

    # read moisture level through capacitive touch pad
    moistureLevel = ss.moisture_read()

    # read temperature from the temperature sensor
    temp = ss.get_temp()

    # Display moisture and temp readings
    print("Moisture Level: {}".format(moistureLevel))
    print("Temperature: {}".format(temp))
    
    # Create message payload
    payload = {"state":{"reported":{"moisture":str(moistureLevel),"temp":str(temp)}}}

    # Update shadow
    deviceShadowHandler.shadowUpdate(json.dumps(payload), customShadowCallback_Update, 5)
    time.sleep(1)
```

将文件保存到您可以找到的位置。在命令行中运行 `moistureSensor.py` 及以下参数：

端点  
您的自定义 AWS IoT 终端节点。有关更多信息，请参阅 [Device Shadow REST API](device-shadow-rest-api.md)。

rootCA  
您的 AWS IoT 根 CA 证书的完整路径。

cert  
 AWS IoT 设备证书的完整路径。

键  
 AWS IoT 设备证书私钥的完整路径。

thingName  
您的事物的名称（在本例中为 `RaspberryPi`）。

clientId  
MQTT 客户端 ID。使用 `RaspberryPi`。

命令行应如下所示：

`python3 moistureSensor.py --endpoint your-endpoint --rootCA ~/certs/AmazonRootCA1.pem --cert ~/certs/raspberrypi-certificate.pem.crt --key ~/certs/raspberrypi-private.pem.key --thingName RaspberryPi --clientId RaspberryPi`

尝试触摸传感器、将其放入花盆或放入一杯水中，查看传感器对各种含水量有何反应。如果需要，可以在 `MoistureSensorRule` 中更改阈值。当湿度传感器的读数低于规则的 SQL 查询语句中指定的值时，会向 Amazon SNS 主题 AWS IoT 发布一条消息。您应会收到一封包含含水量和温度数据的电子邮件。

确认收到来自 Amazon SNS 的电子邮件后，按 **CTRL \$1 C** 停止 Python 程序。该 Python 程序发送的消息应该不足以产生费用，但完成后最好将其停止。