amazon-alexa-control-rapsberry-pi-tutorial

Alexa Voice-controlled Raspberry Pi using Lambda and PubNub



At SwitchDoc Labs, we’re known for producing interesting and inexpensive starter and intermediate kits for the maker movement for the Raspberry Pi, Arduino and the ESP8266.

We are pleased to be presenting this tutorial on how to connect the Raspberry Pi to the Amazon Alexa using PubNub as the highly reliable bidirectional data link.  This is an instructional tutorial to get your Raspberry Pi to Amazon Alexa Interface working. All source code is provided! While we are focusing on a simple LED in this tutorial, the techniques we developed are applicable to a number of different projects, basic to advanced.

Note: the use of PubNub is critical to the function of this project. PubNub as the broker allows us to build a bidirectional data path from the Raspberry Pi to Alexa without exposing the Raspberry Pi to the Internet through your firewall. There is no web server used in the article, especially on the Raspberry Pi.

We will be rolling this really cool feature set into our other major kit offerings including:

Project and Hardware Overview

This project is designed to be a simple hardware project to illustrate how you can use Alexa to control your Raspberry Pi and the devices connected to it. We will be using Alexa to control an LED plugged into a Raspberry Pi.  This project consists of four parts.

We’ll use four different technologies:

  1. Raspberry Pi
  2. Grove LED
  3. Pi2Grover Interface Board
  4. Amazon Echo, Dot or Show (any Alexa-enabled device)

Raspberry Pi

The Raspberry Pi is a series of small single-board computers developed in the United Kingdom by the Raspberry Pi Foundation to promote the teaching of basic computer science in schools and in developing countries. The original model became far more popular than anticipated, selling outside its target market for uses such as robotics. It does not include peripherals (such as keyboards, mice and cases).

Check out our comparison of Raspberry Pi boards here.

Grove LED

The Grove LED is a general purpose LED module using a Grove Digital Port, available in different colors. This LED is designed for monitoring controls from digital ports. It can be mounted to the surface of your box or desk easily and used as pilot lamp for power or signal. The brightness of the LED can be adjusted by the included potentiometer.

Pi2Grover Board

The Pi2Grover board provides 15 Grove connectors for your prototyping needs. 10 Grove Digital, 4 Grove I2C, and one Grove UART. No software drivers are required.  It plugs right into your Raspberry Pi with a special connector that allows you to plug boards or hats on top of the Grove board.

Amazon Echo (or any other Alexa-enabled device)

Amazon Echo is a brand of smart speakers developed by Amazon. The devices connect to the voice-controlled intelligent personal assistant service Alexa, which responds to the name “Alexa”.  This “wake word” can be changed by the user to “Amazon”, “Echo” or “Computer”

The device is capable of voice interaction, music playback, making to-do lists, setting alarms, streaming podcasts, playing audiobooks, and providing weather, traffic, and other realtime information.   It can also control smart devices using itself as a home automation hub. Since it is so inexpensive, we chose it to build a set of interactive programs.

Software Overview

There are four major parts to this project.

  • Alexa Skills controls the Alexa-enabled Echo
  • AWS Lambda Serverless Function brokers information from PubNub to the Alexa Skills
  • PubNub is the MQTT Broker between SmartPlantPi and the AWS Lambda Function
  • Raspberry Pi is the MQTT Publisher and Subscriber for Raspberry Pi information back and forth to PubNub

MQTT

MQTT is a publish-subscribe based “lightweight” messaging protocol for use on top of the TCP/IP protocol, such as the WiFi packets that we are using in this project. It is designed for connections with remote locations where a “small code footprint” is required or the network bandwidth is limited. The publish-subscribe messaging pattern requires a message broker. The broker (PubNub in this case) is responsible for distributing messages to interested clients based on the topic of a message.

