[HowTo] Zeitschaltuhr mit Automatik und Anwesenheit

Für welche Projekte verwendet Ihr OpenHAB? Was habt Ihr automatisiert? Stellt eure Projekte hier vor.

Moderatoren: Cyrelian, seppy

Antworten
MrCrashy
Beiträge: 113
Registriert: 2. Jan 2021 09:53

[HowTo] Zeitschaltuhr mit Automatik und Anwesenheit

Beitrag von MrCrashy »

Einleitung
Hallo, wie sicher viele hier habe ich vor mein Haus mit Smart-Home auszurüsten. Mich hat es jedoch genervt 10 verschiedene Apps für die Steuerung zu verwenden und bin nun bei OpenHAB gelandet. Erschlagen von den ganzen Möglichkeiten habe ich mich einfach hingesetzt und drauf los geschrieben. Schnell habe ich gemerkt dass ich an meine Grenzen komme und habe hier nach Hilfe gefragt. Dank der unermüdlichen Hilfe von udo1toni habe ich es endlich geschafft eine Zeitschaltuhr mit Automatikmodus und Anwesenheitserkennung zu programmieren.
In diesem HowTo möchte ich den Leuten die, so wie ich, Startschwierigkeiten haben einen kleinen Anstoß geben.
Dieses Script habe ich jetzt selber eine Zeit am laufen und funktioniert einwandfrei!
Solltet ihr Fehler finden, dann sagt mir bescheid.
Derzeit funktioniert diese Methode nur mit Android, da Apple meines Wissens die benötigten App-Funktionen nicht hat.

Was ihr benötigt:
- OpenHAB
-OpenHAB - App
- Astro-Binding
- Map Transformation
- OpenHAB Cloud
- Etwas Zeit

Fangen wir an!

Astro-Binding konfigurieren:
Zuerst solltet ihr, sofern nicht schon geschehen, das Astro-Binding in der PaperUI installieren und konfigurieren. Hierzu sucht ihr das Binding bei den Add-Ons und installiert es. Nach der Installation solltet ihr bei Configuration > Things > Astronomische Sonnendaten eure Koordinaten eingeben. Diese könnt ihr über Maps oder andere Anbieter herausfinden. Danach einfach nur Speichern.
Als nächstes erstellt ihr mit einem Editor, in meinem Fall "Visual Studio Code" eine ".things-Datei". Diese nenne ich "astro.things".
Dort müsst ihr folgenden Code eingeben:

Code: Alles auswählen

Thing astro:sun:home  [ geolocation="xxx,xxx", interval=60 ]{
    Channels:
        Type rangeEvent : set#event[
            offset=-30
        ]
        Type rangeEvent : rise#event[
            offset=-30
        ]
}

Thing astro:moon:home [ geolocation="52.305400,8.604877", interval=60 ]
Erklärung: Bei "geolocation" müsst ihr die selben Koordinaten eingeben, wie ihr sie vorher in PaperUI eingegeben habt.
Das Thing "astro:sun:home: ist der "Main-Trigger". Darunter stehen die Channel. In meinem Fall ein "set#event" mit einer Verschiebung von 30 Minuten. Ebenfalls habe ich noch ein "rise#event" mit einer Verschiebung von 30 Minuten. Das sind Sonnenauf- und Sonnenuntergang.

openHAB Cloud
Als nächstes müsst ihr euch das Binding "openHAB Cloud" über PaperUI installieren. Nach der Installation findet ihr in dem Ordner "openHAB-userdata" eine Datei mit dem Namen "UUID". Diese öffnet ihr und speichert den Code in einem Text-Dokument.
Danach müsst ihr wieder in "openHAB-userdata > openhabcloud" da findet ihr eine "secret"-Datei. Diese öffnet ihr ebenfalls wieder und Speichert den Code in der Text-Datei.
Als nächstes müsst ihr euch bei https://myopenhab.org registrieren. Nach der Registrierung solltet ihr direkt aufgefordert werden, den Code der UUID und den Code vom Secret einzugeben. Nachdem ihr das gemacht und gespeichert habt, sollte kurze Zeit später oben links das Feld von "Offline" zu "Online" wechseln. Ist dies nicht der Fall müsst ihr euer OpenHAB einmal neustarten.

