The Internet of Things on AWS – Official Blog

Implement a Connected Building with Amazon Alexa and AWS IoT

This post covers the use case of an organization creating voice-enabled features for its customers. The example use case is building a smart hotel environment that allows hotel guests and employees to use voice commands to control devices within hotel rooms. Throughout this post, we focus on the integration between Amazon Alexa, Amazon API Gateway, AWS Lambda, and AWS IoT Core.

The following are potential use cases for which a smart hotel might choose to build:

  • Hotel staff voice commands
    • “Alexa, tell smart hotel skill to reset room 211.”
      • This triggers the smart TV, lights, vacuum, and shades to begin a new customer workflow.
    • “Alexa, tell smart hotel skill to reset rooms 100 through 110.”
      • This triggers multiple rooms to begin a new customer workflow.
  • Customer voice commands
    • “Alexa, tell smart hotel skill to set room temperature to 72 degrees.”
      • This sends a command to an AWS IoT Core enabled thermostat to change the temperature.
    • “Alexa, tell smart hotel skill to order breakfast from room service.”
      • This notifies the hotel staff that the customer in a specified room wants a meal.

Why Amazon Alexa?

Alexa is Amazon’s cloud-based voice service available on over 100 million devices from Amazon and third-party device manufacturers. With Alexa, you can build natural voice experiences that offer customers a more intuitive way to interact with the devices they use every day. Using the Alexa Skills Kit, developers can build their own voice skill to be used on devices enabled by Alexa globally.

Why AWS IoT?

Billions of devices are in homes, factories, oil wells, hospitals, cars, and thousands of other places. With the proliferation of devices, you increasingly need solutions to connect them and collect, store, and analyze device data. AWS IoT provides broad and deep functionality, spanning the edge to the cloud, so you can build IoT solutions for virtually any use case across a wide range of devices.

Combining Amazon Alexa with AWS IoT

When creating a smart building environment, utilizing both Amazon Alexa and AWS IoT enables builders to create an end-to-end voice-controlled building experience. Unlike traditional architectures, Amazon Alexa and AWS IoT allow for cost-optimized serverless workloads. This means that you don’t have to provision long-running servers. Instead, your functions run only when users invoke Alexa with voice commands.

Prerequisites

  • Alexa Skills Kit account
  • Amazon Web Services account
  • Alexa device (Amazon Echo, Alexa mobile application, third-party hardware with Alexa, and others)

Architecture

This post walks you through the details of building this architecture on AWS.

Architecture diagram of solution

View the full architecture diagram on the Connected Home solution page.

Deploy architecture in AWS account

  1. Download the HotelBackEnd Lambda function zip file.
  2. Upload it to an S3 bucket in the same region you’re working in. Note the name of your S3 bucket.
  3. Download and deploy this AWS CloudFormation template.
    • Click “Raw” button and copy/paste into text editor. Save as IoTBlog.yaml.
  4. During CloudFormation deployment, enter the S3 bucket name and file name (not including .zip) as parameters.

Alexa skill creation

This post doesn’t focus on the development of an Alexa skill. However, we cover some basics. For a more detailed introduction to developing Alexa skills, see the following resources:

First, navigate to the Alexa Console. Create an invocation name that your hotel customers and staff will use to invoke the skill. I’ve set the invocation name of my skill to smart hotel. The invocation name should be two or more words and follow the Alexa Skills Kit guidelines.

Skill Invocation Name is being set to smart hotel

Next, we add our first intent. An intent represents an action that fulfills a user’s spoken request. Intents are specified in a JSON structure called the intent schema. Each intent is mapped to several utterances. The sample utterances specify the words and phrases users can say to invoke your intents.

We create an intent called SetTemperature with many utterances that a user can say to map to this intent. Intents can optionally have arguments called slots. Slots allow for variables to be sent within the intent.

We set the slot by double clicking temp and selecting Add to create new slot. Scroll down and set the slot type to AMAZON.NUMBER. Verify all of the temp slots are highlighted as seen below. The intent is then passed to the backend for processing, which we cover shortly. See the following example:

 User: Alexa, ask Smart Hotel to set my temperature to 72 degrees.

  • Invocation Name: Smart Hotel
  • Intent: SetTemperature
  • Slot: 72

Set Temperature Intent with multiple utterances

The second intent is for the use case where a hotel employee wants to reset all the smart devices in a room to prepare for a new customer. Follow the same steps as before for the ResetRoom intent creation.

  • Intent: ResetRoom
  • Slot: roomNumber

Reset Room Intent with multiple utterances

We stop the Alexa Skill building here, but keep in mind that the skill would typically have many intents (SetLights, SetShades, StartVacuum, OrderRoomService, and more) with each intent holding a robust set of utterances. When done, choose Save, and then choose Build Model.

