Inhalt

Übersicht

In diesem Beispiel wird ein Alexa Custom Skill implementiert, mit dem Du Alexa nach Informationen über Deinen IP Symcon-Server fragen kannst.

Weitere Informationen zu den hier verwendeten Modules des Patami Frameworks findest Du hier:

Das folgende Schaubild zeigt die verschiedenen Komponenten, die am Custom Skills beteiligt sind, und wie diese zusammenhängen:

Einrichtung

Folge den Schritten in diesem Abschnitt, um den Custom Skill bei Amazon und in Deiner IP Symcon-Installation einzurichten.

Framework einrichten

Falls noch nicht geschehen, musst Du das Patami Framework auf Deinem IP Symcon-Server einrichten:

Installiere das Patami Framework, indem Du dieser Anleitung folgst.

Alexa Custom Skill Instanz erstellen

Lege eine neue Alexa Custom Skill Instanz an, indem Du dieser Anleitung folgst.

Setze den WebHook Pfad auf alexa/custom/tutorial/info, indem Du dieser Anleitung folgst.

Übernehme anschließend die Konfiguration. Die Instanz wird als fehlerhaft markiert, da notwendige Angaben (Application ID, User ID) fehlen. Das werden wir später korrigieren, sobald die Informationen vorliegen.

Kopiere die URL des WebHooks in eine Textdatei, indem Du dieser Anleitung folgst.

Die URL sollte (abgesehen vom Host-Teil vor ipmagic.de) so aussehen: https://0123456789abcdef0123456789abcdef.ipmagic.de/hook/alexa/custom/tutorial/info

Alexa Skill erstellen

Erstelle einen neuen Alexa Skill:

Klicke hier, um die Amazon Developer Console zu öffnen und die Liste Deiner Skills anzuzeigen.

Klicke auf Add a New Skill, um einen neuen Skill anzulegen:

Alexa Custom Skill konfigurieren

Konfiguriere den neuen Custom Skill:

Die erste Seite des Assistenten, Skill Information, wird angezeigt:

Gib auf der Seite die folgenden Informationen ein:

LanguageGerman
NameDemo System Information
Invocation NameSystem Informationen

Klicke anschließen auf den Button Save.

Bei den nicht rot markierten Feldern ist bereits der gewünschte Wert vorausgewählt. Dies gilt entsprechend auch für alle weiteren Schritte dieser Anleitung.

Der neue Skill wurde jetzt gespeichert und eine Application ID vergeben.

Die Application ID wird später von der Custom Skill Instanz verwendet, um den Skill zu identifizieren und die Anfragen der Amazon Server zu authentifizieren.

Die Anzeige der ersten Seite des Assistenten ändert sich wie folgt:

Klicke jetzt auf den Button Next, um auf die nächste Seite des Assistenten zu wechseln.

Die zweite Seite des Assistenten, Interaction Model, wird angezeigt:

Klicke auf den Button Launch Skill Builder, um den Skill Builder zu starten.

Der Skill Builder wird angezeigt:

Klicke auf den Button Add + bei den Slot Types, um einen neuen Slot Type hinzuzufügen.

Du kannst die Schritte 4 bis 12 überspringen, indem Du das Interaction Model per Copy & Paste in den Code Editor des Skill Builders kopierst.

Interaction Model JSON
{
  "intents": [
    {
      "name": "AMAZON.CancelIntent",
      "samples": []
    },
    {
      "name": "AMAZON.HelpIntent",
      "samples": []
    },
    {
      "name": "AMAZON.RepeatIntent",
      "samples": []
    },
    {
      "name": "AMAZON.StopIntent",
      "samples": []
    },
    {
      "name": "GetInformation",
      "samples": [
        "{subject} ",
        "informationen über {subject} ",
        "anzahl von {subject} "
      ],
      "slots": [
        {
          "name": "subject",
          "type": "subject",
          "samples": []
        }
      ]
    }
  ],
  "types": [
    {
      "name": "subject",
      "values": [
        {
          "name": {
            "value": "Objekte"
          }
        },
        {
          "name": {
            "value": "Bibliotheken"
          }
        },
        {
          "name": {
            "value": "Module"
          }
        },
        {
          "name": {
            "value": "Instanzen"
          }
        },
        {
          "name": {
            "value": "Variablen"
          }
        },
        {
          "name": {
            "value": "Skripte"
          }
        },
        {
          "name": {
            "value": "Funktionen"
          }
        },
        {
          "name": {
            "value": "Ereignisse"
          }
        },
        {
          "name": {
            "value": "Medien"
          }
        },
        {
          "name": {
            "value": "Links"
          }
        },
        {
          "name": {
            "value": "Kategorien"
          }
        }
      ]
    }
  ]
}

Der Dialog zum Hinzufügen eines Slot Types wird angezeigt:

Führe folgende Schritte aus:

  1. Gib im Eingabefeld den Namen des Slot Types, subject, ein.
  2. Klicke auf den Button Create Slot Type.

Der Dialog zum Bearbeiten des neuen Slot Types subject wird angezeigt:

Führe folgende Schritte aus:

  1. Gib den ersten Wert des Slot Types, Objekte, ein.
  2. Drücke die Eingabetaste, um den Wert zur Liste der Slot Type Werte hinzuzufügen.

Wiederhole das mit den folgenden Werten:

  • Bibliotheken
  • Module
  • Instanzen
  • Variablen
  • Skripte
  • Funktionen
  • Ereignisse
  • Medien
  • Links
  • Kategorien

Danach sollte die Liste der Slot Type Werte wie folgt aussehen:

Klicke auf den Button Add + bei den Intents, um einen neuen Intent hinzuzufügen.

Der Dialog zum Hinzufügen weiterer Intents wird angezeigt:

Führe folgende Schritte aus:

  1. Klicke Use an existing intent from the built-in library an, um einen Built-in Intent hinzuzufügen.
  2. Filtere die Liste der Built-in Intents, indem Du repeat im Eingabefeld eingibst.
  3. Wähle den Intent AMAZON.RepeatIntent aus, indem Du den Haken setzt.
  4. Füge den Intent hinzu, indem Du auf den Button Add intent (1) klickst.

Der Dialog wird weiterhin angezeigt, nachdem der neue Intent hinzugefügt wurde:

Führe die folgenden Schritte aus:

  1. Klicke Create a new custom intent an, um einen Custom Intent hinzuzufügen.
  2. Gib im Eingabefeld GetInformation ein.
  3. Klicke auf den Button Create Intent.

Der Dialog zum Bearbeiten des neuen GetInformation Intents wird angezeigt:

Führe die folgenden Schritte aus:

  1. Gib im Eingabefeld subject ein, um einen neuen Slot Type für die Art der Information, nach der der Benutzer Alexa fragen kann, hinzuzufügen.
  2. Klicke auf den Button Add, um den Slot Type zu erstellen und zum Intent hinzuzufügen.

Weise dem Intent Slot einen Slot Type hinzu:

Führe die folgenden Schritte aus:

  1. Klicke auf den Button Choose a slot type...
  2. Klicke im Popup auf den Slot Type subject.

Füge jetzt Beispielsätze hinzu.