OpenHAB-App
Nun solltet ihr euch um die OpenHAB - App kümmern. Dazu müsst ihr in den Einstellungen der App auf den Reiter "Lokal" gehen. Dort müsst ihr die IP eures OpenHAB eingeben. Wichtig ist hierbei auch der Port "8080" am Ende.
Danach müsst ihr in den Reiter "Fernzugriff" wechseln. Dort gebt ihr unter "Server-URL für Fernzugriff" die IP-Adresse "https://myopenhab.org" ein. Bei Benutzername und Passwort gebt ihr die Daten von dem eben erstellten Account ein.
Bild
Bild
Bild

Map-Transformation
Dieses Binding soll später dafür sorgen, dass in unserer Sitemap nicht mehr "ON oder OFF" als Anwesenheitsstatus angezeigt wird, sondern im besten Fall "Anwesend oder Abwesend". Nachdem ihr dieses Binding installiert habt, müsst ihr über einen Editor in dem Ordner "openhab-config > transform" eine .map-Datei erstellen. Ich nenne sie "anwesenheit.map". Dort schreibt ihr folgendes rein:

Code: Alles auswählen

ON=Zuhause
OFF=Unterwegs
NULL=Undefiniert
Ich denke das ist relativ selbsterklärend.

Ab jetzt müssen wir schreiben:
Zunächst erstelle ich eine "anwesenheit.items" -Datei. Diese Datei sieht wie folgt aus:

Code: Alles auswählen

String WLAN_Handy1 "WLAN [%s]"
String WLAN_Handy2 "WLAN [%s]"
Switch Handy1 "Test1 ist [MAP(anwesenheit.map):%s]" <motion> ["Switchable"]
Switch Handy2 "Test2 ist [MAP(anwesenheit.map):%s]" <motion> ["Switchable"]
Switch Anwesend "[MAP(anwesenheit.map):%s]"
Die beiden Strings lesen später das WLAN-Netzwerk aus mit dem unser Handy verbunden ist. Ich mache es gleich mit zwei Handys, da meist auch zwei oder mehr Handy im Haushalt vorhanden sind. Ist dies nicht der Fall, dann kann man das auch auf ein Handy anwenden.
Die Schalter "Handy1 und Handy2" sind später unsere Anzeige in der Sitemap. Hier wird als Text der Schalter durch das "Map-Transformation" - Binding von "ON" zu "Anwedend" übersetzt.
Den Switch "Anwesend" benötigen wir, wenn wir mehr als ein Handy haben. So muss nicht ständig beide Handys für eine Rule abgefragt werden.

Als nächstes erstellen wir uns eine "anwesenheit.rules"-Datei. Diese ist in zwei Bereiche eingeteilt:
Bereich 1:

Code: Alles auswählen

var Timer timer1
var Timer timer2
rule "Abwesenheit Test1"
when 
    Item WLAN_Handy1 changed 
then
    logInfo("Anwesenheit", "Rule getriggert. WLAN_Handy1 Status: {}",WLAN_Handy1.state)
    if(WLAN_Handy1.state.toString != "DEINE WLAN-SSID"){
        timer1 = createTimer(now.plusSeconds(15), [|
            if(WLAN_Handy1.state.toString != "DEINE WLAN-SSID"){
                Handy1.postUpdate(OFF)
                logInfo("Anwesneheit", "Test1 ist unterwegs!")
            }
        ])
    }else {
        logInfo("Anwesenheit", "Test1 ist Zuhause!")
        Handy1.postUpdate(ON)
    }
end 

rule "Anwesenheit Test2"
when 
    Item WLAN_Handy2 changed 
then 
    if(WLAN_Handy2.state.toString != "DEINE WLAN-SSID"){
        timer2 = createTimer(now.plusSeconds(15), [|
            if(WLAN_Handy2.state.toString != "DEINE WLAN-SSID"){
                Handy2.postUpdate(OFF)
                logInfo("Anwesenheit", "Test2 ist unterwegs!")
            }
        ])
    }else {
        logInfo("Anwesenheit", "Test2 ist zuhause!")
        Handy2.postUpdate(OFF)
    }
