Category Archives: QIVICON

Amazon Alexa im lokalen Smart Home programmieren

Amazon Echo und die eingebaute Sprachassistentin Alexa erlauben eine mehr oder weniger natürliche sprachgesteuerte Interaktion mit vernetzten Geräten wie Leuchten, Thermostaten, Schaltern usw. Doch die Entwicklung neuer Fähigkeiten namens Skills ist etwas mühsam, da es in der Natur von Alexa liegt, dass diese nur über die Cloud funktionieren. Außerdem scheint Amazon die Nutzung der hauseigenen Cloud-Dienste und das entsprechende Tooling zu bevorzugen. Doch dem damit verbundenen zeitraubenden Workflow kann man zumindest während der Entwicklung leicht entkommen. Im Folgenden verbinden wir dafür Alexa über einen sogenannten Tunnel mit dem eigenen Entwicklungsrechner. Das bedeutet, dass der selbsterstellte Skill als Services nun lokal bearbeitet, deployed und getestet wird.

Skill konfigurieren

In der Amazon Developer Console legt man über das Alexa Skills Kit einen Skill an und konfiguriert diesen.

Es gibt verschiedene Arten von Skills. In diesem Beispiel kommt die beliebteste und am wenigsten reglementierte Variante des „Custom Skills“ zum Einsatz. Die Sprache und der Aufruf-Namen (Invocation Name) bestimmen nun den „Rufnamen“, mit dem ein Anwender den Skill anspricht.

Der nächste Schritt legt die Art der Interaktion fest, indem ein Schema mit den möglichen Absichten (Intents) des Anwenders angelegt wird. Die Intents können auch über Variablen verfügen, die Slots genannt werden. Außerdem sind für jede Absicht noch passende Beispiel-Äußerungen (Sample Utterances) erforderlich, mit denen die Absichten aufgerufen werden können.

Innerhalb der Konfiguration kommt nun der entscheidende Schritt für den lokalen Test: Die Auswahl von HTTPS als Endpunkt-Typ und die Angabe einer entsprechenden remote URL für den Tunnel zum lokalen Rechner. Diese Tunnel und die zugehörige URL generieren wir mit Hilfe von ngrok. Dieses Werkzeug besteht aus einem Cloud-Service für den Remote-Zugriff. Außerdem gehört ein für zahlreiche gängige Betriebssysteme verfügbares Kommandozeilentool dazu, um den lokalen Endpunkt für den Tunnel bereitzustellen. Das Kommando

1
ngrok http 3000

leitet beispielsweise Anfragen an eine URL wie https://b22ec890.ngrok.io/ an einen lokalen HTTP-Server mit Port 3000 weiter.

Noch verbirgt sich hinter dem Endpunkt ja noch nichts, aber sobald das im nächsten Schritt erledigt ist, kann der Skill durch die Angabe von beliebigen Äußerungen in Textform innerhalb der Amazon Developer Console getestet werden. Noch realitätsnäher wird der Test natürlich, wenn auch ein Amazon Echo oder Amazon Echo Dot mit dem Entwickler-Konto verbunden ist.

Skill programmieren

Es gibt zahlreiche Möglichkeiten einen Skill zu programmieren. Zu den populärsten zählt sicherlich die Nutzung von Node.js. Amazon stellt extra dafür sogar ein NPM-Paket namens Alexa Skills Kit SDK for Node.js (kurz alexa-sdk) zu Verfügung. Es gibt jedoch leider einen Haken: Dieses Modul arbeitet so erst einmal nur im Rahmen von Amazon Lambda und nicht mit einem lokal laufenden Node.js-Server. Eine Lösung wäre der Verzicht auf das offizielle Alexa SDK und die direkte Verwendung der eingehenden REST-Aufrufe wie hier beschrieben – charmanter Nebeneffekt ist, dass REST auch mit vielen anderen Programmiersprachen und Server-Umgebungen harmoniert. Der Node.js-Code sieht dann so aus:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
app.use(bodyParser.json());
app.post('/', function(req, res) {
  // Deal with incoming request...
  if (req.body.request.type === 'IntentRequest') {
    // ...and build JSON response
    res.json({
      "version": "1.0",
      "response": {
        "shouldEndSession": true,
        "outputSpeech": {
          "type": "SSML",
          "ssml": "<speak>Hmmm</speak>"
        }
      }
    });
  }
}
// Start server and listen for incoming requests
app.listen(3000, function () {
  console.log('Example app listening on port 3000!');
});

Doch mit einem kleinen Trick wird auf das „Nachbauen“ der REST-Schnittstelle verzichtet und doch direkt mit dem offiziellen Alexa SDK gearbeitet. Alles was dafür zusätzlich zu den normalen Beispielen für das SDK getan werden muss ist a) wie oben im Code bereits beschrieben der explizite Start eines Servers und b) das manuelle Erstellen des Context-Objektes. Nun können die Intents genauso verarbeitet werden wie in den offiziellen Beispielen:

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
33
34
35
36
37
38
39
40
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
// Initialize the Alexa SDK
var Alexa = require('alexa-sdk');
app.use(bodyParser.json());
app.post('/', function(req, res) {
    // Build the context manually, because Amazon Lambda is missing
    var context = {
        succeed: function (result) {
            console.log(result);
            res.json(result);
        },
        fail:function (error) {
            console.log(error);
        }
    };
    // Delegate the request to the Alexa SDK and the declared intent-handlers
    var alexa = Alexa.handler(req.body, context);
    alexa.registerHandlers(handlers);
    alexa.execute();
});
// Declare handlers for processing the incoming intents
var handlers = {
    'SwitchOnIntent': function () {
        var item = this.event.request.intent.
         slots.item.value;
        doRequest("ON");
        this.emit(':tell', 'Schalte ' + item);
    },
    'SwitchOffIntent': function () {
        var item = this.event.request.intent.
         slots.item.value;
        doRequest("OFF");
        this.emit(':tell', 'Schalte ' + item);
    }
};
app.listen(3000, function () {
  console.log('Example app listening on port 3000!');
});

