Un esempio di come salvare i dati in formato JSon in un progetto ElectronJS
Prima viene creato un nuovo oggetto vuoto e successivamente si inseriscono le coppie chiave-valore per popolare l'oggetto, l'oggetto viene poi convertito in una stringa Json con stringify ed infine la stringa viene salvata sul filesystem
===============================================================
var sinkhole = {};
sinkhole.localita = sessionStorage.getItem("localita");
sinkhole.comune = sessionStorage.getItem("comune");
sinkhole.data = sessionStorage.getItem("data");
sinkhole.ora = sessionStorage.getItem("ora");
sinkhole.compilatore = sessionStorage.getItem("compilatore");
sinkhole.annotazioni = sessionStorage.getItem("annotazioni");
sinkhole.nord = sessionStorage.getItem("nord");
sinkhole.est = sessionStorage.getItem("est");
sinkhole.sistema = sessionStorage.getItem("sistema");
sinkhole.diametro = diametro;
sinkhole.deformazione = deformazione;
sinkhole.pericolo = pericolo;
sinkhole.elemento = elemento;
var esportazione = JSON.stringify(sinkhole);
const fs = require('fs');
var nome_file = sessionStorage.getItem("comune")+"_"+sessionStorage.getItem("ora")+".json";
fs.writeFile(nome_file, esportazione, (err) => {
if(err){
alert("An error ocurred creating the file "+ err.message)
}
else {
alert("File salvato come " + nome_file);
}
});
venerdì 28 dicembre 2018
giovedì 27 dicembre 2018
DynamoDB con NodeJS
per prima cosa si installa nel progetto AWS SDK per NodeJS con
npm install aws-sdk
si lancia poi DynamoDB in locale come visto qui
npm install aws-sdk
si lancia poi DynamoDB in locale come visto qui
per fare il deploy sui server Amazon del DB si deve decommentare la riga evidenziata in giallo
=========================================================
var AWS = require("aws-sdk");
AWS.config.update({region: "us-west-1",endpoint: "http://localhost:8000"});
// per fare il deploy su DynamoDB sui server Amazon
//AWS.config.update({endpoint: "https://dynamodb.us-west-2.amazonaws.com"});
var dynamodb = new AWS.DynamoDB();
var params = {
TableName : "Informazioni",
KeySchema: [
{ AttributeName: "indice", KeyType: "HASH"}, //Partition key
{ AttributeName: "title", KeyType: "RANGE" } //Sort key
],
AttributeDefinitions: [
{ AttributeName: "indice", AttributeType: "N" },
{ AttributeName: "title", AttributeType: "S" }
],
ProvisionedThroughput: {
ReadCapacityUnits: 10,
WriteCapacityUnits: 10
}
};
dynamodb.createTable(params, function(err, data) {
if (err) {
console.error("Unable to create table. Error JSON:", JSON.stringify(err, null, 2));
} else {
console.log("Created table. Table description JSON:", JSON.stringify(data, null, 2));
}
});
//////////// INSERT ////////////////////////
var docClient = new AWS.DynamoDB.DocumentClient();
var table = "Informazioni";
var indice = 2015;
var title = "Il nome della rosa";
var params = {
TableName:table,
Item:{
"indice": indice,
"title": title,
}
};
console.log("Adding a new item...");
docClient.put(params, function(err, data) {
if (err) {
console.error("Unable to add item. Error JSON:", JSON.stringify(err, null, 2));
} else {
console.log("Added item:", JSON.stringify(data, null, 2));
}
});
//////////// QUERY ////////////////////////
var params = {
TableName : table,
KeyConditionExpression: "#yr = :yyyy",
ExpressionAttributeNames:{
"#yr": "indice"
},
ExpressionAttributeValues: {
":yyyy": 2015
}
};
docClient.query(params, function(err, data) {
if (err) {
console.error("Unable to query. Error:", JSON.stringify(err, null, 2));
} else {
console.log("Query succeeded.");
data.Items.forEach(function(item) {
console.log(" -", item.indice + ": " + item.title);
});
}
});
//////////// DELETE ITEM ////////////////////////
var params = {
TableName:table,
Key:{
"indice": indice,
"title": title
},
ConditionExpression:"indice <= :val",
ExpressionAttributeValues: {
":val": 2016
}
};
console.log("Attempting a conditional delete...");
docClient.delete(params, function(err, data) {
if (err) {
console.error("Unable to delete item. Error JSON:", JSON.stringify(err, null, 2));
} else {
console.log("DeleteItem succeeded:", JSON.stringify(data, null, 2));
}
});
var params = {
TableName : table
};
//////////// DELETE TABLE////////////////////////
dynamodb.deleteTable(params, function(err, data) {
if (err) {
console.error("Unable to delete table. Error JSON:", JSON.stringify(err, null, 2));
} else {
console.log("Deleted table. Table description JSON:", JSON.stringify(data, null, 2));
}
});
=========================================================
var AWS = require("aws-sdk");
AWS.config.update({region: "us-west-1",endpoint: "http://localhost:8000"});
// per fare il deploy su DynamoDB sui server Amazon
//AWS.config.update({endpoint: "https://dynamodb.us-west-2.amazonaws.com"});
var dynamodb = new AWS.DynamoDB();
var params = {
TableName : "Informazioni",
KeySchema: [
{ AttributeName: "indice", KeyType: "HASH"}, //Partition key
{ AttributeName: "title", KeyType: "RANGE" } //Sort key
],
AttributeDefinitions: [
{ AttributeName: "indice", AttributeType: "N" },
{ AttributeName: "title", AttributeType: "S" }
],
ProvisionedThroughput: {
ReadCapacityUnits: 10,
WriteCapacityUnits: 10
}
};
dynamodb.createTable(params, function(err, data) {
if (err) {
console.error("Unable to create table. Error JSON:", JSON.stringify(err, null, 2));
} else {
console.log("Created table. Table description JSON:", JSON.stringify(data, null, 2));
}
});
//////////// INSERT ////////////////////////
var docClient = new AWS.DynamoDB.DocumentClient();
var table = "Informazioni";
var indice = 2015;
var title = "Il nome della rosa";
var params = {
TableName:table,
Item:{
"indice": indice,
"title": title,
}
};
console.log("Adding a new item...");
docClient.put(params, function(err, data) {
if (err) {
console.error("Unable to add item. Error JSON:", JSON.stringify(err, null, 2));
} else {
console.log("Added item:", JSON.stringify(data, null, 2));
}
});
//////////// QUERY ////////////////////////
var params = {
TableName : table,
KeyConditionExpression: "#yr = :yyyy",
ExpressionAttributeNames:{
"#yr": "indice"
},
ExpressionAttributeValues: {
":yyyy": 2015
}
};
docClient.query(params, function(err, data) {
if (err) {
console.error("Unable to query. Error:", JSON.stringify(err, null, 2));
} else {
console.log("Query succeeded.");
data.Items.forEach(function(item) {
console.log(" -", item.indice + ": " + item.title);
});
}
});
//////////// DELETE ITEM ////////////////////////
var params = {
TableName:table,
Key:{
"indice": indice,
"title": title
},
ConditionExpression:"indice <= :val",
ExpressionAttributeValues: {
":val": 2016
}
};
console.log("Attempting a conditional delete...");
docClient.delete(params, function(err, data) {
if (err) {
console.error("Unable to delete item. Error JSON:", JSON.stringify(err, null, 2));
} else {
console.log("DeleteItem succeeded:", JSON.stringify(data, null, 2));
}
});
var params = {
TableName : table
};
//////////// DELETE TABLE////////////////////////
dynamodb.deleteTable(params, function(err, data) {
if (err) {
console.error("Unable to delete table. Error JSON:", JSON.stringify(err, null, 2));
} else {
console.log("Deleted table. Table description JSON:", JSON.stringify(data, null, 2));
}
});
Electron Packager
Mediante Electron Packager si possono creare dei pacchetti nativi per Linux, Windows e Mac OSX usando una sola piattaforma di sviluppo (nel mio caso una Linux Box)
Electron Packager si installa con
npm install electron-packager -g
Per creare i pacchetti Windows in una Linux Box si deve prima installare Wine in modalita' 32 e 64 bit (attezione a questo ultimo aspetto)
Windows 64 bit
electron-packager . sinkholes_electron --overwrite --asar=true --platform=win32 --arch=x64 --prune=true --out=release-builds --version-string.CompanyName=CE --version-string.FileDescription=CE --version-string.ProductName="Sinkholes ElectronJs"
Electron Packager si installa con
npm install electron-packager -g
Per creare i pacchetti Windows in una Linux Box si deve prima installare Wine in modalita' 32 e 64 bit (attezione a questo ultimo aspetto)
Windows 64 bit
electron-packager . sinkholes_electron --overwrite --asar=true --platform=win32 --arch=x64 --prune=true --out=release-builds --version-string.CompanyName=CE --version-string.FileDescription=CE --version-string.ProductName="Sinkholes ElectronJs"
Windows 32 bit
electron-packager . sinkholes_electron --overwrite --asar=true --platform=win32 --arch=ia32 --prune=true --out=release-builds --version-string.CompanyName=CE --version-string.FileDescription=CE --version-string.ProductName="Sinkholes ElectronJs"
electron-packager . sinkholes_electron --overwrite --asar=true --platform=win32 --arch=ia32 --prune=true --out=release-builds --version-string.CompanyName=CE --version-string.FileDescription=CE --version-string.ProductName="Sinkholes ElectronJs"
Mac OsX
electron-packager . --overwrite --platform=darwin --arch=x64 --prune=true --out=release-builds
Linux 64
electron-packager . electron-tutorial-app --overwrite --asar=true --platform=linux --arch=x64 --prune=true --out=release-builds
Per creare pacchetti senza asar si deve usare --no-asar (al contrario di come verrebbe naturale --asar=false)
mercoledì 26 dicembre 2018
Aumentare la RAM su Lenovo T440S
Per prima cosa c'e' da indicare che il Lenovo T440S monta 4 Gb di Ram saldati direttamente su scheda madre e c'e' un solo slot di espansione. In secondo luogo e' importante scegliere delle memoria DDR3 1600 a 1.35 V e non le piu' comuni 1.5 V
Lo smontaggio dello chassis prevede la completa rimozione del fondo...questo e' ad incastro e dopo aver tolto le viti si deve procedere a far saltare i fermi uno ad uno con un plettro di plastica. Attenzione operazione delicata
Lo smontaggio dello chassis prevede la completa rimozione del fondo...questo e' ad incastro e dopo aver tolto le viti si deve procedere a far saltare i fermi uno ad uno con un plettro di plastica. Attenzione operazione delicata
Let's Encrypt e DynDNS su Debian
Ad oggi diventa sempre piu' frequente la necessita' di usare connessioni HTTPS e spesso cio' crea problemi nella fase di sviluppo quando si devono fare delle semplici prove prima di andare in produzione
Una soluzione puo'essere quella di usare i certificati di Let's Encrypt, che garantiscono un traffico criptato su canale HTTPS ma non danno garanzie sull'autenticita' del host da cui le informazioni vengono (Let's Encrypt non effettua nessuna verifica sulla veridicita' dell'host e dell'organizzazione che lo mantiene)
Prima di procedere bisogna pero' indicare che i certificati di Let's Encrypt vengono forniti a server identificati via DNS e non via semplice IP (come spesso accade nelle macchine di sviluppo). Si puo' ovviare con un DNS Dinamico come DynDNS
Su Debian si procede installando il client di DynDNS
apt-get install ddclient
creando il nuovo dyndns nell'interfaccia web di https://dyndns.it/
e configurando il file /etc/ddclient.conf (il nome host e' quello inserito nella pagina web e scelto dall'utente nel formato xxxx.ns0.it
# /etc/ddclient.conf
protocol=dyndns2
use=web, web=checkip.dyndns.it
server=update.dyndns.it
login=INSERIRE_IL_PROPRIO_USERNAME
password='INSERIRE_LA_PROPRIA_PASSWORD'
INSERIRE_IL_NOME_HOST
si controlla che tutto sia a posto con
ddclient -debug
/etc/init.d/ddclient restart
wget https://dl.eff.org/certbot-auto
durante la configurazione si dovra' rispondere ad alcune domande
certbot-auto renew
Una soluzione puo'essere quella di usare i certificati di Let's Encrypt, che garantiscono un traffico criptato su canale HTTPS ma non danno garanzie sull'autenticita' del host da cui le informazioni vengono (Let's Encrypt non effettua nessuna verifica sulla veridicita' dell'host e dell'organizzazione che lo mantiene)
Prima di procedere bisogna pero' indicare che i certificati di Let's Encrypt vengono forniti a server identificati via DNS e non via semplice IP (come spesso accade nelle macchine di sviluppo). Si puo' ovviare con un DNS Dinamico come DynDNS
Su Debian si procede installando il client di DynDNS
apt-get install ddclient
creando il nuovo dyndns nell'interfaccia web di https://dyndns.it/
e configurando il file /etc/ddclient.conf (il nome host e' quello inserito nella pagina web e scelto dall'utente nel formato xxxx.ns0.it
protocol=dyndns2
use=web, web=checkip.dyndns.it
server=update.dyndns.it
login=INSERIRE_IL_PROPRIO_USERNAME
password='INSERIRE_LA_PROPRIA_PASSWORD'
INSERIRE_IL_NOME_HOST
e poi si lancia il servizio
si passa quindi a configurare la parte https
chmod a+x certbot-auto
e si lancia lo script specificando il web server
certbot-auto --apachee si lancia lo script specificando il web server
durante la configurazione si dovra' rispondere ad alcune domande
I certificati di Let's Encrypt hanno validita' di 90 giorni e quindi ci puo' essere la necessita' di mettere in cron il rinnovo automatico con
venerdì 21 dicembre 2018
Integrazione di JQuery in ElectronJS
Il porting di una web app in modalita' desktop con ElectronJS e' una operazione piuttosto indolore ma sorgono dei problemi quando si utilizzano librerie esterne come JQuery
Come riporta da questo link la soluzione e' quella di inserire prima e dopo le righe di importazione le linee evidenziate in giallo
semplice ed efficace
Come riporta da questo link la soluzione e' quella di inserire prima e dopo le righe di importazione le linee evidenziate in giallo
<!-- Insert this line above script imports -->
<script>if (typeof module === 'object') {window.module = module; module = undefined;}</script>
<!-- normal script imports etc -->
<script src="scripts/jquery.min.js"></script>
<script src="scripts/vendor.js"></script>
<!-- Insert this line after script imports -->
<script>if (window.module) module = window.module;</script>
semplice ed efficace
DynamoDB su localhost
Per configurare DynamoDB in localhost si devono seguire un serie di passi
1) Si deve installare AWS Cli tramite pip install awscli
2) Si deve lanciare il comando aws configure per vedere se e' stata impostata la region (di solito e' su None). Nel mio caso ho impostato eu-west-1
3) da questo link si scarica la versione locale di DynamoDB. Si scompatta e si lancia il comando (viene aperto un server in ascolto sulla porta 8000, se la porta e' occupata si possono modificare le impostazioni)
puo'essere necessario indicare la region usando aws configure
aws dynamodb put-item \ --table-name Music \ --item \ '{"Artist": {"S": "No One You Know"}, "SongTitle": {"S": "Call Me Today"}, "AlbumTitle": {"S": "Somewhat Famous"}}' \ --return-consumed-capacity TOTAL
1) Si deve installare AWS Cli tramite pip install awscli
2) Si deve lanciare il comando aws configure per vedere se e' stata impostata la region (di solito e' su None). Nel mio caso ho impostato eu-west-1
3) da questo link si scarica la versione locale di DynamoDB. Si scompatta e si lancia il comando (viene aperto un server in ascolto sulla porta 8000, se la porta e' occupata si possono modificare le impostazioni)
java -D"java.library.path=./DynamoDBLocal_lib" -jar DynamoDBLocal.jar
4) a questo punto si apre un altro terminale si puo' iniziare ad interagire con DynamoDB per esempio con
aws dynamodb list-tables --endpoint-url http://localhost:8000
puo'essere necessario indicare la region usando aws configure
per creare una tabella (esempi da questo link)
Attenzione : se si lavora in locale si deve sempre utilizzare lo switch --endpoint-url http://localhost:8000 ed aggiungerlo ai comandi sottostanti
aws dynamodb create-table \ --table-name Music \ --attribute-definitions \ AttributeName=Artist,AttributeType=S \ AttributeName=SongTitle,AttributeType=S \ --key-schema AttributeName=Artist,KeyType=HASH AttributeName=SongTitle,KeyType=RANGE \ --provisioned-throughput ReadCapacityUnits=1,WriteCapacityUnits=1
e per inserire una riga
venerdì 7 dicembre 2018
UserId su Alexa Skills
Non ho trovato da solo il modo di richiedere ad Alexa l'identificativo dell'utente che utilizza la skill (serve per poi fornire risposte personalizzate basate su DB)...e' venuto incontro il forum
https://forums.developer.amazon.com/questions/193367/userid-alexa.html
la soluzione e'
const userId = handlerInput.requestEnvelope.context.System.user.userId
attenzione che l'userId mostrato non e' relativo all'account Amazon dell'utente. Ogni skill genera un proprio UserID legato all'account Amazon (quest'ultimo rimane sempre mascherato)..se uno stesso utente usa due skill differenti gli UserId che si leggeranno da Alexa risulteranno differenti
https://forums.developer.amazon.com/questions/193367/userid-alexa.html
la soluzione e'
const userId = handlerInput.requestEnvelope.context.System.user.userId
attenzione che l'userId mostrato non e' relativo all'account Amazon dell'utente. Ogni skill genera un proprio UserID legato all'account Amazon (quest'ultimo rimane sempre mascherato)..se uno stesso utente usa due skill differenti gli UserId che si leggeranno da Alexa risulteranno differenti
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
--------------------------------------------------------------
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)
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
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
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
------------------------------------------------------------
{
"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
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
RHEL 8 beta
AGGIORNAMENTO : dopo circa un mese di utilizzo ho provato a personalizzare un po' l'installazione con Wine ed altri pacchetti e mi sono accorto che era impossibile..questa la risposta del forum di RedHat
No, it's not possible in a "normal way" by using yum, because the EPEL
repository is not configured for RHEL 8 yet.
The only way to install it currently would be to do it manually. But I don't
recommend to do this, the beta version is
meant to be used for normal testing purposes in first place, which means
testing native applications and services. :)
tempo di tornare a Debian
------------------------------------------------------------------
Sto provando la beta di RHEL 8 (Red Hat Enterprise). A differenza di Centos 7 l'interfaccia e' passata a Gnome Shell (e quindi ho perso il vantaggio di usare Centos 7 rispetto a Debian)
L'installazione non ha creato problemi. L'unica cosa da ricordare e' che per avere accesso agli aggiornamenti tramite yum con
subscription-manager register
subscription-manager attach --auto
No, it's not possible in a "normal way" by using yum, because the EPEL
repository is not configured for RHEL 8 yet.
The only way to install it currently would be to do it manually. But I don't
recommend to do this, the beta version is
meant to be used for normal testing purposes in first place, which means
testing native applications and services. :)
tempo di tornare a Debian
------------------------------------------------------------------
Sto provando la beta di RHEL 8 (Red Hat Enterprise). A differenza di Centos 7 l'interfaccia e' passata a Gnome Shell (e quindi ho perso il vantaggio di usare Centos 7 rispetto a Debian)
L'installazione non ha creato problemi. L'unica cosa da ricordare e' che per avere accesso agli aggiornamenti tramite yum con
subscription-manager register
subscription-manager attach --auto
venerdì 30 novembre 2018
Testare Lambda NodeJS in locale per Alexa Skills
Per testare una Lambda function per Alexa Skills non e' strettamente necessario utilizzare Amazon AWS con l'editor on line
per esempio si parte dallo scaricare il progetto Basic Starter da SkillTemplates (ask new --template --url https://skilltemplates.com/templates.json)
Si crea quindi nella root del progetto (dove e' contenuta la directory Lambda per capirsi) una directory test e si inseriscono i seguenti tre files
test.js
-------------------------------------------------------------------
var lambda = require('../lambda/custom/index.js');
var context = require('./context.js');
var mockEvent = require('./event.json');
var mockContext = new context();
function callback(error, data) {
if(error) {
console.log('error: ' + error);
} else {
console.log(data);
}
}
lambda.handler(mockEvent, mockContext, callback);
-------------------------------------------------------------------
context.js
-------------------------------------------------------------------
module.exports = function() {
return {
succeed: function(result) {
console.log(JSON.stringify(result, null,'\t') );
},
fail: function(err) {
console.log(JSON.stringify(err, null,'\t') );
},
done: function(err, result) {
//console.log("CONTEXT DONE:", err, result);
},
functionName: 'local_functionName',
awsRequestId: 'local_awsRequestId',
logGroupName: 'local_logGroupName',
logStreamName: 'local_logStreamName',
clientContext: 'local_clientContext',
identity: {
cognitoIdentityId: 'local_cognitoIdentityId'
}
};
};
-------------------------------------------------------------------
{
"session": {
"new": false,
"sessionId": "mock_sessionId",
"application": {
"applicationId": "mock_applicationId"
},
"attributes": {},
"user": {
"userId": "mock_userId"
}
},
"request": {
"type": "LaunchRequest",
"requestId": "mock_requestId",
"locale": "en-US",
"timestamp": "2017-09-19T11:46:23Z"
},
"context": {
"AudioPlayer": {
"playerActivity": "IDLE"
},
"System": {
"application": {
"applicationId": "mock_applicationId"
},
"user": {
"userId": "mock_userId"
},
"device": {
"supportedInterfaces": {}
}
}
},
"version": "1.0"
}
-------------------------------------------------------------------
se si lancia il file test.js con
node.js
si ha come riposta
-------------------------------------------------------------------
{ version: '1.0',
response:
{ outputSpeech:
{ type: 'SSML',
ssml: '<speak>Hello there. What is your name?</speak>' },
reprompt: { outputSpeech: [Object] },
shouldEndSession: false,
card:
{ type: 'Simple',
title: 'Example Card Title',
content: 'Example card body content.' } },
userAgent: 'ask-node/2.0.5 Node/v10.4.1',
sessionAttributes: {} }
-------------------------------------------------------------------
per esempio si parte dallo scaricare il progetto Basic Starter da SkillTemplates (ask new --template --url https://skilltemplates.com/templates.json)
Si crea quindi nella root del progetto (dove e' contenuta la directory Lambda per capirsi) una directory test e si inseriscono i seguenti tre files
test.js
-------------------------------------------------------------------
var lambda = require('../lambda/custom/index.js');
var context = require('./context.js');
var mockEvent = require('./event.json');
var mockContext = new context();
function callback(error, data) {
if(error) {
console.log('error: ' + error);
} else {
console.log(data);
}
}
lambda.handler(mockEvent, mockContext, callback);
-------------------------------------------------------------------
context.js
-------------------------------------------------------------------
module.exports = function() {
return {
succeed: function(result) {
console.log(JSON.stringify(result, null,'\t') );
},
fail: function(err) {
console.log(JSON.stringify(err, null,'\t') );
},
done: function(err, result) {
//console.log("CONTEXT DONE:", err, result);
},
functionName: 'local_functionName',
awsRequestId: 'local_awsRequestId',
logGroupName: 'local_logGroupName',
logStreamName: 'local_logStreamName',
clientContext: 'local_clientContext',
identity: {
cognitoIdentityId: 'local_cognitoIdentityId'
}
};
};
-------------------------------------------------------------------
event.json
-------------------------------------------------------------------{
"session": {
"new": false,
"sessionId": "mock_sessionId",
"application": {
"applicationId": "mock_applicationId"
},
"attributes": {},
"user": {
"userId": "mock_userId"
}
},
"request": {
"type": "LaunchRequest",
"requestId": "mock_requestId",
"locale": "en-US",
"timestamp": "2017-09-19T11:46:23Z"
},
"context": {
"AudioPlayer": {
"playerActivity": "IDLE"
},
"System": {
"application": {
"applicationId": "mock_applicationId"
},
"user": {
"userId": "mock_userId"
},
"device": {
"supportedInterfaces": {}
}
}
},
"version": "1.0"
}
-------------------------------------------------------------------
node.js
si ha come riposta
-------------------------------------------------------------------
response:
{ outputSpeech:
{ type: 'SSML',
ssml: '<speak>Hello there. What is your name?</speak>' },
reprompt: { outputSpeech: [Object] },
shouldEndSession: false,
card:
{ type: 'Simple',
title: 'Example Card Title',
content: 'Example card body content.' } },
userAgent: 'ask-node/2.0.5 Node/v10.4.1',
sessionAttributes: {} }
-------------------------------------------------------------------
questo e' il file che normalmente Lambda passa a Alexa per poi essere trasformato in messaggio vocale ed spedito al dispositivo Alexa
In pratica viene generata l'intent LaunchRequest (event.json) della funzione Lambda che corrisponde a
-------------------------------------------------------------------
const LaunchRequestHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
},
handle(handlerInput) {
const speechText = 'Hello there. What is your name?';
const repromptText = 'Can you tell me your name?';
return handlerInput.responseBuilder
.speak(speechText)
.reprompt(repromptText)
.withSimpleCard('Example Card Title', "Example card body content.")
.getResponse();
},
};
-------------------------------------------------------------------
giovedì 29 novembre 2018
Vi yank and paste
Piccolo promemoria ...visto che me lo scordo sempre
Nell'editor vi per selezionare e copiare testo si deve, in modalita' comando, premere v (comparira' la scritta -- VISUAL -- in basso) e si evidenzia il testo da copiare con i tasti freccia
A questo punto si puo' copiare (yank) con il tasto y o cancellare con d
Per incollare il testo precedentemente copiato usa p (paste)
Nell'editor vi per selezionare e copiare testo si deve, in modalita' comando, premere v (comparira' la scritta -- VISUAL -- in basso) e si evidenzia il testo da copiare con i tasti freccia
A questo punto si puo' copiare (yank) con il tasto y o cancellare con d
Per incollare il testo precedentemente copiato usa p (paste)
Alexa Ask Cli ed Address API
Per installare l'interfaccia di programmazione di Alexa a linea di comando (senza utilizzare gli editor Web online di Alexa ed Aws Lambda) si puo' usare Ask Cli che si installa tramite npm con
npm install -g ask-cli
verra' al termine richiesto di loggardi con la propria user e password su Amazon tramite un finestra di autenticazione web
Nel caso in cui ask risponda con un messaggio di errore del tipo
vuol dire che l'interfaccia Ask Cli non riesce ad auntenticarsi sui server Amazon.
ask new --template --url https://skilltemplates.com/templates.json
(altrimenti se si crea una skill ex novo
ask new --skill-name test --lambda-name test
)
npm install -g ask-cli
verra' al termine richiesto di loggardi con la propria user e password su Amazon tramite un finestra di autenticazione web
Nel caso in cui ask risponda con un messaggio di errore del tipo
InvalidClientTokenId: The security token included in the request is invalid.
La soluzione e' riprocedere con il comando
ask init
(attenzione se non gia' configurato a questo punto verra' chiesto di inserire le proprie credenziali.
Su alcuni SO la procedura funziona senza problemi...in altri casi si deve usare ask init --no-browser a causa di un errore di Unhandled promise rejection)
(attenzione se non gia' configurato a questo punto verra' chiesto di inserire le proprie credenziali.
Su alcuni SO la procedura funziona senza problemi...in altri casi si deve usare ask init --no-browser a causa di un errore di Unhandled promise rejection)
A questo punto si inizia con l'esempio
ask new --template --url https://skilltemplates.com/templates.json
(altrimenti se si crea una skill ex novo
ask new --skill-name test --lambda-name test
)
Dal menu si sceglie Device Location API Starter
si entra quindi nella nuova directory del template e si inserisce
ask deploy
ogni volta che e' stato modificato il codice in locale per effettuare l'upload della skill su Amazon si deve effettuare il deploy. Si puo' effettuare anche un deploy parziale della sola funzione Lambda con
ask lambda upload
Le Address API richiedono una autorizzazione esplicita da parte dell'utente per l'utilizzo. Si deve quindi andare su https://alexa.amazon.it cliccare Le tue Skill, Skill attivate e cercare device-location-api-starter attivare la Skill con l'autorizzazione
a questo punto si e' presentato un problema. La skill era priva di endpoint perche' non e' stata creata la corrispondente funziona Lambda. Ho quindi proceduto a creare una Lambda copiandoci poi sopra il file index.js che ho trovato nel template
----------------------------------------------
/* eslint-disable func-names */
/* eslint-disable no-console */
const Alexa = require('ask-sdk-core');
const APP_NAME = "Location Starter"
const messages = {
NOTIFY_MISSING_PERMISSIONS: 'Please enable device location permissions in the Amazon Alexa app.',
NO_ADDRESS: 'It looks like you don\'t have an address set. You can set your address from the companion app.',
ERROR: 'Uh Oh. Looks like something went wrong.'
};
const DEVICE_LOCATION_PERMISSION = 'read::alexa:device:all:address';
const LaunchRequestHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
},
handle(handlerInput) {
const speechText = `Hello, welcome to ${APP_NAME}. You can ask about device address by saying what is my location`;
const repromptText = 'What would you like to know?';
return handlerInput.responseBuilder
.speak(speechText)
.reprompt(repromptText)
.withSimpleCard(APP_NAME, speechText)
.getResponse();
},
};
const DeviceLocationIntentHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'IntentRequest'
&& handlerInput.requestEnvelope.request.intent.name === 'DeviceLocationIntent';
},
async handle(handlerInput) {
const { requestEnvelope, serviceClientFactory, responseBuilder } = handlerInput;
try {
const { deviceId } = requestEnvelope.context.System.device;
const deviceAddressServiceClient = serviceClientFactory.getDeviceAddressServiceClient();
const address = await deviceAddressServiceClient.getFullAddress(deviceId);
let response;
if (address == undefined || (address.addressLine1 === null && address.stateOrRegion === null)) {
response = responseBuilder.speak(messages.NO_ADDRESS).getResponse();
return response;
} else {
const completeAddress = `${address.addressLine1}, ${address.stateOrRegion}, ${address.postalCode}`;
const response = `Your complete address is, ${completeAddress}`;
return handlerInput.responseBuilder
.speak(response)
.withSimpleCard(APP_NAME, response)
.getResponse();
}
} catch (error) {
console.log(JSON.stringify(error));
if (error.statusCode == 403) {
return responseBuilder
.speak(messages.NOTIFY_MISSING_PERMISSIONS)
.withAskForPermissionsConsentCard([DEVICE_LOCATION_PERMISSION])
.getResponse();
}
console.log(JSON.stringify(error));
const response = responseBuilder.speak(messages.ERROR).getResponse();
return response;
}
},
};
const HelpIntentHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'IntentRequest'
&& handlerInput.requestEnvelope.request.intent.name === 'AMAZON.HelpIntent';
},
handle(handlerInput) {
const speechText = 'You can ask for the address';
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 skillBuilder = Alexa.SkillBuilders.custom();
exports.handler = skillBuilder
.addRequestHandlers(
LaunchRequestHandler,
DeviceLocationIntentHandler,
HelpIntentHandler,
CancelAndStopIntentHandler,
SessionEndedRequestHandler
)
.addErrorHandlers(ErrorHandler)
.withApiClient(new Alexa.DefaultApiClient())
.lambda();
----------------------------------------------
questo e' il file skill.json. Evidenziato in giallo la richiesta dei permessi
----------------------------------------------
{
"manifest": {
"publishingInformation": {
"locales": {
"en-US": {
"summary": "Sample Short Description",
"examplePhrases": [
"Alexa open location starter",
"Alexa ask location starter about my adrees"
],
"keywords": [
"keyword1",
"keyword2",
"keyword3"
],
"name": "device-location-api-starter",
"description": "Sample Full Description",
"smallIconUri": "https://s3.amazonaws.com/cdn.dabblelab.com/img/skill-template-default-sm.png",
"largeIconUri": "https://s3.amazonaws.com/cdn.dabblelab.com/img/skill-template-default-lg.png"
}
},
"isAvailableWorldwide": true,
"testingInstructions": "No special instructions.",
"category": "EDUCATION_AND_REFERENCE",
"distributionCountries": []
},
"apis": {
"custom": {
"endpoint": {
"sourceDir": "lambda/custom"
}
}
},
"manifestVersion": "1.0",
"permissions": [
{
"name": "alexa::devices:all:address:full:read"
}
],
"privacyAndCompliance": {
"allowsPurchases": false,
"locales": {
"en-US": {
"termsOfUseUrl": "http://dabblelab.com/terms",
"privacyPolicyUrl": "http://dabblelab.com/privacy"
}
},
"isExportCompliant": true,
"containsAds": false,
"isChildDirected": false,
"usesPersonalInfo": false
}
}
}
----------------------------------------------
Di default non viene assunto l'indirizzo del dispositivo con quello configurato nel profilo Amazon. Si deve settare in modo esplicito la posizione nella app sul telefono Alexa Amazon per ogni dispositivo
Iscriviti a:
Post (Atom)
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...
-
In questo post viene indicato come creare uno scatterplot dinamico basato da dati ripresi da un file csv (nel dettaglio il file csv e' c...
-
La scheda ESP32-2432S028R monta un Esp Dev Module con uno schermo TFT a driver ILI9341 di 320x240 pixels 16 bit colore.Il sito di riferiment...
-
Questo post e' a seguito di quanto gia' visto nella precedente prova Lo scopo e' sempre il solito: creare un sistema che permet...