Lambda – run your code in cloud

Lambda service of AWS (Amazon Web Services) is a powerful tool how to run any piece of your code without any server or virtual server infrastructure. You can reach to very powerful and low-cost solution when your run just a piece of code when you need it and very simply.

Python powerful

Let’s try to create a function which will consume MQTT message, stores it to DynamoDB and sends response through IoT core. Code in Lambda service can be written in C#, Java, Node.js, Python, Ruby, Go and probably some others in the future. We will create our example in Python 3.7 language.

First of all login to AWS web console, click Services and type Lambda into search box. Choose Lambda and then you should see the Lambda dashboard.

In Lambda dashboard click Create function button.

Because we are “lazy” monkey, on the next screen click Use a blueprint and type hello to search field and press enter. Then select hello-world-python and click Configure.

On next screen type a name of function, select Create a new role with basic Lambda permissions and click Create function button.

After short while you can see your first Lambda function. In upper part of window you can see a Designer screen. This is a simple map defined by AWS policy showing where your function has access rights to. You can click on the boxes and see details. Click on the box with the name of your function you can see a code of your function.

The code is displayed in simple editor where you can create your program. I’d rather do that on local machine with my favorite editor and working code just copy paste to Lambda. It’s up to you.

Very important part is to be able run and test your code directly in Lambda environment. Simply click Configure test events in upper right part of your screen.

This opens a window where you simply define a JSON structure of input parameters to your function. It’t for testing purposes only, these finally will go from other services e.g. Iot core. Type a name of your test then Create button below.

Now your test is ready so then simply run it via Test button pressing.

When you press it you will see a green window with a result of your function. You see any console prints out and also return value.

Lambda policy

First of all we have to setup policy to get access to other AWS services in our case DynamoDB and IoT core. In designer you can see that we have access to Amazon CloudWatch Logs only.

Scroll down to Execution role section and here you have assigned role to the function which happened automatically as above. Click View the.. …role and it opens IAM console for roles and policies definition.

In IAM console populate assigned policy and click Edit policy.

In policy editor click JSON which opens policy as a simple JSON file.

Add access rights to dynamo and IOT core services. We will not specify each particular activity, therefore use star to access all things and resources. The code of JSON file is this one:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "logs:CreateLogGroup",
            "Resource": "arn:aws:logs:us-east-1:146240438812:*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": [
                "arn:aws:logs:us-east-1:146240438812:log-group:/aws/lambda/iotReceiver:*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": "dynamodb:*",
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "iot:*",
            "Resource": "*"
        }        
    ]
}

Then click Review policy button and Save changes. Go back to Lambda and refresh your window and you should see new rights to access IOT and DynamoDB.

IoT core trigger

Now we will add a Iot Core trigger which means that specific MQTT message departing to IoT core will trigger this function. Click Add trigger button.

In Add trigger select AWS IoT, Custom IoT rule, Create a new rule, then type name and description and also type a SQL statement. The SQL statement says how to proceed message. We want to proceed entire message and include first topic item into that.

SELECT *, topic(1) as topic FROM 'MyTest/test1'

Then check Enable trigger and click Add.

That’s it! In designer view you can see that our trigger is available.

Test IoT trigger

Now in other window or tab of your browser go to AWS Iot service by clicking Services and typing iot in search field, then select IoT Core.

In its dashboard select Test and then Publish to a topic.

Then specify topic and MQTT message which should contain entry parameters for function. Then click Publish to topic button.

Now go back to Lambda service and our function and click Monitoring button and you will probably also need to click refresh button. Then you will get interesting metrics about our function run.

Then click View logs in CloudWatch and you can get a detail logs from our function. You can see that we see the similar output to view of our test function. So everything works well!

Create Dynamo DB

Now we will create DynamoDB where our message would be stored. Click Services, type dynamo and select DynamoDB for getting to DynamoDB dashboard.

On dashboard click Create table button.

Here specify a name of the table, Primary key, its type e.g. String and click Create button.

Write data to DynamoDB

Now we can finally start a programming. Go back to our Lambda function, click its name and then go to editor.

Python has a great AWS SDK Boto3 here: https://aws.amazon.com/sdk-for-python/ You can check examples how to work with DynamoDB tables. In our function we will simply take inputs and write them to our DynamoDB table. The code looks like:

import json
import boto3
from boto3.dynamodb.conditions import Key, Attr
from botocore.exceptions import ClientError

print('Loading function')

def createDynamoEntry(event):  

    dynamodb = boto3.resource('dynamodb', region_name='us-east-1')

    table = dynamodb.Table('iotMessages')

    try:
        table.put_item(
            Item={
                'identifier': event['topic'],
                'payload': {
                    event['topic'],
                    event['key1'],
                    event['key2'],
                    event['key3']
                }
            }
        )
    except ClientError as e:
        print(e.response['Error']['Message'])
    else:
        return True

    return False    


def lambda_handler(event, context):
    #print("Received event: " + json.dumps(event, indent=2))
    print("value1 = " + event['key1'])
    print("value2 = " + event['key2'])
    print("value3 = " + event['key3'])

    createDynamoEntry(event)

    return event['key1']  # Echo back the first key value
    #raise Exception('Something went wrong')

Please note that boto3 needs a region code (region_name=’us-east-1′) which depends on your AWS account, please check it inside of your account.

Now modify your Lambda test an insert key topic which is key always automatically added to input message. We ensured this by SQL selector definition during creating IoT core trigger above.

Now click Test and see that your DynamoDB contains one entry with the same JSON structure. Note that in DynamoDB you should always click refresh button.

Test all together

Now go to IoT core service and publish message on topic “MyTest/test1”. You have to stick with this topic since your IoT core trigger reacts on this topic only.

In your DynamoDB table you can see that message successfully departed.

Respond with MQTT

Our demo wouldn’t be complete without MQTT response. So let’s respond to IoT core with simple message that everything is OK. Extend our code this way:

import json
import boto3
from boto3.dynamodb.conditions import Key, Attr
from botocore.exceptions import ClientError

print('Loading function')

def createDynamoEntry(event):  

    dynamodb = boto3.resource('dynamodb', region_name='us-east-1')

    table = dynamodb.Table('iotMessages')

    try:
        table.put_item(
            Item={
                'identifier': event['topic'],
                'payload': {
                    event['topic'],
                    event['key1'],
                    event['key2'],
                    event['key3']
                }
            }
        )
    except ClientError as e:
        print(e.response['Error']['Message'])
    else:
        return True

    return False    


def lambda_handler(event, context):
    #print("Received event: " + json.dumps(event, indent=2))
    print("value1 = " + event['key1'])
    print("value2 = " + event['key2'])
    print("value3 = " + event['key3'])

    status = createDynamoEntry(event)
    
    if status:
        client = boto3.client('iot-data', region_name='us-east-1')
        
        response = client.publish(
            topic='test/resp',
            qos=1,
            payload=json.dumps({
                "response":"All is OK :)"
            })
        )

    return event['key1']  # Echo back the first key value
    #raise Exception('Something went wrong')

We added section executed when entry to DynamoDB is successful, then MQTT message is published to topic “test/resp”. Let’s test i with IoT core.

Go to IoT Core, click Test, then Subscribe to a topic, enter topic to Subscription topic field and click Subscribe to topic button.

Then click Publish to a topic button, specify topic and message body as earlier and click Publish to topic button.

Then you can see a green spot at subscribed message “test/resp”. Click on that and you will see full message from our Lambda function.

Happy coding guys!

You may also like...

Follow by Email
LinkedIn
LinkedIn
Share