end 
Ich erkläre den oberen Teil, der untere Teil ist identisch.
Wir prüfen zunächst ob sich das Item "WLAN_Handy1" geändert hat. (Zum Beispiel, weil die WLAN-SSID geändert wurde. Ist das passiert, wird geprüft, ob die SSID nun nicht mehr die SSID von dem Heimnetzwerk ist. Ist diese nun eine andere SSID, wird ein Timer gesetzt und 15 Sekunden gewartet. Nach Ablauf dieser 15 Sekunden wird nochmal geprüft ob das Handy immer noch aus dem WLAN ausgeloggt ist. Ist das der Fall, dann wird der Schalter "Handy1" ausgeschaltet, also "Abwesend".
Den Timer habe ich eingebaut, da sich mein Handy ab und zu auf meinem WLAN ausloggt. Das ist abhängig davon, wo ich mich im Haus befinde. Da ich aber nicht möchte dass ich im dunkeln stehe, nur weil mein Handy sich kurz ausgeloggt hat, soll zur Sicherheit nochmal 15 Sekunden gewartet werden.

Wenn wir nun nach Hause kommen und die SSID von unserem Handy die selbe SSID wir in der Rule hat, dann wird der Schalter "Handy1" auf "ON" gesetzt, also "Anwesend".
WICHTIG: In der Rule müsst ihr bei "DEINE WLAN-SSID" den Namen von eurem WLAN eingeben!

Der nächste Schritt ist wichtig, wenn man mehr als ein Handy hat

Code: Alles auswählen

rule "Anwesenheit umschalten"
when 
    Item Handy1 changed or 
    Item Handy2 changed 
then 
    if(Handy1.state == OFF && Handy2.state == OFF){
        Anwesend.postUpdate(OFF)
    } else {
        Anwesend.postUpdate(ON)
    }
end 
Hier wird einfach geprüft, ob beide Handys aus dem WLAN ausgeloggt sind. Erst dann soll das Licht ausgeschaltet werden. Sonst steht der andere im Dunkeln, sobald der andere geht.

Als nächsten Schritt erstellen wir eine "beleuchtung.items"-Datei. In diese Datei müssen folgende Items

Code: Alles auswählen

Number Light1_Timer_On "Einschaltzeit Licht 1"
Number Light1_Timer_Off "Ausschaltzeiten Licht 1"
Number Light2_Timer_On "Einschaltzeiten Licht 2"
Number Light2_Timer_Off "Ausschaltzeiten Licht 2"

Switch Sunset "Sonnenuntergang"
Die Number-Items sind für unsere Zeitschaltuhr um später zwischen vordefinierten Zeiten wählen zu können.
Der Switch "Sunset" wird gebraucht damit die nachfolgende Rule erkennt, wenn Sonnenuntergang ist/war.
Info: Um die Übersicht in eurem Script nicht zu verlieren, solltet ihr die Namen der Items nach eurem belieben ändern.

Danach erstellen wir eine "beleuchtung.rules"-Datei. Diese bauen wir in verschiedenen Abschnitten auf, damit es nicht zu unübersichtlich wird.
Erster Abschnitt

Code: Alles auswählen

rule "Sonnenuntergang"
when 
    Channel 'astro:sun:home:set#event' triggered START 
then 
    Sunset.postUpdate(ON)
end

rule "Sonnenaufgang"
when
    Channel 'astro:sun:home:rise#event' triggered START
then 
    Sunset.postUpdate(OFF)
end 
Hier wir die Rule getriggert, wenn der Channel "set#event" getriggert wird. Wenn dieser Channel triggert, dann wird der Schalter "Sunset" eingeschaltet, das heißt dass der Sonnenuntergang stattgefunden hat.
Selbes machen wir auch für den Sonnenaufgang. Hier wird der Schalter "Sunset" wieder ausgeschaltet.

Zweiter Abschnitt

Code: Alles auswählen

rule "Zeitschaltuhr"
when 
    Time cron "0 00 17-20 * * ?" or //täglich um 17, 18, 19 und 20 Uhr
    Time cron "0 00 21-23 * * ?" or //täglich um 21, 22 und 23 Uhr
    Item Sunset changed to ON or
    Item Light1_Timer_On changed or
    Item Light1_Timer_Off changed or
    Item Light2_Timer_On changed or
    Item Light2_Timer_Off changed or
    Item Anwesend changed 
then 
    val Sl1_OnSel = if(Light1_Timer_On.state instanceof Number) (Light1_Timer_On.state as Number) else 0
    val Sl1_OffSel = if(Light1_Timer_Off.state instanceof Number) (Light1_Timer_Off.state as Number) else 0
    val Lc_OnSel = if(Light2_Timer_On.state instanceof Number) (Light2_Timer_On.state as Number) else 0
    val Lc_OffSel = if(Light2_Timer_Off.state instanceof Number) (Light2_Timer_Off.state as Number) else 0
    var Sl = OFF 
    var Lc = OFF 
    if(Anwesend.state == ON){
        if(Sl1_OnSel == 0)
            if(Sunset.state == ON)                                          Sl = ON 
        else if(now.getHourOfDay > (15 + Sl1_OnSel))                        Sl = ON
        if(now.getHourOfDay > (19 + Sl1_OffSel) || now.getHourOfDay < 15)   Sl = OFF
        if(Lc_OnSel == 0)
            if(Sunset.state == ON)                                          Lc = ON
        else if(now.getHourOfDay > (15 + Lc_OnSel))                         Lc = ON 
        if(now.getHourOfDay > (19 + Lc_OffSel) || now.getHourOfDay < 15)    Lc = OFF
    } else {
        Lc = OFF 
        Sl = OFF 
    }
    if(Sl != "Eure Lampe".getStateAs(OnOffType)) "Eure Lampe".sendCommand(Sl)
    if(Lc != "Eure Lampe".getStateAs(OnOffType)) "Eure Lampe".sendCommand(Lc)
end 
Hier wird es unübersichtlicher. Aber ich versuche es so gut wie möglich zu erklären!
Ich erkläre es Abschnitt für Abschnitt.

Code: Alles auswählen

when 
    Time cron "0 00 17-20 * * ?" or //täglich um 17, 18, 19 und 20 Uhr
    Time cron "0 00 21-23 * * ?" or //täglich um 21, 22 und 23 Uhr
    Item Sunset changed to ON or
    Item Light1_Timer_On changed or
    Item Light1_Timer_Off changed or
    Item Light2_Timer_On changed or
    Item Light2_Timer_Off changed or
    Item Anwesend changed 
hier findet der Trigger statt. Der Time-Cron triggert täglich um 17, 18, 19 und 20 Uhr, sowie um 21, 22, 23 Uhr.
Dann soll noch getriggert werden, wenn sich einer der Items verändert.

Code: Alles auswählen

val Sl1_OnSel = if(Light1_Timer_On.state instanceof Number) (Light1_Timer_On.state as Number) else 0
    val Sl1_OffSel = if(Light1_Timer_Off.state instanceof Number) (Light1_Timer_Off.state as Number) else 0
    val Lc_OnSel = if(Light2_Timer_On.state instanceof Number) (Light2_Timer_On.state as Number) else 0
    val Lc_OffSel = if(Light2_Timer_Off.state instanceof Number) (Light2_Timer_Off.state as Number) else 0
    var Sl = OFF 
    var Lc = OFF
Hier werden den Items der Zeitschaltuhr ein Wert zugewiesen. So werden bei einem Neustart oder Stromausfall die Schalter definiert.

Code: Alles auswählen

 if(Anwesend.state == ON){
        if(Sl1_OnSel == 0)
            if(Sunset.state == ON)                                          Sl = ON 

end 
Hier wird geprüft, ob der "Automatik-Modus" eingeschaltet ist. Wenn das der Fall ist, dann wird geprüft ob der Schalter "Sunset" auf "ON" steht. Ist das ebenfalls der Fall, dann wird das Licht eingeschaltet.

Code: Alles auswählen

else if(now.getHourOfDay > (15 + Sl1_OnSel))                        Sl = ON
       	if(now.getHourOfDay > (19 + Sl1_OffSel) || now.getHourOfDay < 15)   Sl = OFF
Sollte der "Automatik-Modus" ausgeschaltet sein, dann soll geprüft werden, auf welche Uhrzeit die Schaltzeituhr steht.
Hier wird die Stunde des Tages + den Schalterzustand der Zeitschaltuhr genommen. Steht der Schalter z.B. auf ein, dann ergibt das 16 Uhr. Da wir aber auf das überschreiten von 16 Uhr triggern, ergibt das 17 Uhr. Also wird um 17 Uhr das Licht eingeschaltet.
Selbes gilt für das Ausschalten!
Das wiederholt sich nochmal, für die zweite Lampe. Das kann auf mehrere Lampen ausgeweitet werden.
WICHTIG: Bei "Eure Lampe" muss der Name der Lampe die ihr einschalten wollt gesetzt werden.

Die Sitemap
Damit ihr später auch eine Uhrzeit auswählen könnt, müsst ihr noch die Items in die Sitemap einbinden.
Ich habe dafür ein Untermenü bei meinen Lampen angelegt. Darin werden dann meine Items erscheinen.

Code: Alles auswählen

Selection item=Light1_Timer_On   label="Einschaltzeiten Licht 1"        mappings=[-1="Aus",0="Sonnenuntergang",1="17:00 Uhr",2="18:00 Uhr",3="19:00 Uhr",4="20:00 Uhr"]
Selection item=Light1_Timer_Off  label="Ausschaltzeiten Licht 1"        mappings=[-1="Aus",1="21:00 Uhr",2="22:00 Uhr",3="23:00 Uhr",4="24:00 Uhr"]
Selection item=Light2_Timer_On      label="Einschaltzeiten Licht 2"     mappings=[-1="Aus",0="Sonnenuntergang",1="17:00 Uhr",2="18:00 Uhr",3="19:00 Uhr",4="20:00 Uhr"]
Selection item=Light2_Timer_Off     label="Ausschaltzeiten Licht 2"     mappings=[-1="Aus",1="21:00 Uhr",2="22:00 Uhr",3="23:00 Uhr",4="24:00 Uhr"]
Das Mapping am Ende zeigt die 1 z.B. als 17:00 Uhr oder 21:00 Uhr an. So soll das alles etwas Übersichtlicher werden. Das sind die Werte, die oben in der Rule in z.B. "Sl1_OnSel" gespeichert und ausgerechnet werden.

Der letzte Schritt
Damit das alles nun funktioniert, müsst ihr nochmal in eure OpenHAB-App. Dort müsst ihr in den Einstellungen zu "Geräteinformationen an Server senden" gehen. Dort müsst ihr die "Ereignisüberwachung" aktivieren. Danach müsst ihr bei "WLAN-Name" das Item "WLAN_Handy1" oder "WLAN_Handy2" eingeben.
WICHTIG: Damit das alles funktioniert müsst ihr den Standort aktivieren und diesen auch für die App-Freigeben.
Danach alles speichern und im OpenHAB-Log auf Fehler prüfen.
Jetzt sollte alles funktionieren!

Viel Spaß mit der neuen Funktion!

Benutzeravatar
udo1toni
Beiträge: 13858
Registriert: 11. Apr 2018 18:05
Answers: 222
Wohnort: Darmstadt

Re: [HowTo] Zeitschaltuhr mit Automatik und Anwesenheit

Beitrag von udo1toni »

Sehr schönes HowTo.

Eine Anmerkung:

Das Item Anwesend kann man wesentlich eleganter als Group Item definieren:

Code: Alles auswählen

Switch Handy1 "Test1 ist [MAP(anwesenheit.map):%s]" <motion> (Anwesend) ["Switchable"]
Switch Handy2 "Test2 ist [MAP(anwesenheit.map):%s]" <motion> (Anwesend) ["Switchable"]
Group:Switch:OR(ON,OFF) Anwesend "[MAP(anwesenheit.map):%s]"
Sobald eines der Items, die zur Gruppe zugeordnet sind ON ist, ist auch die Gruppe ON. Damit kann die Rule "Anwesenheit umschalten" komplett entfallen.
Streng genommen verhält sich das Item in einem Punkt anders: wenn keines der Items ON, aber auch keins der Items OFF ist, ist die Gruppe dennoch OFF (bei der Rule-Variante wäre das Item ON). Das spielt dann beim Neustart von openHAB eine Rolle, solange die beiden Items noch keinen gültigen Wert haben.
Die Gruppe hat den Vorteil, dass ich beliebig viele Handys der Gruppe zuordnen kannn, aber keine Rule anfassen muss.
openHAB4.1.2 stable in einem Debian-Container (bookworm) (Proxmox 8.1.5, LXC), mit openHABian eingerichtet

MrCrashy
Beiträge: 113
Registriert: 2. Jan 2021 09:53

Re: [HowTo] Zeitschaltuhr mit Automatik und Anwesenheit

Beitrag von MrCrashy »

Werde mich sobald ich heute Abend Zuhause bin um die Berichtigung kümmern.
Danke für deine Anmerkung.

dreamar
Beiträge: 74
Registriert: 22. Dez 2017 08:41

Re: [HowTo] Zeitschaltuhr mit Automatik und Anwesenheit

Beitrag von dreamar »

Hallo MrCrashy,

ich habe das auch wie bei dir über die OPenhab-App realisiert, das bei Wlan-Änderung getriggert wird. Bei mir ist jedoch so das es nicht sauber läuft.
Erst wenn ich das Display aktiviere wird das Item aktualisiert. Im Handy ist eingestellt das die App im Hintergrund laufen darf und auch Wlan ist im Standby an. Habe ich eventuell etwas übersehen oder kannst du mir einen Tipp geben?

Gruß
dreamar
Openhab 2.5.10 mit deconz und Homematic

Antworten