Publish-subscribe is a pattern where senders of messages, called publishers (in this case our ESP8266 is the publisher), don’t program the messages to be sent directly to subscribers, but instead characterize message payloads into classes without the specific knowledge of which subscribers the messages are sent to. Similarly, subscribers will only receive messages that are of interest without specific knowledge of which publishers there are.

Mosquitto operates as the broker in this system and routes the published data to the appropriate subscribers.

JSON

JSON is an open standard format that uses human-readable text to transmit data objects consisting of attribute-value pairs. It is the primary data format used for asynchronous browser/server communication, largely replacing XML.

XML is a “heavier” protocol that is also hierarchical in nature, but with a great deal more redundancy that JSON.  Yes, there are class wars going on for people that advocate JSON over XML, but in today’s world of higher speed communication, it rarely matters.  You can make the argument that the higher data density of JSON is a better choice for IOT applications.

PubNub

PubNub is an MQTT broker in the same sense as Mosquitto MQTT Broker is on a Raspberry Pi Platform. PubNub is a global Data Stream Network (DSN) and realtime infrastructure-as-a-service (IaaS) company. PubNub makes products for software and hardware developers to build realtime web, mobile, and Internet of Things (IoT) applications.

PubNub’s offers a realtime MQTT  publish/subscribe messaging API built on their global data stream network which is made up of a replicated network of 15 data centers. The network currently serves over 300 million devices and streams more than 750 billion messages per month.

The foundation of PubNub is providing you the ability to integrate scalable, realtime data streams into your applications. Using the publish/subscribe paradigm, subscribers to a particular channel will receive any and all messages that are published to that channel. It doesn’t matter if there is one subscriber, 10 subscribers, 1000 subscribers or millions of subscribers, a published message will be delivered to all of those subscribers on that channel in less than ¼ second.

Alexa Skills

Alexa is Amazon’s voice service and the brain behind tens of millions of devices like the Amazon Echo, Echo Dot, and Echo Show. Alexa provides capabilities, or skills, that enable customers to create a more personalized experience.

