venerdì 7 dicembre 2018

Alexa Flash Briefing Skill

Un modo rapido di creare una Alexa Skill e' quella di utilizzare un feed RSS mediante la Flash Briefing. Di fatto non e' necessaria nessuna programmazione di un backend lambda ma e' sufficiente creare un file RSS di un certo formato su un sito disponibile in HTTPS ed indicare il link


il feed puo' essere testuale (quindi letto dalla voce di Alexa) oppure un audio MP3

--------------------------------------------------------------
<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <ttl>30</ttl>
    <item>
      <guid>urn:uuid:1335c695-cfb8-4ebb-abbd-80da344efa6b</guid>
      <title>Prova di riunione veloce</title>
      <description>
        prova di trasmissione di Luca Innocenti
      </description>
      <pubDate>2018-12-07T09:30:00.0Z</pubDate>
     </item>
  </channel>
</rss>
--------------------------------------------------------------
La cosa interessante e' che una volta che l'utente si iscrive al flash briefing non e' necessario richiamare la skill ma questa viene attivata ogni volta che vengono richieste le notizie (per esempio "Alexa dammi le notizie" fa partire SkyTG24 ma prima viene proposto il Flash Briefing)
Esiste un limite di 4000 carattere per la parte descrizione

giovedì 6 dicembre 2018

Alexa Skill Code Generator

Uno strumento per avere uno scheletro completo di una funzione Lambda partendo da uno schema di Alexa e' dato CodeGenerator



E' sufficiente copiare il file Json derivante da Alexa Console ed avere la funzione Lambda (anche troppo dettagliata)

Permssi DynamoDB per Alexa Skill

Prima di poter utilizzare DynamoDB in connessione con una Skill si devono settare i permessi del database tramite IAM. Si va quindi in IAM Roles e si ha la lista delle proprie skill. Si clicca su quella di interesse. Di default  c'e' solo il permesso per l'uso di Cloudwatch.

Si puo' procedere cliccando su Attach Policy e spuntando AmazonDynamoDBFullAccess
Altrimenti si puo' usare un approccio piu' granulare creando una inline policy  e selezionando quanto di interesse


Alexa Dev Day Milano 5 dicembre

Partecipazione alla giornata per sviluppatori Alexa a Milano. Un paio di commenti: posto prestigiosissimo, pensavo che fosse piu' utile







mercoledì 5 dicembre 2018

Deploy Alexa Skill con Ask Cli

Per poter effettuare il deploy di  una skill ad Amazon ad ASK Cli e' necessario impostare le proprie credenziali, Si procede con

ask init --aws-setup


a questo punto vengono richieste la Access Key ID e la Secret Access Key che si recuperano dalla console AWS sotto Security Credentials/Access Keys

per poter dialogare con la skill, una volta effettuato il deploy, si usa

ask simulate -l it-IT -t "testo del messaggio"

se la skill e' in inglese si dovra' usare en-US. Nello switch -t si inserisce invece il testo del parlato

martedì 4 dicembre 2018

Alexa Address API

Esempio di API Address di Alexa

------------------------------------------------------------
{
    "interactionModel": {
        "languageModel": {
            "invocationName": "indirizzo",
            "intents": [
                {
                    "name": "GetAddressIntent",
                    "slots": [],
                    "samples": [
                        "dove vivo"
                    ]
                },
                {
                    "name": "AMAZON.CancelIntent",
                    "samples": []
                },
                {
                    "name": "AMAZON.HelpIntent",
                    "samples": []
                },
                {
                    "name": "AMAZON.StopIntent",
                    "samples": []
                }
            ],
            "types": []
        }
    }
}
------------------------------------------------------------

------------------------------------------------------------
/* eslint-disable  no-console */

const Alexa = require('ask-sdk-core');

const messages = {
  WELCOME: 'Benvenuto, cosa vuoi?',
  WHAT_DO_YOU_WANT: 'Cosa vuoi chiedere?',
  NOTIFY_MISSING_PERMISSIONS: 'Abilita i permessi sulla app Alexa',
  NO_ADDRESS: 'Non è stato impostato un indirizzo',
  ADDRESS_AVAILABLE: 'Ecco il tuo indirizzo completo: ',
  ERROR: 'Errore.',
  LOCATION_FAILURE: 'C\'è un errore.Riprova',
  GOODBYE: 'Arriverderci',
  UNHANDLED: 'This skill doesn\'t support that. Please ask something else.',
  HELP: 'Chiedimi dove vivo?',
  STOP: 'Stop',
};

const PERMISSIONS = ['read::alexa:device:all:address'];

const LaunchRequest = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
  },
  handle(handlerInput) {
    return handlerInput.responseBuilder.speak(messages.WELCOME)
      .reprompt(messages.WHAT_DO_YOU_WANT)
      .getResponse();
  },
};

