この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
今回は Greengrass V2 の Lambda コンポーネントで環境変数を使ってみました。
Lambda の環境変数は Greengrass V1 でも利用できますが、使ったことがなかったので V2 で試してみました。
想定する前提
今回実現したい事は下記の通りとします。
- Lambda コンポーネントでセンサーデータを取得したい
- 取得したデータをローカルの指定ファイルに出力したい
- 「ローカルの指定ファイル」を環境変数で渡したい
なお、利用しているセンサーやデバイスは下記の記事の通りとします。
Lambda 関数の作成
まずは環境変数を利用する Lambda 関数を作成します。今回も AWS SAM を使います。
sam init
sam init \
--runtime python3.7 \
--name modbus-sensor-lambda-component \
--app-template hello-world \
--package-type Zip
テンプレート
環境変数は Greengrass コンポーネントの設定で指定するので、Lambda 側で環境変数は定義しません。
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
modbus-sensor-lambda-component
Sample SAM Template for modbus-sensor-lambda-component
Globals:
Function:
Timeout: 3
Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: hello_world/
Handler: app.lambda_handler
Runtime: python3.7
AutoPublishAlias: dev
Outputs:
HelloWorldFunction:
Description: "Hello World Lambda Function ARN"
Value: !GetAtt HelloWorldFunction.Arn
HelloWorldFunctionIamRole:
Description: "Implicit IAM Role created for Hello World function"
Value: !GetAtt HelloWorldFunctionRole.Arn
Lambda コード
環境変数として「FilePath
」を定義して、そこに温湿度データを出力するファイルパスを格納します。
これにより、環境変数のデータを変更するだけでエッジデバイス側の動作を変更できる想定です。
from pymodbus.client.sync import ModbusSerialClient as ModbusClient
import datetime
import time
import os
def run_sync_client():
client = ModbusClient(baudrate=9600, port="/dev/ttyUSB0", method="rtu")
client.connect()
FilePath = os.environ["FilePath"] # Lambda の環境変数からデータ出力ファイルのパスを取得
rr = client.read_input_registers(address=1, count=2, unit=0x1)
temperature = rr.registers[0]/10
humidity = rr.registers[1]/10
# Append the message to the log file.
with open(FilePath, 'a') as f:
print(f"{str(datetime.datetime.now())}\tTemperatur:\t{temperature} ℃", file=f)
print(f"{str(datetime.datetime.now())}\tHumidity:\t{humidity} %", file=f)
client.close()
while True:
run_sync_client()
time.sleep(10)
def lambda_handler(event, context):
return
ビルド
$ sam build \
--use-container \
--build-image Function1=amazon/aws-sam-cli-build-image-python3.7
デプロイ
$ sam package \
--output-template-file packaged.yaml \
--s3-bucket ichida-aws-sam-artifact
$ sam deploy \
--template-file packaged.yaml \
--stack-name modbus-sensor-lambda-component-stack \
--s3-bucket ichida-aws-sam-artifact \
--capabilities CAPABILITY_NAMED_IAM \
--no-fail-on-empty-changeset
Lambda コンポーネントのデプロイ
次に作成した Lambda をデバイスにデプロイします。コンポーネントの画面から「コンポーネントの作成」をクリックします。
(既存のコンポーネントを更新する場合は、コンポーネントの画面から「新しいバージョン」を作成してください。)
先程作成した Lambda 関数を選択して Greengrass サービスにインポートします。
オプション設定で「追加のパラメータ」をクリックして設定項目を展開します。
「環境変数」の設定箇所で下記の通り、環境変数を設定します。環境変数FilePath
の値を/tmp/data_path_default.log
としました。
横着になりますが、Lambda コンポーネントのコンテナモードは「コンテナなし」としました。必要に応じて「Greengrassコンテナ」を選択して、アクセスを許可するデバイスやボリュームを指定してください。
コンポーネントの作成ができたら、次の画面で「デプロイ」をクリックします。この画面にある「デフォルト設定」の表示で、先程設定した環境変数の内容を確認することができますね。
デプロイ設定に進んで、最初にデプロイ対象を指定します。
デプロイのターゲットを指定します。
デプロイするコンポーネントを選択します。先程作成した Lambda コンポーネントを選択します。
スクリーンショットが無いですが、最後にレビュー画面が出るので問題なければデプロイを実行して完了です。
デバイス側の動作確認
デプロイにエラーが出ていないか /greengrass/v2/log/
以下のログを確認します。このディレクトリに「コンポート名.log」 というログファイルが作成されます。
(/greengrass/v2/log/
はデフォルトのログ出力先です。)
下記はエラー発生時のログの一部です。このときはセンサー側の電源が入っていないことが原因のエラーでした。
2021-08-21T04:39:11.351Z [ERROR] (pool-2-thread-19) modbus-sensor-lambda-component--HelloWorldFunction-xxxxxxxxxxxx: FATAL: lambda_runtime.py:427,Failed to initialize Lambda runtime due to exception: 'ModbusIOException' object has no attribute 'registers'. {serviceInstance=0, serviceName=modbus-sensor-lambda-component--HelloWorldFunction-xxxxxxxxxxxx, currentState=RUNNING}
次に温湿度データの出力を確認してみます。
環境変数で指定した/tmp/data_path_default.log
に出力されていますね!
$ tail -f /tmp/data_path_default.log
2021-08-21 14:51:20.410572 Temperatur: 27.6 ℃
2021-08-21 14:51:20.410634 Humidity: 15.4 %
2021-08-21 14:51:30.459651 Temperatur: 27.6 ℃
2021-08-21 14:51:30.459746 Humidity: 15.4 %
2021-08-21 14:51:40.635797 Temperatur: 27.6 ℃
2021-08-21 14:51:40.635893 Humidity: 15.4 %
2021-08-21 14:51:50.684847 Temperatur: 27.6 ℃
2021-08-21 14:51:50.684946 Humidity: 15.4 %
デバイス上でデプロイされているコンポーネントを確認しても、正しい設定内容でデプロイできていることが確認できました。
$ sudo /greengrass/v2/bin/greengrass-cli component list
Component Name: modbus-sensor-lambda-component--HelloWorldFunction-xxxxxxxxxxxx
Version: 1.0.1
State: RUNNING
Configuration: {"containerMode":"NoContainer","containerParams":{"devices":{},"memorySize":16000.0,"mountROSysfs":false,"volumes":{}},"inputPayloadEncodingType":"json","lambdaExecutionParameters":{"EnvironmentVariables":{"FilePath":"/tmp/data_path_default.log"}},"maxIdleTimeInSeconds":60.0,"maxInstancesCount":100.0,"maxQueueSize":1000.0,"pinned":true,"pubsubTopics":{},"statusTimeoutInSeconds":60.0,"timeoutInSeconds":3.0}
最後に
Greengrass V2 の Lambda で環境変数を使う方法は簡単に確認できました。環境変数を使うことで Lambda コードを変更することなくデバイス側の動作を変えることができるようになります。
次回は、環境変数を変えてデバイス側の変更に対応する方法を試してみたいと思います。
以上です。