AWSTemplateFormatVersion: "2010-09-09" Transform: AWS::Serverless-2016-10-31 Description: > Transformation of LoRaWAN binary payloads Parameters: ParamBinaryDecoderName: Type: String Default: sample_device Description: Name of binary decoder as configured in src-iotrule-transformation/app.py TopicOutgoingErrors: Type: String Default: lorawanerror Description: Topic for errors TopicOutgoingTransformedMessages: Type: String Default: lorawantransformed Description: Prefix for outgoing transformed messages EnableNodeJSSupport: Description: If set to true, will deploy AWS Lambda NodeJS function and AWS IoT Rule to perform binary decoding using NodeJS Type: String Default: true AllowedValues: - true - false EnablePythonSupport: Description: If set to true, will deploy AWS Lambda Python function and respective AWS IoT Rule to perform binary decoding using NodeJS Type: String Default: true AllowedValues: - true - false Conditions: IsNodeSupportEnabled: !Equals - !Ref EnableNodeJSSupport - true IsPythonSupportEnabled: !Equals - !Ref EnablePythonSupport - true Resources: ############################################################################################ # Payload transformation Lambda function to be called from AWS IoT Core. This function will refer to # layer "DecoderLayer" to include the necessary decoding libraries ############################################################################################ TransformLoRaWANBinaryPayloadFunctionPython: Type: AWS::Serverless::Function Name: !Sub "${AWS::StackName}-TransformLoRaWANBinaryPayloadFunctionPython" Properties: CodeUri: src-iotrule-transformation Handler: app.lambda_handler Runtime: python3.7 Layers: - Ref: LoRaWANPayloadDecoderLayer Environment: Variables: RETURN_RAW_DATA: True ############################################################################################ # Payload transformation Lambda function to be called from AWS IoT Core. This function will refer to # layer "DecoderLayer" to include the necessary decoding libraries ############################################################################################ TransformLoRaWANBinaryPayloadFunctionNode: Type: AWS::Serverless::Function Condition: IsNodeSupportEnabled Name: !Sub "${AWS::StackName}-TransformLoRaWANBinaryPayloadFunctionNode" Properties: CodeUri: src-iotrule-transformation-nodejs Handler: index.handler Runtime: nodejs12.x Layers: - Ref: LoRaWANPayloadDecoderLayer Environment: Variables: RETURN_RAW_DATA: True ############################################################################################ # LAYERS ############################################################################################ LoRaWANPayloadDecoderLayer: Type: AWS::Serverless::LayerVersion Properties: LayerName: !Sub "${AWS::StackName}-LoRaWANPayloadDecoderLayerDemo" Description: Payload decoders for LoRaWAN devices in Python and Node.JS ContentUri: src-payload-decoders CompatibleRuntimes: - python3.8 - python3.7 - python3.6 - nodejs14.x - nodejs12.x - nodejs14.x RetentionPolicy: Retain ############################################################################################ # This IoT Rule converts a binary message to a JSON message using a payload decoder, and then # republishes the JSON message. # After transformation, the rule will republish the JSON payload to: # dt/lorawantransformed ############################################################################################ TransformLoRaWANBinaryPayloadPythonRule: Type: "AWS::IoT::TopicRule" Condition: IsPythonSupportEnabled Properties: RuleName: !Sub "${AWS::StackName}_TransformLoRaWANBinaryPayloadPython_${ParamBinaryDecoderName}" TopicRulePayload: AwsIotSqlVersion: "2016-03-23" RuleDisabled: false Sql: !Sub - | SELECT aws_lambda("${LambdaARN}", {"PayloadDecoderName": "${ParamBinaryDecoderName}", "PayloadData":PayloadData, "WirelessDeviceId": WirelessDeviceId, "WirelessMetadata": WirelessMetadata}) as transformed_payload, WirelessDeviceId as transformed_payload.WirelessDeviceId, WirelessMetadata.LoRaWAN.DevEui as transformed_payload.DevEui, WirelessDeviceId as lns_payload.WirelessDeviceId, WirelessMetadata as lns_payload.WirelessMetadata, PayloadData as lns_payload.PayloadData, timestamp() as timestamp - { LambdaARN: !GetAtt TransformLoRaWANBinaryPayloadFunctionPython.Arn, } Actions: - Republish: RoleArn: !GetAtt TransformLoRaWANBinaryPayloadRuleActionRole.Arn Topic: !Join ["", [!Ref TopicOutgoingTransformedMessages]] Qos: 0 ErrorAction: Republish: RoleArn: !GetAtt TransformLoRaWANBinaryPayloadRuleActionRole.Arn Topic: !Ref TopicOutgoingErrors Qos: 0 ############################################################################################ # This IoT Rule converts a binary message to a JSON message using a payload decoder, and then # republishes the JSON message. # After transformation, the rule will republish the JSON payload to: # dt/lorawantransformed ############################################################################################ TransformLoRaWANBinaryPayloadNodeRule: Type: "AWS::IoT::TopicRule" Condition: IsNodeSupportEnabled Properties: RuleName: !Sub "${AWS::StackName}_TransformLoRaWANBinaryPayloadNode_${ParamBinaryDecoderName}" TopicRulePayload: AwsIotSqlVersion: "2016-03-23" RuleDisabled: false Sql: !Sub - | SELECT aws_lambda("${LambdaARN}", {"PayloadDecoderName": "${ParamBinaryDecoderName}", "PayloadData":PayloadData, "WirelessDeviceId": WirelessDeviceId, "WirelessMetadata": WirelessMetadata}) as transformed_payload, WirelessDeviceId as transformed_payload.WirelessDeviceId, WirelessMetadata.LoRaWAN.DevEui as transformed_payload.DevEui, WirelessDeviceId as lns_payload.WirelessDeviceId, WirelessMetadata as lns_payload.WirelessMetadata, PayloadData as lns_payload.PayloadData, timestamp() as timestamp - { LambdaARN: !GetAtt TransformLoRaWANBinaryPayloadFunctionNode.Arn } Actions: - Republish: RoleArn: !GetAtt TransformLoRaWANBinaryPayloadRuleActionRole.Arn Topic: !Join ["", [!Ref TopicOutgoingTransformedMessages]] Qos: 0 ErrorAction: Republish: RoleArn: !GetAtt TransformLoRaWANBinaryPayloadRuleActionRole.Arn Topic: !Ref TopicOutgoingErrors Qos: 0 TransformLoRaWANBinaryPayloadFunctionPythonPermission: Type: AWS::Lambda::Permission Condition: IsPythonSupportEnabled Properties: FunctionName: !GetAtt TransformLoRaWANBinaryPayloadFunctionPython.Arn Action: lambda:InvokeFunction Principal: iot.amazonaws.com TransformLoRaWANBinaryPayloadFunctionNodePermission: Type: AWS::Lambda::Permission Condition: IsNodeSupportEnabled Properties: FunctionName: !GetAtt TransformLoRaWANBinaryPayloadFunctionNode.Arn Action: lambda:InvokeFunction Principal: iot.amazonaws.com TransformLoRaWANBinaryPayloadRuleActionRole: Type: "AWS::IAM::Role" Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - iot.amazonaws.com Action: - "sts:AssumeRole" Policies: - PolicyName: root PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: iot:Publish Resource: !Join [ "", [ "arn:aws:iot:", !Ref "AWS::Region", ":", !Ref "AWS::AccountId", ":topic/*", ], ] Outputs: IoTRuleNamePython: Condition: IsPythonSupportEnabled Description: "Please add this AWS IoT Rule name as a Destination to AWS IoT Core for LoRaWAN " Value: !Ref TransformLoRaWANBinaryPayloadPythonRule IoTRuleNameNode: Description: "Please add this AWS IoT Rule name as a Destination to AWS IoT Core for LoRaWAN " Condition: IsNodeSupportEnabled Value: !Ref TransformLoRaWANBinaryPayloadNodeRule TransformPayloadFunctionFunctionPython: Condition: IsPythonSupportEnabled Description: "Lambda Function ARN python" Value: !GetAtt TransformLoRaWANBinaryPayloadFunctionPython.Arn TransformPayloadFunctionFunctionNode: Description: "Lambda Function ARN node" Condition: IsNodeSupportEnabled Value: !GetAtt TransformLoRaWANBinaryPayloadFunctionNode.Arn TransformPayloadFunctionIamRole: Description: "Implicit IAM Role created for Lambda function" Value: !GetAtt TransformLoRaWANBinaryPayloadRuleActionRole.Arn DecoderLayerARN: Value: !Ref LoRaWANPayloadDecoderLayer Description: "ARN of payload decoder layer "