May 14, 2016

Using AWS IoT button - Simple Example

Amazon did a limited release of the programmable Dash button and unsurprisingly it got sold out within a day. It’s stated in amazon.com that “We don’t know when or if this item will be back in stock.”, hence you might need to wait to get one.

I take this opportunity to write a post about how I used the AWS IoT button that I received in AWS re:Invent 2015 to show case AWS IoT to the team.

AWS IoT Button

This IoT button should be configured to connect to a WiFi network and once connected it shall send three different clickType events SINGLE, DOUBLE & LONG. As the name says it gets generated based on single click, double click or long press. AWS docs contains detailed steps about how to create Lambda rule to work with AWS IoT.

I created a Lambda function which will create CloudFormation stack for event type SINGLE, event type DOUBLE will get the list of EC2 instances created by the CloudFormation stack and stop them and event type LONG will delete that CloudFormation stack. This is a simple example but this showcases how easy it’s to use this and how much we can exploit this for our requirement.

Lambda function that handles IoT event

exports.handler = function(event, context) {
  console.log('REQUEST RECEIVED:\n', JSON.stringify(event));
  var aws = require('aws-sdk');
  var cfn = new aws.CloudFormation({Region: aws.config.region});
  var ec2 = new aws.EC2({Region: aws.config.region});
  var async = require('async');

  if (event.clickType == 'SINGLE') {
    var params = {
      StackName: 'IoTDemoStack',
      TimeoutInMinutes: 10,
      TemplateURL: 'https://s3.amazonaws.com/cf-templates-kpzyp42nwmh6-us-east-1/prakash/IoT-Demo.json'
    };

    cfn.createStack(params, function(err, data) {
      if (err) {
        console.log('Failed to create stack.');
        console.log(err);
      }
      else {
        setTimeout(function() {
          console.log('Successfully triggered creation of the stack with StackId', data.StackId);
        }, 3000);
      }
    });
  }
  else if (event.clickType == 'DOUBLE') {
    async.waterfall([
      function getPublicIp(callback) {
        var cfnparams = {
          StackName: 'IoTDemoStack'
        };
        cfn.describeStacks(cfnparams, function(err, cfnout) {
          setTimeout(function() {
            if (err) {callback(err);}
            else {callback(null, JSON.stringify(cfnout.Stacks[0].Outputs[0].OutputValue));}
          }, 1000);
        });
      },
      function getInstanceId(publicIp, callback) {
        var ec2params = {
          Filters: [
            {
              Name: 'ip-address',
              Values: [
                publicIp
              ]
            }
          ]
        };
        console.log('EC2 params ', ec2params);
        ec2.describeInstances(ec2params, function(err, ec2data) {
          setTimeout(function() {
            if (err) {callback(err);}
            else {callback(null, ec2data.Reservations[0].Instances[0].InstanceId);}
          }, 3000);
        });
      },
      function stopInstance(instanceId, callback) {
        var stopparams = {
          InstanceIds: [instanceId]
        };
        console.log('Stop instance params ', stopparams);
        ec2.stopInstances(stopparams, function(err) {
          setTimeout(function() {
            if (err) {callback(err);}
            else {callback(null);}
          }, 3000);
        });
      }
    ], function(err) {
      if (err) {
        console.log('Stopping Instance Failed.', err);
      }
      else {
        setTimeout(function() {
          console.log('Successfully stopped the instance.');
        }, 1000);
      }
    });
  }
  else if (event.clickType == 'LONG') {
    var params = {
      StackName: 'IoTDemoStack'
    };
    cfn.deleteStack(params, function(err, data) {
      if (err) {
        console.log('Failed to delete stack.');
        console.log(err);
      }
      else {
        setTimeout(function() {
          console.log('Successfully triggered deletion of stack.');
        }, 1000);
      }
    });
  }
  setTimeout(function() {
    context.done();
  }, 3000);
};

© Prakash P 2015 - 2023

Powered by Hugo & Kiss.