// 1. Text strings =====================================================================================================
// Modify these strings and messages to change the behavior of your Lambda function
let speechOutput;
let reprompt;
let welcomeOutput = "Welcome to my home automation demo, You can ask me to demo the whole house, or just certain systems like lights, locks, cameras, audio video systems, ceiling fans, etc...";
let welcomeReprompt = "You can say something like demo the whole home, or demo the lights. I will give you short demo of the system of your choice.";
// 2. Skill Code =======================================================================================================
"use strict";
const Alexa = require('alexa-sdk');
const APP_ID = undefined; // TODO replace with your app ID (OPTIONAL).
speechOutput = '';
const handlers = {
'LaunchRequest': function () {
this.emit(':ask', welcomeOutput, welcomeReprompt);
},
'AMAZON.HelpIntent': function () {
speechOutput = 'Placeholder response for AMAZON.HelpIntent.';
reprompt = '';
this.emit(':ask', speechOutput, reprompt);
},
'AMAZON.CancelIntent': function () {
speechOutput = 'Placeholder response for AMAZON.CancelIntent';
this.emit(':tell', speechOutput);
},
'AMAZON.StopIntent': function () {
speechOutput = 'Ok, stopping my home demo';
this.emit(':tell', speechOutput);
},
'SessionEndedRequest': function () {
speechOutput = 'Demo Ended';
//this.emit(':saveState', true);//uncomment to save attributes to db on session end
this.emit(':tell', speechOutput);
},
'AMAZON.NavigateHomeIntent': function () {
speechOutput = '';
//any intent slot variables are listed here for convenience
//Your custom intent handling goes here
speechOutput = "This is a place holder response for the intent named AMAZON.NavigateHomeIntent. This intent has no slots. Anything else?";
this.emit(":ask", speechOutput, speechOutput);
},
'playdemointent': function () {
var speechOutput = '';
var speechReprompt = '';
//any intent slot variables are listed here for convenience
let system_typeSlot = resolveCanonical(this.event.request.intent.slots.system_type);
console.log(system_typeSlot);
let lengthSlot = resolveCanonical(this.event.request.intent.slots.length);
console.log(lengthSlot);
var demos = {
'lights' : {
'short' : '/isy/<isy address>/rest/programs/0024/runthen',
'long': '/isy/<isy address>/rest/programs/0024/runthen'
},
'cameras' : {
'short' : '/isy/<isy address>/rest/programs/013F/runThen',
'long': '/isy/<isy address>/rest/programs/013F/runThen'
},
'fans' : {
'short' : '/isy/<isy address>/rest/programs/0367/runThen',
'long': '/isy/<isy address>/rest/programs/0367/runThen'
},
'pool' : {
'short' : '/isy/<isy address>/rest/programs/02C9/runThen',
'long': '/isy/<isy address>/rest/programs/02C9/runThen'
},
'Lock' : {
'short' : '/isy/<isy address>/rest/programs/0439/runIf',
'long': '/isy/<isy address>/rest/programs/0439/runIf'
}
}
var lengths = [
'short',
'long'
];
var demo = '';
var length = '';
if(!system_typeSlot) {
this.emit(':ask', 'I did not hear a system. Which system do you want to demo?', 'You can say something like cameras, lights, audio video system, etc..');
} else {
demo = system_typeSlot.toLowerCase();
this.attributes['demo'] = demo;
}
if(lengthSlot) {
length = lengthSlot.toLowerCase();
}
if(demos[demo]) {
if(lengthSlot && lengths.indexOf(lengthSlot) > -1) {
length = lengthSlot;
} else {
length = 'short';
}
const url = demos[demo][length];
"use strict";
const https = require('https');
const username = 'xxxxxxx@hotmail.com';
const password = 'xxxxxxxx';
https.globalAgent = new https.Agent({ keepAlive: true });
exports.handler = function (event, context) {
console.log('Input:', event);
var options = {
protocol: 'https:',
hostname: 'my.isy.io',
port: 443,
path: url,
method: 'GET',
rejectUnauthorized: true,
auth: username + ':' + password
};
// console.log();
var req = https.request(options);
// when the response comes back
req.on('response', function(res){
res.body = '';
res.setEncoding('utf-8');
res.on('data', function(chunk) {
res.body += chunk;
});
// when the response has finished
res.on('end', function() {
console.log('DATA:', res.body);
context.succeed(res.body);
});
res.on('error', function (err) {
console.log('ERROR:', err);
context.fail(JSON.stringify({ error: 'error' }));
});
});
// write data to request body
//req.write(body);
req.end(); // Can't recall if you need this for a GET
};
speechOutput = 'Ok, here is a ' + length + ' demo of the ' + demo;
this.emit(":tell", speechOutput);
} else {
speechOutput = 'Sorry, the system you asked for is not supported yet.';
speechReprompt = 'I support lights, locks, ceiling fans, audio video systems, cameras, pool equipment, etc..';
}
this.emit(":tell", speechOutput);
},
'Unhandled': function () {
speechOutput = "The skill didn't quite understand what you wanted. Do you want to try something else?";
this.emit(':ask', speechOutput, speechOutput);
}
};
exports.handler = (event, context) => {
const alexa = Alexa.handler(event, context);
alexa.appId = APP_ID;
// To enable string internationalization (i18n) features, set a resources object.
//alexa.resources = languageStrings;
alexa.registerHandlers(handlers);
//alexa.dynamoDBTableName = 'DYNAMODB_TABLE_NAME'; //uncomment this line to save attributes to DB
alexa.execute();
};
// END of Intent Handlers {} ========================================================================================
// 3. Helper Function =================================================================================================
function resolveCanonical(slot){
//this function looks at the entity resolution part of request and returns the slot value if a synonyms is provided
let canonical;
try{
canonical = slot.resolutions.resolutionsPerAuthority[0].values[0].value.name;
}catch(err){
console.log(err.message);
canonical = slot.value;
};
return canonical;
};
function delegateSlotCollection(){
console.log("in delegateSlotCollection");
console.log("current dialogState: "+this.event.request.dialogState);
if (this.event.request.dialogState === "STARTED") {
console.log("in Beginning");
let updatedIntent= null;
// updatedIntent=this.event.request.intent;
//optionally pre-fill slots: update the intent object with slot values for which
//you have defaults, then return Dialog.Delegate with this updated intent
// in the updatedIntent property
//this.emit(":delegate", updatedIntent); //uncomment this is using ASK SDK 1.0.9 or newer
//this code is necessary if using ASK SDK versions prior to 1.0.9
if(this.isOverridden()) {
return;
}
this.handler.response = buildSpeechletResponse({
sessionAttributes: this.attributes,
directives: getDialogDirectives('Dialog.Delegate', updatedIntent, null),
shouldEndSession: false
});
this.emit(':responseReady', updatedIntent);
} else if (this.event.request.dialogState !== "COMPLETED") {
console.log("in not completed");
// return a Dialog.Delegate directive with no updatedIntent property.
//this.emit(":delegate"); //uncomment this is using ASK SDK 1.0.9 or newer
//this code necessary is using ASK SDK versions prior to 1.0.9
if(this.isOverridden()) {
return;
}
this.handler.response = buildSpeechletResponse({
sessionAttributes: this.attributes,
directives: getDialogDirectives('Dialog.Delegate', null, null),
shouldEndSession: false
});
this.emit(':responseReady');
} else {
console.log("in completed");
console.log("returning: "+ JSON.stringify(this.event.request.intent));
// Dialog is now complete and all required slots should be filled,
// so call your normal intent handler.
return this.event.request.intent;
}
}
function randomPhrase(array) {
// the argument is an array [] of words or phrases
let i = 0;
i = Math.floor(Math.random() * array.length);
return(array[i]);
}
function isSlotValid(request, slotName){
let slot = request.intent.slots[slotName];
//console.log("request = "+JSON.stringify(request)); //uncomment if you want to see the request
let slotValue;
//if we have a slot, get the text and store it into speechOutput
if (slot && slot.value) {
//we have a value in the slot
slotValue = slot.value.toLowerCase();
return slotValue;
} else {
//we didn't get a value in the slot.
return false;
}
}
//These functions are here to allow dialog directives to work with SDK versions prior to 1.0.9
//will be removed once Lambda templates are updated with the latest SDK
function createSpeechObject(optionsParam) {
if (optionsParam && optionsParam.type === 'SSML') {
return {
type: optionsParam.type,
ssml: optionsParam['speech']
};
} else {
return {
type: optionsParam.type || 'PlainText',
text: optionsParam['speech'] || optionsParam
};
}
}
function buildSpeechletResponse(options) {
let alexaResponse = {
shouldEndSession: options.shouldEndSession
};
if (options.output) {
alexaResponse.outputSpeech = createSpeechObject(options.output);
}
if (options.reprompt) {
alexaResponse.reprompt = {
outputSpeech: createSpeechObject(options.reprompt)
};
}
if (options.directives) {
alexaResponse.directives = options.directives;
}
if (options.cardTitle && options.cardContent) {
alexaResponse.card = {
type: 'Simple',
title: options.cardTitle,
content: options.cardContent
};
if(options.cardImage && (options.cardImage.smallImageUrl || options.cardImage.largeImageUrl)) {
alexaResponse.card.type = 'Standard';
alexaResponse.card['image'] = {};
delete alexaResponse.card.content;
alexaResponse.card.text = options.cardContent;
if(options.cardImage.smallImageUrl) {
alexaResponse.card.image['smallImageUrl'] = options.cardImage.smallImageUrl;
}
if(options.cardImage.largeImageUrl) {
alexaResponse.card.image['largeImageUrl'] = options.cardImage.largeImageUrl;
}
}
} else if (options.cardType === 'LinkAccount') {
alexaResponse.card = {
type: 'LinkAccount'
};
} else if (options.cardType === 'AskForPermissionsConsent') {
alexaResponse.card = {
type: 'AskForPermissionsConsent',
permissions: options.permissions
};
}
let returnResult = {
version: '1.0',
response: alexaResponse
};
if (options.sessionAttributes) {
returnResult.sessionAttributes = options.sessionAttributes;
}
return returnResult;
}
function getDialogDirectives(dialogType, updatedIntent, slotName) {
let directive = {
type: dialogType
};
if (dialogType === 'Dialog.ElicitSlot') {
directive.slotToElicit = slotName;
} else if (dialogType === 'Dialog.ConfirmSlot') {
directive.slotToConfirm = slotName;
}
if (updatedIntent) {
directive.updatedIntent = updatedIntent;
}
return [directive];
}