Rule für Raffstores in Zwischenposition (Lüftung)

Einrichtung der openHAB Umgebung und allgemeine Konfigurationsthemen.

Moderatoren: seppy, udo1toni

Antworten
curius
Beiträge: 78
Registriert: 1. Aug 2019 10:10
Answers: 0

Rule für Raffstores in Zwischenposition (Lüftung)

Beitrag von curius »

Hallo Leute!

Ich bin seit einiger Zeit "stiller" Mitleser und absoluter Anfänger im Hinblick auf OpenHab und die Erstellung von Rules. Ich habe schon einige Tipps und Hinweise hier in diesem Forum finden können, die mich im Hinblick auf meine Heimautomatisierung weiter gebracht haben.
Besten Dank für die tolle Unterstützung.

Nun habe ich jedoch ein Problem mit meiner Beschattung und hoffe auf eure Hilfe ;-)

Mein Anliegen ist folgendes:
Ich möchte eine sogenannte Lüftungsposition bei meinen Raffstores bzw. Jalousien verwirklichen.
Wenn die Raffstores komplett geschlossen sind und ich öffne das dazugehörige Fenster, so sollen die Raffstores sich wenden und in die Lüftungsposition fahren. Nach dem Schließen des Fensters, sollen sich dann auch die Raffstores wieder komplett schließen.

Nun zu meinem Problem:
Ich kann bei den Raffstores keine Lüftungsposition programmieren und dann direkt über OpenHab anfahren.

Das heißt die Raffstores kennen nur folgende Stati zuverlässig:
100 - komplett geschlossen (Endlage unten)
0 - komplett geöffnet (Endlage oben)
50 - irgend eine Position zwischen geschlossen und geöffnet

Weiters habe ich zur Steuerung nur folgende Befehle:
UP - zum vollständigen Öffnen
DOWN - zum vollständigen Schließen
STOP - zum Stoppen der Raffstores / Jalousien

Meine Rules für Öffnen und schließen sehen nun wie folgt aus und funktionieren soweit auch einwandfrei:
Öffnen:

Code: Alles auswählen

// Lüftungsautomatik - öffnen
rule "Lüftungsautomatik - öffnen"
when
    Item KU_Vio changed from OFF to ON
then
    if (Rollershutter3.state == 100 && KU_Vio.state == ON) { 
        Rollershutter3.sendCommand(UP)
        createTimer(now.plusSeconds(3)) [|
        Rollershutter3.sendCommand(STOP)
        ]
    }
end
Schließen:

Code: Alles auswählen

// Lüftungsautomatik - schließen
rule "Lüftungsautomatik - schließen"
when
    Item KU_Vio changed from ON to OFF
then
    if (Rollershutter3.state == 50 && KU_Vio.state == OFF) { 
        Rollershutter3.sendCommand(DOWN)
    }
end

Soweit alles gut und es funktioniert grundsätzlich auch einwandfrei...
Jedoch jetzt zum eigentlichen Problem.

Wie in der Rule ersichtlich frage ich beim Schließen der Raffstores nur ab, ob die Raffstores vorab in der Position (50) sind - also irgendwo zwischen geöffnet und geschlossen.
Ich habe leider keinen anderen Anhaltspunkt. Durch das Öffnen der Raffstores durch die Rule oben fahren sie ja nach oben, stoppen nach drei Sekunden und befinden sich dann somit in Position (50).

Ich möchte jedoch sicherstellen, dass die Raffstores sich nur dann wieder schließen, wenn sie auch NUR durch die oben beschriebene Rule sich geöffnet haben.

Beispiel:
Ich öffne das Fenster - Rule zum Öffnen wird ausgeführt und die Raffstores fahren für 3 Sekunden nach oben. Anschließend schließe ich das Fenster wieder und die Raffstores fahren wieder nach unten => alles Perfekt!

Aber Angenommen ich fahre jetzt tagsüber die Raffstores händisch in irgend eine Zwischenposition (nicht zum Lüften) und öffne anschließend das Fenster, so würden bei meiner Regel nach dem Schließen des Fensters wieder die Raffstores nach unten fahren, was ich aber eigentlich gar nicht möchte.
Der Vorgang sollte nur geschehen, wenn die Raffstores durch die Öffnen-Regel vorab geöffnet wurden.

