
Szenen anlegen im Smarthome
Manchmal möchte man nicht nur einen einzigen Befehl ausführen, sondern eine ganze Gruppe von Befehlen. Bei einem DVD-Abend z.B. möchte man mit einem Klick die Lichter auschalten, das Media Center starten, und eventuell die Heizung auf eine bestimmte Temperatur regeln. Das Zauberwort heißt „Szene“. Mit Szenen werden Befehlsketten zu einem einzigen Befehl zusammengefasst, um häufig zusammen ausgeführte Befehle zu vereinen. In diesem Tutorial erfährt du, wie du ganz einfach in deinem Smarthome-System Szenen anlegen kannst.
Was wird benötigt?
Um diesem Tutorial folgen zu können solltest du folgendes besitzen:
Außerdem solltest du bereits folgenden Tutorials dieser Website gefolgt sein:
- Raspberry Pi einrichten
- Funksteckdosen mit Raspberry Pi schalten
- Datenbank anlegen & verwalten
- Funksteckdosen per Internet schalten
- RaZberry Modul auf Raspberry installieren
- Datenbank: Sensorwerte speichern
Was wird in diesem Tutorial gemacht?
In diesem Tutorial werden folgende Dinge getan:
- Eine Tabelle für die Szenen anlegen
- Ein Script erstellen, das die Befehle der ausgeführten Szene verarbeitet
- Ein Script erstellen, um Szenen anlegen zu können
- Ein Script erstellen, um vorhandene Szenen abzufragen (wird für später erstellte Smarthome App benötigt)
Tabelle für Szene in Datenbank erstellen
Um die Tabelle zu erstellen, öffnest du in deinem Browser folgende URL:
http://[IP DES RASPBERRY]/database/phpliteadmin.php
Dort gibst du unter dem Punkt „Create new table on database data.sqlite“ bei Name „SCENES“ und bei „Number of Fields“ die Zahl 3 ein. Anschließend klickst du auf „Go“, um zum Definitions-Bildschirm zu gelangen. Dort werden die Felder folgendermaßen definiert:
- NAME (Text): Dies ist der Name der Szene (dieser wird auch in der später erstellten App angezeigt)
- ROOM (Text): Im Feld „ROOM“ wird der Raum gespeichert, bei dem die Szene in der später erstellten App angezeigt wird
- ACTIONS (Text): Hier werden die Aktionen dieser Regel im JSON-Format abgespeichert
Dann schließt du die Definition der Tabelle mit einem klick auf „Create“ ab.
Script für die Steuerung erstellen
Nun erstellst du per FTP im Hauptverzeichnis deines Servers einen Ordner mit dem Namen „scenes“. Anschließend wechselst du in diesen Ordner und erstellst du eine Datei namens „runScene.php“. Diese Datei ist für die Ausführung der Szenen zuständig. Öffne diese Datei und füge den folgenden Quellcode ein.
<?php function runScene($room, $scene, $db){ //Szenen aus Datenbank laden $results = $db->prepare("SELECT * FROM 'SCENES' WHERE ROOM == :room AND NAME == :scene"); $results->execute(array('room' => $room, 'scene' => $scene)); foreach($results->fetchAll(PDO::FETCH_ASSOC) as $row){ $array = json_decode($row['ACTIONS'], true); foreach($array['actions'] as $action) { //Wenn Bedingung erfüllt ist oder keine Bedingung angegeben, führe Befehl aus if($action['if']==null || conditionTrue($action['if'])){ //Verarbeitung der Aktion anhand des Aktionstyps (Schalter, Heizung, etc.) switch($action['type']){ case 'switch': setModes($action['location'], $action['device'], $action['value'], $db); break; case 'heizung': //Heizungssteuerung wird noch implementiert break; } } } } return "ok"; } //Prüft die übergebene Bedingung auf Wahrheit und gibt dementsprechend true/false zurück function conditionTrue($condition){ switch($condition['type']){ //Sensorwert abfragen case 'sensor': $value = getData($condition['room'], $condition['sensorart'], '', $db); break; //Schalter abfragen case 'switch': $value = getModes($condition['room'], $condition['device'], $db); break; } //vergleicht den abgefragten Wert mit dem übergebenen Wert switch($condition['comparator']){ case '<': return ($value < $condition['value']); case '<=': case '=<': return ($value <= $condition['value']); case '>': return ($value > $condition['value']); case '>=': case '=>': return ($value >= $condition['value']); case '==': case '=': return ($value == $condition['value']); default: return false; } } ?>
Erklärung des Scripts
Das Script fragt zuerst die Befehlskette im JSON-Format ab, die der Szene zugewiesen ist, prüft, ob die zugewiesene Bedingung erfüllt ist und führt anschließend die entsprechenden Befehle anhand der zugewiesenen Typen aus (momentan wird nur der Typ „switch“ unterstützt, damit lassen sich Szenen für Funksteckdosen erstellen – weitere Befehlstypen werden im weiteren Verlauf dieser Tutorialreihe implementiert, z.b. Steckdosen, Befehle fürs Media Center, etc).
Die Methode conditionTrue($condition) prüft, ob die vorhandene Bedingung für eine Aktion erfüllt ist oder nicht.
Momentan implementierte Bedingungen sind (weitere folgen in Zukunft):
- bestimmter Sensorwert größer (oder gleich) als angegebener Grenzwert
- bestimmter Sensorwert kleiner (oder gleich) als angegebener Grenzwert
- bestimmter Sensorwert gleich dem angegebenen Grenzwert
- Bestimmtes Gerät AN bzw. AUS
Script, um Szenen anlegen zu können
Nun erstellst du im Ordner „scenes“ eine weitere Datei namens „createScene.php“. Mit dieser Datei kannst du später neue Szenen anlegen.In das Script fügst du nun folgenden Code ein:
<?php function createScene($devices, $rooms, $types, $values, $conditions, $room, $name, $db){ //Prüfen, ob alle Arrays ($devices, $rooms, $types, $modes) gleich viele Elemente haben, gibt andernfalls Fehlermeldung aus if(sizeOf($devices) < sizeOf($rooms) || sizeOf($rooms) < sizeOf($types) || sizeOf($types) < sizeOf($values) || sizeOf($values) < sizeOf($devices)){ exit("error"); } $scene = array(); //Die Übergabe-Arrays in ein einziges Array zusammensetzen for($counter = 0; $counter < sizeOf($devices); $counter++){ $action_item = array('device' => $devices[$counter], 'location' => $rooms[$counter], 'value' => $values[$counter], 'type' => $types[$counter], 'if' => $conditions[$counter]); array_push($scene, $action_item); } //Array als JSON-Objekt ausgeben header('Content-type: application/json'); $action_string = json_encode(array('actions' => $scene)); //Prüfen, ob $room leer ist, wenn ja Default-Wert setzen if($room == ''){ $room = 'NONE'; } //Szene in Datenbank schreiben $statement = $db->prepare("INSERT INTO SCENES(NAME, ROOM, ACTIONS)VALUES(?,?,?)"); $statement->execute(array($name ,$room, $action_string)); return "ok"; } ?>
Erklärung des Scripts
Als Parameter werden die einzelnen Befehle der Szene als Arrays übergeben. Das Skript setzt aus den einzelnen Arrays nun ein JSON-Objekt zusammen, das anschließend zusammen mit dem Namen der Szene und dem zugewiesenen Raum in die Datenbank geschrieben wird. Wenn die einzelnen Arrays der Übergabe nicht gleich lang sind, also unvollständig, bricht das Skript ab und gibt „error“ zurück. Läuft das Skript hingegen vollständig und erfolgreich ab, so wird „ok“ zurückgegeben.
Script, um vorhandene Szenen abzufragen
Als letztes muss du eine Datei mit dem Namen „getScenes.php“ im Ordner „scenes“ erstellen. Diese Datei gibt bei Aufruf alle zugehörigen Szenen eines Raumes zurück. Den folgenden Code fügs du anschließend in das Script ein:
<?php function getScenes($room, $db){ //Szenen aus Datenbank laden //INFO: Es werden alle Szenen abgefragt, die entweder dem Raum des Parameters $room oder dem Raum 'NONE' zugewiesen sind $results = $db->prepare("SELECT * FROM 'SCENES' WHERE ROOM == :room OR ROOM == 'NONE'"); $results->execute(array('room' => $room)); $scenes = array(); //Namen aller gefundenen Szenen in Array schreiben foreach($results->fetchAll(PDO::FETCH_ASSOC) as $row){ $scene_item = array('name' => $row['NAME'], 'room' => $row['ROOM'], 'actions' => $row['ACTIONS']); array_push($scenes, $scene_item); } //Array als JSON-Objekt ausgeben header('Content-type: application/json'); return json_encode(array('scenes' => $scenes)); } ?>
Erklärung des Scripts
Das Script fragt bei Aufruf die Datenbank nach allen Szenen ab, die dem übergebenen Raum (oder keinem Raum) zugewiesen sind und gibt dann ein JSON-Objekt zurück, in dem alle Szenen dieser Suche mit dem Namen und dem zugewiesenen Raum aufgelistet sind.
Benutzung der Skripte
Um Szenen abfragen, ausführen oder anlegen zu können wird eine Schnittstelle benötigt. Diese Schnittstelle wird vor Programmierung der Android-App angelegt.
Wenn du Schwierigkeiten oder Fragen hast, kannst du mir gerne einen Kommentar hinterlassen.