Die im Code referenzierte Funktion doRequest macht übrigens nichts Anderes als REST-Aufrufe an andere Geräte zu senden, um beispielsweise eine Philips HUE Leuchte ein oder auszuschalten. Dafür nutzt das Beispiel Eclipse SmartHome bzw. openHAB. Diese Heimautomatisierungs-Gateways verfügen über eine REST-Schnittstelle deren Dokumentation normalerweise über http://127.0.0.1:8080/doc/index.html erreichbar ist. Dort können passende REST-Aufrufe leicht ausprobiert werden:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// body holds one of the supported values for the used channel (i.e. ON or OFF)
var doRequest = function (body) {
    var request = new http.ClientRequest({
        hostname: "127.0.0.1",
        port: 8080,
        // Path to the channel for the device we like to control (see REST documentation)
        path: "/rest/items/minecraft_minecraft_switch_192_168_0_17__9998_88ad955d_ce14_4c78_bb2c_942a64a9da7c_channelPowered",
        method: "POST",
        headers: {
            "Content-Type": "text/plain",
            "Content-Length": Buffer.byteLength(body)
        }
    })
    request.end(body)
}

Um die Entwicklung eines Amazon Alexa Skills zu erleichtern, kann also ein lokaler Server leicht über einen Tunnel genutzt werden. Auch für Tests und private Einsatzzwecke hat sich das bewährt. Eine Veröffentlichung eines Skills ist so jedoch nicht möglich, da beispielweise die Verifikation von Aufrufen fehlt. Dies ließe sich dadurch lösen, dass der fertige Skill doch bei Amazon Lambda landet. Alternativ könnte diese Verifikation auch mit Hilfe eines weiteren NPM-Paketes wie hier beschrieben umgesetzt werden.

Coding the Internet of Things for creative beginners and kids

Last week I had a trip to the Droidcon Moscow where I talked about the Internet of Things, in particular smart home for creative developers and rookies. It was really exciting to see how interested and open minded the developers in the awesome Russian capital are.

Moscow State UniversityWell, the weather was not the best in front of the Moscow State University. Anyway, my personal favorite in Moscow is the weather-proofed subway: It’s soviet era charm is stunning.

I did the only English sessions and both have been packed (sorry for the parallel track ;)). Usually I get questions on privacy, security and stuff like that. But at Droidcon Moscow it was surprisingly different. The Russian developers seem to be really eager to start with the Internet of Things themselves and did ask a lot on how to do that. Especially the part on how to get technology-laggards and kids into that topic was very well received.

To make one really wanting to become a developer, it’s important rather to motivate than to teach: Teaching feels like school! But it’s more about continuous offering, playing and explaining. Especially because being a developer of new and innovative ideas does not mean you have to be a fulltime programmer. Nowadays almost everybody who is keen to get into the Internet of Things can do so thanks to various available easy toolkits.

