Created
September 15, 2016 23:44
-
-
Save jinman/1dfae868bb18e950b0c031c80158e942 to your computer and use it in GitHub Desktop.
LambdaToNannyCheckinCheckout
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* This is a sample Lambda function that records nanny check in/out activities | |
* in DynamoDB and sends SMS messages to the phone number on file. | |
* | |
* This function creates a DynamoDB table 'button_nanny_checkin' the first time | |
* it runs. The table uses button's DSN as hash key and timestamp as range key. | |
* Each entry has an activity message. | |
* | |
* If phone number is set, an SMS message about this check in/out activity will | |
* be sent. | |
* | |
* Permissions required for this function to run are the following: | |
{ | |
"Version": "2012-10-17", | |
"Statement": [ | |
{ | |
"Sid": "Stmt1472255738000", | |
"Effect": "Allow", | |
"Action": [ | |
"dynamodb:CreateTable", | |
"dynamodb:DescribeTable", | |
"dynamodb:PutItem", | |
"dynamodb:Query" | |
], | |
"Resource": [ | |
"arn:aws:dynamodb:*:*:table/button_nanny_checkin" | |
] | |
}, | |
{ | |
"Sid": "Stmt1472255738001", | |
"Effect": "Allow", | |
"Action": [ | |
"sns:Publish" | |
], | |
"Resource": [ | |
"*" | |
] | |
} | |
] | |
} | |
*/ | |
const AWS = require('aws-sdk'); | |
const SNS = new AWS.SNS({ apiVersion: '2010-03-31' }); | |
const dynamodb = new AWS.DynamoDB(); | |
const TABLE_NAME = "button_nanny_checkin"; // DynamoDB table name | |
const PHONE_NUMBER = null; // config your phone number for SMS or null | |
function getButtonAttributes(event, callback) { | |
Iot.describeThing({ thingName: 'IotButton_' + event.serialNumber }, callback); | |
} | |
function sendSMS(event, phoneNumber, callback) { | |
if (phoneNumber !== null) { | |
console.log(`Sending SMS to ${phoneNumber}`); | |
const params = { | |
PhoneNumber: phoneNumber, | |
Message: getMessage(event) | |
}; | |
// result will go to function callback | |
SNS.publish(params, callback); | |
} else { | |
callback(null); | |
} | |
} | |
/** | |
* Checks whether the table exists and is active by calling DescribeTable. | |
*/ | |
function createTableIfNeeded(tableName, callback) { | |
dynamodb.describeTable({ TableName: tableName }, (err, data) => { | |
if (err) { | |
if (err.code === 'ResourceNotFoundException') { | |
createTable(tableName, (err, data) => { | |
if (err) { | |
callback(err); | |
} else { | |
callback('Table has been created but is not ready.'); | |
} | |
}); | |
} else { | |
callback(err); | |
} | |
} else { | |
// table already created | |
if (data.Table.TableStatus !== "ACTIVE") { | |
callback(`Table ${tableName} is not ready with status ${data.Table.TableStatus}.`); | |
} else { | |
callback(null, data); | |
} | |
} | |
}); | |
} | |
/** | |
* The table uses button's DSN as hash key and timestamp as range key. | |
* Each entry has an activity message. | |
*/ | |
function createTable(tableName, callback) { | |
const param = { | |
TableName: tableName, | |
KeySchema: [ | |
{ AttributeName: "dsn", KeyType: "HASH" }, | |
{ AttributeName: "timestamp", KeyType: "RANGE" } | |
], | |
AttributeDefinitions: [ | |
{ AttributeName: "dsn", AttributeType: "S" }, | |
{ AttributeName: "timestamp", AttributeType: "N" } | |
], | |
ProvisionedThroughput: { | |
ReadCapacityUnits: 10, | |
WriteCapacityUnits: 5 | |
} | |
}; | |
dynamodb.createTable(param, callback); | |
} | |
/** | |
* Saves nanny check in/out activity into DynamoDB | |
*/ | |
function saveEvent(event, callback) { | |
const params = { | |
TableName: TABLE_NAME, | |
Item: { | |
dsn: { S: event.serialNumber }, | |
timestamp: { N: new Date().getTime().toString() }, | |
message: { S: getMessage(event) } | |
} | |
}; | |
dynamodb.putItem(params, callback); | |
} | |
/** | |
* The following JSON template shows what is sent as the payload: | |
{ | |
"serialNumber": "GXXXXXXXXXXXXXXXXX", | |
"batteryVoltage": "xxmV", | |
"clickType": "SINGLE" | "DOUBLE" | "LONG" | |
} | |
* | |
* A "LONG" clickType is sent if the first press lasts longer than 1.5 seconds. | |
* "SINGLE" and "DOUBLE" clickType payloads are sent for short clicks. | |
* | |
* For more documentation, follow the link below. | |
* http://docs.aws.amazon.com/iot/latest/developerguide/iot-lambda-rule.html | |
*/ | |
function getMessage(event) { | |
if (event.clickType === 'SINGLE') { | |
return 'Your nanny checked in.'; | |
} | |
if (event.clickType === 'DOUBLE') { | |
return 'Your nanny checked out.'; | |
} | |
if (event.clickType === 'LONG') { | |
return 'Your nanny needs help!'; | |
} | |
return 'Unknown event: ' + event.clickType; | |
} | |
exports.handler = (event, context, callback) => { | |
console.log('Received event:', event.clickType); | |
// checks whether the table is ready | |
createTableIfNeeded(TABLE_NAME, (err, data) => { | |
if (err) { | |
console.log("Something wrong with table: " + TABLE_NAME, err); | |
context.done("Failed to access DynamoDB table."); | |
return; | |
} | |
// writes event into Dynamo | |
saveEvent(event, (err, data) => { | |
if (err) { | |
console.log("Failed to save event: " + JSON.stringify(event), err); | |
context.done("Failed to save event."); | |
} else { | |
console.log("Successfully recorded event."); | |
// and sends an SMS message if configured | |
sendSMS(event, PHONE_NUMBER, (err, data) => { | |
if (err) { | |
console.log("Failed to send SMS"); | |
context.done(err); | |
} else { | |
context.done(null, event); | |
} | |
}); | |
} | |
}); | |
}); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment