How to Voice Enable your IoT device with Echo Dot

REST

Before we get into things I’d like to explain what a RESTful API is because that’s how we’ll interface with the IoT device.  In my case, a Smart Home Thermostat, take a look here.

Just like your web browser fetches a web page or posts a form over HTTP, REST is a way of using standard HTTP transactions, to interface with network services. REST is required to work without prior knowledge of your system or remembering what transactions you’ve completed previously ;( i.e. it is client-server based, and stateless), so it’s future proof and scalable. In case you’re wondering REST stands for Representational State Transfer. It is the architecture that underpins file/media transfer on the Web. See Wikipedia for more.

In the context of IoT devices the REST endpoint is typically an action to be performed by a network device; e.g. to tell a light to turn on in a hypothetical cloud based smart home control service:

https://mycloudservice/myhome/lights/kitchen/on

typically there would be some authentication:

https://mycloudservice/myhome/lights/kitchen/on?access_token=34abcdef2

The response from the server would be a JSON formatted payload over HTTP: e.g.

{
  "cmd": "LightOn",
  "result": "OK",
}

The diagram illustrates this. Note that this is simplified in that we’re not showing how the cloud service communicates with the light; it would also be performed in a RESTful manner .

The endpoint or server can be queried in a similar fashion.

 

Voice Control

There are basically two things you need to do to voice enable your IoT device for use with an Echo or Echo Dot:

1    Create a Lambda Function

2    Setup a Custom Skill

The Lambda function is an Amazon Web Service (AWS) that allows you to write the function to handle the requests that come from Alexa. The Lambda function can be written in Node-js, Java or Python. It’s available to run 24/7 and is hosted on Amazon’s servers. In our situation it will handle the RESTful interface with the IoT device.

The Custom Skill consists of configuring the Actions you want to take (“Device Directives” in AWS speak), and the words you’ll say to Alexa to trigger those Actions (“Utterances” in AWS speak). It performs the task of triggering the Lambda function when you speak a phrase to your Echo Dot that matches a trigger phrase.

 

As an example consider a Lambda function called Hello World, whose function is to say “Hello World” whenever you trigger it. Your trigger phrase will be “Say Hi“, so you’ve also configured a Custom Skill to recognise that phrase. To trigger the Lambda Function you say:  “Alexa, ask Hello World  to Say Hi“.  “Alexa” is the wake-word to tell the Echo Dot to listen, followed by the name of the Service/Function you’re asking it to trigger and finally the Trigger phrase. Once triggered like this, Alexa responds with the response programmed by the Lambda Function “Hello World”.

To really get to grips with this, take a few minutes to read over this Hello World example.

 

Also, please take a look through the Smart Home Thermostat  we’ll be controlling, so you can understand the RESTful API.

 

Step 1

Firstly you’ll need an Amazon Web Services account to host your Lambda function: https://aws.amazon.com/lambda/

You’ll be asked for Credit Card details even though you’ll be using the Free Tier.

 

Step 2

Create the Lambda function to handle the requests from Alexa. I’ll focus on our IoT example so I  won’t go through a detailed walkthrough of this, you can find that on Amazon’s developer portal. You’ll need to read through this to understand the process.

 

Step 3

Program the Lambda function.

Here’s a basic Lambda function in Node.js to interface with the  Smart Heating System.

It implements three Intents (simplified for clarity):

  1. GetDownTempIntent  : Asks for the temperature from the downstairs sensor
  2. TurnOnIntent:   Turns the heating On
  3. SetDownTempFRACIntent  : Sets the downstairs setpoint

Much of the example Lambda function is composed of infrastructure and helper functions. One area we’re interested in is mapping the Intents to the functions that carry out the intents.

(Remember the Intents are coming from the Custom Skill that we have yet to setup).

This is the relevant section of code. See how intentName (coming from Alexa)  is checked for the specified intent e.g.

if ("GetDownTempIntent" === intentName) { ... }

and in more detail

/**
 * Called when the user specifies an intent for this skill.
 */
function onIntent(intentRequest, session, callback) {
    console.log("onIntent requestId=" + intentRequest.requestId
                + ", sessionId=" + session.sessionId);

    var intent = intentRequest.intent,
        intentName = intentRequest.intent.name;

    // Dispatch to your skill's intent handlers
    if ("GetDownTempIntent" === intentName) {
        GetDownTemp(intent, session, callback);
    }
    else if ("TurnOnIntent" === intentName) {
        TurnOn(intent, session, callback);
    }
    else if ("SetDownTempFRACIntent" === intentName) {
        SetDownTempFRAC(intent, session, callback);
    }else{
        throw "Invalid intent";
    }
}

 

You can see that the GetDownTemp() function, see below, is called when the GetDownTempIntent is triggered.

Notice that the function prepares a cardTitle to show on the Alexa App on your phone, calls GET() to perform request the data from the Particle Cloud and prepares a speechOutput once the response is received.

 

function GetDownTemp(intent,session,callback){
    var sessionAttributes = {};
    var cardTitle = "GetDownTemp";
    var repromptText=null;
    
    GET("tempDOWN",function(response) {    
    var speechOutput = "The down stairs temperature is "+response/10+" degrees";
    
    var shouldEndSession = true;
    
    callback(sessionAttributes,
             buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
    });
}

The GET() function uses the GET method to request the data as follows. Obviously you would use your own Particle Photon’s deviceid and access token.

function GET(cmd,response) {
    var https = require('https');
    
    var url = 'https://api.particle.io/v1/devices/1234fffe/\
'+cmd+'\
?access_token=dada1234';
    
    https.get(url, function(res) {
      var body = '';
      res.on('data', function(chunk) {
        body += chunk;
      });
      res.on('end', function() {
    	var jsData = JSON.parse(body);
    	response(jsData.result);
      });
    }).on('error', function(e) {
      console.log("Got error: " + e.message);
    }); 
}

 

The POST method for the RESTful API is hadled in a similar way; see the full code.

Step 4

Setup the Custom Skill to trigger the Lambda function.

To do this, first: create or sign into your Developer Portal account and navigate to Apps& Services/Alexa/Alexa Skills Kit

A few things to be careful of here:

Make sure the Language matches the Language you’ve selected for your developer account. If it doesn’t you’re app will be unresponsive on your Echo Dot, reporting an unkown error.

Make sure to put in the application ID of your Lambda Function.

The Intent Schema defines your Actions or Intents:

{
  "intents": [
    {
      "intent": "GetDownTempIntent"
    },
    {
      "intent": "TurnOnIntent"
    },
    {
      "intent": "SetDownTempFRACIntent",
      "slots": [
        {
        "name": "DownSetInt",
        "type": "AMAZON.NUMBER"
        },
        {
        "name": "DownSetFrac",
        "type": "AMAZON.NUMBER"
        }
      ]
    }
  ]
}

 

And the Sample Utterances are the words you’ll use to trigger the Intents:

 GetDownTempIntent get the temperature downstairs
 GetDownTempIntent get the downstairs temperature
 GetDownTempIntent what's the temperature downstairs
 GetDownTempIntent what's the downstairs temperature
 GetDownTempIntent what the temperature is downstairs
 TurnOnIntent turn on
 SetDownTempFRACIntent Set the downstairs temperature to {DownSetInt} point {DownSetFrac} degrees
 SetDownTempFRACIntent Set the temperature downstairs to {DownSetInt} point {DownSetFrac} degrees

 

Step 5

Have fun. Go ahead and apply this to your own RESTful IoT device.