Diese Seite beschreibt die allgemeine socket.io API, für die Geräte-spezifische siehe: smart-home-control APIs.

Der smart-home-control Socket.IO Server ist eine Art zentrales Hub für die Verknüpfungen und Kommunikation im Smart Home. Die Geräte kommunizieren nicht untereinander, sondern immer nur über den smart-home-control Server.

Im wesentlichen bietet der Server zwei Funktionen:

  1. Der Server bietet "Kanäle", wobei es je Gerät ein Kanal gibt. In diesen Kanäle können Geräte Daten hinterlegen. Immer wenn die Daten aktualisiert werden, werden alle anderen Clients in Echtzeit benachrichtigt.
  2. Über die Kanäle gibt es auch ein System, um Events (vergleichbar mit Funktionsaufrufen) an Geräte zu schicken. Events erkennt man am ":" im Namen.

Darüber hinaus gibt es noch ein paar spezielle Funktionen, die vom Server bereitgestellt werden:

  • Für die Simulation von Rollenspielen gibt es ein Rollen-Management. Damit können die Endgeräte von Personen im Rollenspiel Zugriff auf bestimmte Daten bekommen oder entzogen werden.
  • Für Webclients und Kamerabilder gibt es ein Server für statische Dateien. Bei den Kamerabildern geht es vor allem auch um das Cachen/Zwischenspeichern der Bilder, damit diese nicht von den Kameras direkt abgerufen werden müssen. Das ist notwendig für Clients, die von außerhalb auf das Smart Home LAN zugreifen. Darum kümmert sich ein Proxy Server.
  • Der Server hat auch ein paar zusätzliche Funktionen für Gerätesteuerungen, um diesen ihre Konfiguration zu schicken und deren Status zu erfassen bzw. Geräte zu (de)aktivieren.
  • Für das gesamt Smart Home gibt es auch noch Funktionen zum Zurücksetzen, Neustarten und Herunterfahren.

Zu Kanälen und Events stehen mehr Details und Beispiele in den Grundlagen der API. Zu den anderen Funktionen sind im Folgenden ein paar Beschreibungen.

Rollen-Management

Als spezielle Funktion, damit man Rollen einfach konfigurieren kann, gibt es die Möglichkeit, Rollen statt Kanäle zu abbonieren. Rollen haben standardmäßig Zugriff auf bestimmte Kanäle, aber es ist möglich (z.B. von der Steuerungs-App aus), zu ändern, welche Kanäle eine Rolle abboniert hat. Also im Prinzip auf welche Informationen die Rolle Zugriff hat, nur dass das Feature keine Sicherheitsmechanismen hat, sondern nur dem Rollenspiel dient.

Wird Zugriff auf einen Kanal aktiviert, bekommt der Client den aktuellen Zustand. Wird der Zugriff deaktiviert, wird als Zustand null gesendet. Außerdem werden keine Events mehr ausgelöst, wenn der Eventname mit dem zugehörigen Kanalname beginnt.

Außerdem kann die Rollen-Konfiguration über den speziellen Kanal rollen abgefragt werden:

{
	"nachbar": {
		"name": "Max",
                "rolle": "Nachbar",
                "zugriffe": {
		    "sturzalarm": true,
		    "kuehlschrank": false,
                }
	},
	// ...
}

Statische Dateien & Cache

Läuft der Server unter Port 3030, werden auf drei Pfaden statische Dateien bereitgestellt:

Der Pfad /extern dient dem Proxy Server für Clients, die nicht im Smart Home LAN sind. Dateien in /cache können dynamisch hinzugefügt werden. Dazu gibt es die Funktion/das Event cache:update (siehe unten).

Gerätesteuerungen & -status

Um die Konfiguration im Smart Home einfacher updaten zu können, liegt die gesamte Konfiguration beim smart-home-control Server. Meldet sich ein Gerät in dem in Grundlagen der API beschrieben Prozess an, erhält es seine Konfiguration. Außerdem updatet der Server im Kanal status automatisch, wenn sich das Gerät verbunden hat, oder die Verbindung beendet.

Über den Kanal status können Gerätesteuerungen auch (de)aktiviert werden. Dazu werden die entsprechenden Events an den zugehörigen Client der Gerätesteuerung weitergeleitet.

