この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
以前にAWS IoT Eventsで作成したハートビート監視は、次のタイミングでデバイス毎にメール送信していました。
- オフライン状態(デバイス切断)になったとき
- オンライン状態(デバイス復帰)になったとき
しかし、ハートビート監視をしていると「1時間毎に現在オフライン状態のデバイス一覧がメールで欲しい」ことがあります。
というわけで、AWS IoT Eventsを使っている場合にどうするのかを試してみました。
おすすめの方
- AWS IoT Eventsでディテクターの一覧を取得したい方
- SNSトピック経由でメール送信したい方
サーバーレスアプリの作成
作成する全体像は下記です。1時間毎に動くLambdaを作成し、AWS IoT Eventsからデバイス(ディテクター)の一覧を取得し、SNSトピック経由でメール送信しています。
AWS SAMの初期化
sam init \
--runtime python3.7 \
--name iot-events-get-sample \
--app-template hello-world
template.yamlの作成
template.yaml
は下記です。Lambdaを定義しています。なお、以前に手動作成したSNSトピックを流用しています。
template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: iot-events-get-sample
Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: hello_world/
Handler: app.lambda_handler
Runtime: python3.7
Timeout: 10
Policies:
- arn:aws:iam::aws:policy/AWSIoTEventsReadOnlyAccess
- arn:aws:iam::aws:policy/AmazonSNSFullAccess
Environment:
Variables:
# 以前、手動作成しちゃったSNSトピックを使う
SNS_TOPIC_ARN: arn:aws:sns:ap-northeast-1:1234567890:heartbeat-send-mail-topic
Events:
CheckHeartbeat:
Type: Schedule
Properties:
Schedule: cron(0 0/1 * * ? *) # 日本時間で毎日0時から1時間毎
HelloWorldFunctionLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub /aws/lambda/${HelloWorldFunction}
Lambdaコードの作成
Lambdaコードは下記です。IoT Eventsのディテクターについて、offline状態の一覧を取得し、メッセージを作成してSNSトピックにPublishしています。
app.py
import boto3
import json
import os
iot_events_client = boto3.client('iotevents-data')
sns_client = boto3.client('sns')
def lambda_handler(event, context):
detectors = get_detectors_offline('SampleHeartbeatModel')
if len(detectors) != 0:
message = create_message(detectors)
send_email(message)
def get_detectors_offline(model_name, token=None):
options ={
'detectorModelName': model_name,
'stateName': 'offline'
}
if token is not None:
options['nextToken'] = token
res = iot_events_client.list_detectors(**options)
detectors = res.get('detectorSummaries', [])
if 'nextToken' in res:
detectors += get_detectors_offline(model_name, res['nextToken'])
return detectors
def create_message(detectors):
devices = []
for item in detectors:
device_id = item['keyValue']
devices.append(device_id)
return '\n'.join(devices)
def send_email(message):
sns_client.publish(
TopicArn=os.environ['SNS_TOPIC_ARN'],
Subject='お知らせ:切断中のデバイス一覧',
Message=message
)
デプロイ
sam build
sam package \
--output-template-file packaged.yaml \
--s3-bucket cm-fujii.genki-deploy
sam deploy \
--template-file packaged.yaml \
--stack-name IoT-Events-Get-Sample-Stack \
--capabilities CAPABILITY_NAMED_IAM \
--no-fail-on-empty-changeset
動作確認
オフライン状態のデバイスが2個のとき
ディテクターは2つ存在しており、すべてoffline状態です。
この状態でLmabdaを動かすと、メールが来ました!
オフライン状態のデバイスが1個のとき
1つのデバイスをonline状態に変更しました。
この状態でLambdaを動かすと、メールが来ました!
内容もoffline状態のデバイスだけです。
オフライン状態のデバイスが0個のとき
2つのデバイスをonline状態に変更しました。
この状態でLambdaを動かすと、メールが来ませんでした。期待通りです。
さいごに
AWS IoT EventsとLambdaを組み合わせることで、特定状態のデバイス一覧を取得してメール送信することができました。 発想次第でもっとたくさんのことができそうですね。