AWS Lambda and Losant Workflows

Michael Kuehl
Michael Kuehl | 5 minute read

Here at Losant, while we love devices and sensors and "things" (and all of their associated data) we understand that folks have non-IoT related data as well – data that probably won't be stored inside of Losant. And when there is data stored elsewhere, it ends up being almost guaranteed that to correctly deal with your IoT data, you will need access to that external data in order to run business logic. Losant workflows already have some nodes that make doing this possible (the HTTP node, the Webhook trigger), but we have now added another that lends itself almost perfectly to solving this kind of problem: the AWS Lambda node.

AWS Lambda is a service that lets you run predefined code blocks that can do whatever you want or need – and they are easily integrated with other AWS services. So if the data that you need to access is stored somewhere in AWS infrastructure, a Lambda node is the perfect way to pull that data into a Losant workflow. Today we are going to build such an example, where DynamoDB stores user data and device-to-user mappings, and we use a Lambda node to pull in the appropriate user when a Losant workflow runs.

Our devices in DynamoDB are stored by device serial numbers, not by Losant device IDs – the first step is to make sure that the serial numbers are available on our Losant devices. We do this with device tags, either through our bulk creation process (which would let you import a CSV of all of the serial numbers and create the devices), or just by adding tags manually. By having the serial as a tag, we will have the serial number available for use as a lookup key later. Below you can see one such tag, where the device has the the deviceSerial tag of 64QujxoyzCsuqv.

Device Tags with Key deviceSerial in Losant IoT platform.

Now lets start building our workflow. The goal of our workflow is to alert the device owner when the current draw of the device goes over an acceptable value.  Who the owner of a device is and how to contact them is stored in DynamoDB, which is where our Lambda node will come into play. So first, we start out with a trigger:

Owner Alert workflow with a Device trigger node in Losant IoT platform.

Here we are triggering this workflow using a device trigger. This workflow will run any time a device with the deviceSerial tag set reports to Losant (that way we know we have something to do the lookup by). Next, the alert conditions:

Owner Alert workflow with an Amperage Latch node in Losant IoT platform.

Here we are using a latch node to define the alert condition. In this case, if current draw exceeds 20, this is an alertable condition (and the alert condition won't fire again until current draw goes back below 19).  So now that we have a device, and we have an alertable condition, it is time to actually look up the owner to alert.  Enter the Lambda node:

Owner Alert workflow with AWS Lambda node in Losant IoT platform.

The first step when using a Lambda node is configuring AWS itself: this means the access key/secret as well as what AWS region. We recommend using workflow globals as the place to store things like access keys and secrets, which is why those two fields above are templated using global variables. Below you can see what the Globals tab of this workflow looks like:

Owner Alert Workflow Globals with AWS Lambda node in Losant IoT platform.

As a note, when using any AWS API, you should always use an AWS key pair with the most restrictive permissions possible for safety's sake. Using Losant is no different; in the case above, the AWS key and secret should be a pair that only has permission to execute Lambda functions and nothing else.

Owner Alert workflow Lambda Config with AWS Lambda node in Losant IoT platform.

Above is the rest of the configuration for the Lambda node. We are going to run the Lambda function named userLookup, hand it the current deviceTags (an array on the root of the workflow payload) as the function argument, and store the result at the JSON path data.userResult. A sample workflow payload as the workflow enters this node might look like the following:

{ 
"
time": Fri Feb 19 2016 17:26:00 GMT-0500 (EST),
"
data": { "current": 25, "on": true, },
"
globals": { "awsKey": "KEY_HERE", "awsSecret": "SECRET" },
"
applicationId": "568beedeb436ab01007be53d",
"
triggerId": "568bf74ab436ab01007be53e",
"
triggerType": "deviceId",
"
deviceTags": [ { "key": "deviceSerial", "value": "64QujxoyzCsuqv" } ],
"
flowId": "56c74add04d0b50100043381"
}

So by handing the Lambda function the deviceTags, the function will have the deviceSerial value, which we will need to actually look up the user.

And at this point you might be wondering what this magical function userLookup even does ... but wonder no more!  Below is the code for the Lambda function:

The goal of the code above is to take a device serial number and find the owner. We have two DynamoDB tables that we care about here: one called deviceMapping, which has rows that look like the following:

{"deviceSerial":"dqzBv2yB6sMkQQ", "userId":"568beedeb436ab01007be53d"}

And one called users, which has rows that look like this:

{
"
email": "janedoe@example.com",
"
firstName": "Jane",
"
id": "568beedeb436ab01007be53d",
"
lastName": "Doe",
"
phoneNumber": "867-5309"
}

So first, in the Lambda function node, we extract the device serial number from the device tags. Once we have that, we attempt to look up the associated user in the deviceMapping table. If we find a row there, we now have a user ID, which we can use to look up the user in the users table. And once we have that user, we call the callback function with that user. If at any point we didn't find something, we call the callback with null.

Now something is getting returned from the Lambda function; so how does that appear back on the workflow side of things?  Well, it looks something like the following:

{ 
"
time": Fri Feb 19 2016 17:26:00 GMT-0500 (EST),
"
data": {
"current": 25,
"on": true,
"userResult": {
"StatusCode": 200,
"LogResult": "START RequestId: ...lambda logs here...",
"Payload": {
"id": "56c74add04d0b50100043381",
"phoneNumber": "8128675309",
"email": "john@example.com",
"lastName": "Smith",
"firstName": "John"
}
}
}
,
"
globals": { "awsKey": "KEY_HERE", "awsSecret": "SECRET" },
"
applicationId": "568beedeb436ab01007be53d",
"
triggerId": "568bf74ab436ab01007be53e",
"triggerType": "deviceId",
"deviceTags": [ { "key": "deviceSerial", "value": "64QujxoyzCsuqv" } ],
"flowId": "56c74add04d0b50100043381"
}

We now have a userResult object on the payload with all the information needed to actually contact the user. Lambda also returns some other information to us, such as a status code and logging information, but for our purposes today, if we got a user back, we are good to go.

Owner Alert workflow with User Exists Conditional node in Losant IoT platform.

That check for a user is exactly what we are doing in this next node, a simple conditional. If you remember, there are multiple possible cases where the Lambda function might return null (i.e., no user found).  We need to make sure we deal with that case here by making sure there exists a userResult object and a userResult.Payload object.  If so, then we can continue onward with actually notifying the owner:

Owner Alert workflow with Email node in Losant IoT platform.

First, lets send that user an email. It is a simple thing now to pull the user's email address out of the user result that we got back from the Lambda function call. But an email isn't enough; we can alert them even more:

Owner Alert workflow with SMS node in Losant IoT platform.

 A text message alert is just as simple as the email alert, since the phone number is also right there on the user object we got back from the userLookup Lambda function call.

And that is everything! Using a Lambda node/function, we can easily integrate data outside of Losant with data flowing through Losant. While the particular example here might not cover your exact needs, there are a number of core ideas here that are common to many IoT applications, and hopefully you will be able to expand and build on these concepts to create a solution that fits your problem.

If you have any questions or comments, feel free to leave them below. Also, if anyone takes these ideas and runs with them to make something, please let us know! We love to hear how people are using Losant to do their own things.

Tagged