Zurücksetzen, Neustarten, Herunterfahren

Diese Funktionen dienen speziell dem möglichst einfachen Umgang mit dem Smart Home für Anwender:innen. Damit können die Funktionen einfach als ein Button im Steuerungstablet eingebaut werden. Die Umsetzung von Neustart und Herunterfahren basiert auf Skripten, die von Ansible generiert werden.

Client API

get: Zustand abfragen

z.B. socket.emit("get", "fenster")

Fordert den Server auf, einmal den aktuellen Zustand im Kanal fenster zu senden. Existiert der Kanal (noch) nicht, wird nichts gesendet.

Bisher wird die Funktion noch nicht verwendet, evtl. ist es daher sinnvoll sie zu entfernen.

sub: Kanal abbonieren

z.B. socket.emit("sub", "mikrofon")

Fordert den Server auf, einmal den aktuellen Zustand im Kanal mikrofon zu senden, und bei jeder Änderung erneut. Existiert der Kanal (noch) nicht, wird nichts gesendet.

Das Abbonieren eines Kanals ist außerdem notwendig, um dort Events zu erhalten. (Das ist deswegen, damit das für Rollen einfacher gehandhabt werden kann).

put: Zustand ändern

z.B. socket.emit("put", "fenster", {"offen": true})

Setzt den Zustand des Kanals auf das mitgegebene Objekt. Alle Clients, die den Kanal abboniert haben (außer dem Client, der put aufruft), werden benachrichtigt. Dabei werden die Objekte gemerged, das heißt falls ein Key im aktuellen Zustand enthalten ist, im gegebenen Objekt aber nicht, bleibt dieser Key und der Wert dazu unverändert.

Geschützte Kanäle, wie z.B. status, können nicht überschrieben werden.

Event abfangen

z.B. socket.on("steckdose:anschalten", callback)

Ruft callback mit den Argumenten des Events auf, falls ein Client steckdose:anschalten auslöst. Dazu muss der Kanal steckdose abboniert sein (immer das was vor dem ersten : steht). Mit once() statt on() wird das Event nur einmal empfangen, danach nicht mehr.

Aktuell können Clients ein Event auch selbst empfangen, wenn sie es auslösen. Mal schauen, ob das sinnvoll ist.

Event auslösen

z.B. socket.emit("steckdose:anschalten", <optionale Argumente>)

Löst das Event steckdose:anschalten bei allen Clients aus, die einen Handler für das Event haben. Der Eventname muss aus zwei mit : getrennten Teilen bestehen (um Events von serverseitigen Daten-Updates zu unterscheiden).

Rolle abbonieren

z.B. socket.emit("rollen:sub", "nachbar")

Abboniert als Client die Rolle nachbar. Details zur Rolle erhält der Client dann über das Event rollen:rolle:

{
    "name": "Max",
    "rolle": "Nachbar"
}

Rolle: Kanäle modifizieren

z.B. socket.emit("rollen:set", "nachbar", "sturzalarm", false)

Stellt den Zugriff auf sturzalarm für die Rolle nachbar auf false.

Cache

z.B. socket.emit("cache:update", "kamera.jpg", "http://192.168.178.45:3000/photo", callback)

Lädt die Datei unter dem zweiten Argument herunter, und stellt sie in /cache/<fname> zur Verfügung, wobei fname vom ersten Argument gegeben wird.

Wenn optional ein callback gegeben ist, wird am Ende das callback aufgerufen mit dem Cache-Pfad als relativen (/cache/datei.jpg?1234) URL. In allen Fällen wird auch cache:updated mit dem gleichen URL als Argument aufgerufen, damit eventuelle Bridges die Datei auch cachen könnten.

status:anmelden: Gerätesteuerung anmelden

z.B. socket.emit("status:anmelden", "fenster", callback)

Meldet die Gerätesteuerung anhand des ersten Arguments an. Zu jedem Gerätenamen kann nur eine Gerätesteuerung verbunden sein, um Fehler zu vermeiden. Es können aber mehrere Gerätesteuerungen den gleichen Kanal verwenden. Das ist der Fall beim Kühlschrank, wo die Gerätesteuerung dann zum Beispiel kuehlschrank.sensor als Namen im ersten Argument angibt, und dann aber im Kanal kuehlschrank schreibt, aber nur im Feld sensor, und die Kameras in kameras.

