In unserem Haus sind inzwischen alle Lichtschalter mit Aktoren von Homematic ersetzt und ein Raspberry Pi 3 übernimmt mit openHAB die Steuerung, siehe hierzu diverse vorherige Blogartikel.
Aber letztlich ist es egal, ob es Homematic oder irgendein anderer Hersteller benutzt wird: Hauptsache die Geräte werden durch openHAB unterstützt.
Nun steht demnächst die Urlaubszeit an und auch hier kann man den Raspberry und openHAB dazu verwenden, das Zuhause zu schützen. Ein Element des Schutzes kann eine Anwesenheitssimulation sein. Ist Licht an, wird vielleicht jemand zu Hause sein. Idealerweise „lebt“ das Zuhause auch noch durch das Wechseln verschiedener Lichtschaltungen, so dass der Eindruck entsteht, es ist wirklich jemand zu Hause.
Folgende Anforderungen sollen umgesezt werden:
- Die Präsenzsteuerung soll via Oberfläche ein- und ausschaltbar sein
- Die Präsenzsteuerung soll nicht an sein, wenn die Sonne noch nicht untergegangen ist und spätestens um halb zwei Nachts beendet sein
- Die Präsenzsteuerung soll definierte Lampen für die Vorder- und Rückseite des Hauses kennen und zufällig schalten; dabei sollen Übergangszeiten und Zufallszahlen-Anteile abrupte Übergänge verhindern und die Schaltbilder sollen alls 15 Minuten wechseln
Zum Ablauf:
- Um auf Sonnenauf- und -untergang zurückgreifen zu können ist das astro-binding installiert.
- Das Scheduling erfolgt via Cronjob.
- Die Lampen, welche für vorne und hinten zur Verfügung stehen sollen sind in der .items-Datei der Gruppe pSimH und pSimV zugewiesen (vorn und hinten)
- Soll geschalten werden, sucht die Rule zufällig eine Lampe je für vorn und für hinten aus, welche noch nicht an ist. Diese Lampe wird dann an geschalten und mit einem Timer versehen und nach der Wartezeit inkl. etwas Puffer wieder ausgeschalten.
- Um das Ganze besser verfolgen zu können erfolgt ein Logging in der openhab.log
.items-Datei:
Group pSimH Group pSimV Switch praesenzSimulation "Präsenz-Simulation" <shield> DateTime astro_Sonnenaufgang "Sonnenaufgang [%1$tH:%1$tM]" (gruppeAstro) {astro="planet=sun, type=rise, property=start"} DateTime astro_Sonnenuntergang "Sonnenuntergang [%1$tH:%1$tM]" (gruppeAstro) {astro="planet=sun, type=set, property=start"}
.sitemap-Datei:
(...) Text label="Präsenz-Simulation" icon="network" { Switch item=praesenzSimulation } (...)
.rules-Datei:
import org.openhab.core.library.types.* import org.joda.time.* import java.util.TimeZone val java.util.Random rand = new java.util.Random rule "Praesenzsimulation durchführen" when Time cron "0 0/15 17-23 * * ?" or Time cron "0 0/15 0-1 * * ?" // Rule soll alle fünfzehn Minuten aktiv werden im Zeitraum von 17:00 - 01:30 Uhr then var Integer schaltintervall = 15 // Sollte mit Cron-Aufruf-Intervall übereinstimmen var Integer schaltueberlappung = 4 // Zufällige Überlappung, damit nicht alle Lampen gleichzeitig ausgehen (plus zus. 1 Minute) var DateTime datumSonnenaufgang = new DateTime((astro_Sonnenaufgang.state as DateTimeType).calendar.timeInMillis) var DateTime datumSonnenuntergang = new DateTime((astro_Sonnenuntergang.state as DateTimeType).calendar.timeInMillis) val boolean istDunkel = datumSonnenaufgang.afterNow || datumSonnenuntergang.beforeNow val Boolean log = true if (log) logInfo('rules','Präsenzsimulation: Rule gestartet. istDunkel=' + istDunkel.toString() + ' praesenzSimulation=' + praesenzSimulation.state.toString()) if (praesenzSimulation.state == OFF) { if (log) logInfo('rules','Präsenzsimulation: Präsenzsimulation ausgesetzt - nicht aktiv!') } else if ((praesenzSimulation.state == ON) && (!istDunkel)) { if (log) logInfo('rules','Präsenzsimulation: Präsenzsimulation ausgesetzt - aktiv, aber es ist noch nicht dunkel!') } else { // es ist dunkel und die Simulation wurde aktiviert if (log) logInfo('rules','Präsenzsimulation: Präsenzsimulation wird ausgeführt') // Je Präsenzsimulations-Lichtergruppe soll mindestens ein Licht geschalten sein. (pSimH und pSimV) var pSimHAnzahl = (pSimH.members.size) var pSimVAnzahl = (pSimV.members.size) // je Gruppe eine zufallsgenerierte Lampen schalten für Zufallszeit zwischen schaltintervall + schaltüberlappung in Minuten var Integer schaltzeitH = rand.nextInt(schaltueberlappung) + schaltintervall + 1 var Integer schaltzeitV = rand.nextInt(schaltueberlappung) + schaltintervall + 1 var Integer counterH = 0 var lampeHON = true var lampeH = 0 var boolean exitFlag = false // LampeH suchen, welche noch nicht AN ist, maximal 30 Versuche, sonst endlosschleife, wenn alle Lampen an wären while (lampeHON && !exitFlag) { lampeH = rand.nextInt(pSimHAnzahl) lampeHON = (pSimH.members.get(lampeH).state == ON) || (pSimH.members.get(lampeH).state > 0) if (log) logInfo('rules', 'Präsenzsimulation: Versuch Nr. ' + counterH + ' Ermittelte LampeH (Index) ' + lampeH + '/' + pSimH.members.get(lampeH).name + ' Status lampeHON ' + lampeHON.toString()) counterH = counterH + 1 if (counterH > 30) exitFlag = true } if (!exitFlag) { // LampeH schalten und Timer für Ausschalten setzen if (log) logInfo('rules', 'Präsenzsimulation: Schalte LampeH an: ' + pSimH.members.get(lampeH).name + ' für ' + schaltzeitH + ' Minuten') pSimH.members.get(lampeH).sendCommand(ON) createTimer(now.plusSeconds(schaltzeitH * 60)) [| pSimH.members.get(lampeH).sendCommand(OFF) if (log) logInfo('rules', 'Präsenzsimulation: Schalte LampeH aus: ' + pSimH.members.get(lampeH).name + ' nach ' + schaltzeitH + ' Minuten') ] } else { logInfo('rules','Präsenzsimulation: Keine freie LampeH gefunden!') } // LampeV suchen, welche noch nicht AN ist, maximal 30 Versuche, sonst ergibt sich evtl eine Endlosschleife, wenn alle Lampen an wären var Integer counterV = 0 var lampeVON = true var lampeV = 0 exitFlag = false while (lampeVON && !exitFlag) { lampeV = rand.nextInt(pSimVAnzahl) lampeVON = (pSimV.members.get(lampeV).state == ON) || (pSimV.members.get(lampeV).state > 0) if (log) logInfo('rules', 'Präsenzsimulation: Versuch Nr. ' + counterV + ' Ermittelte LampeV (Index) ' + lampeV + '/' + pSimV.members.get(lampeV).name + ' Status lampeVON ' + lampeVON.toString()) counterV = counterV + 1 if (counterV > 30) exitFlag = true } if (!exitFlag) { // LampeV schalten und Timer für Ausschalten setzen if (log) logInfo('rules', 'Präsenzsimulation: Schalte LampeV an: ' + pSimV.members.get(lampeV).name + ' für ' + schaltzeitV + ' Minuten') pSimV.members.get(lampeV).sendCommand(ON) createTimer(now.plusSeconds(schaltzeitV * 60)) [| pSimV.members.get(lampeV).sendCommand(OFF) if (log) logInfo('rules', 'Präsenzsimulation: Schalte LampeV aus: ' + pSimV.members.get(lampeV).name + ' nach ' + schaltzeitV + ' Minuten') ] } else { if (log) logInfo('rules','Präsenzsimulation: Keine freie LampeV gefunden!') } } end
Viel Spaß damit
Hi,
klasse idee und ich habe es direkt auch mal übernommen. Leider bekomme ich eine Fehlermeldung im Log wenn die 17 Uhr erreicht werden. Error during the execution of rule Präsenzsimulation durchführen
java.lang.NullPointerException: null
Finde den Fehler irgendwie nicht.
Hallo Marco,
Danke für den Hinweis – im geposteten Script war leider ein kleiner Fehler enthalten, der sich wohl beim Hineinkopieren eingeschlichen hatte…
Ich habe das Script aktualisiert, das aktuelle Script funktionierte bei mir nun im Test. Versuche es bitte nocheinmal damit!
Viele Grüße
Florian
Hallo Florian,
Funktioniert wunderbar. Hab es gestern bei mir neu eingespielt und laufen lassen.
Läuft stabil und macht was es soll. Sehr cool. Danke.
Gruß Marco
Hallo Florian,
eine tolle Anwendung – vielen Dank dafür.
Einen kleinen Fehler habe ich noch gefunden – in der while-schleife (lampeVON && !exitFlag) muss es beim ersten if „+ counterV +“ lauten, anstatt „+ counterH +“ , sonst steht im Logfile immer für die vorderen Lampen „Versuch Nr. 31“.
Im VS Code-Editor gibt es diverse Fehlermeldungen (Cannot refer to the non-final variable lampeH inside a lambda expression), die aber scheinbar ignoriert werden können – sieht aber nicht so schön aus …
https://github.com/eclipse/smarthome/issues/4711
Dirk
Hallo Dirk,
Danke für das Feedback, da hast Du recht, das war ein kleiner Fehler, der sich aber nur in der leicht fehlerhaften Log-Ausgabe niedergeschlagen hat. Ich habe das entsprechend abgeändert im Script.
Bezüglich der lambda-expression-Ferhler: Ja, die Fehler sind irritierend, die im Editor angezeigt werden, aber man kann sie getrost ignorieren. Eine Lösung um die loszuwerden wäre z.B, diese global in der Rule zu definieren. Aber das finde ich persönlich nicht so schön, denn dann gibt es globale Variablen die aber dann doch nur Rule-spezifisch sind… Von daher habe ich lieber die angeblichen Fehler, die der Editor anzeigt, ist in meinen Augen sauberer….
Viele Grüße
Florian
Hallo Florian,
auch von mir erstmal vielen Dank für deine Mühe und die investierte Zeit.
Könntest du mir ggf. bein einem Problem mit der Rules Datei weiterhelfen?
Ich bekomme im Log immer folgende Fehlermeldung und komme damit nicht weiter:
2018-12-18 23:48:00.640 [ERROR] [ntime.internal.engine.ExecuteRuleJob] – Error during the execution of rule ‚Praesenzsimulation durchführen‘: Could not cast NULL to org.eclipse.smarthome.core.library.types.DateTimeType; line 16, column 50, length 41
es verweist auf diese Zeile:
var DateTime datumSonnenaufgang = new DateTime((astro_Sonnenaufgang.state as DateTimeType).calendar.timeInMillis)
Vielleicht hast du ja einen Tip, der mich weiterbringt.
Danke
SaWo