Gibt es in OpenHab eine Möglichkeit soetwas zu programmieren?
Meine Gedanken waren nämlich folgende:
Vielleicht kann man nach dem Ablauf der Öffnen-Regel irgendwo eine Variable beschreiben, die den Zustand definiert (Bsp.: geöffnet durch Öffnen-Regel), und diese Variable dann bei der Schließen-Regel vorab abfragen, sodas diese nur dann durchgeführt wird, wenn vorab durch die Öffnen-Regel geöffnet wurde. Bei jeder anderen Betätigung müsste diese Variable wieder gelöscht werden.

Ich hab leider keine Ahnung wie man so etwas umsetzen könnte.

Vielleicht denke ich aber auch einfach nur viel zu kompliziert und es gibt eine noch einfachere Variante das Problem zu lösen...

Ich hoffe auch, dass ich den Sachverhalt zumindest ein bisschen verständlich darstellen konnte... war für mich nicht leicht zu beschreiben :-)

Bin auf jeden Fall für jeden Hinweis dankbar...

Beste Grüße
Christian

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

Re: Rule für Raffstores in Zwischenposition (Lüftung)

Beitrag von udo1toni »

Du denkst zu kompliziert :)

Es reicht ja, wenn die Rule sich merkt, dass sie selbst den Raffstore bewegt hat. Die Rules können auch zu einer Rule zusammengefasst werden:

Code: Alles auswählen

// Globale Variablen immer zu Beginn der Datei definieren!
var boolean bLueftung = false

// Lüftungsautomatik
rule "Lüftungsautomatik"
when
    Item KU_Vio changed
then
    if(KU_Vio.state == ON && bLueftung == false && Rollershutter3.state == 100) { 
        bLueftung = true
        Rollershutter3.sendCommand(UP)
        createTimer(now.plusSeconds(3)) [|
            Rollershutter3.sendCommand(STOP)
        ]
    } else if(KU_Vio.state == OFF && bLueftung == true && Rollershutter3.state == 50) { 
        bLueftung = false
        Rollershutter3.sendCommand(DOWN)
    }
end
Wahlweise kannst Du auch ein ungebundenes Switch Item verwenden, um zu speichern, ob die Rule für die Zwischenlage verantwortlich ist.

Einen Haken hat die Geschichte noch, es könnte ja sein, dass Du den Store manuell verfährst, während das Fenster geöffnet ist. Du bräuchtest also eine weitere Rule, die triggert, wenn der Aktor einen Befehl erhält. Jetzt wird's aber kompliziert, denn diese Rule muss entscheiden, ob die Änderung des Stores durch die erste Rule ausgelöst wurde. Sie muss also überprüfen, ob KU_Vio in den letzten Sekunden den Status gewechselt hat. Falls ja, darf die Rule nichts tun, falls nein, muss die Rule prüfen, ob bLueftung true ist und es gegebenenfalls auf false setzen.
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

curius
Beiträge: 78
Registriert: 1. Aug 2019 10:10
Answers: 0

Re: Rule für Raffstores in Zwischenposition (Lüftung)

Beitrag von curius »

Wahnsinn - ich bin begeistert!

Besten Dank für deine rasche Unterstützung!
Du hast mir da echt eine smarte, elegante Lösung zu dem Problem gezeigt ;-)
Absolut Spitze!

Grüße
Christian

curius
Beiträge: 78
Registriert: 1. Aug 2019 10:10
Answers: 0

Re: Rule für Raffstores in Zwischenposition (Lüftung)

Beitrag von curius »

Hallo udo1toni,

ich habe die von dir geschriebene Rule jetzt für alle meine Fenster erweitert, was soweit auch einwandfrei funktioniert.
Sicher bin ich mir jedoch, dass das auch irgendwie einfacher geht :-)
Die Fensterkontakte beispielsweise könnte ich alle schon mal in eine Gruppe zusammenfassen und dann das Gruppenitem abfragen.
Aber woher weiß ich dann, welches Element aus der Gruppe gerade triggert?

