Präsenz-Simulation mit openHAB

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

openHAB - Oberfläche: Präsenzsteuerung
openHAB – Oberfläche: Präsenzsteuerung

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. ' + counterH + ' 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

 

3 Antworten auf „Präsenz-Simulation mit openHAB“

  1. 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.

    1. 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

  2. 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

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.