

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

# 教程：开发可延迟组件更新的 Greengrass 组件
<a name="defer-component-updates-tutorial"></a>

您可以完成本教程来开发延迟 over-the-air部署更新的组件。在将更新部署到设备时，您可能需要根据条件延迟更新，例如：
+ 设备的电池电量不足。
+ 设备正在运行无法中断的进程或作业。
+ 设备的互联网连接有限或昂贵。

**注意**  
*组件*是在 AWS IoT Greengrass 核心设备上运行的软件模块。您可以利用这些组件创建和管理复杂的应用程序，并将其作为离散构建基块在不同的 Greengrass 核心设备之间重复使用。

在本教程中，您将执行以下操作：

1. 在开发计算机上安装 Greengrass Development Kit CLI（GDK CLI）。GDK CLI 提供的功能可帮助您开发自定义 Greengrass 组件。

1. 开发 Hello World 组件，当核心设备的电池电量低于阈值时，该组件会延迟组件更新。此组件使用 [SubscribeToComponentUpdates](ipc-component-lifecycle.md#ipc-operation-subscribetocomponentupdates)IPC 操作订阅更新通知。收到通知时，它会检查电池电量是否低于可自定义的阈值。如果电池电量低于阈值，它会使用 [DeferComponentUpdate](ipc-component-lifecycle.md#ipc-operation-defercomponentupdate)IPC 操作将更新推迟 30 秒。您可以使用 GDK CLI 在开发计算机上开发此组件。
**注意**  
该组件从您在核心设备上创建的文件中读取电池电量，以模仿真实的电池，因此您可以在没有电池的核心设备上完成本教程。

1. 将该组件发布到 AWS IoT Greengrass 服务。

1. 将该组件从部署 AWS 云 到 Greengrass 核心设备上进行测试。然后，您可以修改核心设备上的虚拟电池电量，并创建其他部署，以查看当电池电量不足时，核心设备如何推迟更新。

您预计需要花费 20-30 分钟来完成本教程。

# 先决条件
<a name="defer-component-updates-tutorial-prerequisites"></a>

要完成本教程，您需要：
+ AWS 账户。如果没有，请参阅[设置一个 AWS 账户](setting-up.md#set-up-aws-account)。
+ 具有管理员权限的 AWS Identity and Access Management（IAM）用户。
+ 支持互联网连接的 Greengrass 核心设备。有关如何设置核心设备的更多信息，请参阅[设置 AWS IoT Greengrass 核心设备](setting-up.md)。
  + [Python](https://www.python.org/downloads/) 3.6 或更高版本已为所有用户安装在核心设备上，并已添加到 `PATH` 环境变量中。在 Windows 上，您还必须为所有用户安装适用于 Windows 的 Python 启动程序。
**重要**  <a name="windows-core-device-python-installation"></a>
在 Windows 中，默认情况下不会为所有用户安装 Python。安装 Python 时，您必须自定义安装以对其进行配置，以便 AWS IoT Greengrass 软件运行 Python 脚本。例如，如果您使用图形化 Python 安装程序，则执行以下操作：  
选择**为所有用户安装启动程序（推荐）**。
选择 **Customize installation**。
选择 **Next**。
选择 **Install for all users**。
选择 **Add Python to environment variables**。
选择**安装**。
有关更多信息，请参阅 [Python 3 文档](https://docs.python.org/3/using/windows.html)中的*在 Windows 上使用 Python*。
+ 支持互联网连接的 Windows、macOS 或类 Unix 的开发计算机。
  + 开发计算机上已安装 [Python 3.6](https://www.python.org/downloads/) 或更高版本。
  + 开发计算机上已安装 [Git](https://git-scm.com/)。
  + <a name="development-component-aws-cli-prerequisite"></a>开发计算机上已安装AWS Command Line Interface（AWS CLI）并使用凭证进行配置。有关更多信息，请参阅《AWS Command Line Interface 用户指南》中的[安装、更新和卸载 AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html) 以及[配置 AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html)。**
**注意**  
如果您使用 Raspberry Pi 或其他 32 位 ARM 设备，请安装 AWS CLI V1。AWS CLIV2 不适用于 32 位 ARM 设备。有关更多信息，请参阅[安装、更新和卸载 AWS CLI 版本 1](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv1.html)。

# 第 1 步：安装 Greengrass 开发工具包 CLI
<a name="install-gdk-cli-defer-updates"></a>

[Greengrass 开发工具包 CLI（GDK CLI）](greengrass-development-kit-cli.md)提供的功能可帮助您开发自定义 Greengrass组件。您可以使用 GDK CLI 来创建、构建和发布自定义组件。

如果您尚未在开发计算机上安装 GDK CLI，请完成以下步骤进行安装。

**安装最新版本 GDK CLI**

1. 在开发计算机上，运行以下命令，从 [GitHub 存储库](https://github.com/aws-greengrass/aws-greengrass-gdk-cli)安装最新版本 GDK CLI。

   ```
   python3 -m pip install -U git+https://github.com/aws-greengrass/aws-greengrass-gdk-cli.git@v1.6.2
   ```

1. <a name="gdk-cli-verify-installation"></a>运行以下命令验证是否已成功安装 GDK CLI。

   ```
   gdk --help
   ```

   如果未找到 `gdk` 命令，请将其文件夹添加到 PATH。
   + 在 Linux 设备上，将 `/home/MyUser/.local/bin` 添加到 PATH，然后将 *MyUser* 替换为您的用户名。
   + 在 Windows 设备上，将 `PythonPath\\Scripts` 添加到 PATH，然后将 *PythonPath* 替换为设备上 Python 文件夹的路径。

# 步骤 2：开发可延迟更新的组件
<a name="develop-component-defer-updates"></a>

在本节中，您将在 Python 中开发一个 Hello World 组件，当核心设备的电池电量低于您在部署组件时配置的阈值时，该组件会延迟组件更新。在此组件中，您将使用 AWS IoT Device SDK 适用于 Python 的 v2 中的[进程间通信 (IPC) 接口](interprocess-communication.md)。当核心设备收到部署时，您可以使用 [SubscribeToComponentUpdates](ipc-component-lifecycle.md#ipc-operation-subscribetocomponentupdates)IPC 操作接收通知。然后，您可以根据设备的电池电量使用 [DeferComponentUpdate](ipc-component-lifecycle.md#ipc-operation-defercomponentupdate)IPC 操作来推迟或确认更新。

**要开发可延迟更新的 Hello World 组件，请执行以下步骤：**

1. 在开发计算机上，为组件源代码创建一个文件夹。

   ```
   mkdir com.example.BatteryAwareHelloWorld
   cd com.example.BatteryAwareHelloWorld
   ```

1. 使用文本编辑器创建名为 `gdk-config.json` 的文件。GDK CLI 从名为 `gdk-config.json` 的 [GDK CLI 配置文件](gdk-cli-configuration-file.md)中读取数据，以生成和发布组件。此配置文件存在于组件文件夹的根目录中。

   <a name="nano-command-intro"></a>例如，在基于 Linux 的系统上，您可以运行以下命令来使用 GNU nano 创建该文件。

   ```
   nano gdk-config.json
   ```

   将以下 JSON 复制到该文件中。
   + *Amazon*用你的名字替换。
   + *us-west-2*替换为核心设备的运行 AWS 区域 位置。GDK CLI 将在此 AWS 区域发布该组件。
   + *greengrass-component-artifacts*替换为要使用的 S3 存储桶前缀。当您使用 GDK CLI 发布组件时，GDK CLI 会使用以下格式将组件的项目上传到 S3 存储桶，其名称由此值 AWS 区域、和您的 AWS 账户 ID 组成：。`bucketPrefix-region-accountId`

     例如，如果您指定**greengrass-component-artifacts**和，且您的 AWS 账户 ID 为 **us-west-2****123456789012**，则 GDK CLI 将使用名为`greengrass-component-artifacts-us-west-2-123456789012`的 S3 存储桶。

   ```
   {
     "component": {
       "com.example.BatteryAwareHelloWorld": {
         "author": "Amazon",
         "version": "NEXT_PATCH",
         "build": {
           "build_system" : "zip"
         },
         "publish": {
           "region": "us-west-2",
           "bucket": "greengrass-component-artifacts"
         }
       }
     },
     "gdk_version": "1.0.0"
   }
   ```

   配置文件可指定以下内容：
   + GDK CLI 将 Greengrass 组件发布到云服务时要使用的版本。 AWS IoT Greengrass `NEXT_PATCH`指定在 AWS IoT Greengrass 云服务中可用的最新版本之后选择下一个补丁版本。如果组件在 AWS IoT Greengrass 云服务中还没有版本，GDK CLI 会使用`1.0.0`。
   + 组件生成系统。当您使用 `zip` 生成系统时，GDK CLI 会将组件的源代码打包成一个 ZIP 文件，该文件将成为该组件的单个构件。
   + GDK CLI AWS 区域 在那里发布 Greengrass 组件。
   + GDK CLI 上传组件构件的 S3 存储桶前缀。

1. 使用文本编辑器在名为 `main.py` 的文件中创建组件源代码。

   <a name="nano-command-intro"></a>例如，在基于 Linux 的系统上，您可以运行以下命令来使用 GNU nano 创建该文件。

   ```
   nano main.py
   ```

   将以下 Python 代码复制到该文件中。

   ```
   import json
   import os
   import sys
   import time
   import traceback
   
   from pathlib import Path
   
   from awsiot.greengrasscoreipc.clientv2 import GreengrassCoreIPCClientV2
   
   HELLO_WORLD_PRINT_INTERVAL = 15  # Seconds
   DEFER_COMPONENT_UPDATE_INTERVAL = 30 * 1000  # Milliseconds
   
   
   class BatteryAwareHelloWorldPrinter():
       def __init__(self, ipc_client: GreengrassCoreIPCClientV2, battery_file_path: Path, battery_threshold: float):
           self.battery_file_path = battery_file_path
           self.battery_threshold = battery_threshold
           self.ipc_client = ipc_client
           self.subscription_operation = None
   
       def on_component_update_event(self, event):
           try:
               if event.pre_update_event is not None:
                   if self.is_battery_below_threshold():
                       self.defer_update(event.pre_update_event.deployment_id)
                       print('Deferred update for deployment %s' %
                             event.pre_update_event.deployment_id)
                   else:
                       self.acknowledge_update(
                           event.pre_update_event.deployment_id)
                       print('Acknowledged update for deployment %s' %
                             event.pre_update_event.deployment_id)
               elif event.post_update_event is not None:
                   print('Applied update for deployment')
           except:
               traceback.print_exc()
   
       def subscribe_to_component_updates(self):
           if self.subscription_operation == None:
               # SubscribeToComponentUpdates returns a tuple with the response and the operation.
               _, self.subscription_operation = self.ipc_client.subscribe_to_component_updates(
                   on_stream_event=self.on_component_update_event)
   
       def close_subscription(self):
           if self.subscription_operation is not None:
               self.subscription_operation.close()
               self.subscription_operation = None
   
       def defer_update(self, deployment_id):
           self.ipc_client.defer_component_update(
               deployment_id=deployment_id, recheck_after_ms=DEFER_COMPONENT_UPDATE_INTERVAL)
   
       def acknowledge_update(self, deployment_id):
           # Specify recheck_after_ms=0 to acknowledge a component update.
           self.ipc_client.defer_component_update(
               deployment_id=deployment_id, recheck_after_ms=0)
   
       def is_battery_below_threshold(self):
           return self.get_battery_level() < self.battery_threshold
   
       def get_battery_level(self):
           # Read the battery level from the virtual battery level file.
           with self.battery_file_path.open('r') as f:
               data = json.load(f)
               return float(data['battery_level'])
   
       def print_message(self):
           message = 'Hello, World!'
           if self.is_battery_below_threshold():
               message += ' Battery level (%d) is below threshold (%d), so the component will defer updates' % (
                   self.get_battery_level(), self.battery_threshold)
           else:
               message += ' Battery level (%d) is above threshold (%d), so the component will acknowledge updates' % (
                   self.get_battery_level(), self.battery_threshold)
           print(message)
   
   
   def main():
       # Read the battery threshold and virtual battery file path from command-line args.
       args = sys.argv[1:]
       battery_threshold = float(args[0])
       battery_file_path = Path(args[1])
       print('Reading battery level from %s and deferring updates when below %d' % (
           str(battery_file_path), battery_threshold))
   
       try:
           # Create an IPC client and a Hello World printer that defers component updates.
           ipc_client = GreengrassCoreIPCClientV2()
           hello_world_printer = BatteryAwareHelloWorldPrinter(
               ipc_client, battery_file_path, battery_threshold)
           hello_world_printer.subscribe_to_component_updates()
           try:
               # Keep the main thread alive, or the process will exit.
               while True:
                   hello_world_printer.print_message()
                   time.sleep(HELLO_WORLD_PRINT_INTERVAL)
           except InterruptedError:
               print('Subscription interrupted')
           hello_world_printer.close_subscription()
       except Exception:
           print('Exception occurred', file=sys.stderr)
           traceback.print_exc()
           exit(1)
   
   
   if __name__ == '__main__':
       main()
   ```

   该 Python 应用程序执行以下操作：
   + 从您稍后将在核心设备上创建的虚拟电池电量文件中读取核心设备的电池电量。该虚拟电池电量文件模拟真实电池，因此您可以在没有电池的核心设备上完成本教程。
   + 读取电池电量阈值和虚拟电池电量文件路径的命令行参数。组件配方根据配置参数设置这些命令行参数，因此您可以在部署组件时自定义这些值。
   + 使用 [Python 版本 2 中的 IPC 客户端AWS IoT Device SDK V](https://github.com/aws/aws-iot-device-sdk-python-v2) 2 与核心软件通信。 AWS IoT Greengrass 与初始 IPC 客户端相比，IPC 客户端 V2 减少了在自定义组件中使用 IPC 所需编写的代码量。
   + 使用 [SubscribeToComponentUpdates](ipc-component-lifecycle.md#ipc-operation-subscribetocomponentupdates)IPC 操作订阅更新通知。C AWS IoT Greengrass ore 软件在每次部署之前和之后都会发送通知。每次收到通知时，该组件都会调用以下函数。如果通知涉及即将进行的部署，则组件会检查电池电量是否低于阈值。如果电池电量低于阈值，则组件会使用 [DeferComponentUpdate](ipc-component-lifecycle.md#ipc-operation-defercomponentupdate)IPC 操作将更新推迟 30 秒。否则，如果电池电量不低于阈值，则组件会确认更新，因此更新可以继续进行。

     ```
     def on_component_update_event(self, event):
         try:
             if event.pre_update_event is not None:
                 if self.is_battery_below_threshold():
                     self.defer_update(event.pre_update_event.deployment_id)
                     print('Deferred update for deployment %s' %
                           event.pre_update_event.deployment_id)
                 else:
                     self.acknowledge_update(
                         event.pre_update_event.deployment_id)
                     print('Acknowledged update for deployment %s' %
                           event.pre_update_event.deployment_id)
             elif event.post_update_event is not None:
                 print('Applied update for deployment')
         except:
             traceback.print_exc()
     ```
**注意**  
 AWS IoT Greengrass Core 软件不发送本地部署的更新通知，因此您可以使用 AWS IoT Greengrass 云服务部署此组件来对其进行测试。

1. 使用文本编辑器在名为 `recipe.json` 或 `recipe.yaml` 的文件中创建组件配方。组件*配方*定义了组件的元数据、默认配置参数和平台特定的生命周期脚本。

------
#### [ JSON ]

   <a name="nano-command-intro"></a>例如，在基于 Linux 的系统上，您可以运行以下命令来使用 GNU nano 创建该文件。

   ```
   nano recipe.json
   ```

   将以下 JSON 复制到该文件中。

   ```
   {
     "RecipeFormatVersion": "2020-01-25",
     "ComponentName": "COMPONENT_NAME",
     "ComponentVersion": "COMPONENT_VERSION",
     "ComponentDescription": "This Hello World component defers updates when the battery level is below a threshold.",
     "ComponentPublisher": "COMPONENT_AUTHOR",
     "ComponentConfiguration": {
       "DefaultConfiguration": {
         "BatteryThreshold": 50,
         "LinuxBatteryFilePath": "/home/ggc_user/virtual_battery.json",
         "WindowsBatteryFilePath": "C:\\Users\\ggc_user\\virtual_battery.json"
       }
     },
     "Manifests": [
       {
         "Platform": {
           "os": "linux"
         },
         "Lifecycle": {
           "install": "python3 -m pip install --user awsiotsdk --upgrade",
           "Run": "python3 -u {artifacts:decompressedPath}/com.example.BatteryAwareHelloWorld/main.py \"{configuration:/BatteryThreshold}\" \"{configuration:/LinuxBatteryFilePath}\""
         },
         "Artifacts": [
           {
             "Uri": "s3://BUCKET_NAME/COMPONENT_NAME/COMPONENT_VERSION/com.example.BatteryAwareHelloWorld.zip",
             "Unarchive": "ZIP"
           }
         ]
       },
       {
         "Platform": {
           "os": "windows"
         },
         "Lifecycle": {
           "install": "py -3 -m pip install --user awsiotsdk --upgrade",
           "Run": "py -3 -u {artifacts:decompressedPath}/com.example.BatteryAwareHelloWorld/main.py \"{configuration:/BatteryThreshold}\" \"{configuration:/WindowsBatteryFilePath}\""
         },
         "Artifacts": [
           {
             "Uri": "s3://BUCKET_NAME/COMPONENT_NAME/COMPONENT_VERSION/com.example.BatteryAwareHelloWorld.zip",
             "Unarchive": "ZIP"
           }
         ]
       }
     ]
   }
   ```

------
#### [ YAML ]

   <a name="nano-command-intro"></a>例如，在基于 Linux 的系统上，您可以运行以下命令来使用 GNU nano 创建该文件。

   ```
   nano recipe.yaml
   ```

   将以下 YAML 复制到该文件中。

   ```
   ---
   RecipeFormatVersion: "2020-01-25"
   ComponentName: "COMPONENT_NAME"
   ComponentVersion: "COMPONENT_VERSION"
   ComponentDescription: "This Hello World component defers updates when the battery level is below a threshold."
   ComponentPublisher: "COMPONENT_AUTHOR"
   ComponentConfiguration:
     DefaultConfiguration:
       BatteryThreshold: 50
       LinuxBatteryFilePath: "/home/ggc_user/virtual_battery.json"
       WindowsBatteryFilePath: "C:\\Users\\ggc_user\\virtual_battery.json"
   Manifests:
     - Platform:
         os: linux
       Lifecycle:
         install: python3 -m pip install --user awsiotsdk --upgrade
         Run: python3 -u {artifacts:decompressedPath}/com.example.BatteryAwareHelloWorld/main.py "{configuration:/BatteryThreshold}" "{configuration:/LinuxBatteryFilePath}"
       Artifacts:
         - Uri: "s3://BUCKET_NAME/COMPONENT_NAME/COMPONENT_VERSION/com.example.BatteryAwareHelloWorld.zip"
           Unarchive: ZIP
     - Platform:
         os: windows
       Lifecycle:
         install: py -3 -m pip install --user awsiotsdk --upgrade
         Run: py -3 -u {artifacts:decompressedPath}/com.example.BatteryAwareHelloWorld/main.py "{configuration:/BatteryThreshold}" "{configuration:/WindowsBatteryFilePath}"
       Artifacts:
         - Uri: "s3://BUCKET_NAME/COMPONENT_NAME/COMPONENT_VERSION/com.example.BatteryAwareHelloWorld.zip"
           Unarchive: ZIP
   ```

------

   此配方可指定以下内容：
   + 电池阈值、Linux 核心设备上的虚拟电池文件路径以及 Windows 核心设备上的虚拟电池文件路径的默认配置参数。
   + 安装适用于 Python 的最新版本 AWS IoT Device SDK v2 的 `install` 生命周期。
   + 在 `run` 中运行 Python 应用程序的 `main.py` 生命周期。
   + 占位符，例如 `COMPONENT_NAME` 和 `COMPONENT_VERSION`，其中 GDK CLI 在生成组件配方时会替换信息。

   有关组件配方的更多信息，请参阅 [AWS IoT Greengrass 组件配方参考](component-recipe-reference.md)。

# 步骤 3：将组件发布到 AWS IoT Greengrass 服务
<a name="publish-component-defer-updates"></a>

在本节中，你将 Hello World 组件发布到 AWS IoT Greengrass 云服务。在 AWS IoT Greengrass 云服务中提供组件后，您可以将其部署到核心设备。您可以使用 GDK CLI 将组件从开发计算机发布到 AWS IoT Greengrass 云服务。GDK CLI 会上传组件的配方和构件。

**将 Hello World 组件发布到该 AWS IoT Greengrass 服务**

1. 运行以下命令，使用 GDK CLI 构建组件。[组件构建命令](greengrass-development-kit-cli-component.md#greengrass-development-kit-cli-component-build)基于 GDK CLI 配置文件创建配方和构件。在此过程中，GDK CLI 会创建一个包含组件源代码的 ZIP 文件。

   ```
   gdk component build
   ```

   您应该会看到类似于以下示例的消息。

   ```
   [2022-04-28 11:20:16] INFO - Getting project configuration from gdk-config.json
   [2022-04-28 11:20:16] INFO - Found component recipe file 'recipe.yaml' in the  project directory.
   [2022-04-28 11:20:16] INFO - Building the component 'com.example.BatteryAwareHelloWorld' with the given project configuration.
   [2022-04-28 11:20:16] INFO - Using 'zip' build system to build the component.
   [2022-04-28 11:20:16] WARNING - This component is identified as using 'zip' build system. If this is incorrect, please exit and specify custom build command in the 'gdk-config.json'.
   [2022-04-28 11:20:16] INFO - Zipping source code files of the component.
   [2022-04-28 11:20:16] INFO - Copying over the build artifacts to the greengrass component artifacts build folder.
   [2022-04-28 11:20:16] INFO - Updating artifact URIs in the recipe.
   [2022-04-28 11:20:16] INFO - Creating component recipe in 'C:\Users\finthomp\greengrassv2\com.example.BatteryAwareHelloWorld\greengrass-build\recipes'.
   ```

1. 运行以下命令将组件发布到 AWS IoT Greengrass 云服务。[组件发布命令](greengrass-development-kit-cli-component.md#greengrass-development-kit-cli-component-publish)将组件的 ZIP 文件构件上传到 S3 存储桶。然后，它会在组件配方中更新 ZIP 文件的 S3 URI，并将配方上传到 AWS IoT Greengrass 服务。在此过程中，GDK CLI 会检查 AWS IoT Greengrass 云服务中已有哪个版本的 Hello World 组件，因此它可以选择该版本之后的下一个补丁版本。如果该组件尚不存在，GDK CLI 将使用版本 `1.0.0`。

   ```
   gdk component publish
   ```

   您应该会看到类似于以下示例的消息。输出会显示 GDK CLI 创建的组件版本。

   ```
   [2022-04-28 11:20:29] INFO - Getting project configuration from gdk-config.json
   [2022-04-28 11:20:29] INFO - Found component recipe file 'recipe.yaml' in the  project directory.
   [2022-04-28 11:20:29] INFO - Found credentials in shared credentials file: ~/.aws/credentials
   [2022-04-28 11:20:30] INFO - No private version of the component 'com.example.BatteryAwareHelloWorld' exist in the account. Using '1.0.0' as the next version to create.
   [2022-04-28 11:20:30] INFO - Publishing the component 'com.example.BatteryAwareHelloWorld' with the given project configuration.
   [2022-04-28 11:20:30] INFO - Uploading the component built artifacts to s3 bucket.
   [2022-04-28 11:20:30] INFO - Uploading component artifacts to S3 bucket: greengrass-component-artifacts-us-west-2-123456789012. If this is your first time using this bucket, add the 's3:GetObject' permission to each core device's token exchange role to allow it to download the component artifacts. For more information, see https://docs.aws.amazon.com/greengrass/v2/developerguide/device-service-role.html.
   [2022-04-28 11:20:30] INFO - Not creating an artifacts bucket as it already exists.
   [2022-04-28 11:20:30] INFO - Updating the component recipe com.example.BatteryAwareHelloWorld-1.0.0.
   [2022-04-28 11:20:31] INFO - Creating a new greengrass component com.example.BatteryAwareHelloWorld-1.0.0
   [2022-04-28 11:20:31] INFO - Created private version '1.0.0' of the component in the account.'com.example.BatteryAwareHelloWorld'.
   ```

1. 从输出中复制 S3 存储桶名称。您稍后会使用桶名称来允许核心设备从该桶下载组件构件。

1. （可选）在 AWS IoT Greengrass 控制台中查看组件以验证其是否成功上传。执行以下操作：

   1. 在 [AWS IoT Greengrass 控制台](https://console.aws.amazon.com/greengrass)导航菜单中，选择**组件**。

   1. 在**组件**页面上，选择**我的组件**选项卡，然后选择 **com.example.BatteryAwareHelloWorld**。

      在此页面上，您可以看到组件的配方以及有关该组件的其他信息。

1. <a name="core-device-allow-s3-bucket-access-console-intro-1"></a>允许核心设备访问 S3 存储桶中的组件构件。

   <a name="core-device-allow-s3-bucket-access-console-intro-2"></a>每台核心设备都有一个[核心设备 IAM 角色](device-service-role.md)，允许其与云进行交互 AWS IoT 并将日志发送到 AWS 云端。默认情况下，此设备角色不允许访问 S3 存储桶，因此您必须创建并附加一个允许核心设备从 S3 存储桶检索组件构件的策略。

   <a name="core-device-allow-s3-bucket-access-console-intro-3"></a>如果设备的角色已允许访问 S3 存储桶，则可跳过此步骤。否则，请创建允许访问的 IAM 策略并将其附加到该角色，如下所示：

   1. <a name="core-device-allow-s3-bucket-access-console-step-1"></a>在 [IAM 控制台](https://console.aws.amazon.com/iam)的导航菜单中，选择**策略**，然后选择**创建策略**。

   1. 在 **JSON** 选项卡中，将占位符内容替换为以下策略。*greengrass-component-artifacts-us-west-2-123456789012*替换为 GDK CLI 上传组件工件的 S3 存储桶的名称。

      例如，如果您在 GDK CLI 配置文件中指定了 **greengrass-component-artifacts** 和 **us-west-2**，而您的 AWS 账户 ID 为 **123456789012**，则 GDK CLI 将使用名为 `greengrass-component-artifacts-us-west-2-123456789012` 的 S3 存储桶。

------
#### [ JSON ]

****  

      ```
      {
        "Version":"2012-10-17",		 	 	 
        "Statement": [
          {
            "Effect": "Allow",
            "Action": [
              "s3:GetObject"
            ],
            "Resource": "arn:aws:s3:::greengrass-component-artifacts-us-west-2-123456789012/*"
          }
        ]
      }
      ```

------

   1. <a name="core-device-allow-s3-bucket-access-console-step-3"></a>选择**下一步**。

   1. <a name="core-device-allow-s3-bucket-access-console-step-4"></a>在**策略详细信息部分**，对于**名称**，请输入 **MyGreengrassV2ComponentArtifactPolicy**。

   1. <a name="core-device-allow-s3-bucket-access-console-step-5"></a>选择**创建策略**。

   1. <a name="core-device-allow-s3-bucket-access-console-step-6"></a>在 [IAM 控制台](https://console.aws.amazon.com/iam)导航菜单中，选择**角色**，然后选择核心设备的角色名称。您在安装 C AWS IoT Greengrass ore 软件时指定了此角色名称。如果您未指定名称，则默认使用 `GreengrassV2TokenExchangeRole`。

   1. <a name="core-device-allow-s3-bucket-access-console-step-7"></a>在**权限**下，选择**添加权限**，然后选择**附加策略**。

   1. <a name="core-device-allow-s3-bucket-access-console-step-8"></a>在**添加权限**页面，选中与您创建的策略 `MyGreengrassV2ComponentArtifactPolicy` 对应的复选框，然后选择**添加权限**。

# 第 4 步：在核心设备上部署和测试组件
<a name="deploy-component-defer-updates"></a>

在本部分中，您将组件部署到核心设备以测试其功能。在核心设备上，您创建虚拟电池电量文件以模拟真实电池。然后，您创建其他部署并观察核心设备上的组件日志文件，以查看组件延迟并确认更新。

**部署和测试可延迟更新的 Hello World 组件**

1. 使用文本编辑器创建虚拟电池电量文件。此文件模拟真实电池。
   + 在 Linux 核心设备上，创建一个名为 `/home/ggc_user/virtual_battery.json` 的文件。使用 `sudo` 权限运行文本编辑器。
   + 在 Windows 核心设备上，创建一个名为 `C:\Users\ggc_user\virtual_battery.json` 的文件。以管理员身份运行文本编辑器。

   <a name="nano-command-intro"></a>例如，在基于 Linux 的系统上，您可以运行以下命令来使用 GNU nano 创建该文件。

   ```
   sudo nano /home/ggc_user/virtual_battery.json
   ```

   将以下 JSON 复制到该文件中。

   ```
   {
     "battery_level": 50
   }
   ```

1. 将 Hello World 组件部署到核心设备。执行以下操作：

   1. 在 [AWS IoT Greengrass 控制台](https://console.aws.amazon.com/greengrass)导航菜单中，选择**组件**。

   1. 在**组件**页面上，选择**我的组件**选项卡，然后选择 **com.example.BatteryAwareHelloWorld**。

   1. 在 **com.example.BatteryAwareHelloWorld** 页面上，选择**部署**。

   1. <a name="deploy-component-choose-deployment-step"></a>从**添加到部署**中，选择要修改的现有部署，或者选择创建新部署，然后选择**下一步**。

   1. <a name="deploy-component-choose-target-step"></a>如果您选择创建新部署，请为部署选择目标核心设备或事物组。在**指定目标**页面的**部署目标**下面，选择核心设备或事物组，然后选择**下一步**。

   1. 在**选择组件**页面上，确认已选择 **com.example.BatteryAwareHelloWorld** 组件，然后选择**下一步**。

   1. 在**配置组件**页面上，选择 **com.example.BatteryAwareHelloWorld**，然后执行以下操作：

      1. 选择**配置组件**。

      1. 在**配置 com.example.BatteryAwareHelloWorld** 模式的**配置更新**下**要合并的配置**中，输入以下配置更新。

         ```
         {
           "BatteryThreshold": 70
         }
         ```

      1. 选择**确认**以关闭模式，然后选择**下一步**。

   1. 在**确认高级设置**页面上**部署策略**部分的**组件更新策略**下面，确认已选择**通知组件**。在您创建新部署时，默认会选择**通知组件**。

   1. <a name="deploy-component-review-and-deploy-step"></a>在 **检查** 页上，选择 **部署**。

      完成部署可能最多需要 1 分钟。

1.  AWS IoT Greengrass Core 软件将组件进程中的 stdout 保存到文件夹中的日志文件中。`logs`运行以下命令，验证 Hello World 组件是否正在运行并打印状态消息。

------
#### [ Linux or Unix ]

   ```
   sudo tail -f /greengrass/v2/logs/com.example.BatteryAwareHelloWorld.log
   ```

------
#### [ Windows Command Prompt (CMD) ]

   ```
   type C:\greengrass\v2\logs\com.example.BatteryAwareHelloWorld.log
   ```

------
#### [ PowerShell ]

   ```
   gc C:\greengrass\v2\logs\com.example.BatteryAwareHelloWorld.log -Tail 10 -Wait
   ```

------

   您应该会看到类似于以下示例的消息。

   ```
   Hello, World! Battery level (50) is below threshold (70), so the component will defer updates.
   ```
**注意**  
如果文件不存在，则部署可能尚未完成。如果文件在 30 秒内不存在，则部署可能已失败。例如，如果核心设备无权从 S3 存储桶下载组件的构件，则可能会发生这种情况。运行以下命令查看 AWS IoT Greengrass 核心软件日志文件。此文件包含来自 Greengrass 核心设备的部署服务的日志。  

   ```
   sudo tail -f /greengrass/v2/logs/greengrass.log
   ```

   ```
   type C:\greengrass\v2\logs\greengrass.log
   ```
<a name="windows-cmd-type-observe-logs"></a>`type` 命令将文件内容写入终端。多次运行此命令，以观察文件中的更改。

   ```
   gc C:\greengrass\v2\logs\greengrass.log -Tail 10 -Wait
   ```

1. 在核心设备上创建新的部署，以验证组件是否延迟更新。执行以下操作：

   1. 在 [AWS IoT Greengrass 控制台](https://console.aws.amazon.com/greengrass)导航菜单中，选择**部署**。

   1. 选择您之前创建或修订的部署。

   1. 在部署页上，选择**修订**。

   1. 在**修订部署**模式中，选择**修订部署**。

   1. 在每步中选择**下一步**，然后选择**部署**。

1. 运行以下命令，再次查看组件的日志，并验证组件是否延迟更新。

------
#### [ Linux or Unix ]

   ```
   sudo tail -f /greengrass/v2/logs/com.example.BatteryAwareHelloWorld.log
   ```

------
#### [ Windows Command Prompt (CMD) ]

   ```
   type C:\greengrass\v2\logs\com.example.BatteryAwareHelloWorld.log
   ```

------
#### [ PowerShell ]

   ```
   gc C:\greengrass\v2\logs\com.example.BatteryAwareHelloWorld.log -Tail 10 -Wait
   ```

------

   您应该会看到类似于以下示例的消息。组件将更新延迟 30 秒，因此组件会重复打印此消息。

   ```
   Deferred update for deployment 50722a95-a05f-4e2a-9414-da80103269aa.
   ```

1. 使用文本编辑器编辑虚拟电池电量文件并将电池电量更改为高于阈值的值，以便部署可以继续进行。
   + 在 Linux 核心设备上，编辑名为 `/home/ggc_user/virtual_battery.json` 的文件。使用 `sudo` 权限运行文本编辑器。
   + 在 Windows 核心设备上，编辑名为 `C:\Users\ggc_user\virtual_battery.json` 的文件。以管理员身份运行文本编辑器。

   <a name="nano-command-intro"></a>例如，在基于 Linux 的系统上，您可以运行以下命令来使用 GNU nano 创建该文件。

   ```
   sudo nano /home/ggc_user/virtual_battery.json
   ```

   将电池电量更改为 `80`。

   ```
   {
     "battery_level": 80
   }
   ```

1. 运行以下命令，再次查看组件的日志，并验证组件是否确认更新。

------
#### [ Linux or Unix ]

   ```
   sudo tail -f /greengrass/v2/logs/com.example.BatteryAwareHelloWorld.log
   ```

------
#### [ Windows Command Prompt (CMD) ]

   ```
   type C:\greengrass\v2\logs\com.example.BatteryAwareHelloWorld.log
   ```

------
#### [ PowerShell ]

   ```
   gc C:\greengrass\v2\logs\com.example.BatteryAwareHelloWorld.log -Tail 10 -Wait
   ```

------

   您应该会看到类似于以下示例的消息。

   ```
   Hello, World! Battery level (80) is above threshold (70), so the component will acknowledge updates.
   Acknowledged update for deployment f9499eb2-4a40-40a7-86c1-c89887d859f1.
   ```

您已完成本教程。Hello World 组件会根据核心设备的电池电量来推迟或确认更新。有关本教程探讨的主题的更多信息，请参阅以下内容：
+ [开发 AWS IoT Greengrass 组件](develop-greengrass-components.md)
+ [将 AWS IoT Greengrass 组件部署到设备](manage-deployments.md)
+ [使用 AWS IoT Device SDK 与 Greengrass 原子核、其他组件进行通信，以及 AWS IoT Core与 Greengrass 核、其他组件进行通信 AWS IoT Core](interprocess-communication.md)
+ [AWS IoT Greengrass 开发工具包命令行界面](greengrass-development-kit-cli.md)