Vielleicht kannst du mir einen Tipp geben, wie ich die Rule verkürzen kann?

Besten Dank

Grüße
Christian

Code: Alles auswählen

var boolean bLueftung_wz = false
var boolean bLueftung_ku = false
var boolean bLueftung_wc = false

var boolean bLueftung_bz = false
var boolean bLueftung_sz = false
var boolean bLueftung_kij = false
var boolean bLueftung_kiv = false

// Lüftungsautomatik
rule "Lüftungsautomatik"
when
    Item WZ_Vio changed or
    Item KU_Vio changed or
    Item WC_Vio changed or

    Item BZ_Vio changed or
    Item SZ1_Vio changed or
    Item SZ2_Vio changed or
    Item KIJ_Vio changed or
    Item KIV_Vio changed
then
    if(WZ_Vio.state == ON && bLueftung_wz == false && Rollershutter1.state == 100 && Lueftung.state == ON) { 
        bLueftung_wz = true
        Rollershutter1.sendCommand(UP)
        createTimer(now.plusSeconds(3)) [|
            Rollershutter1.sendCommand(STOP)
        ]
    } else if(WZ_Vio.state == OFF && bLueftung_wz == true && Rollershutter1.state == 50) { 
        bLueftung_wz = false
        Rollershutter1.sendCommand(DOWN)
    }

    else if(KU_Vio.state == ON && bLueftung_ku == false && Rollershutter3.state == 100 && Lueftung.state == ON) { 
        bLueftung_ku = true
        Rollershutter3.sendCommand(UP)
        createTimer(now.plusSeconds(4)) [|
            Rollershutter3.sendCommand(STOP)
        ]
    } else if(KU_Vio.state == OFF && bLueftung_ku == true && Rollershutter3.state == 50) { 
        bLueftung_ku = false
        Rollershutter3.sendCommand(DOWN)
    }

    else if(WC_Vio.state == ON && bLueftung_wc == false && Rollershutter4.state == 100 && Lueftung.state == ON) { 
        bLueftung_wc = true
        Rollershutter4.sendCommand(UP)
        createTimer(now.plusSeconds(4)) [|
            Rollershutter4.sendCommand(STOP)
        ]
    } else if(WC_Vio.state == OFF && bLueftung_wc == true && Rollershutter4.state == 50) { 
        bLueftung_wc = false
        Rollershutter4.sendCommand(DOWN)
    }

    else if(BZ_Vio.state == ON && bLueftung_bz == false && Rollershutter5.state == 100 && Lueftung.state == ON) { 
        bLueftung_bz = true
        Rollershutter5.sendCommand(UP)
        createTimer(now.plusSeconds(4)) [|
            Rollershutter5.sendCommand(STOP)
        ]
    } else if(BZ_Vio.state == OFF && bLueftung_bz == true && Rollershutter5.state == 50) { 
        bLueftung_bz = false
        Rollershutter5.sendCommand(DOWN)
    }

    else if(SZ1_Vio.state == ON && bLueftung_sz == false && Rollershutter6.state == 100 && Lueftung.state == ON) { 
        bLueftung_sz = true
        Rollershutter6.sendCommand(UP)
        createTimer(now.plusSeconds(5)) [|
            Rollershutter6.sendCommand(STOP)
        ]
    } else if(SZ1_Vio.state == OFF && SZ2_Vio.state == OFF && bLueftung_sz == true && Rollershutter6.state == 50) { 
        bLueftung_sz = false
        Rollershutter6.sendCommand(DOWN)
    }

    else if(SZ2_Vio.state == ON && bLueftung_sz == false && Rollershutter6.state == 100 && Lueftung.state == ON) { 
        bLueftung_sz = true
        Rollershutter6.sendCommand(UP)
        createTimer(now.plusSeconds(5)) [|
            Rollershutter6.sendCommand(STOP)
        ]
    } else if(SZ2_Vio.state == OFF && SZ1_Vio.state == OFF && bLueftung_sz == true && Rollershutter6.state == 50) { 
        bLueftung_sz = false
        Rollershutter6.sendCommand(DOWN)
    }

    else if(KIJ_Vio.state == ON && bLueftung_kij == false && Rollershutter7.state == 100 && Lueftung.state == ON) { 
        bLueftung_kij = true
        Rollershutter7.sendCommand(UP)
        createTimer(now.plusSeconds(6)) [|
            Rollershutter7.sendCommand(STOP)
        ]
    } else if(KIJ_Vio.state == OFF && bLueftung_kij == true && Rollershutter7.state == 50) { 
        bLueftung_kij = false
        Rollershutter7.sendCommand(DOWN)
    }

    else if(KIV_Vio.state == ON && bLueftung_kiv == false && Rollershutter8.state == 100 && Lueftung.state == ON) { 
        bLueftung_kiv = true
        Rollershutter8.sendCommand(UP)
        createTimer(now.plusSeconds(6)) [|
            Rollershutter8.sendCommand(STOP)
        ]
    } else if(KIV_Vio.state == OFF && bLueftung_kiv == true && Rollershutter8.state == 50) { 
        bLueftung_kiv = false
        Rollershutter8.sendCommand(DOWN)
    }
    
