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 java.util.*
import org.openhab.*

val java.util.Random rand = new java.util.Random

rule "Präsenzsimulation 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
        if (praesenzSimulation.state == OFF) {
            logInfo('rules','Präsenzsimulation: Präsenzsimulation ausgesetzt - nicht aktiv!')
        else if ((praesenzSimulation.state == ON) && (!istDunkel)) {
            logInfo('rules','Präsenzsimulation: Präsenzsimulation ausgesetzt - aktiv, aber es ist noch nicht dunkel!')
        } else if ((praesenzSimulation.state == ON) && (istDunkel)) {
            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)
//                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
                logInfo('rules', 'Präsenzsimulation: Schalte LampeH an: ' + pSimH.members.get(lampeH).name + ' für ' + schaltzeitH + ' Minuten')
                sendCommand(pSimH.members.get(lampeH), ON)
                createTimer(now.plusSeconds(schaltzeitH * 60)) [|
                    sendCommand(pSimH.members.get(lampeH), OFF)
                    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 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)
//                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
                logInfo('rules', 'Präsenzsimulation: Schalte LampeV an: ' + pSimV.members.get(lampeV).name + ' für ' + schaltzeitV + ' Minuten')
                sendCommand(pSimV.members.get(lampeV), ON)
                createTimer(now.plusSeconds(schaltzeitV * 60)) [|
                    sendCommand(pSimV.members.get(lampeV), OFF)
                    logInfo('rules', 'Präsenzsimulation: Schalte LampeV aus: ' + pSimV.members.get(lampeV).name + ' nach ' + schaltzeitV + ' Minuten')
                ]    
            } else {
                logInfo('rules','Präsenzsimulation: Keine freie LampeV gefunden!')
            }
        }
end

Viel Spaß damit

 

Schreibe einen Kommentar

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