Link to Building a Custom Alexa Skill - Part 2
If you are this far, lets go back to our “index.js” file for our lamda function. If you have been following along, a lot of this will be “copy and paste” for you.
First and foremost, we need to define a constant for our lighting URL. Go to the top of your index.js file and add the following variable declaration (note, the double slash is a comment):
//endpoint URLS
const houseLightsURL = 'http://yourdomain:1880/endpoint/lights';
Go back to your HouseLightsIntent, and replace it with this:
const HouseLightsIntent = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
&& Alexa.getIntentName(handlerInput.requestEnvelope) === 'HouseLightsIntent';
},
async handle(handlerInput) {
//set default as place holders
var entity = 'default';
var action = 'default';
var brightness_pct = 0;
var speakOutput = 'There was an error talking to Node Red, please try again';
var jsonData = {};
//Set up Session to record entity
const sessionAttributes = handlerInput.attributesManager.getSessionAttributes();
var requestedEntity = sessionAttributes.requestedEntity;
var requestedAction = sessionAttributes.requestedAction;
var requestedBrightness = sessionAttributes.requestedAction;
var requestedColor = sessionAttributes.color;
//entity name
if (handlerInput.requestEnvelope.request.intent.slots.entity.value !== '' && handlerInput.requestEnvelope.request.intent.slots.entity.value !== undefined) {
requestedEntity = handlerInput.requestEnvelope.request.intent.slots.entity.value;
jsonData["entity"] = requestedEntity;
}
//action
if (handlerInput.requestEnvelope.request.intent.slots.action.value !== '' && handlerInput.requestEnvelope.request.intent.slots.action.value !== undefined) {
requestedAction = handlerInput.requestEnvelope.request.intent.slots.action.value;
jsonData["action"] = requestedAction;
}
//brightness
if (handlerInput.requestEnvelope.request.intent.slots.percentage_brightness.value !== '' && handlerInput.requestEnvelope.request.intent.slots.percentage_brightness.value !== undefined) {
requestedBrightness = handlerInput.requestEnvelope.request.intent.slots.percentage_brightness.value
jsonData["percentage_brightness"] = requestedBrightness;
}
//color
if (handlerInput.requestEnvelope.request.intent.slots.color.value !== '' && handlerInput.requestEnvelope.request.intent.slots.color.value !== undefined) {
requestedColor = handlerInput.requestEnvelope.request.intent.slots.color.value
jsonData["color"] = requestedColor;
}
sessionAttributes.requestedEntity = requestedEntity;
sessionAttributes.requestedAction = requestedAction;
sessionAttributes.requestedBrightness = requestedBrightness;
sessionAttributes.color = requestedColor;
handlerInput.attributesManager.setSessionAttributes(sessionAttributes);
//call Node Red endpoint
try {
const resplights = await fetchURLwithJSON(houseLightsURL, jsonData);
speakOutput = JSON.stringify(resplights.response) + ' If you are finished, please tell me goodbye';
}
catch (error) {
speakOutput = 'There was an error talking to Node Red, please try again';
}
if (requestedEntity === 'default' || requestedAction === 'default') {
return handlerInput.responseBuilder
.speak("I'm sorry. I don't know how to do that. Please restate what you would like to do and file a bug report with hunky hubby")
.reprompt("I'm sorry. I don't know how to do that. Please restate what you would like to do and file a bug report with hunky hubby")
.getResponse();
}
else {
return handlerInput.responseBuilder
.speak(speakOutput)
.reprompt(speakOutput)
.getResponse();
}
}
};
NOTE: I’m not a Javascript expert (I’m an old C# dood), so I probably took the “long way round” on some of these things, but it helps me so I hope it helps you.
The key part we care about is the ‘async handle(handlerInput)
’ method. This is where the bulk of the work will occur on each intent.
Lets break down what is going on in this code
First we declare some variables that will be used later:
var entity = 'default';
var action = 'default';
var brightness_pct = 0;
var speakOutput = 'There was an error talking to Node Red, please try again';
var jsonData = {};
We turn on Sessions (this allows us to be more conversational as we can “ask for clarity” and hold on to what was originally said, although I haven’t fully implemented this yet). This is key to when Alexa asks you “did you mean XXXX”, although there is more to it than that programmatically, but this lays the foundation.
This block, grabs the current session, and sets values:
//Set up Session to record entity
const sessionAttributes = handlerInput.attributesManager.getSessionAttributes();
var requestedEntity = sessionAttributes.requestedEntity;
var requestedAction = sessionAttributes.requestedAction;
var requestedBrightness = sessionAttributes.requestedAction;
var requestedColor = sessionAttributes.color;
This block does some “sanity checking” and builds our JSON object to send to NodeRed:
//entity name
if (handlerInput.requestEnvelope.request.intent.slots.entity.value !== '' && handlerInput.requestEnvelope.request.intent.slots.entity.value !== undefined) {
requestedEntity = handlerInput.requestEnvelope.request.intent.slots.entity.value;
jsonData["entity"] = requestedEntity;
}
//action
if (handlerInput.requestEnvelope.request.intent.slots.action.value !== '' && handlerInput.requestEnvelope.request.intent.slots.action.value !== undefined) {
requestedAction = handlerInput.requestEnvelope.request.intent.slots.action.value;
jsonData["action"] = requestedAction;
}
//brightness
if (handlerInput.requestEnvelope.request.intent.slots.percentage_brightness.value !== '' && handlerInput.requestEnvelope.request.intent.slots.percentage_brightness.value !== undefined) {
requestedBrightness = handlerInput.requestEnvelope.request.intent.slots.percentage_brightness.value
jsonData["percentage_brightness"] = requestedBrightness;
}
//color
if (handlerInput.requestEnvelope.request.intent.slots.color.value !== '' && handlerInput.requestEnvelope.request.intent.slots.color.value !== undefined) {
requestedColor = handlerInput.requestEnvelope.request.intent.slots.color.value
jsonData["color"] = requestedColor;
}
handlerInput.requestEnvelope.request.intent.slots.entity.value
in the first line above is the VALUE of the SLOT that you defined. So if I asked Alexa to “turn kitchen lights on” and my pattern to match was “turn {entity} lights {action}”, this response object would contain the value of “kitchen”. Inside the if statement, we set the session variable to (in this example) “kitchen”, while also adding a JSON document entry of “entity”:”kitchen”.
Moving on to the next code block:
sessionAttributes.requestedEntity = requestedEntity;
sessionAttributes.requestedAction = requestedAction;
sessionAttributes.requestedBrightness = requestedBrightness;
sessionAttributes.color = requestedColor;
handlerInput.attributesManager.setSessionAttributes(sessionAttributes);
Sets the session values, and stores them until the session ends (in this case . . . telling your skill goodbye).
//call Node Red endpoint
try {
const resplights = await fetchURLwithJSON(houseLightsURL, jsonData);
speakOutput = JSON.stringify(resplights.response) + ' If you are finished, please tell me goodbye';
}
catch (error) {
speakOutput = 'There was an error talking to Node Red, please try again';
}
This TRY’s to call our node red endpoint const const resplights = await fetchURLwithJSON(houseLightsURL, jsonData);
and sets the text to “speak” to our response.
And the last bit of sanity checking:
if (requestedEntity === 'default' || requestedAction === 'default') {
return handlerInput.responseBuilder
.speak("I'm sorry. I don't know how to do that. Please restate what you would like to do and file a bug report with hunky hubby")
.reprompt("I'm sorry. I don't know how to do that. Please restate what you would like to do and file a bug report with hunky hubby")
.getResponse();
}
else {
return handlerInput.responseBuilder
.speak(speakOutput)
.reprompt(speakOutput)
.getResponse();
}
Note: .reprompt(speakOutput)
is used to “reply and wait” (it keeps your session of interactivity “open” so you can provide more info to your skill.
Save, build, Deploy . . . if everything is correct, you shouldn’t have any issues. But What do we do with that Webservice call?
Look for the next part