Alexa Settings API Example Skill

A Settings API Example Skill Template for Alexa

Sign in with GitHub to access the code for this template.

Steve Tingiris

Getting the Time zone, temperature, and distance setting in an Alexa skill

In this tutorial, we'll use the Alexa Settings API to get a user's time zone, temperature unit, and distance unit settings.

To follow along you'll just need an Amazon developer account which you can get for free at Amazon Developer Console.

Overview Steps

  1. Create a new Alexa-Hosted skill
  2. Update the skill's interaction model
  3. Update the skill's package.json file
  4. Update the skill's intent handlers
  5. Test the skill

1. Create a new Alexa-Hosted skill

After creating an Amazon developer account, you'll need to login and create a new skill through the Alexa developer console. To do that, complete the following steps:

  • Login to developer.amazon.com
  • Navigate to the Alexa developer console
  • Click the Create skill button
  • Enter a name for your skill
  • Choose a locale for your skill
  • Use the default template
  • Use the default hosting option (Alexa-Hosted Node.js)

2. Update the skill's interaction model

We'll update the skill's interaction model to include the following:

{
  "interactionModel": {
    "languageModel": {
      "invocationName": "template eleven",
      "intents": [
        {
          "name": "AMAZON.NavigateHomeIntent",
          "samples": [

          ]
        },
        {
          "name": "AMAZON.CancelIntent",
          "samples": []
        },
        {
          "name": "AMAZON.HelpIntent",
          "samples": []
        },
        {
          "name": "AMAZON.StopIntent",
          "samples": []
        },
        {
          "name": "TimezoneIntent",
          "samples": [
            "time",
            "timezone",
            "time zone",
            "what is my timezone"
          ]
        },
        {
          "name": "DistanceIntent",
          "samples": [
            "distance",
            "distance unit",
            "distance measurement unit"
          ]
        },
        {
          "name": "TemperatureIntent",
          "samples": [
            "temperature",
            "temperature unit",
            "temperature measurement unit"
          ]
        }
      ]
    }
  }
}

3. Update the skill's package.json file

{
  "name": "dabblelab-alexa-settings-skill-template",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Dabble Lab",
  "license": "ISC",
  "dependencies": {
    "ask-sdk-core": "^2.0.7",
    "ask-sdk-model": "^1.5.0",
    "moment": "^2.22.2",
    "moment-timezone": "^0.5.21"
  }
}

4. Update the skill's intent handlers

/* eslint-disable  func-names */
/* eslint-disable  no-console */

const Alexa = require('ask-sdk-core');
const momenttz = require('moment-timezone');
const moment = require('moment');
const APP_NAME = "Template Eleven"

const LaunchRequestHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
  },
  handle(handlerInput) {
    const speechText = 'Say: timezone, distance, or temperature, to hear your Alexa settings.';
    const reprompt = 'Say: timezone, distance, or temperature.';

    return handlerInput.responseBuilder
      .speak(speechText)
      .reprompt(reprompt)
      .withSimpleCard(APP_NAME, speechText)
      .getResponse();
  },
};

const TimezoneIntentHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'IntentRequest'
      && handlerInput.requestEnvelope.request.intent.name === 'TimezoneIntent';
  },
  async handle(handlerInput) {
    const { requestEnvelope, serviceClientFactory, responseBuilder } = handlerInput;

    let {deviceId} = requestEnvelope.context.System.device;
    const upsServiceClient = serviceClientFactory.getUpsServiceClient();
    const usertimeZone = await upsServiceClient.getSystemTimeZone(deviceId);
    const now = momenttz.utc();
    const localTime = now.tz(usertimeZone).format('h:mma');
    let speechText = `Your timezone is ${usertimeZone}. Your local time is ${localTime}. `;

    speechText += calculateGreeting(localTime);

    return handlerInput.responseBuilder
    .speak(speechText)
    .getResponse();
    
  },
}

const DistanceIntentHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'IntentRequest'
      && handlerInput.requestEnvelope.request.intent.name === 'DistanceIntent';
  },
  async handle(handlerInput) {
    const { requestEnvelope, serviceClientFactory, responseBuilder } = handlerInput;
    let {deviceId} = requestEnvelope.context.System.device;
    const upsServiceClient = serviceClientFactory.getUpsServiceClient();
    const userDistanceMeasurementUnit = await upsServiceClient.getSystemDistanceUnits(deviceId);
    if (!userDistanceMeasurementUnit) {
      const speechText = `It looks like you don\'t have distance measurement unit set. You can set it from the companion app.`
      return responseBuilder
                    .speak(speechText)
                    .withSimpleCard(APP_NAME, speechText)
                    .getResponse();
    }
    console.log("Your distance measurement unit is", JSON.stringify(userDistanceMeasurementUnit));
    const speechText = `Your distance measurement unit is ${userDistanceMeasurementUnit}`;
    return handlerInput.responseBuilder
    .speak(speechText)
    .withSimpleCard('Hello World', speechText)
    .getResponse();
  }
}

const TemperatureIntentHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'IntentRequest'
      && handlerInput.requestEnvelope.request.intent.name === 'TemperatureIntent';
  },
  async handle(handlerInput) {
    const { requestEnvelope, serviceClientFactory, responseBuilder } = handlerInput;
    let {deviceId} = requestEnvelope.context.System.device;
    const upsServiceClient = serviceClientFactory.getUpsServiceClient();
    const userTemperatureUnit = await upsServiceClient.getSystemTemperatureUnit(deviceId);
    if (!userTemperatureUnit) {
      const speechText = `It looks like you don\'t have temperature measurement unit set. You can set it from the companion app.`
      return responseBuilder
                    .speak(speechText)
                    .withSimpleCard(APP_NAME, speechText)
                    .getResponse();
    }
    console.log("Temperature measurement unit is", JSON.stringify(userTemperatureUnit));
    const speechText = `Your temperature measurement unit is ${userTemperatureUnit}`;
    return handlerInput.responseBuilder
    .speak(speechText)
    .getResponse();
  }
}



const HelpIntentHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'IntentRequest'
      && handlerInput.requestEnvelope.request.intent.name === 'AMAZON.HelpIntent';
  },
  handle(handlerInput) {
    const speechText = 'You can say; timezone, distance, or temperature, to hear your Alexa settings.';

    return handlerInput.responseBuilder
      .speak(speechText)
      .reprompt(speechText)
      .getResponse();
  },
};

const CancelAndStopIntentHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'IntentRequest'
      && (handlerInput.requestEnvelope.request.intent.name === 'AMAZON.CancelIntent'
        || handlerInput.requestEnvelope.request.intent.name === 'AMAZON.StopIntent');
  },
  handle(handlerInput) {
    const speechText = 'Goodbye!';

    return handlerInput.responseBuilder
      .speak(speechText)
      .getResponse();
  },
};

const SessionEndedRequestHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'SessionEndedRequest';
  },
  handle(handlerInput) {
    console.log(`Session ended with reason: ${handlerInput.requestEnvelope.request.reason}`);

    return handlerInput.responseBuilder.getResponse();
  },
};

const ErrorHandler = {
  canHandle() {
    return true;
  },
  handle(handlerInput, error) {
    console.log(`Error handled: ${error.message}`);

    return handlerInput.responseBuilder
      .speak('Sorry, I can\'t understand the command. Please say again.')
      .reprompt('Sorry, I can\'t understand the command. Please say again.')
      .getResponse();
  },
};

const RequestLog = {
  process(handlerInput) {
    console.log(`REQUEST ENVELOPE = ${JSON.stringify(handlerInput.requestEnvelope)}`);
  },
};

const ResponseLog = {
  process(handlerInput) {
    console.log(`RESPONSE BUILDER = ${JSON.stringify(handlerInput)}`);
  },
};

function calculateGreeting(localTime){
  var currentTime = moment(localTime, 'h:mma');
  var morningTime = moment('4:00am', 'h:mma');
  var noonTime = moment('12:00pm', 'h:mma');
  var eveningTime = moment('4:00pm', 'h:mma');
  var nightTime = moment('8:00pm', 'h:mma');
  if(currentTime.isAfter(morningTime) && currentTime.isBefore(noonTime)){
    return " Good Morning";
  }
  else if(currentTime.isAfter(noonTime) && currentTime.isBefore(eveningTime)){
    return " Good Afternoon";
  }
  else if(currentTime.isAfter(eveningTime) && currentTime.isBefore(nightTime)){
    return " Good Evening";
  }
  else{
    return " Good Night";
  }
}
const skillBuilder = Alexa.SkillBuilders.custom();

exports.handler = skillBuilder
  .addRequestHandlers(
    LaunchRequestHandler,
    TimezoneIntentHandler,
    DistanceIntentHandler,
    TemperatureIntentHandler,
    HelpIntentHandler,
    CancelAndStopIntentHandler,
    SessionEndedRequestHandler
  )
  .addRequestInterceptors(RequestLog)
  .addResponseInterceptors(ResponseLog)
  .addErrorHandlers(ErrorHandler)
  .withApiClient(new Alexa.DefaultApiClient())
  .lambda();

5. Test the skill

Now that you have the skill setup, you can test it from the Alexa test console. To do that complete the following steps:

  • Click on the test link in the top navigation bar
  • Enter the skill's name in the input field
  • Click on the "Test" button

Comments