Now that you have built your Alexa skill, you must link it with a Lambda function in order to pass the intent schema to be processed. In our case, we will be using Lambda and API Gateway to authenticate the user and send the command to IoT Core, which will handle the interaction with the hardware. To link the skill with Lambda, go to your AWS account and navigate to the SmartHotelBackend Lambda function. Smart Hotel Lambda Function

Copy the ARN of the Lambda function.

The ARN of the Lambda function being copied

Paste it in the Endpoint tab of the Alexa Developer Console. Make note of Your Skill ID. Choose Save Endpoints.

Endpoint screen in Alexa Developer console. Paste the Lambda ARN. Click Build model.

Choose the Build tab, and then choose Build Model.

On build tab. Click Build model.
Now copy the Skill ID and paste it into the Add trigger menu within your Lambda function.

Lambda function. Add trigger menu.
Navigate to Amazon API Gateway, and copy your API Invoke URL from Stages > smart-hotel-api.

API Gateway stages tab.
Paste the API Invoke URL into the environment variable section of your SmartHotelBackend Lambda function with api as the key.

Lambda function environment variables section.

Lambda and API Gateway

The Alexa Event Handler Lambda function receives the JSON payload from the Alexa skill and sends it to API Gateway for authentication and routing to the relevant Lambda function. Then, API Gateway authorizes the request using a Lambda authorizer. This function verifies the access token from the request and optionally checks it against an internal Amazon DynamoDB database. For example, the authorizer might look up the hotel customer’s credentials to determine whether the user is authorized to receive the requested content.

After the request has been authorized, API Gateway sends the request on to the specified API URI, which invokes the Lambda function associated with that specified logic. For this example, we send the request on to the Lambda function that triggers AWS IoT Core functionality.

Lambda authorizer template

import json

#Format return policy that API Gateway expects
def generatePolicy(principalId, effect, resource):
  return {
    'principalId': principalId,
    'policyDocument': {
      'Version': '2012-10-17',
      'Statement': [{
        'Action': 'execute-api:Invoke',
        'Effect': effect,
        'Resource': resource
      }]
    }
  };
def customLogicFunction(token):
    #Run your custom authorization here
    #i.e. Check your DynamoDB table for token associated with user
    #Return true or false

def lambda_handler(event, context):
    
    #if(customLogicFunction(event['authorizationToken']) == true)
        return generatePolicy('user', 'Allow', event['methodArn'])
    
    #else
      #return generatePolicy('user', 'Deny', event['methodArn'])
 
       

This is the Lambda authorizer that does your custom authorization logic. Notice the format of response API Gateway is expecting. API Gateway passes the source token to this Lambda authorizer function in the event.authorizationToken attribute. The Lambda authorizer function reads the token and acts as follows:
If the token value is Allow, the authorizer function returns a 200 OK HTTP response and an IAM policy that looks like the following, and the method request succeeds:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "execute-api:Invoke",
      "Effect": "Allow",
      "Resource": "arn:aws:execute-api:us-east-1:xxxxxxxxxxxx:m88ssxznb7/ESTestInvoke-stage/GET/"
    }
  ]
}

Finally, be sure to set the Lambda function trigger to API Gateway, associate a role based on least privilege, and set the timeout time to 10 seconds.

API Gateway

The CloudFormation template creates two URIs for our API. One is for authorized hotel staff to reset the room (“Alexa, tell smart hotel skill to reset room 211”), which will use the authorizer function. The second is for hotel guests to set the temperature (“Alexa, tell smart hotel skill to set room temperature to 72 degrees”), which will not need authorization. Each URI will have a method with a Lambda function that is called.

The first lambda function is for the room reset logic. We called this “smart-hotel-reset-room”. This function sends messages to the IoT Core topic associated with the specific room. Each device within the room is subscribed to it. Examples of this are turning off the TV, resetting room temperature, turning lights off, and closing the blinds.

Notice the method request requires authorization using our custom authorizer function. This is to ensure only authorized hotel employees can reset the room.

Reset room method
Here is the code that backs the /set-room resource:

import json
import boto3
import datetime
timestamp = datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%f')
client = boto3.client('iot-data')


def lambda_handler(event, context):
    roomId = event['multiValueQueryStringParameters']['room'][0]
    # TODO implement
    temp = 72
    response = client.publish(
        topic = 'resetRoom',
        qos = 0,
        payload = json.dumps({"roomid": roomId, "timestamp": timestamp, "shades": "up", "theater": "stopped", "thermostat": temp})
    )
    return {
        "statusCode": 200,
    }

The second Lambda function is for customers to set the temperature. We called it “smart-hotel-set-temp”, and the code simply writes to the temperature topic for the specific room. The thermostat is subscribed to this topic. The roomId and temperature are passed in from the API gateway request. Note that we are not utilizing Device Shadow here. Part 2 of this post series will cover the hardware side of this solution and will utilize Device Shadow for devices with sporadic internet connection.

import json
import boto3
import datetime
timestamp = datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%f')
client = boto3.client('iot-data')


