AWS IoTルールでMQTTメッセージ受信時にLambda関数を実行する
この記事では、AWS IoTルールを使用して、MQTTメッセージ受信時にLambda関数を実行する方法を確認します。
Lambda (lambda) AWS Lambda アクションは関数を呼び出し、MQTT メッセージを渡します。 AWS IoT Lambda 関数を非同期的に呼び出します。
Lambda
この記事では、AWS IoTルールとLambda関数、SNSを組み合わせて、特定の条件下でSMS通知を行うシステムを構築します。これにより、MQTTメッセージの内容に応じて動的に処理を行い、結果をリアルタイムに通知できます。
構成

- AWS IoTルールを作成し、特定のトピックに発行されたメッセージをLambda関数に渡します。
- AWS IoTルール用のIAMロールを作成します。
- Lambda関数はSNSトピックにメッセージを送信するパブリッシャーとして動作します。
- 関数のランタイム環境はPython 3.12です。
- SNSの通知先にSMSを指定し、携帯電話の電話番号を設定します。
リソース
AWS IoTリソース

AWS IoTルールの基本的な事項については、以下のページをご確認ください。

SQL
SQLで具体的なルールを定義します。4つのデータで構成されるメッセージを作成します。
- device_id:castおよびtopic関数を使用して、トピック名をスラッシュで分割した際の2番目の文字列を数値に変換します。
- reported_temperature:元のメッセージのtemperatureという名前のデータをリネームして使用します。
- max_temperature:値は固定で「30」を設定します。
- notify_topic_arn:SNSトピックのARNを指定します。
FROM句では、トピック名device/+/dataを対象とします。WHERE句を用いて、temperatureの値が30より大きい場合のみSNSに通知します。
Action

アクションとしてLambda関数を指定します。
Lambda
関数

SNSトピックにメッセージを発行するLambda関数です。関数に渡された引数を使用して、メッセージの本文を作成します。特に、メッセージの通知先のSNSトピックも引数で渡されます。
関数で実行するコードは、以下のページのものを参考にしました。
IAMロール

メッセージを発行するための必要な権限を付与します。通知先のSNSトピックが引数として渡されるため、ワイルドカード(*)を使用して不特定のSNSトピックへのメッセージ発行を許可します。
SNS
SNSトピックの通知先に携帯電話の電話番号を指定し、通知プロトコルにSMSを設定します。
詳細につきましては、以下のページをご確認ください。

CloudFormationテンプレート
AWS IoTルール
Resources:
  TopicRule:
    Type: AWS::IoT::TopicRule
    Properties:
      RuleName: wx_friendly_text
      TopicRulePayload: 
        Actions: 
          - Lambda: 
              FunctionArn: !Ref FunctionArn
        AwsIotSqlVersion: 2016-03-23
        RuleDisabled: false
        Sql: !Sub |
          SELECT 
            cast(topic(2) AS DECIMAL) as device_id, 
            temperature as reported_temperature,
            30 as max_temperature,
            '${SnsTopicArn}' as notify_topic_arn
          FROM '${TopicName}' WHERE temperature > 30
Code language: YAML (yaml)Lambdaパーミッション
Resources:
  Permission:
    Type: AWS::Lambda::Permission
    Properties:
      Action: lambda:InvokeFunction
      FunctionName: !Ref FunctionArn
      Principal: iot.amazonaws.com
      SourceAccount: !Ref AWS::AccountId
      SourceArn: !GetAtt TopicRule.Arn
Code language: YAML (yaml)Lambda 関数を呼び出すには、lambda:InvokeFunctionにアクセス権限を付与するポリシーを設定する必要があります。 AWS IoT AWS IoT Lambda AWS リージョン ポリシーが存在するのと同じ場所で定義された Lambda 関数のみを呼び出すことができます。Lambda 関数はリソースベースのポリシーを使用するため、ポリシーを Lambda 関数自体にアタッチする必要があります。
Lambda
Lambda
関数
Resources:
  Function:
    Type: AWS::Lambda::Function
    Properties:
      Architectures:
        - !Ref Architecture
      Code:
        ZipFile: |
          import boto3
          
          def lambda_handler(event, context):
            sns = boto3.client('sns')
            message_text = "Device {0} reports a temperature of {1}, which exceeds the limit of {2}.".format(
            
              str(event['device_id']),
              str(event['reported_temperature']),
              str(event['max_temperature'])
            )
            
            response = sns.publish(
              TopicArn = event['notify_topic_arn'],
              Message = message_text
            )
            return response
      FunctionName: !Sub "${Prefix}-function"
      Handler: !Ref Handler
      Runtime: !Ref Runtime
      Role: !GetAtt FunctionRole.Arn
Code language: YAML (yaml)IAMロール
Resources:
  FunctionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action: sts:AssumeRole
            Principal:
              Service:
                - lambda.amazonaws.com
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
      Policies:
        - PolicyName: SNSPublishPolicy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - sns:Publish
                Resource:
                  - !Sub "arn:aws:sns:${AWS::Region}:${AWS::AccountId}:*"
Code language: YAML (yaml)SNS
Resources:
  Topic:
    Type: AWS::SNS::Topic
    Properties:
      FifoTopic: false
      Subscription: 
        - Endpoint: !Ref PhoneNumber
          Protocol: sms
      TopicName: !Sub "${Prefix}-sns-topic"
Code language: YAML (yaml)テンプレート全体
動作確認
MQTT test clientページにアクセスして、動作を確認します。
トピックdevice/+/dataをサブスクライブします。

トピックdevice/32/dataにメッセージを発行します。

device/+/dataでメッセージを受信できます。temperatureの値が38であり、30より大きいです。AWS IoTルールの条件を満たしているため、SNSトピックにメッセージが送信されます。
携帯電話のSMSアプリを確認すると、メッセージが届いています。

メッセージ内容は、Lambda関数でフォーマットされたものです。
次に、トピックdevice/33/dataにtemperatureの値を28としてメッセージを発行します。

メッセージの発行は成功しますが、SMSは届きません。temperatureの値が30以下のため、AWS IoTルールの条件を満たしていません。
まとめ
AWS IoTルールを使用して、MQTTメッセージ受信時にLambda関数を実行し、条件に応じてSNSでSMS通知を行う方法を確認しました。これにより、デバイスからのデータをリアルタイムで監視し、異常値が検出された際に即時通知する仕組みを構築できます。