Anyway, a basic understanding of programming does not hurt. If anything. A good starting point could be the following selection of trainings and tools. I made quite a good experience using these in the given order with my son and his classmates:

  • Hour of Code: You can choose among several themes from Minecraft to Frozen in this online programming environment where you have to fulfill easy tasks to solve the challenges.
  • Scratch: Scratch is a project of the Lifelong Kindergarten Group at the MIT Media Lab. It is both a visual programming environment and a story telling tool. So, start your interactive fairy tales and games right now. There’s also an extendable version named ScratchX, which we use for IoT prototypes connected to the real world (see here). By the way, Scratch is the prefiguration of a lot of visual programming environments like the following.
  • App Inventor: App Inventor was originally provided by Google, and is now maintained by the Massachusetts Institute of Technology (MIT). It is based on the same visual programming approach like Scratch, but suited for mobile apps one can use on a real device.
  • Minecraft and ComputerCraft: There are a few Minecraft based ways, to learn programming. Our personal favorite so far is ComputerCraft. It introduces virtual Computers and peripherals like printers in Minecraft. All programmable with Lua, one of the easier programming languages. Furthermore, you can extend it with your own API (application programming interface) to add some additional capabilities (i.e. to connect your smart home as shown here). Lua is not just a more and more popular programming language, it is also common for IoT solutions (i.e. based on the ESP8266 chip with NodeMCU firmware).

Well, as mentioned above that worked like a charm with my son. Even my daughter did great, but unfortunately she just does not like it that much until now: But I will not give up offering, playing and explaining and once I find a way, I will let you know…

Minecraft Mod-Entwickung

Nachdem es in dem letzten Blogpost gelungen ist, das eigene Smart Home mit Minecraft durch die Erweiterung ComputerCraft zu verbinden, geht es nun an eine erste eigene sogenannte Mod. Für die Minecraft-Laien: Eine Mod steht für das englische Modification und beschreibt Erweiterungen (Plug-ins) zur Anpassung von Spielen. So lässt sich Minecraft beinahe beliebig um eigene Ideen ergänzen.

iotworkshop
Connected Worlds and IoT: Digital Crafting Habitat Workshop vom 23. April 2016 gemeinsam mit der rheinjug Düsseldorf.

Diesen Weg geht auch das Digital Crafting Habitat. Hier wird die reale mit der virtuellen Welt verbunden. Zum Einsatz kommen Raspberry Pis, Sensoren, die Datenbank Redis und natürlich Minecraft. Dafür wird eine Minecraft Mod im Rahmen von Workshops weiterentwickelt. Den Java-Code auf Basis von Minecraft Forge 1.7. stellt das Digital Crafting Habitat in ihrem GIT-Repository inklusive zahlreicher Beispiele zur Verfügung.

Einrichten

Wer ganz von vorne anfangen möchte, der benötigt Java-Kenntnisse, ein wenig Gradle und eine Entwicklungsumgebung wie Eclipse IDE oder IntelliJ IDEA. Die wesentliche Zutat ist jedoch Minecraft Forge in Form eines Mod Development Kit, kurz MDK. Dieses kann in der gewünschten Version unter http://files.minecraftforge.net/ heruntergeladen werden. Die Version ist durchaus wichtig, da sich die Programmierschnittstelle (API) häufig verändert. In diesem Beispiel kommt Version 1.8.9 zum Einsatz. Eine eigenständige Version von Minecraft ist übrigens nicht unbedingt erforderlich, da diese schon im MDK enthalten ist.

Für das Setup sollte man sich unbedingt ein wenig Zeit nehmen und über eine ordentliche Internetverbindung verfügen. Als erstes wird nun das MDK heruntergeladen und entpackt – es handelt sich hierbei um ein normales Archiv. Innerhalb des entpackten Ordners fehlt noch eine optionale gradle.properties-Datei mit dem folgenden Inhalt, um die nächsten Schritte zu optimieren:

1
2
org.gradle.daemon=true
org.gradle.jvmargs=-Xmx1024M

Anschließend wird über die Kommandozeile via gradle setupDecompWorkspace ein Arbeitsbereich inklusive einer Minecraft Programmierschnittstelle erzeugt und abschließend durch gradle eclipse bzw. gradle idea für die gewünschte Entwicklungsumgebung eingerichtet. Jetzt kann man schon den Workspace in Eclipse oder das Projekt in IntelliJ öffnen und Minecraft inklusive der Mod über die Kommandozeile gradle runClient bzw. direkt aus der Entwicklungumgebungen heraus starten. In Eclipse findet sich das innerhalb der RunConfiguration unter Java Application, in IntelliJ innerhalb des Gradle-Views unter Tasks/forgegradle.

Programmieren