const GetAddressIntent = {
  canHandle(handlerInput) {
    const { request } = handlerInput.requestEnvelope;

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

    const consentToken = requestEnvelope.context.System.user.permissions
      && requestEnvelope.context.System.user.permissions.consentToken;
    if (!consentToken) {
      return responseBuilder
        .speak(messages.NOTIFY_MISSING_PERMISSIONS)
        .withAskForPermissionsConsentCard(PERMISSIONS)
        .getResponse();
    }
    try {
      const { deviceId } = requestEnvelope.context.System.device;
      const deviceAddressServiceClient = serviceClientFactory.getDeviceAddressServiceClient();
      const address = await deviceAddressServiceClient.getFullAddress(deviceId);

      console.log('Address successfully retrieved, now responding to user.');

      let response;
      if (address.addressLine1 === null && address.stateOrRegion === null) {
        response = responseBuilder.speak(messages.NO_ADDRESS).getResponse();
      } else {
        const ADDRESS_MESSAGE = `${messages.ADDRESS_AVAILABLE + address.addressLine1}, ${address.stateOrRegion}, ${address.postalCode}`;
        response = responseBuilder.speak(ADDRESS_MESSAGE).getResponse();
      }
      return response;
    } catch (error) {
      if (error.name !== 'ServiceError') {
        const response = responseBuilder.speak(messages.ERROR).getResponse();
        return response;
      }
      throw error;
    }
  },
};

const SessionEndedRequest = {
  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 UnhandledIntent = {
  canHandle() {
    return true;
  },
  handle(handlerInput) {
    return handlerInput.responseBuilder
      .speak(messages.UNHANDLED)
      .reprompt(messages.UNHANDLED)
      .getResponse();
  },
};

const HelpIntent = {
  canHandle(handlerInput) {
    const { request } = handlerInput.requestEnvelope;

    return request.type === 'IntentRequest' && request.intent.name === 'AMAZON.HelpIntent';
  },
  handle(handlerInput) {
    return handlerInput.responseBuilder
      .speak(messages.HELP)
      .reprompt(messages.HELP)
      .getResponse();
  },
};

const CancelIntent = {
  canHandle(handlerInput) {
    const { request } = handlerInput.requestEnvelope;

    return request.type === 'IntentRequest' && request.intent.name === 'AMAZON.CancelIntent';
  },
  handle(handlerInput) {
    return handlerInput.responseBuilder
      .speak(messages.GOODBYE)
      .getResponse();
  },
};

const StopIntent = {
  canHandle(handlerInput) {
    const { request } = handlerInput.requestEnvelope;

    return request.type === 'IntentRequest' && request.intent.name === 'AMAZON.StopIntent';
  },
  handle(handlerInput) {
    return handlerInput.responseBuilder
      .speak(messages.STOP)
      .getResponse();
  },
};

const GetAddressError = {
  canHandle(handlerInput, error) {
    return error.name === 'ServiceError';
  },
  handle(handlerInput, error) {
    if (error.statusCode === 403) {
      return handlerInput.responseBuilder
        .speak(messages.NOTIFY_MISSING_PERMISSIONS)
        .withAskForPermissionsConsentCard(PERMISSIONS)
        .getResponse();
    }
    return handlerInput.responseBuilder
      .speak(messages.LOCATION_FAILURE)
      .reprompt(messages.LOCATION_FAILURE)
      .getResponse();
  },
};


const skillBuilder = Alexa.SkillBuilders.custom();

exports.handler = skillBuilder
  .addRequestHandlers(
    LaunchRequest,
    GetAddressIntent,
    SessionEndedRequest,
    HelpIntent,
    CancelIntent,
    StopIntent,
    UnhandledIntent,
  )
  .addErrorHandlers(GetAddressError)
  .withApiClient(new Alexa.DefaultApiClient())
  .lambda();
------------------------------------------------------------


Per la skill deve essere abilitato il permesso nella parte Permission di Alexa Console



Si devono abilitare i permessi di localizzazione su https://alexa.amazon.it
(attenzione : per ricevere una risposta di deve inserire l'indirizzo di ogni dispositivo all'interno della app Alexa, non esiste un geocoding basato su IP o su GPS




Atom Editor

Alcuni comandi per Atom Editor


CTRL + e - aumeta e diminuisce il carattere
CTRL N nuovo tab
CTRL O apre un file
ALT 1, ALT 2, ALT n sposta il focus tra i vari tab

CTRL SHIFT P apre l'help di Atom in cui ci sono gli shortcuts da tastiera

Per usare i Pane si usano combinazioni di tasto
CTRL K CTRL W chiude un pane
CTRL K CTRL N sposta il focus sul prossimo pane

per aprire l'albero a sinistra con i file "Toggle TreeView" oppure CTRL + \ (backslash)

per avere una finestra di shell si puo' installare il pacchetto Platformio-ide-terminal. Per aprire un terminale si usa ALT SHIFT T, per avere il focus sul terminale CTRL "apice inverso" la stessa combinazione di tasti esce dal terminale e ritorna nell'editor

Debugger integrato ESP32S3

Aggiornamento In realta' il Jtag USB funziona anche sui moduli cinesi Il problema risiede  nell'ID USB della porta Jtag. Nel modulo...