Enterprise Android in a Hosted Cloud IoT Solution: Part 3: Amazon Web Services (AWS)

This is part three in a series of blog posts looking at integrating Zebra Android devices as IoT clients in a public cloud infrastructure.  For other posts in this series, please see the links below:

This post will walk through an example cloud IoT infrastructure using Amazon Web Services: IoT as the entry point.  An MQTT client will mimic device location, Android OS info and battery information and this data will be stored in a database for later retrieval.  The next part in this series will move to using a real device.

This example is based loosely on Ed Lima’s excellent post on implementing an IoT backend with AWS Lambda & DynamoDB

Disclaimers:

  • This is a very simple example, but the aim is to show the principles of subscribing to an MQTT topic, taking action on data posted to that topic by an IoT client and storing the IoT data for later retrieval and analysis.
  • Any hosted cloud computing solution may incur costs, please ensure you are aware of the costs associated with the cloud components you are using and how to monitor and set spending limits.

Objectives:

  • Publish simulated device telemetry data to an MQTT topic
  • Use AWS IoT rules to trigger specific logic in response to posts on an MQTT topic
  • Deploy an AWS lambda function to subscribe to the telemetry data and store the received values in an AWS DynamoDB
  • Visualize low battery events from any device providing data
  • Data that will be simulated along with some sample values, defined in JSON:

{

  "deviceId": "Test-device",

  "dateTime": "2018-11-14T10:29:45",

  "model": "TC57",

  "lat": "35.6602997",

  "lng": "139.7282743",

  "battLevel": "20",

  "battHealth": "50",

  "osVersion": "8.1.0",

  "patchLevel": "2019-02-01",

  "releaseVersion": "01-10-09.00-OG-U00-STD"

}

Source Code:

The source code discussed in this tutorial is available from GitHub.

Pre-requisites:

Configure an AWS project

  1. Navigate to https://console.aws.amazon.com and sign in with an Amazon account

Create a role with DynamoDB the required ‘execution role’ on DynamoDB

This will allow the lambda function to store data in the DynamoDB that it receives from the MQTT topic.

  1. Open the IAM Management console
  2. Select roles
  3. Choose ‘Create role’
  4. Choose the ‘Lambda’ service (allows Lambda functions to call AWS services on your behalf)

  1. Choose ‘Next: Permissions’
  2. Choose ‘AmazonDynamoDBFullAccess’ and ‘AWSLambdaBasicExecutionRole’

  1. Choose ‘Next: Tags’.  Do not assign any tags
  2. Choose ‘Next: Review’.
  3. Assign a role name (e.g. store-data-role)

  1. Choose ‘Create Role’

Create the Lambda function to insert new device data into the database

This function will be called when data is received on the MQTT topic.  The function will store received data in a DynamoDB table and console log when a low battery condition is seen.

  1. Open the Lambda console
  2. Choose ‘Create function’
  3. Assign a function name (e.g. store-device-data)
  4. Choose a Node.js runtime
  5. Chose the ‘Existing role’ you created in the previous step, in this case ‘store-data-role’

  1. Choose ‘Create function’
  2. Add an AWS IoT trigger to the function

  1. Scroll down to Function code
  2. Enter the following function code, available from GitHub.

console.log('Loading function');

var AWS = require('aws-sdk');

var dynamo = new AWS.DynamoDB.DocumentClient();

var table = "device-data";

exports.handler = function(event, context) {

    //console.log('Received event:', JSON.stringify(event, null, 2));

   var params = {

    TableName:table,

    Item:{

        "deviceId": event.deviceId,

        "dateTime": event.dateTime,

        "model": event.model,

        "lat": event.lat,

        "lng": event.lng,

        "battLevel": event.battLevel,

        "battHealth": event.battHealth,

        "osVersion": event.osVersion,

        "patchLevel": event.patchLevel,

        "releaseVersion": event.releaseVersion

        }

    };

    console.log("Received device data");

    dynamo.put(params, function(err, data) {

        if (err) {

            console.error("Unable to add device. Error JSON:", JSON.stringify(err, null, 2));

            context.fail();

        } else {

            console.log("Received device data:", JSON.stringify(data, null, 2));

            context.succeed();

        }

    });

}

  1. Scroll down and choose the IoT type ‘Custom IoT rule’
  2. Choose to ‘Create a new rule’
  3. Assign the rule a name, e.g. storeDeviceDataRule
  4. Define the query statement as “ SELECT * from ‘deviceTelemetry’ “
  5. Choose Add and Save
  6. The completed rule should look something like this

Create the DynamoDB table

The DynamoDB will hold received device data

  1. Open the DynamoDB console
  2. Choose create table
  3. Define a table name, e.g. device-data
  4. Define the primary key as ‘deviceId’ and the sort key as ‘dateTime’

  1. Click ‘Create’
  2. The table will be created.  You can view the items in the table by selecting the ‘Items’ tab.

Test data is being stored

Testing MQTT is very easy with AWS thanks to the inbuilt test client.

  1. Return to the AWS IoT home
  2. Select ‘Test’ to launch the MQTT client
  3. Publish to the topic ‘deviceTelemetry’ (you can copy / paste the sample code from the top of this post)

  1. Returning to your DynamoDB table, you should see the data has appeared

  1. Be sure to modify the dateTime or deviceId attributes on subsequent messages to ensure the primary key is unique.

Visualizing low battery events

Because we performed a console log in the Lambda function whenever a low batter condition was seen (15% or less), we can create a rudimentary view of this as a log insight:

  1. Open the AWS CloudWatch
  2. Select Logs Insights
  3. Select the previously created lambda from the dropdown, in my case ‘store-device-data’
  4. Add the following query:

fields @message

| filter @message like /BATTERY LOW/

  1. Run the query to see any devices which have reported a low battery level

There would be many superior ways to query low batteries, for example extracting the levels from the DynamoDB table but the above technique may well be sufficient for small / medium volume installations.

Debugging

If something does not work after you have performed the above steps, try using AWS CloudWatch to determine what might be causing the error.

You will need to make sure you have the “AWSLambdaBasicExecutionRole” policy associated with the store-data-role you created earlier in the IAM Management console

Conclusion

The astute observer will note that we have not actually created an IoT device in AWS during this tutorial but have used an IoT rule and MQTT topic to perform the core functionality of data collection.  The next step in this post series will integrate with a physical Android device and set up the IoT shadow at that stage which would allow for communication with and control of the IoT device.