Der Programmierung steht nun nichts mehr im Wege, abgesehen von einer etwas verteilten und unvollständigen Dokumentation. Gute Quellen sind der YouTube-Kanal „Minecraft Forge Modding 1.8”. Gamepedia und natürlich die Website von Minecraft Forge (http://www.minecraftforge.net/) sowie dessen GIT-Repository.

Meist benötigt man eine Java-Klasse, um den Mod zu initialisieren und die eigenen Erweiterungen dort zu registrieren. Die Initialisierung erfolgt über die Annotation @Mod unter Angabe eines eindeutigen Bezeichners.

1
2
3
4
5
@Mod(modid = SmartHomeMod.MODID, version = SmartHomeMod.VERSION)
public class SmartHomeMod {
 
	public static final String MODID = "smarthomemod";
	public static final String VERSION = "0.1";

Dazu passend muss noch die mcmod.info-Datei im Ressourcen-Verzeichnis src/main/resources angepasst werden – insbesondere die Bezeichnungen (modid) müssen identisch sein:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[
 {
  "modid": "smarthomemod",
  "name": "SmartHome",
  "description": "My Minecraft Smart Home",
  "version": "${version}",
  "mcversion": "${mcversion}",
  "url": "http://wolter.biz",
  "updateUrl": "",
  "authorList": ["Sascha Wolter"],
  "credits": "",
  "logoFile": "",
  "screenshots": [],
  "dependencies": []
 }
]

Innerhalb der Klasse können nun verschiedene Ereignisse verarbeitet werden. Gängig sind

  • FMLPreInitializationEvent für alles vor dem Start,
  • FMLInitializationEvent für alles währen des Starts,
  • FMLPostInitializationEvent für alles nach dem Start und zum Schluss
  • FMLServerStartingEvent während des Starts des Servers (auch lokal ohne expliziten Server).

Der richtige Ort für den eigenen Code hängt davon ab, was genau man in Minecraft verändern möchte. Beispielsweise kann man eigene Kommandos erst während des Starts des Servers registrieren. Die komplette Klasse sieht dann so aus:

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package biz.wolter.minecraft;
 
import biz.wolter.minecraft.commands.HelloCommand;
import net.minecraft.command.CommandBase;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.event.FMLServerStartingEvent;
 
/**
 * @author Sascha Wolter
 */
@Mod(modid = SmartHomeMod.MODID, version = SmartHomeMod.VERSION)
public class SmartHomeMod {
 
	public static final String MODID = "smarthomemod";
	public static final String VERSION = "0.1";
 
	/* Commands */
	public static CommandBase HELLO_COMMAND = new HelloCommand();
 
	// FMLPreInitializationEvent happens as #1 right before Minecraft loads. Used for most registration.
	@EventHandler
	public void preInit(FMLPreInitializationEvent event) {
	}
 
	// FMLInitializationEvent happens as #2 when Minecraft loads.
	@EventHandler
	public void init(FMLInitializationEvent event) {
	}
 
	// FMLPostInitializationEvent happens #3 when World generators and alike are loaded.
	@EventHandler
	public void postInit(FMLPostInitializationEvent event) {
		System.out.println("postInit");
 
	}
 
	// FMLServerStartingEvent happens #4 right before starting the server.
	@EventHandler
	public void registerCommands(FMLServerStartingEvent event) {
		event.registerServerCommand(HELLO_COMMAND);
	}	
 
}

Das zugehörige Kommando wird von der CommandBase-Klasse abgeleitet und überschreibt die folgenden Methode:

  • getCommandName, um den eigenen Namen anzugeben,
  • getCommandUsage erklärt die Nutzung und
  • processCommand führt letztendlich das Kommando aus.

Der vollständige Code könnte dann so aussehen:

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
33
34
35
36
37
38
39
40
package biz.wolter.minecraft.commands;
 
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.EnumChatFormatting;
 
/**
 * @author Sascha Wolter
 */
public class HelloCommand extends CommandBase {
 
	public static final String COMMAND_NAME = "hello";
 
	@Override
	public String getCommandName() {
		return COMMAND_NAME;
	}
 
	@Override
	public String getCommandUsage(ICommandSender sender) {
		// TODO
		return String.format("/%s <name>", COMMAND_NAME);
	}
 
	@Override
	public void processCommand(ICommandSender sender, String[] args) throws CommandException {
 
		if (sender instanceof EntityPlayer) {
			sender.addChatMessage(new ChatComponentText(EnumChatFormatting.GREEN + "Hello " + args[0]));
		} else {
			sender.addChatMessage(new ChatComponentText(
					EnumChatFormatting.RED + "This command is not available inside the console."));
		}
 
	}
 
}

Das Kommando wird in Minecraft nun über den Chat (Taste T) und mit einem führenden Schrägstrich eingegeben. Innerhalb der processCommand-Methode könnten nun natürlich auch komplexerer Anweisungen platziert werden, die beispielsweise ein Smart Home steuern. Oder man erfindet gleich eigene Gegenstände und Blöcke, die mit der Außenwelt kommunizieren…