Skip to content

tom's blog

blogging since 2017

tom's blog

  • Home
  • Datenschutz
  • Impressum
Search

Eigener Alexa Skill [Tutorial]

First posted: 1 September 201711 July 2018Kategorisiert: nodejs
  • programmieren
  • Tutorials
Kommentieren

Hey,

wie ihr eventuell schon in diesem Post mitbekommen habt, habe ich mir neulich einen kleinen Alexa Skill selber geschrieben. Hier möchte ich euch mal kurz zeigen wie das ganze funktioniert – komplett ohne Amazon Lambda, sondern 100% Self Hosted.

Wir werden heute einfach einen Skill schreiben, der uns die aktuelle NodeJS Version sagt – komplett ohne Parameter oder so.

Was wird benötigt:

  • nodeJS (ich nutze v8.4.0)
  • Server mit SSL Zertifikat (kann auch Selbst Signiert werden)
  • Amazon Developer Konto

Los geht’s!

Übersicht:

Schritt 1: Skill bei Amazon registrieren

Schritt 2: Interaction Model

 

 

Skill bei Amazon registrieren

Als erster müssen wir unseren Skill bei Amazon registrieren.

Dazu gehen wir einfach auf in der Amazon Developer Console auf Get Started bei den Alexa Skills Kit’s.

Nun erstellen wir einen neuen Skill, in dem wir oben rechts auf “Add a Skill” klicken.

 

Das ganze sollte dann so aussehen:

Die Skill Typen

In diesem Tutorial erstellen wir einen “Custom Interaction Skill” – das heißt, dass wir alles selber definieren werden was der Skill machen kann.

SmartHome Skills sind – wie der Name schon sagt – für ein SmartHome gedacht. Diese Skills können nur Sachen ein oder ausschalten oder die Temperatur verändern.

Flash Briefing sind Skills, die zur Tageszusammenfassung gehören -> “Alexa, was ist meine Tageszusammenfassung”, da würde der Skill dann greifen

Video Skills können Videos abspielen, wie Serien oder Filme (wie genau das funktioniert weiß ich nicht, da ich mich damit noch nicht auseinander gesetzt habe)

Eine genauere Erklärung der Typen findet ihr hier.

 

 

Des Weiteren müssen wir noch einen Skill Namen und einen Invocation Name festlegen. Der Skill Name wird später in der AlexaApp angezeigt (also wie ein App Name) und der Invocation Name ist der Aufruf Name. Dort könnt ihr ein Wort eintragen (oder mehrere). Darauf reagiert dann euer Skill.

Nennt ihr ihn also Node Version würde er durch folgenden Aufruf gestartet werden: “Alexa, frage Node Version ...”.

Da wir weder einen Audio Player, noch die anderen beiden Dinge aus den Global Fields brauchen können wir diese alle auf No lassen.

Dann auf “Save” klicken und zum nächsten Schritt gehen

 

Das Interaction Model

Im Interaction Model legen wir fest, auf welche Sätze unser Skill hört, welche Parameter übergeben werden können und welche Intents wir haben.

Ein Intent ist eine Aktion, die durch den Aufruf des Nutzers ausgeführt werden kann.

Unser Interaction Model könnte zum Beispiel so aussehen:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 
{
  "intents": [
    {
      "intent": "getNodeVersion"
    },
    {
      "intent": "AMAZON.HelpIntent"
    },
    {
      "intent": "AMAZON.StopIntent"
    },
    {
      "intent": "AMAZON.CancelIntent"
    }
  ]
}
 

Unser eigener Intent ist der getNodeVersion Intent. Die anderen sind Standard.

Da wir keine Parameter haben, können wir Custom Slot Types überspringen und direkt zu den Sample Utterances gehen. Das sind die Sätze, bei denen unser Intent aufgerufen wird. Hier ist es wichtig, so viele Möglichkeiten wie ihr findet reinzuschreiben, also ihr müsst euch überlegen was ein Benutzer alles sagen könnte, um euren Skill zu benutzen / den Intent aufzurufen.

Da das hier nur ein Tutorial ist, habe ich einfach nur einen genommen:

Als Anfang müsst ihr euren Intent, der durch den Satz aufgerufen werden soll definieren. Danach den Satz ohne Invocation Name

Dieser würde jetzt greifen, wenn man “Alexa, frage Node Version welche die aktuellste Version ist” – also ein Aufruf besteht aus folgendem Schema

RUFWORT ECHO – ” frage ” – INVOCATION NAME – SAMPLE UTTERANCE

Dann wieder speichern und zum nächsten Schritt.

 

Endpunkte und Berechtigungen

