本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
步骤 2:开发可延迟更新的组件
在本节中,您将在 Python 中开发一个 Hello World 组件,当核心设备的电池电量低于您在部署组件时配置的阈值时,该组件会延迟组件更新。在此组件中,您将使用适用于 Python 的 Amazon IoT Device SDK v2 中的进程间通信(IPC)接口。当核心设备收到部署时,您可以使用 SubscribeToComponentUpdates IPC 操作来接收通知。然后,您可以根据设备的电池电量,使用 DeferComponentUpdate IPC 操作来推迟或确认更新。
要开发可延迟更新的 Hello World 组件,请执行以下步骤:
-
在开发计算机上,为组件源代码创建一个文件夹。
mkdir com.example.BatteryAwareHelloWorld cd com.example.BatteryAwareHelloWorld -
使用文本编辑器创建名为
gdk-config.json的文件。GDK CLI 从名为gdk-config.json的 GDK CLI 配置文件中读取数据,以生成和发布组件。此配置文件存在于组件文件夹的根目录中。例如,在基于 Linux 的系统上,您可以运行以下命令来使用 GNU nano 创建该文件。
nano gdk-config.json将以下 JSON 复制到该文件中。
-
将
Amazon替换为您的名字。 -
将
us-west-2替换为核心设备的运行位置 Amazon Web Services 区域。GDK CLI 将在此 Amazon Web Services 区域 发布该组件。 -
将
greengrass-component-artifacts替换为 S3 存储桶前缀,以便使用。当您使用 GDK CLI 发布组件时,GDK CLI 会使用以下格式将组件构件上传至 S3 存储桶,该存储桶的名称由此值、Amazon Web Services 区域,和您的 Amazon Web Services 账户 ID 组成:。bucketPrefix-region-accountId例如,如果您指定
greengrass-component-artifacts和us-west-2,且您的 Amazon Web Services 账户 ID 为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 组件发布到 Amazon IoT Greengrass 云服务时要使用的版本。
NEXT_PATCH指定在 Amazon IoT Greengrass 云服务中可用的最新版本之后选择下一个补丁版本。如果组件尚无 Amazon IoT Greengrass 云服务版本,则 GDK CLI 会使用1.0.0。 -
组件生成系统。当您使用
zip生成系统时,GDK CLI 会将组件的源代码打包成一个 ZIP 文件,该文件将成为该组件的单个构件。 -
GDK CLI 发布 Greengrass 组件的 Amazon Web Services 区域。
-
GDK CLI 上传组件构件的 S3 存储桶前缀。
-
-
使用文本编辑器在名为
main.py的文件中创建组件源代码。例如,在基于 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 的 Amazon IoT Device SDK v2
中的 IPC 客户端 V2 与 Amazon IoT Greengrass Core 软件通信。与初始 IPC 客户端相比,IPC 客户端 V2 减少了在自定义组件中使用 IPC 所需编写的代码量。 -
使用 SubscribeToComponentUpdates IPC 操作订阅更新通知。Amazon IoT Greengrass Core 软件会在每次部署之前和之后发送通知。每次收到通知时,该组件都会调用以下函数。如果通知涉及即将进行的部署,则组件会检查电池电量是否低于阈值。如果电池电量低于阈值,则组件会使用 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()注意
Amazon IoT Greengrass Core 软件不发送本地部署的更新通知,因此您可以使用 Amazon IoT Greengrass 云服务部署此组件来对其进行测试。
-
-
使用文本编辑器在名为
recipe.json或recipe.yaml的文件中创建组件配方。组件配方定义了组件的元数据、默认配置参数和平台特定的生命周期脚本。此配方可指定以下内容:
-
电池阈值、Linux 核心设备上的虚拟电池文件路径以及 Windows 核心设备上的虚拟电池文件路径的默认配置参数。
-
安装适用于 Python 的最新版本 Amazon IoT Device SDK v2 的
install生命周期。 -
在
run中运行 Python 应用程序的main.py生命周期。 -
占位符,例如
COMPONENT_NAME和COMPONENT_VERSION,其中 GDK CLI 在生成组件配方时会替换信息。
有关组件配方的更多信息,请参阅 Amazon IoT Greengrass 组件配方参考。
-