We are building an Alexa skill that will interface to the SmartPlantPi from Switchdoc Labs. It provides the interface from your Amazon echo to the SmartPlantPi system. The Alexa skill manages the voice part of the project.   It takes verbal commands (“Alexa, ask Smart Plant Status” which gives the current status of YOUR SmartPlantPi.

An Amazon Alexa skill takes voice input from an Amazon Echo or other devices, translates it to text, compares it against what the skill is expecting (“utterances”) and then sends a JSON response to a specific application or server.

The Alexa Skills Kit (ASK) is a collection of self-service APIs, tools, documentation, and code samples that makes it fast and easy for you to add skills to Alexa. ASK enables designers, developers, and brands to build engaging skills and reach customers through tens of millions of Alexa-enabled devices. With ASK, you can leverage Amazon’s knowledge and pioneering work in the field of voice design.

AWS Lambda Serverless Function

AWS Lambda is an event-driven, serverless computing platform provided by Amazon as a part of the Amazon Web Services. It is a compute service that runs code in response to events and automatically manages the compute resources required by that code. It was introduced in 2014.

Lambda Function is the most difficult to understand part of this project. Why do we need this? An Amazon Alexa Skill is concerned with “utterances” and how to interpret them. When you talk to Alexa, Alexa translates your speech to text, sends a request to the Lambda function.

The Lambda function interprets this Alexa JSON request, gathers the SmartPlantPi data via an MQTT history request from PubNub (which came from SmartPlantPi via MQTT), and sends a text response (JSON again) to Alexa with the required plant data embedded, and Alexa speaks the result.

We are using Node.js to write our Lambda Function. Parts were very challenging (dealing with asynchronous callbacks in an environment that will terminate when you are done running code), but we got it to work perfectly.

The purpose of Lambda, as compared to AWS EC2 (cloud-based servers), is to simplify building smaller, on-demand applications that are responsive to events and new information. AWS targets starting a Lambda instance within milliseconds of an event. Node.js, Python, Java and C# through .NET Core are all officially supported as of 2016, and other languages can be supported via call-outs.

However, some runtimes, such as the Java Virtual Machine, may be slower than others to start. Below is a JSON request from the Alexa Skill to the Lambda Function. Note the Lambda function is event-driven, so it wakes up with this request, gets the plant data via MQTT from PubNub, builds the response and sends it back to Alexa (with confidential stuff redacted):

{

  "session": {

    "new": true,
    
    "sessionId": "SessionId.f02ae7fb-5045-4c86-8937-b44a74e63f6e",
    
    "application": {
      
    "applicationId": "amzn1.ask.skill.1XXXXX"
    
    },
    
    "attributes": {},
    
    "user": {
      
    "userId": "amzn1.ask.account.XXXXXXXX"
    
    }
  
},
  
"request": {

    "type": "IntentRequest",
    
    "requestId": "EdwRequestId.3560fc59-308d-41a4-8396-2e56d4781ce3",
    
    "intent": {
      
    "name": "LEDOn",
      
    "slots": {}
    
    },
    
    "locale": "en-US",
    
    "timestamp": "2017-12-30T00:45:17Z"
  
},
  
"context": {
    
  "AudioPlayer": {
      
  "playerActivity": "IDLE"
    
 },
    
 "System": {
      
 "application": {
        
 "applicationId": "amzn1.ask.skill.111c1582-8cc3-43af-afb9-984fb01f805a"
      
 },
      
 "user": {
        
 "userId": "amzn1.ask.account.XXXX"
      
 },
      
 "device": {
        
 "supportedInterfaces": {}
      
 }
    
 }
  
 },
  
 "version": "1.0"
}

And the JSON reply to the Alexa Skill from the Lambda function:

{
  
  "version": "1.0",
  
  "response": {
    
    "outputSpeech": {
      
      "type": "PlainText",
      
      "text": "L E D turned on."
    
    },
    
    "shouldEndSession": true
  
  },
  
  "sessionAttributes": {}

}

A valid question at this point, is why the Lambda function doesn’t just subscribe (via MQTT) to the Raspberry Pi Data channel (Pi2Alexa_Status) on PubNub?

The reason is that we don’t want the Lambda Function to be running all the time (which you need to be running to be a subscriber), we want the Lambda function to awake only on a request from Alexa. Lambda Functions are event-driven from triggers. Alexa is our trigger in this case.

On a technical note, Lambda functions wake up “stateless” every time.  The function has no execution to execution built int to the function.   You can use an external database (Amazon Elastic Beanstalk for example), but that just increases the cost.  Lucky for us, the “state” information we have (the plant information) is stored at PubNub and our Lambda function just grabs it there in the PubNub channel history. AWS Lambda supports securely running native Linux executables via calling out from a supported runtime such as Node.js. AWS Lambda usage below a threshold (which we will be under) is free.

Raspberry Pi MQTT Interface

The Pi2Alexa interface based on a Raspberry Pi single board computer.  We use Python to program this device and the open source code is up on our GitHub repository here. After you set up the PubNub keys on Pi2Alexa.py, you will periodically (every 60 seconds currently) update PubNub via MQTT.

JSON Data Payload

Here is an example of the data packet we are using in the Pi2ALexa.py for sending status information in JSON for the MQTT payload:

{
  
  "TimeStamp": "01/24/2018 19:27:58",
  
  "Pi2Alexa_LEDState": "Off",
  
  "Pi2Alexa_CurrentStatus": "Active",
  
  "Pi2Alexa_Version": "002"

}

And the message coming back to the Raspberry Pi controlling the LED:

{

  "LED": "On"

}

PubNub Setup

PubNub is used to provide an MQTT connection from the Raspberry Pi to the Amazon Lambda Function. We use the Raspberry Pi processor to publish status information to PubNub, which is then fetched by the Amazon Lambda Function and relayed to the Alexa Skill. The Lambda function also sends the control JSON information to PubNub for the Raspberry Pi.

You’ll first have to sign up for a free PubNub account. Now, let’s setup the MQTT info to connect up OurWeather.

Create a new App by clicking on “NEW APP +”..   Type in Pi2Alexa in the “enter a new app” filed and hit the “CREATE NEW APP +” button.

You should see this (except SunIOT will be Pi2Alexa):

Click on the Pi2Alexa App page.

The enter “Pi2Alexa” in the “Enter a New Keyset Name” field and hit the “CREATE NEW KEYSET +” button. That will get you a page that looks like this.

You’ll see your unique pub/sub keys from the PubNub Dashboard. You’ll need those in a bit.

Scroll down on the page and turn “Storage & Playback” to On. If you don’t do this, nothing will work. Leave the retention on 1 day. Now you are set up on PubNub. Nex,t we put together the Alexa Skill.

Setting up the Alexa Skill

The Alexa skill talks to the Amazon Echo. It is a bidirectional link, sending received voice for translation to text by the Amazon servers, and then returning text that will be rendered as voice through the Alexa device.

Following are the steps for setting up an Amazon Skill on developer.amazon.com.

We will need to tell the Alexa Skill what phrase (“invocation”) we want it to respond to (“Ask Smart Plant” in this case), which will activate our app (“skill”) and then what commands (“intents”) to listen for. We also specify what endpoint it should ping (which we will generate in part 4 – the Lambda Function).

Set up your Free Developer Account

Make a new Account on developer.amazon.com. Make sure you use the same Amazon account name and password that you use on your Echo devices or else you won’t be able to talk to your Alexa Devices.

Once you are logged in you should see a screen like this.  Click on the Amazon Alexa link.

Next click on “Add Capabilities to Alexa.” Then click on “Start a Skill” and we are off to the races.

Building Your Skill

Now we’ll give Amazon some information about your application. If you want to change some of this, you will be able to do that later. The names you use for this Alexa Skill are unique to your account. If we were to publish this (which we will NOT be doing – it is only for your own account) we would need to have a unique name.

  • Leave skill type as “Custom Interaction Model”
  • Type in “Alexa Raspberry ” for the name
  • Type in “raspberry pi” for the invocation (this is what we’ll say to activate this Alexa app)
  • Leave the other fields at “no”

You should have a screen that looks like this:

Click “save” and then the application ID will be generated. Do a cut and paste and save this application ID. We will need it for the Lambda function. Your screen will then look the this.

Note: This application ID below will not work. It has been disabled. You must use your own.

Now click “Next” to continue or on the “Interaction Model” tab to the left.

Intent Schema and Utterances

When you create a custom skill, you implement the logic for the skill, and you also define the voice interface through which users interact with the skill. To define the voice interface, you map users’ spoken input to the intents your cloud-based service can handle. This is done by inputting Intents and Utterances .

  1. Intents: An intent represents an action that fulfills a user’s spoken request. Intents can optionally have arguments called slots, which we will not be using. The Intents are entered using JSON format.
  2. Utterances: A set of likely spoken phrases mapped to the intents. This should include as many representative phrases as possible. This is entered in the form: Name of Intent (from above) on right and the phrase a user might speak to signal that intent on the right.
  3. Custom slot types: A representative list of possible values for a slot. Custom slot types are used for lists of items that are not covered by one of Amazon’s built-in slot types. We are not using this in the SmartPlantPi Skill, but we could.
  4. Dialog model (optional): A structure that identifies the steps for a multi-turn conversation between your skill and the user to collect all the information needed to fulfill each intent. This simplifies the code you need to write to ask the user for information. We will not be building a dialog model for our simple skill.

Note: do not click the Launch Skill Builder Beat at this time.  If you do, go to the bottom of the Skill Builder and click “opt-out of the beta program.” It’s not ready for what we want to do.

Copy and paste the following JSON into the Intent Schema box. We are building a pretty simple skill with simple intents.   These intents will show up as input to our AWS Lambda Function.

{
  
  "intents": [
    
  {
      
    "intent": "about"
    
  },
    
  {
      
    "intent": "status"
    
  },
    
  {
      
    "intent": "LEDON"
    
  },
    
  {
      
    "intent": "LEDOFF"
    
  },
    
  {
      
    "intent": "timestamp"
    
  }
  
  ]

}

Next copy and paste the following into the Sample Utterances Box.

Note that they are of the form “intent” “phrase”, where intent is from the above Intent Schema box.

status tell me status

status tell me all

status status

status give me status

status give me all

about about

about tell me about

about tell me about you

timestamp timestamp

LEDON L E D On

LEDON On

LEDOFF Off

LEDOFF L E D Off

Your screen should now look like the following:

Now Click Save and then click Next.

Configuration Screen

This is the screen where we tell Alexa where to go when we send one of our commands. It can be any endpoint or server (we have used it to point to a web server on a Raspberry Pi for example). What we will be doing is pointing it an Amazon Lambda Function for simplicity and since we don’t need the function to run all the time.

We can use the serverless Lambda function. We will come back to this screen once we have built our Lambda Function. We’ll come back to enter in the AWS Lambda ARN as the endpoint.

Remember to make note of your Alexa app id as we’ll need it in the Lambda code.

Test, Publishing Information and Privacy & Compliance Tabs

We can safely ignore all of the other screens at this point. The Test tab is something we can come back to later.

Now on to the Lambda function!

Setting Up the Lambda Function

First you’ll have to sign up for an AWS developer account. It will  require a credit card number, even though we are using the free tier services.

Once you have signed up, you’re presented with a ton of options. AWS is a very robust and multifaceted cloud server provider.  Type “lambda” in the search bar

Click on “Create Function” and you will see the screen below:

Enter “Pi2Alexa” into the Lambda Function Name field. Leave the runtime at the default, “Node.js 6.10” Click on Create Custom Role in the dropdown under “Role” Leave the defaults on the page below and click “allow.”

Now select “lambda_basic_execution” under existing role. Sometimes this page glitches and nothing will show under “Role”.

Click on “Create Function.” Now you will have the screen below (however your screen will be title Pi2Alexa instead of SDL2Alexa). Most of these options below, we will not touch.

Next click on Add Triggers-> Alexa Skills Kit and then on “Add” under Configure Triggers. Finally, click on “Save” in the upper right corner of the page. Now, you should have this:

At the top of this screen you will see your ARN (Amazon Resource Name) that we need to connect to the Amazon Alexa Application.Copy the ARN number (behind the “- “)  and then open up your Alexa Skill that you set up earlier in another browser (login to developer.amazon.com).

Our example ARN above (which will not work for you, you need your own) was “arn:aws:lambda:us-west-2:770035828910:function:Pi2Alexa”. Click on the configuration tab in your Alexa Raspberry Pi Alexa App from above and click on the radio button “AWS Lambda ARN” and then enter your ARN number as the default under endpoint as below:

Our Alexa Skill configuration is now complete. We now go back to the Lambda Function and install our software. Add the Alexa Skills Kit Trigger, if it isn’t shown: (Add triggers->Alexa Skill Kit, then Add).

Now finally, click on the SDL2Alexa button at the top of the Designer Block to look at your code. Your Lambda screen should now look like this (with the exception that yours should show Pi2Alexa instead of SDL2Alexa):

Now we can install the Lambda software.

Installing the Lambda Software Alexa2SDLPi

We have the Lambda software and all required libraries, here in a zip file. It is also included in the Github files below (when you start on the Raspberry Pi).

Download this to your computer. Under Function code, click on the drop-down “Code entry type” and select “Upload a .ZIP file”. Then click on Upload and select the Zip file from your computer you just downloaded. It should be “SDL2AlexaPi.zip”.

If you are on a Mac, it may automatically unzip the file, in which case go into the SDL2AlexaPi directory, select all the files, right-click, and compress it again (it will be archive.zip in the program directory).

Then click “Save” in the top right corner. Click on the highlighted Trigger (Pi2Alexa). Now go down to the Function code block to the Code entry type drop-down and select “Edit code inline” and you should now see this:

Configure the Lambda Function

Almost done now. We have a couple of things to configure in the Lambda code. In the function code block, get your PubNub pub/sub keys and paste it into the text slot string for pub_key and sub_key. This is how your code will look once you’ve done so:

var pubnub =  new PubNub({

    ssl           : true,  
    
    publish_key   : "YOUR_PUB_KEYS",
    
    subscribe_key : "YOUR_SUB_KEYS",
 

});

var subscribechannel = 'Pi2Alexa_Status';

var publishchannel = 'Pi2Alexa_Data';

Put in the Alexa Skill ID. The one below will NOT WORK. You must grab your Alexa Skill Application ID (see the Alexa Skill you built above- it will be under the Skill Information Tab in your Alexa App). Now that part of the lambda code should look like this:

/**
 
 * App ID for the skill
 
 */

var APP_ID = 'amzn1.ask.skill.2ff2989c-6a37-4166-9f69-b16e9545dab8'; //replace with "amzn1.echo-sdk-ams.app.[your-unique-value-here]";

That is it for configuration. Save the function. Now onto testing.

Testing Your App

Testing Alexa Skills

Back to the Alexa Skill. Go to the “Test” tab and enable the test if you haven’t already. Down in the Service Simulator in the text tab, type “status” and click, “Ask SmartPlantPi Alexa App”.

You will get a failure for the Service response (we have no data yet because we haven’t set up SmartPlantPi yet), but what we really want is the JSON Service request. W

e are going to use that in the Lambda Function test. Copy all of the JSON code out of the Service Request. It will look something like this (this code BELOW WILL NOT WORK! – You must get your own):

{

  "session": {

    "new": true,
    
    "sessionId": "SessionId.e378cb07-fc7a-4464-8ad6-f3e12e52610d",
    
    "application": {
      
    "applicationId": ""amzn1.ask.skill.83324277-3dda-4a60-91f4-4657da0e92f0"
    
    },
    
    "attributes": {},
    
    "user": {
      
    "userId": "amzn1.ask.account.AH"
    
    }
  
},
  
"request": {

    "type": "IntentRequest",
    
    "requestId": "EdwRequestId.8c2fda51-30ce-48e4-abe5-411055b524ce",
    
    "intent": {
      
    "name": "status",
      
    "slots": {}
    
    },
    
    "locale": "en-US",
    
    "timestamp": "2018-01-07T22:12:32Z"
  
},
  
"context": {
    
  "AudioPlayer": {
      
  "playerActivity": "IDLE"
    
 },
    
 "System": {
      
 "application": {
        
 "applicationId": "amzn1.ask.skill.83324277-3dda-4a60-91f4-4657da0e92f0"
      
 },
      
 "user": {
        
 "userId": "amzn1.ask.account.AH"
      
 },
      
 "device": {
        
 "supportedInterfaces": {}
      
 }
    
 }
  
 },
  
 "version": "1.0"
}

Now let’s go test the Lambda Function.

Testing the Lambda Function

Click on the drop-down menu next to the test button and select “Configure test events”. On the next screen, call your Event name, “Status” and then paste the JSON Service Request code from the previous step. Clicking the Test button now will show a failure. We need to load up some data on PubNub first for the Lambda Function to work.

After we set up SmartPlantPi in the next Part, we will have live data to work on. But right now, let’s publish a message that the Lambda Node will be able to pick up.  Here is a JSON message from SmartPlantPi to PubNub that we will use in our testing.

{
  
  "TimeStamp": "01/26/2018 08:39:38",
  
  "Pi2Alexa_LEDState": "Off",
  
  "Pi2Alexa_CurrentStatus": "Active",
  
  "Pi2Alexa_Version": "002"

}

Go to your PubNub account and go down into your SDL2Alexa App and then select your subscribe key from the Pi2Alexa (you should have this saved somewhere else too).

Next, click on the side tab to Debug Console. Make the Default channel “Pi2Alexa_Status” and place your pub-sub key into the Authorization key. Click on Add Client. Make sure you get the channel right! Then make another client by using the same authorization key and make the channel “Pi2Alexa_Data”.

Now you should have a screen that looks like this:

Paste the JSON message from Pi2Alexa (above) into the test message slot and press send.

Now our Lambda will have something to chew on. Go back to your Lambda page and click on Test (running the Status Test that we sent up earlier!). Look at the Execution Results in the Function code block and you should have your first success full Response.

Now let’s go back to the Alexa Skill. Go back to the Service Simulator, type “status” into the Enter Utterance box and hit the “Ask Alexa Raspberry Pi App”.

Now you have connected all the way from your Alexa Skill to your Lambda Function, which reads the PubNub channel and sends back the status. Hit the listen button to hear what it would sound like on your Echo.

Testing Your Alexa

OK, now the rubber hits the road.

We have the Alexa Skill working, we have the Lambda Function working, let’s go to your phone and add the Alexa App.

Note you must be logged into the same email address and account for your Alexa App on your phone (and have registered your Echos to the same account (email address) for your app to show up).

On your app, click the menu, then select Skills. Then click on Your Skills at the top right. Look under All Skills or just updated and you will find your new skill (Alexa Raspberry Pi in this case). Select your new skill. Finally, slide over the tabs from Recently Added all the way to the right and you should see DEV SKILL. Click that and you should see something like this (OurWeather is another SwitchDoc Labs Kit):

Next is the big moment.

Ask Alexa “Alexa, ask Raspberry Pi Status”. You should be rewarded as below.

Next, we’ll hook up the LED and the Raspberry Pi to our system.

Lambda Node.js Intent Software – Promises, Promises!

Before we move on, let’s discuss the Lambda Node.js code. If you recall, Lambda Functions quit when they stop running code. This is a problem for a node.js program that deals with asynchronous callbacks.

In our Lambda code, we request a history on the SmartPlantPi station channel: SmartPlantPi_Alexa from the MQTT channel on PubNub. This takes a while to come back (on the order of 100ms or so) and if we don’t stop the Lambda Function somehow, it will stop before the callback comes back because of the nature of a node.js program.

How do we solve this? The key is Promises.

We essentially make the Node.js Lambda function “promise” to wait until the callback routine returns (or the 3 to 7 second default lambda function timeout happens). When the callback is processed (the promise being kept) and the response is then sent to the Alexa skill and the lambda function terminates.

What are Promises?

The core idea behind promises is that a promise represents the result of an asynchronous operation. A promise is in one of three different states:

  • pending – The initial state of a promise.
  • fulfilled – The state of a promise representing a successful operation.
  • rejected – The state of a promise representing a failed operation.

Once a promise is fulfilled or rejected, it is immutable (i.e. it can never change again).   An example promise for the “status” intent in the Pi2Alexa lambda code:

/// status intent
status: function (intent, session, response) {
           


var first = pubnub.history({
    channel: subscribechannel,
    reverse: false, // Setting to true will traverse the time line in reverse starting with the oldest message first.
    count: 1, // how many items to fetch

}).then((response) => { 
    var obj = JSON.parse(JSON.stringify(response));

    var msgs = obj.messages;
    var msg = msgs[0];
    var parsedJSON = JSON.parse(JSON.stringify(msg.entry));
    JSONMessage = parsedJSON;

    return;
 
}).catch((error) => { 
    console.log(error) 
});

  return Promise.all([first])
        .then(function (responses) {
            var myText;
            myText = "";
            
            
          
            myText = "Raspberry Pi Status. ";

            myText = myText +  " L E D is  "+ JSONMessage.Pi2Alexa_LEDState+ "."; 
            myText = myText +  " Pi2Alexa Version:  "+ JSONMessage.Pi2Alexa_Version+ "."; 
         var myTime;
            myTime = JSONMessage.TimeStamp;
            myTime = myTime.replace(" ", "  at Time:  ");
 
                
                 
                 myText = myText + "  I last heard from The Raspberry Pi on Date: "+myTime+ ".  Time is From the Raspberry Pi";


            response.tell(myText);


            return ;
        });


    },

The syntax is somewhat obscure, but you can see the return from the history call (the”first” function) is in the Promise.all function call that waits for the history PubNub return and builds the response for the Alexa Skill. What’s Next?  Installing Pi2Alexa on your Raspberry Pi.

Hooking Up Your Raspberry Pi

The Hookup for this project is easy.  You put the Pi2Grover carefully on the Raspberry Pi and then you plug a Grove cable into D4/5 on the Pi2Grover and plug the other end into the Grove connector on the Grove LED.

That’s it!   Now power up your Raspberry Pi and if all is well you will see a blue LED on the Pi2Grover board and most of the time, you will see the Grove LED turn on (the GPIOs on the Raspberry Pi wake up as Inputs, so the pull-ups in the voltage translation circuitry will either resolve the input as a one or as a zero, always a one on the Pi2Grover.

Pi2Alexa Software

Installation

In order to install the software for the Pi2Alexa, you need to have some experience with the command line and installing software on the Raspberry Pi.

The Pi2Alexa software is at this link on GitHub. You can download the software by running the following commands.

cd

git clone https://github.com/switchdoclabs/SDL_Pi_Pi2Alexa.git

Configuration

Almost done now. We next need to configure the Pi2ALexa software to talk with PubNub.

In the terminal window, cd down to the SDL_Pi_Pi2Alexa directory. Then use your favorite text editor (like nano or vi) to open the Pi2Alexa.py file. Using your PubNub publish and subscribe keys, put your keys into this section of code near the top of the file.

# PubNub configuration


Pubnub_Publish_Key = "pub-c-xxx"

Pubnub_Subscribe_Key = "sub-c-xxx"

Starting Pi2Alexa

Once you have put the keys into the program, start it by running:

python Pi2Alexa.py

You should see something like the below, if you have your PubNub keys correct.

pi@RPi3-60:~/SDL_Pi_Pi2Alexa $ python Pi2Alexa.py

{'TimeStamp': '01/26/2018 15:05:16', 'Pi2Alexa_LEDState': 'Off', 'Pi2Alexa_CurrentStatus': 'Active', 'Pi2Alexa_Version': '002'}

status.is_error False

status.original_response [1, u'Sent', u'15170079171253133']

First, we can check to see that your MQTT message is getting to PubNub. Go to your PubNub account and go down into your Pi2Alexa App and then select your subscribe key from the Pi2Alexa Key (you should have this saved somewhere else too).

Next, Click on the side tab to Debug Console.

Make the Default channel “SPi2Alexa_Status” and place your pub-sub subscribe key into the Authorization key. Click on Add Client.  Then do the same thing again, but put in the channel, “Pi2Alexa_Data”. Wait a few minutes and you should receive a JSON MQTT message from Pi2Alexa as below:

You are wired up!

The Ultimate Full System Test

Well, now after setting up the Alexa Skill, the Lambda Function, PubNub, the Raspberry Pi and Pi2ALexa, we are ready to go for our full system test. Say to your echo, “Alexa, Ask Raspberry Pi Turn LED On” You should hear the following, and see the LED connected to your Raspberry Pi turn on.

Conclusion

Experiment with using the other commands, such as: About, status, LED On, LED Off, On and Off. Now that you have this whole framework running, it is pretty easy to add your own commands and control other devices hooked up to your Raspberry Pi.

Use Cases:

Try PubNub Today