Jetzt müssen wir unsere Endpunkte für den Skill festlegen. Da wir das ganze ohne Amazon Lambda machen wollen, müssen wir dementsprechend auf HTTPS gehen.

Im Feld “Default” müsst ihr dann eure URL eintragen, wo der Alexa Server (welchen wir gleich noch erstellen) läuft.

Ich nutze einen Raspberry Pi mit NGINX und einer Subdomain, da CloudFlare kostenlose SSL Zertifikate anbietet, nutze ich dieses einfach gleich mit!

Account Linking und so weiter brauchen wir auch bei unserem einfachen Beispiel nicht, deswegen wieder Speichern und zum nächsten Schritt!

SSL Zertifikat einrichten

Im nächsten Schritt geht es darum, das Zertifikat einzurichten. Wie ich schon sagte nutze ich eine Subdomain. Cloudflare ist eine “Trusted Certificate Authority” deswegen muss ich das 2. Anwählen.

Habt ihr nun bspw. eine eigene Domain für euren Skill dann müsst ihr das erste nehmen.

Habt ihr keine Domain oder wollt nur im lokalen Netzwerk arbeiten müsst ihr euch selber ein SSL Zertifikat Signieren. Da gibt es einige Tutorials im Netz! Dieses müsstet ihr dann im nächsten Schritt hochladen.

Habt ihr auch das SSL Zertifikat eingerichtet, kommen wir endlich nun zu dem Punkt, wo wir unseren Alexa Server schreiben.

 

Der nodeJS-Alexa Server

Um einen eigenen Server zum laufen zu bringen, der mit dem Echo (Dot) kommunizieren kann, ist gar nicht soviel nötig.

Als erstes erstellen wir uns mal einen Ordner und nennen ihn Alexa-Skill-NodeVersion (oder wie auch immer ihr ihn nennen wollt) und öffnen ein Terminal und unseren Editor hier.

Da der Node Package Manager auf dem Raspberry Pi unglaublich langsam ist, nutzen wir direkt Yarn. Yarn greift auf exakt die selben Pakete zu, ist aber trotzdem deutlich schneller. Wer Yarn noch nicht installiert hat, findet hier eine Anleitung wie das geht.

Zuerst das Projekt initialisieren:

$ yarn init

An sich könnt ihr erstmal alles mit Enter bestätigen. Nun solltet ihr eine package.json im Projekt sehen.

Wir benötigen folgende Dependencies:

  • express
  • alexa-sdk
  • body-parser
  • request

Diese installieren wir einfach mit

$ yarn add express alexa-sdk body-parser request

Express ist ein Framework für WebServer und das alexa-sdk ist das Alexa SDK für nodeJS. Durch den BodyParser können wir einfach den Body, der in einer Post Anfrage kommt, als JSON verarbeiten!

 

Um nun einen ersten Test durchzuführen benötigt es nicht viel:

Wie müssen lediglich einen Express Server aufsetzen und die Handler für Alexa einrichten:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
const express = require('express');
const app = express();
const Alexa = require('alexa-sdk');
const bodyParser = require('body-parser');
 
app.use(bodyParser.json());
 
app.post('/', function (req, res) {
    const context = {
        succeed: (result) => {
            res.json(result);
        },
        fail: (error) =>{
            console.log(error);
        }
    };
    const alexa = Alexa.handler(req.body, context);
    alexa.appId = '';
    alexa.registerHandlers(handlers);
    alexa.execute();
});
const handlers = {
    'getNodeVersion': function() {
        this.emit(':tell', 'Die aktuelle nodeJS Version ist 8.4.0');
    },
    'Unhandled': function() {
        this.emit(':ask', "Es gab leider einen Fehler");
    }
};
app.listen(1064, () => {
    console.log('Alexa Server listening on port 1064!');
});

Erklärung zum Code:

In den ersten 3 Zeilen laden wir alle unsere Dependencies und erstellen unseren express Server. Danach richten wir die POST Route auf ‘/’ (also direkt unsere Domain). Dahin sendet der Skill die Anfragen

Der Context (eigentlich von Lambda) wird aber auch hier genutzt um Fehler und Antworten zu loggen und die Antwort zu senden.

Danach erstellen wir noch unsere Alexa Instanz mit dem gesendeten RequestBody und unserem Context. Die Zeile  alexa.appId = <eure ID> Legt eure AppID fest, welche ihr euch von der Developer Seite holen könnt (steht unter eurem Projektnamen).

Die wohl spannendste Zeile ist  alexa.registerHandlers(handlers);  – hier registrieren wir die Handler, die Aufgerufen werden. Ein Handler hat den den selben Namen wie das Intent, auf welches er reagieren soll. Der Unhandled Intent ist für Fehler. Allerdings funktioniert dieser nicht immer und Alexa gibt ihre eigenen Fehler aus.