end

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

Re: Rule für Raffstores in Zwischenposition (Lüftung)

Beitrag von udo1toni »

Der Trick für schlanke wiederverwendbare Rules besteht darin, die beteiligten Items zum einen in Gruppen zusammenzufassen und zum anderen die Items geschickt zu benennen, damit man aus dem Namen des triggernden Items auf die Namen der zu steuernden Items rückschließen kann.

Einfaches Beispiel: Ich habe ein ungebundendes Item, mit welchem ich ein Licht einschalten will. Sagen wir, das Item heißt Schalter_1 und das Licht heißt Licht_1. Die Schalter sind in einer Gruppe gSchalter, die Lichter in einer Gruppe gLichter. Dann reicht eine Rule:

Code: Alles auswählen

rule "Schaltergruppe auf Lichtergruppe"
when
    Member of gSchalter received command
then
    gLichter.members.filter[i | 
        i.name.split("_").get(1) == triggeringItem.name.split("_").get(1)
    ].head.sendComand(receivedCommand)
end
Der Witz ist nun, dass es vollkommen egal ist, wieviele Items nun in den beiden Gruppen vorhanden sind, es gibt nur ein paar Bedingungen:
1. der jeweils 2. Teil des Itemnamens muss für Itempaare jeweils identisch sein
2. der 2. Teil des Namens muss innerhalb der Gruppe eindeutig sein
Statt 1 könnte da also auch Hugendubel oder SchroEder stehen, solange in beiden Gruppen jeweils exakt ein passendes Item zu finden ist, wird der Befehl jeweils an das passende weitergeleitet.

Für Deine Rule bedeutet dies, Du solltest die Namen der Rollläden Items anpassen. z.B. so:

Code: Alles auswählen

Group gShutter
Rollershutter Rollershutter_WZ_3  (gShutter) // Rollershutter1
Rollershutter Rollershutter_KU_4  (gShutter) // Rollershutter3
Rollershutter Rollershutter_WC_4  (gShutter) // Rollershutter4
Rollershutter Rollershutter_BZ_4  (gShutter) // Rollershutter5
Rollershutter Rollershutter_SZ_5  (gShutter) // Rollershutter6
Rollershutter Rollershutter_KIJ_6 (gShutter) // Rollershutter7
Rollershutter Rollershutter_KIV_6 (gShutter) // Rollershutter8

Group gVio
Switch WZ_Vio  (gVio)
Switch KU_Vio  (gVio)
Switch WC_Vio  (gVio)
Switch BZ_Vio  (gVio)
Switch SZ_Vio  (gVio)
Switch KIJ_Vio (gVio)
Switch KIV_Vio (gVio)