def lambda_handler(event, context):
    temp = event['multiValueQueryStringParameters']['temp'][0]
    print(event)
    roomId = 101
    response = client.publish(
        topic = 'setTemp',
        qos = 0,
        payload = json.dumps({"roomid": roomId,"timestamp": timestamp, "thermostat": temp })
    )
    return {
        "statusCode": 200,
    } 

We do not authorize calls to this URI because the customers do not need an account to change their temperature.

Set temperature method screen.

Alexa skill event handler

This function is named Alexa Event Handler in the architecture diagram above. This function is called whenever a user invokes the Smart Hotel Alexa Skill. It routes the command to the appropriate API method (either /set-temp or /set-room). As your skill becomes more complex, you add more resources or methods to your API to accommodate additional functionality.

Creating an event handler for an Alexa skill can be the subject of a post in itself. However, we supply the following sample code that routes to either method based on specific intents. We created a SetTemp and ResetRoom intent in Alexa Skills Kit.

'use strict';
const Alexa = require('alexa-sdk');
const req = require('request');
const APP_ID = undefined;

const SKILL_NAME = 'SmartHotel';
const GET_FACT_MESSAGE = "";
const HELP_MESSAGE = 'Please repeat.';
const HELP_REPROMPT = 'What can I help you with?';
const STOP_MESSAGE = 'Goodbye!';


var AWS = require('aws-sdk');
const apiLink = process.env.api;

const handlers = {
    'LaunchRequest': function () {
        this.emit('SetTemperature');
    },
    'SetTemperature': function () {
        var temp = this.event.request.intent.slots.temp.value;
        var url = apiLink + '/set-temp?temp=' + temp
        req.post(url, function(err, res, body) {
            if(err){
                console.log('error', err);
            } else{
                console.log('success', body);
            }
        });
        const speechOutput = 'Sounds good! I\'ve set your temperature to ' + temp;
        this.response.cardRenderer(SKILL_NAME, speechOutput);
        this.response.speak(speechOutput);
        this.emit(':responseReady');
    },
    'ResetRoom': function () {
        var room = this.event.request.intent.slots.roomNumber.value;
        var postBody = {url: apiLink + '/set-room?room=' + room, 
                        headers: {Authorization: this.event.context.System.apiAccessToken}}
        req.post(postBody, function(err, res, body) {
            if(err){
                console.log('error', err);
            } else{
                console.log('success', body);
            }
        });
        const speechOutput = 'Okay! Resetting room ' + room + ' now.';
        this.response.cardRenderer(SKILL_NAME, speechOutput);
        this.response.speak(speechOutput);
        this.emit(':responseReady');
    },
    'AMAZON.HelpIntent': function () {
        const speechOutput = HELP_MESSAGE;
        const reprompt = HELP_REPROMPT;

        this.response.speak(speechOutput).listen(reprompt);
        this.emit(':responseReady');
    },
    'AMAZON.CancelIntent': function () {
        this.response.speak(STOP_MESSAGE);
        this.emit(':responseReady');
    },
    'AMAZON.StopIntent': function () {
        this.response.speak(STOP_MESSAGE);
        this.emit(':responseReady');
    },
};

exports.handler = function (event, context, callback) {
    const alexa = Alexa.handler(event, context, callback);
    alexa.appId = APP_ID;
    alexa.registerHandlers(handlers);
    alexa.execute();
};

Testing

Now that we’ve set up our Alexa to AWS IoT architecture, let us see the topics where the messages are going. Go to AWS IoT Core, and choose the Test tab. Subscribe to the setTemp topic.

Subscribing to set temperature topic in IoT Core Test tab.

In a new tab, go to Alexa Skills Kit and choose the Test tab. Either speak through the microphone or type in the box to interact with your skill.

Alexa developer console testing interface.
Navigate back to the AWS IoT Core test console to see the message.

IoT Core Test screen showing message from Alexa to device.

You can do the same for resetRoom topic.

This shows you the topic’s incoming messages and simulates what the hardware device will subscribe to. When the device receives the setTemp message, it will grab the temperature value and change the temperature value of the device. The resetRoom topic will be subscribed to by multiple devices within the hotel room such as the shades, the thermostat, and the television or smart plug.

Conclusion

This post walked you through how to create an Alexa skill and an AWS IoT Core architecture that enables the use of voice commands to control devices in a smart hotel setting. You can use this architecture as a foundation when building solutions for more complex use cases in smart buildings, hotels, and homes.

We have shown you one way to add voice to your devices, but there are several other options available for customers. If you are a device maker interested in developing inexpensive Alexa built-in products on resource constrained devices, see Introducing Alexa Voice Service Integration for AWS IoT Core, a new way to cost-effectively bring Alexa Voice to any type of connected device to learn how you can quickly and cost-effectively go to market with the new Alexa Voice Service (AVS) Integration for AWS IoT Core.