1
this.emit(':tell', 'Die aktuelle Version ist v8.4.0')

Ist dann die Antwort. Diese kann in SSML gegeben werden, wollt ihr aber nur was sagen reicht auch einfach ein String als 2. Argument.

 

Abfrage der aktuellen Node Version

Wie schon gesagt machen wir das Ganze natürlich automatisch, also so dass wir nicht jedes mal selber den ganzen Skill updaten müssen wenn eine neue nodeJS Version rauskommt.

Wir erstellen uns mal eine neue Datei und nennen diese “GetNodeVersion.js”.

In dieser Datei exportieren wir lediglich eine Funktion, welche über eine http Request sich die aktuellste Version holt:

JavaScript
1
2
3
4
5
6
7
8
9
10
11
12
const request = require('request');
 
module.exports = () => {
    return new Promise((getVersionResolve, getVersionReject) => {
        request('https://nodejs.org/dist/index.json', (err, body, result) => {
            if(err) getVersionReject(err);
            else {
                getVersionResolve(JSON.parse(result)[0].version)
            }
        })
    })
};

Erklärung zum Code:

Wie schon gesagt exportiert diese Datei eine Funktion ( module.exports). Parameter werden keine benötigt. Da ich allgemein gerne in ECMAScript 6 schreibe, habe ich Promises und ArrowFunctions benutzt.

Falls ihr keine Ahnung habt, was das ist und immer in ECMAScript 5 programmiert, könnt ihr euch in der GitHub Repo zu dem Projekt auch die ECMAScript 5 Version des Code angucken!

request ist ein Modul um HTTP Anfragen auszuführen. Auf der Seite https://nodejs.org/dist/index.json werden immer alle nodeJS Versionen mit vielen weiteren Informationen gegeben. Da wir immer die aktuelle Version wollen, können wir einfach auf das 1. (0.) Objekt im Array zugreifen, da an dieser Stelle immer die aktuellste Version ist.

Führt man das nun aus, würde man die Versionsnummer zurückbekommen. Nun bauen wir das ganze noch in den Skill ein!

 

Abfrage mit dem Skill verbinden

Um nun unsere GetNodeVersion.js mit unserem Handler zu verbinden wechseln wir wieder in die Datei Skill.js.

Dort fügen wir oben folgende Zeile an:

JavaScript
1
const version = require('./GetNodeVersion');

Somit wird unsere GetNodeVersion.js Datei geladen und wir können im späteren Teil des Programmes darauf zugreifen.

In unserem getNodeVersion-Handler fügen wir folgende Zeilen ein:

JavaScript
1
2
3
4
5
6
7
    'getNodeVersion': () => {
        version().then((version) => {
            this.emit(':tell', 'Die aktuelle nodeJS Version ist ' + version);
        }).catch((err) => {
            this.emit(':tell', 'Es gab leider einen Fehler ' + err.message);
        });
    }

Durch  version() wird unsere Funktion aufgerufen. Da es ein Promise ist können wir mit  .then((version) => {})  auf die Version zugreifen, welche nun als Variable “version” verfügbar ist.

this.emit(':tell', 'Die aktuelle nodeJS Version ist ' + version);

macht dann noch einen ganzen Satz daraus und fertig ist unser BackEnd-Server. Jetzt müssen wir diesen einfach starten!

 

Testen

Um unseren Skill zu testen müssen wieder auf die Amazon Developer Seite wechseln, unseren Skill auswählen und im Seitenmenü “Test” auswählen.

Dort können wir dann unten unsere Sätze eingeben und bekommen – wenn alles klappt – die Antwort von unserem Server und können sie uns sogar anhören!

nodejs, programmieren, Tutorials
  • alexa
  • data
  • iot
  • programmieren
  • Tutorials

Post navigation

Previous Post:

Eigener Alexa Skill

Next Post:

Heftige Sicherheitslücke in macOS?

Über den Author

tom

Alle Beiträge vontom

Verstecken

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

GitHub

dunklesToast (Tom)

Tom

dunklesToast
RND RedaktionsNetzwerk Deutschland
Hanover
Joined on Feb 16, 2016
56 Public Repositories
5 Public Gists

Recent Posts

  • Get Instagram Profile Pictures in Full Size
  • Heftige Sicherheitslücke in macOS?
  • Eigener Alexa Skill [Tutorial]
  • Eigener Alexa Skill
  • Der 24h Stream von QNerd und meine Statistik Seite

Archives

  • July 2018
  • November 2017
  • September 2017
  • August 2017

Categories

  • javascript
  • nodejs
  • programmieren
  • Tutorials
  • Unkategorisiert
  • Datenschutz
  • Impressum