Group gLueftung
Switch Lueftung_WZ  (gLueftung) // statt Variable
Switch Lueftung_KU  (gLueftung) // statt Variable
Switch Lueftung_WC  (gLueftung) // statt Variable
Switch Lueftung_SZ  (gLueftung) // statt Variable
Switch Lueftung_KIJ (gLueftung) // statt Variable
Switch Lueftung_KIV (gLueftung) // statt Variable
Im Fall von SZ1 und SZ2 müsstest Du erläutern, was es damit auf sich hat. Da beide Schalter offensichtlich identisch wirken, sollte man die Schalter über eine Rule zu einem Schalter zusammenfassen (wird der eine Schalter betätigt, springt auch der 2. Schalter in die gleiche Stellung)

Nun reicht eine kleine Rule

Code: Alles auswählen

// Globale Variablen immer am Anfang der Datei definieren!
var GenericItem Shutter = null

// Lüftungsautomatik
rule "Lüftungsautomatik"
when
    Member of gVio changed
then
    var String strPart = triggeringItem.name.split("_").get(0)
    Shutter = gShutter.members.filter[i | i.name.split("_").get(1) == strPart].head
    var Luft = gLueftung.members.filter[i | i.name.split("_").get(1) == strPart].head
    var Integer nTime = Integer::parseInt(Shutter.name.split("_").get(2))

    if(triggeringItem.state == ON && Luft.state == OFF && Shutter.state == 100 && Lueftung.state == ON) { 
        Luft.postUpdate(ON)
        Shutter.sendCommand(UP)
        createTimer(now.plusSeconds(nTime)) [|
            Shutter.sendCommand(STOP)
        ]
    } else if(triggeringItem.state == OFF && Luft.state == ON && Shutter.state == 50) { 
        Luft.postUpdate(OFF)
        Shutter.sendCommand(DOWN)
    }
end
Die Rule extrahiert zunächst den eindeutigen Teil des Namens, der die anderen zu verwendenden Items bestimmt. In diesem Fall ist das der erste Teil des Namens bis zum _ (das Item, welches die Rule ausgelöst hat, steht als implizites Objekt triggeringItem zur Verfügung)
Nun bestimmt die Rule die beiden anderen Items und speichert sie in einem passenden Objekt. .head ist das erste Element einer Liste, .filter[] ergibt eine Liste von Elementen, die dem Filter entsprechen, .members sind alle unmittelbaren Member einer Gruppe.
Der Filterausdruck durchläuft die Liste und setzt jedes Item in das Objekt i ein (i vor dem |) Anschließend prüft er, ob der Ausdruck nach dem | zutrifft i.name -> der Name des Items als String, .split("_") -> string in mehrere Teilstrings zerlegen, Trennzeichen ist _ und taucht in der Liste der Teilstrings nicht auf, .get(1) liefert den 2. Teilstring zurück (der Index ist 0-basiert)
Nun wird noch die Variable nTime passend gesetzt.

Anschließend reicht der allgemein gefasste Code, um jedes Item eindeutig zu steuern.

Jetzt kommt allerdings ein großes ABER. Diese Art der Programmierung setzt voraus, dass immer nur ein Rollladen in Lüftungsposition gefahren wird, der verwendete Timer zum Stoppen des Ladens hat keine Kenntnis über das ursprünglich triggernde Item, und es gibt meines Wissens auch keinen Weg, diese Information zur Verfügung zu stellen.

Du kannst aber sehen, dass ich zu ein paar Tricks gegriffen habe. Zum Einen habe ich Items zur Zwischenspeicherung verwendet, da dies der effizienteste Weg ist, um den jeweiligen Namen abzubilden.
Zum Zweiten habe ich beim Namen der Rollershutter Items noch einen dritten Teil ergänzt, in dem ich die Laufzeit speichere. Das ist nicht sonderlich elegant, geht aber. Man könnte soetwas auch über Tags erledigen, das habe ich allerdings noch nicht ausprobiert.
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

curius
Beiträge: 78
Registriert: 1. Aug 2019 10:10
Answers: 0

Re: Rule für Raffstores in Zwischenposition (Lüftung)

Beitrag von curius »

Hallo udo1toni!

Perfekt - wie immer ;-)
Besten Dank für deine Unterstützung, da sind wieder einige Dinge dabei die ich so nicht kannte und die ich bei einigen meiner Rules umsetzen kann...
Einfach TOP !
:D

Schöne Grüße
Christian

Antworten