[IoT Events] シンプルなハートビート監視をCloudFormationで作る

デバイスからの通信が一定時間無いときにデバイス切断と判断してメール送信する仕組み(ハートビート監視)をCloudFormationで作ってみました。
2021.03.30

AWS IoT Eventsを使えば、LambdaやDynamoDBを使わずにハートビート監視ができます。

実際に案件等で使う場合、CloudFormationを使うことになるので、実際に作ってみました。

ハートビートの概要図

おすすめの方

  • AWS IoT Eventsの雰囲気を知りたい方
  • AWS IoT Eventsでハートビートを実現したい方
  • AWS IoT EventsをCloudFormationで作成したい方

ハートビートの動作を決める

デバイスの動作

  • 下記のトピックにハートビート用のデータを送信する
    • sample/<デバイスID>/heartbeat
  • 2分毎に送信する
  • ハートビート用のデータは下記とする(データが届いたかどうかで判断するため、EmptyでOK)
{}

クラウドの動作

  • ハートビート用のタイマーがゼロになったとき、デバイス切断と判断してSNSトピックを発行する(メール送信する)
  • デバイス切断状態でハートビート用のデータが届いたとき、デバイス接続が復旧したと判断してSNSトピックを発行する(メール送信する)
  • デバイス接続状態でハートビート用のデータが届いたとき、ハートビート用のタイマーをReStartする
  • ハートビート用のタイマーは5分とする

AWS IoT EventsをCloudFormationで作成する

CloudFormationテンプレート

下記を定義しています。

  • メール通知用のSNSトピック
  • IoTルール
  • IoTルール用のIAMロール
  • IoT Eventsの入力情報
  • IoT Eventsの探知器モデル
  • IoT Eventsの探知器モデル用のIAMロール

iot_events.yml

AWSTemplateFormatVersion: 2010-09-09
Description: IoT Events Heartbeat Sample

Parameters:
  HeartbeatTimerDefaultSeconds:
    Type: String
    Default: 300

Resources:
  HeartbeatNotifyTopic:
    Type: AWS::SNS::Topic
    Properties:
      Subscription:
        - Endpoint: sample@example.com
          Protocol: email

  HeartbeatlTopicRule:
    Type: AWS::IoT::TopicRule
    Properties:
      RuleName: heartbeat_topic_rule
      TopicRulePayload:
        AwsIotSqlVersion: "2016-03-23"
        RuleDisabled: false
        Sql: >-
          SELECT
            topic(2) as deviceId, * as payload
          FROM
            'sample/+/heartbeat'
        Actions:
          - IotEvents:
              InputName: !Ref HeartbeatEventsInput
              RoleArn: !GetAtt HeartbeatTopicRuleRole.Arn

  HeartbeatTopicRuleRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: heartbeat-topic-rule-role
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: iot.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AWSIoTEventsFullAccess

  HeartbeatEventsInput:
    Type: AWS::IoTEvents::Input
    Properties:
      InputName: HeartbeatInputData
      InputDefinition:
        Attributes:
          - JsonPath: deviceId

  HeartbeatDetectorModel:
    Type: AWS::IoTEvents::DetectorModel
    Properties:
      DetectorModelName: heartbeat-detector-model
      Key: deviceId
      EvaluationMethod: BATCH
      RoleArn: !GetAtt HeartbeatEventsDetectorModelRole.Arn
      DetectorModelDefinition:
        InitialStateName: Online
        States:
          - StateName: Online
            OnEnter:
              Events:
                - EventName: init_timer
                  Condition: true
                  Actions:
                    - SetTimer:
                        TimerName: HeartbeatTimer
                        Seconds: !Ref HeartbeatTimerDefaultSeconds
            OnInput:
              Events:
                - EventName: reset_timer
                  Condition: currentInput("HeartbeatInputData")
                  Actions:
                    - ResetTimer:
                        TimerName: HeartbeatTimer
              TransitionEvents:
                - EventName: to_offline
                  Condition: timeout("HeartbeatTimer")
                  NextState: Offline
          - StateName: Offline
            OnEnter:
              Events:
                - EventName: send-mail-to-offline
                  Actions:
                    - Sns:
                        TargetArn: !Ref HeartbeatNotifyTopic
                        Payload:
                          Type: STRING
                          ContentExpression: "'デバイスの切断を検知しました。対象デバイスID: ${$input.HeartbeatInputData.deviceId}'"
            OnInput:
              TransitionEvents:
                - EventName: to_online
                  Condition: currentInput("HeartbeatInputData")
                  NextState: Online
            OnExit:
              Events:
                - EventName: send-mail-to-online
                  Actions:
                    - Sns:
                        TargetArn: !Ref HeartbeatNotifyTopic
                        Payload:
                          Type: STRING
                          ContentExpression: "'デバイスの接続が復旧しました。対象デバイスID: ${$input.HeartbeatInputData.deviceId}'"


  HeartbeatEventsDetectorModelRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: heartbeat-detector-model-role
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: iotevents.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AWSIoTEventsFullAccess
        - arn:aws:iam::aws:policy/AmazonSNSFullAccess

デプロイする

aws cloudformation deploy \
    --template-file iot_events.yml \
    --stack-name IoT-Events-Heartbeat-Sample-Stack \
    --capabilities CAPABILITY_NAMED_IAM \
    --no-fail-on-empty-changeset

デプロイされた探知器モデルを確認する

バッチリですね。

IoT Eventsのモデルの様子(Online)

IoT Eventsのモデルの様子(Offline)

動作確認

1. データ送信すると、Online状態になる

  • トピック: sample/d0001/heartbeat
{}

タイマーも5分後に設定されています。

Online状態になる

2. 2分毎にデータ送信すると、Online状態のまま

  • トピック: sample/d0001/heartbeat
{}

タイマーも更新(ReStart)されています。

Online状態のまま

3. 5分ほど放置すると、Offline状態になる

Offlineになる

デバイス切断のメールも来ました。

Offline状態になったメールが来た

4. データ送信すると、Online状態に戻る

  • トピック: sample/d0001/heartbeat
{}

Online状態に戻った

デバイス接続復旧のメールも来ました。

Online状態になったメールが来た

参考