Gib dazu im Eingabefeld der Sample Utterances zunächst { (eine geöffnete, geschweifte Klammer) ein. Ein Popup öffnet sich, in dem Du den Slot Type auswählen kannst:

Klicke subject an und drücke anschließend die Eingabetaste.

Wiederhole das für die folgenden Sätze:

  • informationen über {subject}
  • anzahl von {subject} 

Danach sollten die Sample Utterances so aussehen:

Der Skill Builder bietet die Möglichkeit, den subject Intent Slot so zu konfigurieren, dass Alexa eine Rückfrage stellt, falls der Benutzer den Slot nicht nennt, wenn der GetInformation Intent aufgerufen wird. Diese Möglichkeit wird in diesem Beispiel nicht genutzt, da die Behandlung von nicht vorhandenen Intent Slots durch das Alexa Custom Skill Modul in dieser Anleitung demonstriert werden soll.

Speichere nun die Konfiguration des Interaction Models, indem Du auf Save Model klickst:

Kompiliere das Interaktionsmodell, indem Du auf Build Model klickst:

Der Vorgang kann einige Minuten in Anspruch nehmen.

Beende den Skill Builder, indem Du auf Configuration klickst:

Die dritte Seite des Assistenten, Configuration, wird angezeigt:

Führe die folgenden Schritte aus:

  1. Klicke HTTPS an.
  2. Markiere die Checkbox Europe.
  3. Trage im Eingabefeld Europe die IP Symcon-Connect URL des Alexa Skills ein, die Du in Schritt 3 des Abschnittes Alexa Custom Skill Instanz erstellen in eine Textdatei kopiert hast.

Klicke anschließend auf den Button Next.

Die vierte Seite des Assistenten, SSL Certificate, wird angezeigt:

Führe die folgenden Schritte aus:

  1. Klicke My development endpoint is a sub-domain of a domain that has a wildcard certificate from a certificate authority an.
  2. Klicke auf den Button Next.

Die fünfte Seite des Assistenten, Test, wird angezeigt:

Klicke auf den Button Disabled, um den Custom Skill in Deinem Account für das Testen freizuschalten.

Der Service Simulator auf der Seite ist nun freigeschaltet:

Trage im Feld Enter Utterance den Satz Frage System Informationen nach Objekten ein und drücke die Eingabetaste.

Die Abfrage wird eine Fehlermeldung im Feld Service Response erzeugen, da der Skill auf der IPS Seite noch nicht konfiguriert ist.

GetInformation Alexa Custom Skill Intent Instanz erstellen

Kehre zurück zur IP Symcon Management Console und lege eine neue Alexa Custom Skill Intent Instanz an, indem Du dieser Anleitung folgst.

Setze den Intent-Namen GetInformation, indem Du dieser Anleitung folgst.

Übernehme anschließend die Konfiguration.

Benenne die Instanz um, indem Du dieser Anleitung folgst.

Die Konfiguration der Instanz sollte nun so aussehen:

Bearbeite nun das Skript Action unterhalb der Instanz und ersetze den Inhalt des Skriptes durch den folgenden PHP Code:

<?
use Patami\IPS\System\IPS;

function Execute(Request $request)
{
	// Get the subject slot
	$subject = strtolower($request->slots->subject);
	
	// Get the requested information
	switch ($subject) {
		case 'objekte':
		case 'objekten':
			$text = sprintf('Es sind %d Objekte vorhanden.', IPS::GetObjectCount());
			break;
		case 'bibliothek':
		case 'bibliotheken':
			$text = sprintf('Es sind %d Bibliotheken vorhanden.', IPS::GetLibraryCount());
			break;
		case 'module':
		case 'modulen':
			$text = sprintf('Es sind %d Module vorhanden.', IPS::GetModuleCount());
			break;
		case 'instanzen':
			$text = sprintf('Es sind %d Instanzen vorhanden.', IPS::GetInstanceCount());
			break;
		case 'variablen':
			$text = sprintf('Es sind %d Variablen vorhanden.', IPS::GetVariableCount());
			break;
		case 'skripte':
		case 'skripten':
			$text = sprintf('Es sind %d Skripte vorhanden.', IPS::GetScriptCount());
			break;
		case 'funktionen':
			$text = sprintf('Es sind %d Funktionen vorhanden.', IPS::GetFunctionCount(0));
			break;
		case 'ereignisse':
		case 'ereignissen':
			$text = sprintf('Es sind %d Ereignisse vorhanden.', IPS::GetEventCount());
			break;
		case 'medien':
			$text = sprintf('Es sind %d Medien vorhanden.', IPS::GetMediaCount());
			break;
		case 'links':
			$text = sprintf('Es sind %d Links vorhanden.', IPS::GetLinkCount());
			break;
		case 'kategorien':
			$text = sprintf('Es sind %d Kategorien vorhanden.', IPS::GetCategoryCount());
			break;
		case '':
			// The subject slot was not set
			// Ask the user for the object type
			return AskResponse::CreatePlainText(
				'Ich kann Dir sagen wie viele Objekte unterschiedlicher Typen im System vorhanden sind. ' .
				'Zu welcher Art von Objekt willst Du Informationen haben?'
			)->SetRepromptPlainText(
				'Wie bitte?'
			); 
		default:
			// The subject slot was invalid
			// Ask the user for the correct object type
			return AskResponse::CreatePlainText(
				'Diese Objektart kenne ich nicht. Was meintest Du?'
			)->SetRepromptPlainText(
				'Wie bitte?'
			);
	}
	
	// Tell the user the requested number of objects
	return TellResponse::CreatePlainText(
		$text
	)->SetSimpleCard(
		'IP-Symcon Informationen',
		$text
	);	
}
Entwickler-Informationen zum PHP Code

Allgemein

Das Framework ruft die Execute() Funktion bei einem Launch oder Intent Request automatisch auf und übergibt ein Request Objekt, über das alle relevanten Informationen über die Anfrage verfügbar sind.

Vom Framework wird erwartet, dass die Funktion ein Objekt vom Typ TellResponse oder AskResponse (genauer gesagt: ein Objekt der Basisklasse Response) zurückgibt. Ist dies nicht der Fall, wird intern eine entsprechende Exception erzeugt und Alexa gibt eine Fehlermeldung aus.

Fehler in der Verarbeitung von Requests durch die Execute() Funktion können ebenfalls mit einer Exception signalisiert werden (was nützlich zur Flusssteuerung innerhalb des Skriptes ist). Exceptions, die von Patami\IPS\Exception abgeleitet sind, enthalten lokalisierte Fehlermeldungen, die vom Framework unverändert an Alexa durchgereicht werden.


Verwendete Klassen und Methoden

Der PHP Code des Action-Skriptes verwendet eine Reihe von Klassen aus dem Patami Framework und dem Patami Alexa Skill Framework:

FQCNBeschreibung
Patami\IPS\Services\Alexa\Skills\Custom\Request

Sobald eine Anfrage von Alexa an IPS gestellt wird, erzeugt das Framework aus den von Amazon übermittelten Informationen ein Objekt von diesem Typ und übergibt es der Execute() Funktion.

Im Beispiel-Code wird das Attribut $slots verwendet, um den Wert des subject Intent Slots auszulesen:

$subject = strtolower($request->slots->subject);

Das Attribut ist selbst ein Objekt (vom Typ Patami\IPS\Services\Alexa\Skills\Custom\IntentSlots), das alle von Amazon übergebenen Intent Slots als Attribute (im Beispiel $request->slots->subject) oder über ein ArrayAccess-Interface (z.B. $request->slots['subject']) zur Verfügung stellt.

Es wird empfohlen, die Intent Slot Werte in Kleinbuchstaben zu konvertieren, da die Werte von Alexa nicht konsistent gesetzt werden. Außerdem kommt es häufig vor, dass von den Amazon Servern auch Werte übergeben werden, die nicht in der Slot Type-Konfiguration angegeben wurden. Würde man beispielsweise Frage System Informationen nach Test sagen, würde auch Test übermittelt werden. Daher wird oben in der switch-Anweisung auch der default-Fall geprüft und eine entsprechende Fehlermeldung erzeugt. Auch sollte man auf Einzahl/Mehrzahl der Begriffe prüfen und Zahlen als Text schreiben.

Über $request->attributes stehen (wenn auch hier nicht genutzt) die in der Alexa Session gespeicherten Attribute zur Verfügung.

Beide Attribute, $slots und $attributes, können gelesen und gesetzt werden. Indem man Werte im $attributes Objekt speichert, können Informationen innerhalb einer Alexa Session zwischen verschiedenen Launch und Intent Requests weitergegeben werden.

Das Framework sorgt zudem automatisch dafür, dass Intent Slots, die in einem Request einer Session von Alexa übergeben worden sind, in allen folgenden Requests einer Session ebenfalls zur Verfügung stehen, sodass kumulativ Informationen gesammelt werden können. Hierzu werden in der Session ein Reihe von Daten gespeichert:

Auszug aus der Antwort des Custom Skills
{
  [...]
  "sessionAttributes": {
    "slots": {},
    "callbackIntent": "GetInformation",
    "attributes": []
  }
}

Die Klasse stellt eine Reihe weiterer Methoden zur Verfügung, mit denen man z.B. den Intent Namen, die Sprache (bzw. das Locale), den Request Typ (Launch oder Intent Request) ermitteln kann.

Patami\IPS\Services\Alexa\Skills\Custom\TellResponse

Der Beispiel-Code erzeugt ein Objekt von diesem Typ, um Alexa eine Antwort vorlesen zu lassen und die Session zu beenden (deshalb "Tell").

Das Objekt wird über die statische Factory-Method TellResponse::CreatePlainText() erzeugt, an die der Text der Antwort übergeben werden muss:

return TellResponse::CreatePlainText('Hallo.');

Mit TellResponse::CreateSSML() könnte man eine Antwort erzeugen, deren Text mit Speech Synthesis Markup Language (SSML) ausgezeichnet ist, wodurch es möglich ist, die Sprachausgabe zu optimieren und z.B. Betonungen zu setzen:

return TellResponse::CreateSSML('<say-as interpret-as="spell-out">hello</say-as>.');

Zu beachten ist, dass alle Factory- und Set-Methoden der Framework Klassen Method Chaining (Fluent Interfaces) unterstützen und somit mehrere Methodenaufrufe in einer Zeile verkettet werden können. Dies wird im konkreten Fall bei SetSimpleCard() verwendet, um dem Antwortobjekt eine Karte für die Alexa App hinzuzufügen:

return TellResponse::CreatePlainText('Hallo.')->SetSimpleCard('Titel', 'Text');

Es stehen weitere Methoden zur Verfügung, mit der die Antwort erweitert bzw. verändert werden kann. Details dazu finden sich in der Dokumentation der Klasse.

Patami\IPS\Services\Alexa\Skills\Custom\AskResponse

Der Beispiel-Code erzeugt ein Objekt von diesem Typ, wenn Alexa dem Benutzer eine Frage stellen und die Session aufrecht erhalten soll (deshalb "Ask"). Bei den Echo-Geräten bleibt der Leuchtring nach dem Vorlesen der Frage an, um dem Benutzer zu signalisieren, dass Alexa eine weitere Spracheingabe erwartet.

Im konkreten Fall wird dies genutzt, wenn kein subject Intent Slot übergeben wurde (z.B. weil der Launch Request aufgerufen wurde) oder wenn Alexa einen unbekannten Wert für den Intent Slot übermittelt hat. Alexa fragt den Benutzer nach einem Objekttyp und erwartet, dass dieser antwortet (z.B. Objekte, Variablen, ...). Antwortet der Benutzer nun mit einem Objekttyp, so matched dies auf den in der Amazon Developer Console konfigurierten Sample Utterance {subject} und ruft den GetInformation Intent erneut auf, der nun alle notwendigen Informationen hat, um die gewünschte Antwort zu erzeugen.

Der Beispiel-Code ergänzt die Frage über Method Chaining mit SetRepromptPlainText() um eine weitere Sprachausgabe, die von Alexa vorgelesen wird, wenn der Benutzer nicht auf die Frage antwortet:

return AskResponse::CreatePlainText('Wie geht es Dir?')->SetRepromptPlainText('Wie bitte?');

Nach dem Vorlesen der Frage wartet Alexa 7 Sekunden und gibt dann den Reprompt Text aus, um den Benutzer daran zu erinnern, dass von ihm eine Eingabe erwartet wird. Nach weiteren 7 Sekunden wird die Session beendet.

Die AskResponse Klasse ist im Übrigen eine spezialisierte (Kind-)Klasse der TellResponse Klasse. Alle Methoden stehen auch hier zur Verfügung. Der einzige Unterschied ist, dass bei der AskResponse Klasse automatisch das "Flag" zum Aufrechterhalten der Session gesetzt wird. Dies könnte man auch erreichen, indem man die Methode ContinueSession() eines TellResponse Objektes aufruft.

Patami\IPS\System\IPS

Die IPS Klasse stellt alle IP Symcon Kernfunktionen (IPS_*, GetValue*, SetValue*) als statische Methoden zur Verfügung.

Darüber hinaus bietet die Klasse eine Reihe weiterer Komfortfunktionen, wie z.B. GetVariableCount(), um die Anzahl der von GetVariableList() zurückgegebenen IPS Variablenobjekte zu zählen. Die Get*Count() Methoden werden im Beispiel-Code genutzt, um die Anzahl der verschiedenen Objekttypen zu ermitteln.

Details zu den verfügbaren Methoden finden sich in der API Dokumentation der Klasse.

Namespaces

In Bezug auf die Nutzung von Namespaces ist bei der Execute() Funktion zu beachten, dass diese im globalen Namensraum evaluiert wird.

Dies hat zur Folge, dass man auf alle Framework-Klassen mit ihren vollqualifizierten Namen (FQCN) zugreifen muss.

Über den Befehl use kann man FQCNs mit einem Alias importieren. Im Beispiel oben wird dies für die Klasse Patami\IPS\System\IPS genutzt, da diese im Beispiel-Code häufig verwendet wird. Durch den Import steht die Klasse mit dem kurzen Namen IPS zur Verfügung.

Im Beispiel-Code oben wird auffallen, dass die anderen drei verwendeten Klassen nicht vollqualifiziert verwendet werden. Dass dies möglich ist, liegt daran, dass das Framework den Code der Funktion vor dem Aufruf automatisch um use-Statements für die folgenden Klassen ergänzt:

AMAZON.HelpIntent Alexa Custom Skill Intent Instanz erstellen

Lege eine weitere neue Alexa Custom Skill Intent Instanz an, indem Du dieser Anleitung folgst.

Setze den Intent-Namen AMAZON.HelpIntent, indem Du dieser Anleitung folgst.

Ändere die Aktion des Intents auf Sprachausgabe, indem Du dieser Anleitung folgst.

Setze hierbei den deutschen Text wie folgt: Ich kann Dir sagen wie viele Objekte unterschiedlicher Typen im System vorhanden sind. Mögliche Objekttypen sind Objekte, Bibliotheken, Module, Instanzen, Variablen, Skripte, Funktionen, Ereignisse, Medien, Links und Kategorien.

Du musst die englischen Texte nicht ändern, da sie nicht verwendet werden (wir haben den Custom Skill in der Amazon Developer Console nur auf Deutsch angelegt).

Setze den Haken bei Session fortsetzen, damit Alexa nach der Sprachausgabe der Hilfe auf eine weitere Eingabe des Benutzer wartet.

Übernehme anschließend die Konfiguration.

Benenne die Instanz um, indem Du dieser Anleitung folgst.

Die Konfiguration der Instanz sollte anschließend so aussehen:

Alexa Custom Skill Instanz konfigurieren

Öffne die Konfigurationsseite der Alexa Custom Skill Instanz, indem Du dieser Anleitung folgst.

Konfiguriere die Application ID und die User ID, indem Du dieser Anleitung folgst.

Sowohl die Application ID als auch die User ID sind spezifisch für den Custom Skill, den Du über die Amazon Developer Console angelegt hast.

Insbesondere ist die User ID nicht für alle Deine Custom Skills dieselbe.

Lege die GetInformation Alexa Custom Skill Intent Instanz als Launch Request Intent fest, indem Du dieser Anleitung folgst.

Übernehme anschließend die Konfiguration.

Die Konfiguration der Instanz sollte nun so aussehen:

Fehlerbehandlung

Details zur Behandlung von Fehlern und zum Debugging findest Du hier.

Beispiele

Im Folgendes findest Du eine Reihe von Beispielen für Interaktionen mit dem Custom Skill:

Beispiel 1

BenutzerStarte System Informationen
AlexaIch kann Dir sagen wie viele Objekte unterschiedlicher Typen im System vorhanden sind. Zu welcher Art von Objekt willst Du Informationen haben?
BenutzerVariablen
Alexa

Es sind 2745 Variablen vorhanden.

Die Alexa App zeigt bei der Antwort die folgende Karte an:

Beispiel 2

BenutzerFrage System Informationen nach Funktionen
Alexa

Es sind 1129 Funktionen vorhanden.

Die Alexa App zeigt bei der Antwort die folgende Karte an:

Beispiel 3

BenutzerStarte System Informationen
AlexaIch kann Dir sagen wie viele Objekte unterschiedlicher Typen im System vorhanden sind. Zu welcher Art von Objekt willst Du Informationen haben?
BenutzerTest
AlexaDiese Objektart kenne ich nicht. Was meintest Du?
Benutzer(Der Benutzer sagt nichts und es tritt nach 7 Sekunden ein Timeout auf)
AlexaWie bitte?
BenutzerHilfe
AlexaIch kann Dir sagen wie viele Objekte unterschiedlicher Typen im System vorhanden sind. Mögliche Objekttypen sind Objekte, Bibliotheken, Module, Instanzen, Variablen, Skripte, Funktionen, Ereignisse, Medien, Links und Kategorien.
BenutzerStopp
AlexaOK