├── .gitignore ├── ASK ├── speechAssets │ ├── IntentSchema.json │ └── SampleUtterances.txt └── src │ ├── AlexaSkill.js │ └── index.js ├── Arduino └── ParticleExample.ino ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | # Mobile Tools for Java (J2ME) 4 | .mtj.tmp/ 5 | 6 | # Package Files # 7 | *.jar 8 | *.war 9 | *.ear 10 | 11 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 12 | hs_err_pid* 13 | -------------------------------------------------------------------------------- /ASK/speechAssets/IntentSchema.json: -------------------------------------------------------------------------------- 1 | { 2 | "intents": [ 3 | { 4 | "intent": "ParticleIntent", 5 | "slots": [ 6 | { 7 | "name": "command", 8 | "type": "LIST_OF_COMMANDS" 9 | } 10 | ] 11 | }, 12 | { 13 | "intent": "AMAZON.HelpIntent" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /ASK/speechAssets/SampleUtterances.txt: -------------------------------------------------------------------------------- 1 | ParticleIntent {command} 2 | ParticleIntent turn {command} 3 | ParticleIntent to turn {command} 4 | ParticleIntent thing {command} 5 | ParticleIntent turn thing {command} 6 | ParticleIntent to turn thing {command} 7 | -------------------------------------------------------------------------------- /ASK/src/AlexaSkill.js: -------------------------------------------------------------------------------- 1 | // Alexa SDK for JavaScript v1.0.00 2 | // Copyright (c) 2014-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. Use is subject to license terms. 3 | 'use strict'; 4 | function AlexaSkill(appId) { 5 | this._appId = appId; 6 | } 7 | 8 | AlexaSkill.prototype.requestHandlers = { 9 | LaunchRequest: function (event, context, response) { 10 | this.eventHandlers.onLaunch.call(this, event.request, event.session, response); 11 | }, 12 | 13 | IntentRequest: function (event, context, response) { 14 | this.eventHandlers.onIntent.call(this, event.request, event.session, response); 15 | }, 16 | 17 | SessionEndedRequest: function (event, context) { 18 | this.eventHandlers.onSessionEnded(event.request, event.session); 19 | context.succeed(); 20 | } 21 | }; 22 | 23 | /** 24 | * Override any of the eventHandlers as needed 25 | */ 26 | AlexaSkill.prototype.eventHandlers = { 27 | /** 28 | * Called when the session starts. 29 | * Subclasses could have overriden this function to open any necessary resources. 30 | */ 31 | onSessionStarted: function (sessionStartedRequest, session) { 32 | }, 33 | 34 | /** 35 | * Called when the user launches the skill without specifying what they want. 36 | * The subclass must override this function and provide feedback to the user. 37 | */ 38 | onLaunch: function (launchRequest, session, response) { 39 | throw "onLaunch should be overriden by subclass"; 40 | }, 41 | 42 | /** 43 | * Called when the user specifies an intent. 44 | */ 45 | onIntent: function (intentRequest, session, response) { 46 | var intent = intentRequest.intent, 47 | intentName = intentRequest.intent.name, 48 | intentHandler = this.intentHandlers[intentName]; 49 | if (intentHandler) { 50 | console.log('dispatch intent = ' + intentName); 51 | intentHandler.call(this, intent, session, response); 52 | } else { 53 | throw 'Unsupported intent = ' + intentName; 54 | } 55 | }, 56 | 57 | /** 58 | * Called when the user ends the session. 59 | * Subclasses could have overriden this function to close any open resources. 60 | */ 61 | onSessionEnded: function (sessionEndedRequest, session) { 62 | } 63 | }; 64 | 65 | /** 66 | * Subclasses should override the intentHandlers with the functions to handle specific intents. 67 | */ 68 | AlexaSkill.prototype.intentHandlers = {}; 69 | 70 | AlexaSkill.prototype.execute = function (event, context) { 71 | try { 72 | console.log("session applicationId: " + event.session.application.applicationId); 73 | 74 | // Validate that this request originated from authorized source. 75 | if (this._appId && event.session.application.applicationId !== this._appId) { 76 | console.log("The applicationIds don't match : " + event.session.application.applicationId + " and " 77 | + this._appId); 78 | throw "Invalid applicationId"; 79 | } 80 | 81 | if (!event.session.attributes) { 82 | event.session.attributes = {}; 83 | } 84 | 85 | if (event.session.new) { 86 | this.eventHandlers.onSessionStarted(event.request, event.session); 87 | } 88 | 89 | // Route the request to the proper handler which may have been overriden. 90 | var requestHandler = this.requestHandlers[event.request.type]; 91 | requestHandler.call(this, event, context, new Response(context, event.session)); 92 | } catch (e) { 93 | console.log("Unexpected exception " + e); 94 | context.fail(e); 95 | } 96 | }; 97 | 98 | var Response = function (context, session) { 99 | this._context = context; 100 | this._session = session; 101 | }; 102 | 103 | Response.prototype = (function () { 104 | var buildSpeechletResponse = function (options) { 105 | var alexaResponse = { 106 | outputSpeech: { 107 | type: 'PlainText', 108 | text: options.output 109 | }, 110 | shouldEndSession: options.shouldEndSession 111 | }; 112 | if (options.reprompt) { 113 | alexaResponse.reprompt = { 114 | outputSpeech: { 115 | type: 'PlainText', 116 | text: options.reprompt 117 | } 118 | }; 119 | } 120 | if (options.cardTitle && options.cardContent) { 121 | alexaResponse.card = { 122 | type: "Simple", 123 | title: options.cardTitle, 124 | content: options.cardContent 125 | }; 126 | } 127 | var returnResult = { 128 | version: '1.0', 129 | response: alexaResponse 130 | }; 131 | if (options.session && options.session.attributes) { 132 | returnResult.sessionAttributes = options.session.attributes; 133 | } 134 | return returnResult; 135 | }; 136 | 137 | return { 138 | tell: function (speechOutput) { 139 | this._context.succeed(buildSpeechletResponse({ 140 | session: this._session, 141 | output: speechOutput, 142 | shouldEndSession: true 143 | })); 144 | }, 145 | tellWithCard: function (speechOutput, cardTitle, cardContent) { 146 | this._context.succeed(buildSpeechletResponse({ 147 | session: this._session, 148 | output: speechOutput, 149 | cardTitle: cardTitle, 150 | cardContent: cardContent, 151 | shouldEndSession: true 152 | })); 153 | }, 154 | ask: function (speechOutput, repromptSpeech) { 155 | this._context.succeed(buildSpeechletResponse({ 156 | session: this._session, 157 | output: speechOutput, 158 | reprompt: repromptSpeech, 159 | shouldEndSession: false 160 | })); 161 | }, 162 | askWithCard: function (speechOutput, repromptSpeech, cardTitle, cardContent) { 163 | this._context.succeed(buildSpeechletResponse({ 164 | session: this._session, 165 | output: speechOutput, 166 | reprompt: repromptSpeech, 167 | cardTitle: cardTitle, 168 | cardContent: cardContent, 169 | shouldEndSession: false 170 | })); 171 | } 172 | }; 173 | })(); 174 | 175 | module.exports = AlexaSkill; -------------------------------------------------------------------------------- /ASK/src/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Particle.io account information 3 | * Replace these with your particle.io device id and access token 4 | */ 5 | var deviceId = "put-your-particle.io-device-ID-here"; 6 | var accessToken = "put-your-particle.io-access-token-here"; 7 | 8 | /** 9 | * Particle.io cloud function 10 | * The Arduino sketch specifies the REST URI when it makes 11 | * the particle.function() 12 | * For example, particle.function("myFunction", myFunction) 13 | * would be specified as: var cloudName = "myFunction" 14 | * You can leave this "myFunction", or change it later 15 | * if you change the sketch code. 16 | */ 17 | var cloudName = "myFunction"; 18 | 19 | /** 20 | * Update skillName and invocationName to match the values 21 | * that you specify in the Alexa Skill Kit. 22 | * These are only used in responses from Alexa. 23 | */ 24 | var skillName = "Particle" 25 | var invocationName = "Particle"; 26 | 27 | /** 28 | * App ID for the skill 29 | * Update and use this if/when you publish your skill publicly. 30 | * It's ok to leave this undefined until then. 31 | */ 32 | var APP_ID = undefined; //replace with "amzn1.echo-sdk-ams.app.[your-unique-value-here]"; 33 | 34 | /** 35 | * The AlexaSkill prototype and helper functions 36 | * Particle is a child of AlexaSkill. 37 | */ 38 | var http = require('https'); 39 | var AlexaSkill = require('./AlexaSkill'); 40 | var Particle = function () { 41 | AlexaSkill.call(this, APP_ID); 42 | }; 43 | 44 | // Extend AlexaSkill 45 | Particle.prototype = Object.create(AlexaSkill.prototype); 46 | Particle.prototype.constructor = Particle; 47 | 48 | Particle.prototype.eventHandlers.onSessionStarted = function (sessionStartedRequest, session) { 49 | console.log(invocationName + "onSessionStarted requestId: " + sessionStartedRequest.requestId 50 | + ", sessionId: " + session.sessionId); 51 | // any initialization logic goes here 52 | }; 53 | 54 | Particle.prototype.eventHandlers.onLaunch = function (launchRequest, session, response) { 55 | console.log(invocationName + " onLaunch requestId: " + launchRequest.requestId + ", sessionId: " + session.sessionId); 56 | var speechOutput = "Welcome to " + skillName + ", you can tell me to turn on or off"; 57 | var repromptText = "You can tell me to turn on or off"; 58 | response.ask(speechOutput, repromptText); 59 | }; 60 | 61 | Particle.prototype.eventHandlers.onSessionEnded = function (sessionEndedRequest, session) { 62 | console.log(skillName + " onSessionEnded requestId: " + sessionEndedRequest.requestId 63 | + ", sessionId: " + session.sessionId); 64 | // any cleanup logic goes here 65 | }; 66 | 67 | Particle.prototype.intentHandlers = { 68 | // Register custom intent handlers. 69 | // This simple skill only uses one, but more can be added. 70 | "ParticleIntent": function (intent, session, response) { 71 | var requestURI = "/v1/devices/" + deviceId + "/" + cloudName; 72 | 73 | var commandSlot = intent.slots.command; 74 | var command = commandSlot ? intent.slots.command.value : ""; 75 | var speakText = ""; 76 | 77 | console.log("Command = " + command); 78 | 79 | // Verify that a command was specified. 80 | // We can extend this to prompt the user, 81 | // but let's keep this simple for now. 82 | if(command.length > 0){ 83 | 84 | var postData = "args=" + command; 85 | console.log("Post data = " + postData); 86 | 87 | makeParticleRequest(requestURI, postData, function(resp){ 88 | var json = JSON.parse(resp); 89 | console.log(command + ": " + json.return_value); 90 | response.tellWithCard(skillName, invocationName, "Thing is " + command ); 91 | }); 92 | } else { 93 | response.tell("I don't know whether to turn thing on or off."); 94 | } 95 | }, // ParticleIntent 96 | 97 | "AMAZON.HelpIntent": function (intent, session, response) { 98 | response.ask("You can tell " + invocationName + " to turn on or off."); 99 | } // HelpIntent 100 | }; 101 | 102 | // Create the handler that responds to the Alexa Request. 103 | exports.handler = function (event, context) { 104 | var particleSkill = new Particle(); 105 | particleSkill.execute(event, context); 106 | }; 107 | 108 | function makeParticleRequest(requestURI, postData, callback){ 109 | var options = { 110 | hostname: "api.particle.io", 111 | port: 443, 112 | path: requestURI, 113 | method: 'POST', 114 | headers: { 115 | 'Content-Type': 'application/x-www-form-urlencoded', 116 | 'Authorization': 'Bearer ' + accessToken, 117 | 'Accept': '*.*' 118 | } 119 | }; 120 | 121 | var req = http.request(options, function(res) { 122 | console.log('STATUS: ' + res.statusCode); 123 | console.log('HEADERS: ' + JSON.stringify(res.headers)); 124 | 125 | var body = ""; 126 | 127 | res.setEncoding('utf8'); 128 | res.on('data', function (chunk) { 129 | console.log('BODY: ' + chunk); 130 | body += chunk; 131 | }); 132 | 133 | res.on('end', function () { 134 | callback(body); 135 | }); 136 | }); 137 | 138 | req.on('error', function(e) { 139 | console.log('problem with request: ' + e.message); 140 | }); 141 | 142 | // write data to request body 143 | req.write(postData.toString()); 144 | req.end(); 145 | } 146 | -------------------------------------------------------------------------------- /Arduino/ParticleExample.ino: -------------------------------------------------------------------------------- 1 | void setup() { 2 | Serial.begin(57600) 3 | Serial.println("ParticleExample started.") 4 | 5 | Particle.function("myFunction",myFunction); 6 | } 7 | 8 | void loop() { 9 | // put your main code here, to run repeatedly: 10 | 11 | } 12 | 13 | int myFunction(String command) { 14 | Serial.println("myFunction called."); 15 | // We don't need to return anything. 16 | // Just return an easy to recognize number for testing 17 | return 123; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Ron Lisle 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # alexaParticleBridge 2 | 3 | AlexaParticleBridge provides instructions and sample code to connect an 4 | Amazon Echo to a Particle.io compatible Arduino using Alexa spoken 5 | voice commands. 6 | 7 | This will let you "talk" to your Amazon Echo, and use what you say to 8 | invoke a function running on an Arduino. 9 | 10 | I've used information from a several sources, including the Amazon developer doc, 11 | a [one hour tutorial](https://developer.amazon.com/public/community/post/TxDJWS16KUPVKO/New-Alexa-Skills-Kit-Template-Build-a-Trivia-Skill-in-under-an-Hour) 12 | by Kevin Utter, the [Particle_Alexa package on GitHub]( https://github.com/krvarma/Particle_Alexa) 13 | by Krishnaraj Varma, and some collaboration with my buddies Dan, Don and Sean. 14 | Thanks, guys! 15 | 16 | My intent is to fill in some gaps, provide answers to some puzzles that 17 | we ran into, and provide an easy to use template for projects. 18 | 19 | ## What you will need 20 | 21 | 1. A free Amazon Web Services (AWS) account 22 | 1. A free account on the Amazon developer portal 23 | 1. A free Particle.io account 24 | 1. A Particle.io compatible Arduino, such as the Photon or Oak 25 | 26 | I recommend the Particle.io Photon, which is $19 as of January, 2016. 27 | 28 | I'm also looking forward to completion of the Digistump Oak, 29 | which will cost only $10 each, and promises Particle.io support. 30 | 31 | The Alexa Skills Kit provides a simulator to help testing your code. 32 | This allows you to type what you would say, instead of talking to an 33 | actual Echo device. You will need an Amazon Echo to actually speak to. 34 | But this allows anyone to experiment with Alexa support, even if they 35 | don't own or have access to an Echo. 36 | 37 | ## Create an AWS Account 38 | 39 | An AWS account is free, but you will need a valid credit card to setup 40 | an account. 41 | 1. Go to aws.amazon.com and choose Create a Free AWS Account. 42 | 2. Follow the instructions. Don't worry about the IAM role, 43 | we'll do that later. 44 | 2. You'll need to enter your credit card info, even though this is a 45 | free tier. 46 | 2. Follow the confirmation process to activate your account. 47 | 1. Sign into the Console 48 | 2. It may take awhile for your new account to become active. 49 | 2. You will receive an email when your account is activated 50 | 51 | ## Create a free Amazon Develop Portal account 52 | 53 | 1. Go to developer.amazon.com and then select Alexa 54 | 1. Select Create Free Account (in the upper right) 55 | 2. Follow the instructions to create your account 56 | 57 | ## Connect Particle.io to your arduino 58 | 59 | If you haven't already associated your Arduino with your particle.io account, 60 | you'll need to do so. This should be very simple. 61 | Refer to the particle.io help if you run into any problems: 62 | 1. Power-up your new particle 63 | 2. Go to your particle.io dashboard and connect to the new device 64 | 65 | ## Create a free particle.io account 66 | 67 | 1. Go to the [particle.io dashboard](https://dashboard.particle.io) 68 | 2. Select Signup for an account 69 | 70 | ## Starting with a Simple Skill 71 | 72 | Amazon has named code that extends Alexa a "Skill", as opposed to an "app" 73 | or a "program". For this example, we're going to create a simple skill, 74 | keeping it about as simple as possible. 75 | Once you know how to get something simple working, I think that you will 76 | find it easy to extend to handle more complex interactions. 77 | 78 | So what we're going to build is an Alexa Skill that can 79 | respond to a few simple on/off commands. We will enable our skill to 80 | understand the following sentences: 81 | 82 | * "Alexa, tell **Particle** to **turn on**" 83 | * "Alexa, ask **Particle** to **turn off**" 84 | 85 | ## Wake Word 86 | 87 | In order to interact with Echo, the user must first wake it up. 88 | This is done by speaking the word "Alexa". Once awoken, Alexa then 89 | listens for an invocation name to select the skill to invoke. 90 | 91 | ## Invocation Name 92 | 93 | So the first thing that a skill needs is an invocation name. 94 | In the above example, the invocation name is **Particle**. 95 | It is the thing that causes Alexa to launch our Skill. 96 | The Amazon Doc [Choosing the Invocation Name for an Alexa 97 | Skill](https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/choosing-the-invocation-name-for-an-alexa-skill) 98 | provides a lot of information about choosing a good invocation name, 99 | but basically it needs to be several syllables long, and best if not 100 | similar to words that Alexa already recognizes as a command. 101 | So the word "Particle" is pretty good, since it is fairly unique and 102 | 3 syllables. But using the word "weather" would not be good because 103 | Alexa already responds to that word. 104 | 105 | ## Creating an Alexa Skill 106 | 107 | So now that your accounts are setup, and you've decided what invocation 108 | name to use, we're ready to go ahead an create a new Alexa Skill that 109 | will invoke a function on our Photon. You'll need to do 4 things: 110 | 111 | 1. Create a web service that will process the voice input 112 | * We'll create an AWS lambda function to do this. 113 | * Don't worry, this will be mostly cut-and-paste, with a couple edits 114 | to provide your own specific account information. 115 | 2. Use the Alexa Skill Kit portal to configure our Alexa skill 116 | * List the sentences that Alexa will recognize 117 | * Provide lists of any variable information we want to use in our sentences. 118 | For example, the words "on" and "off" in our example. 119 | 120 | ## Create an AWS Lambda Function 121 | 122 | This is probably the most difficult part of this process. 123 | I've tried to simplify it as much as possible. 124 | I recommend that you keep it simple until everything is working, 125 | and only then go back and make any desired modifications. 126 | 127 | The first step will be to edit the javascript files included in 128 | this package to add your particular account and device information. 129 | then you'll need to upload them to your AWS account. 130 | 131 | ### Editing the Javascript Files 132 | 133 | The javascript files are located in the ASK folder of the repository. 134 | 1. The AlexaSkill.js file is boiler plate code, and does not 135 | need to be edited at all. 136 | 2. Open index.js 137 | 3. Near the top of this file are 2 lines that must be edited: 138 | * Locate the [Device ID](https://dashboard.particle.io/user/devices) 139 | for your particle.io Arduino device 140 | and copy it into the ***deviceId = "<...>"*** between the double-quote marks. 141 | * Locate your Particle.io [access token](https://build.particle.io) in the 142 | build settings section and copy it into 143 | the ***accessToken = "<...>"*** line between the double-quote marks. 144 | 4. Now save your changes, and zip both files up in a single archive file. 145 | You'll need the archive file in the next section. 146 | 147 | ### Configure the Lambda Function 148 | 149 | 1. Sign into your AWS account console 150 | 2. Select ***US East (N. Virginia)*** region (upper right) 151 | 3. Select ***lambda*** in compute services. 152 | 4. Select the ***Skip*** button in the bottom right to skip 153 | selecting a blueprint. 154 | This should take you to the "Configure Function" screen. 155 | 5. Enter a ***Name*** and ***Description*** of your choosing. 156 | 6. Set Runtime to ***node.js*** 157 | 7. Set Code entry type to ***Upload a .ZIP file*** 158 | 8. Click the ***Upload*** button, and select the archive file 159 | containing the javascript files you edited in the previous 160 | section. 161 | 9. Select ***Next*** 162 | 10. Select ***Create Function*** 163 | Now that you've created the function, this page will appear 164 | different when you come back later. You can upload new code, 165 | but a Save button will appear in the top left instead of the 166 | Create Function button in the bottom right. 167 | 11. Select the ***Configuration*** tab 168 | * Leave handler as ***"index.handler"*** 169 | * Set role to ***lambda_basic_execution*** 170 | * Enter a description as you wish 171 | 12. You will be prompted for an IAM role if not previously done 172 | * Leave the Advanced settings as default, and select ***Next*** 173 | * Select ***Create your Function*** 174 | 13. Select the ***Event sources*** tab 175 | * Select ***Add event source*** 176 | * Select type ***Alexa Skill Kit*** 177 | 14. Copy the ARN information displayed in the upper right. 178 | It should look something like 179 | "arn:aws:lambda:us-east-1:123456789012:function:ParticleExample" 180 | Copy everything after the leading "ARN -". 181 | We'll paste that into the Alexa portal in the upcoming steps. 182 | I recommend that you leave this page open so you can copy 183 | the ARN later when it is needed. 184 | 185 | **Congratulations!** You've completed the part that I found most difficult. 186 | Hopefully it was easier for you. 187 | 188 | ## Setup Skill in the Develop Portal 189 | 190 | Now you will tell Alexa about the sentences you want it to 191 | recognize, and provide the link to the lambda function just created. 192 | 193 | 1. Sign into the 194 | [Alexa Skills Kit Portal](https://developer.amazon.com/appsandservices/solutions/alexa/alexa-skills-kit) 195 | by selecting ***SIGN IN*** in the upper right. 196 | 2. Select the ***APPS & SERVICES*** tab 197 | 3. Select ***Alexa*** in the horizontal menu near the top. 198 | 4. Select the ***Alexa Skills Kit*** Get Started button. 199 | You may want to bookmark this page. 200 | 5. Select ***Add a New Skill*** 201 | 6. Provide a name of your choosing (eg. "Particle") 202 | 7. Provide the invocation name "Particle" 203 | 8. Provide a version number of your choosing (eg. "1.0") 204 | 9. Set the Endpoint to ***Lambda ARN (Amazon Resource Name)*** 205 | 10. Copy into the Endpoint field the ARN that you previously copied. 206 | You can go back to the AWS console and copy it again if needed, 207 | or if you copied the wrong text. 208 | 11. Click ***Next*** 209 | You may receive an error here if the lambda function event source 210 | wasn't set to Alexa Skills Kit. Go back to AWS and do so, then try 211 | Next again. 212 | 213 | ### Interaction Model 214 | The above steps should result in display of the Interaction Model page. 215 | This is where we will define the things that we can say to Alexa. 216 | 217 | 1. Copy and paste the contents of the IntentSchema.json file from the 218 | speechAssets folder into the Intent Schema section. 219 | 2. Select ***Add Slot Type*** 220 | 3. Enter Type ***LIST_OF_COMMANDS*** 221 | 4. Enter the values 222 | * ParticleIntent on 223 | * ParticleIntent off 224 | Ensure that each is entered onto its own line. 225 | 5. Select OK 226 | 6. Copy the text below (or from the SampleUtterances.txt file) 227 | into the Sample Utterances section. 228 | **Sample Utterance** 229 | ParticleIntent {command} 230 | ParticleIntent turn {command} 231 | ParticleIntent to turn {command} 232 | ParticleIntent thing {command} 233 | ParticleIntent turn thing {command} 234 | ParticleIntent to turn thing {command} 235 | 7. Select ***Next*** 236 | 237 | And this will bring you to the test page. You're ready to test your new skill. 238 | 239 | **Testing Your Skill** 240 | 241 | There are several ways to test the new skill. 242 | 243 | * Enter text into the **Enter Utterance** field on the Alexa test page. 244 | * If you have an Echo, and it is associated with your account, you can test 245 | right away by speaking "Alexa, tell Particle to turn on" 246 | 247 | ## Debugging 248 | 249 | There are a couple tools available for debugging: 250 | 251 | * Alexa Skills Kit Test Page*** 252 | You can use the Alexa Skills Kit test page to Enter Utterances, and view the 253 | JSON that is sent to and received from the Lambda function. 254 | 255 | * AWS CloudWatch 256 | From the AWS Lambda Functions page for your Lambda function, select the 257 | Monitoring tab, then click ***View logs in CloudWatch***. 258 | This will display the console output from the Lambda Function. 259 | Be observant of the timestamps of the logs. 260 | You will probably need to refresh each time you rerun the test. 261 | Note that sometimes logs are grouped together, so instead of generating 262 | a new timestamped log, the entries are put into the bottom of the previous log. 263 | 264 | * Arduino Console output 265 | Connect a USB cable to the Arduino and write debug comments in your sketch. 266 | Even though the Arduino can be programmed using WiFi, 267 | it still requires a USB cable to view console output. 268 | 269 | ### References 270 | 271 | * [One Hour Tutorial](https://developer.amazon.com/public/community/post/TxDJWS16KUPVKO/New-Alexa-Skills-Kit-Template-Build-a-Trivia-Skill-in-under-an-Hour) 272 | * [Particle_Alexa package on GitHub](https://github.com/krvarma/Particle_Alexa) 273 | * [Amazon AWS](https://aws.amazon.com) 274 | * [Alexa Skills Kit Portal](https://developer.amazon.com/appsandservices/solutions/alexa/alexa-skills-kit) 275 | * [Choosing the Invocation Name for an Alexa 276 | Skill](https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/choosing-the-invocation-name-for-an-alexa-skill) 277 | * [Particle.io Dashboard](https://dashboard.particle.io) 278 | --------------------------------------------------------------------------------