Das zweite Argument ist ein Callback, der mit dem Ergebnis der Anmeldung aufgerufen wird. Falls die Anmeldung geklappt hat, wird zurückgegeben:

{
    erfolgreich: true,
    aktiviert: true,  // Ob das Gerät zu Beginn aktiviert sein soll (default: true)
    config: {...}  // Die Konfiguration für das Gerät
}

Ansonsten wird im Falle eines Fehlers zurückgeschickt:

{
    erfolgreich: false
}

Der Prozess der Anmeldung ist auch in Grundlagen der API dargestellt.

status:aktivieren: Gerät aktivieren

z.B. socket.emit("status:aktivieren", "mikrofon")

Aktiviert die Gerätesteuerung, die zu dem gegeben Namen (in der Regel Name des Kanals) gehört. Dazu wird das Event an den passenden Client weitergeleitet (Der Client der Gerätesteuerung erhält das Event status:aktivieren ohne Argument).

Nur wenn die Gerätesteuerung aktiv ist, verarbeitet sie Events und updatet Daten. Gerätesteuerungen können außerdem eigene Handler für das (De)Aktivieren haben. So kann zum Beispiel das Mikrofon die Spracherkennung starten oder beenden.

status:deaktivieren: Gerät deaktivieren

Genauso wie status:aktivieren.

status:update: Gerätestatus updaten

z.B. socket.emit("status:update", "sensfloor", true)

Über diese API Funktion kann eine Gerätesteuerung selbst den eigenen Status updaten. Aktuell betrifft das nur das Feld pending, dessern Wert über das zweite Argument gegeben wird. Mit pending kann angegeben werden, dass eine Statusänderung aussteht, aber noch nicht abgeschlossen ist. Zum Beispiel braucht der SensFloor etwas zum Starten, wenn er deaktiviert war und aktiviert wird. Wird das Feld dann wieder auf false gesetzt, ist die Statusänderung abgeschlossen.

extern:anmelden: Externen Proxy anmelden

z.B. socket.emit("extern:anmelden", "<token>", callback)

Passt das Token, sendet der Server über das callback die Konfiguration des externen Proxy. Ein Token gibt es deswegen, weil in der Konfiguration API Keys stehen. Die API ist in Anlehung an status:anmelden benannt, es wird vom Server aktuell aber nicht getrackt, ob der externe Proxy verbunden ist.

reset: Smart Home zurücksetzen (Server neustarten)

Startet den smart-home-control Server neu, woraufhin eine neue Session ID generiert wird. Daraufhin starten auch alle Clients neu (dargestellt in Grundlagen der API). Beim Neustart werden alle Daten gelöscht.

neustart: Smart Home neustarten

Startet über ein Skript, das von Ansible generiert wird, alle Raspis im Smart Home neu.

herunterfahren: Smart Home herunterfahren

Fährt über ein Skript, das von Ansible generiert wird, alle Raspis im Smart Home herunter.

Plugins

Mit Plugins können dem Server zusätzliche, Kanal-spezifische (und damit meistens Gerät-spezifische) Funktionen hinzugefügt werden.

Das kann insbesondere sein, dass man Geräte ein- und ausschalten kann, was naturgemäß ein ausgeschaltetes Gerät nicht selbst machen kann. Aber zum Beispiel die WebPush Benachrichtigungen sind auch über ein Plugin (mit zugehörigem Kanal push-api) implementiert.

Plugins liegen in smart-home-control/plugins.js, wo auch ein Template für ein neues Plugin enthalten ist.

Verhalten im Falle eine Reconnects

Falls die Verbindung beim ersten Start geklappt hat, kümmert sich Socket.io selbst darum, verlorene Verbindungen wieder aufzubauen. Wenn das passiert, wird connect im Client nochmal ausgelöst. Man muss dann allerdings nur nochmal sub an den Server senden, aber nicht nochmal Socket.io Eventhandler (socket.on()) initialisieren. Alternativ kann man mit socket.removeAllListeners("eventname") zu Beginn jedes connect die Handler zurücksetzen.