Itemnamen aus Variablen zusammensetzen

Allgemeine Fragen rund um die "Smart Home" Hardware/Komponenten

Moderatoren: seppy, udo1toni

MISPEZI
Beiträge: 23
Answers: 0
Registriert: 16. Jan 2022 15:00

Itemnamen aus Variablen zusammensetzen

Beitrag von MISPEZI »

Hallo Zusammen,
mich beißt ein Problem zu dem ich so keine Lösung weiß.
Ich habe Rollosteuerung in der inzwischen 10 Rolläden integriert sind. Die eigendliche Fahrt wird jeweils von ESPs gesteuert, die per MQTT an mein OH 2.5 angeschlossen sind. Jedes Rollo läßt sich entweder manuell, nach voreingestellten Zeiten oder per Sonnenstand fahren. Dafür habe ich einen richtigen Rule-Djungel gebaut. Den möchte ich jetzt entflechten und zwar mit Gruppen.
Es gibt also zB. eine Steuerungsgruppe, eine Gruppe Auffahrbewegung und Abwärtsbewegung.
Wenn also ein Item der Steuerungsgruppe das zB. "RS_EGEZ_10_REGEL" heißt auf "Auf" getrigggert wird sollte das zugehörige Item in der Aufgruppe,
das dann "RS_EGEZ_10_DWRE" heißt mittels sendCommand(1) gesteuert werden.
Das Item der Steuerungsgruppe bekomme ich noch per filter, split und get zerlegt.
Allerdings weiß ich im Moment nicht wie ich das wieder zuammenbauen muß damit ich mein sendCommand nutzen kann.

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

Re: Itemnamen aus Variablen zusammensetzen

Beitrag von udo1toni »

Wenn Du mit gruppen arbeiten willst, ist es wichtig, die Itemnamen günstig zu wählen. Deine Beschreibung ist insgesamt aber etwas verwirrend (vielleicht nur für mich...)
Wie bestimmst Du, ob ein Laden öffnen, schließen oder die Position halten soll?
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

MISPEZI
Beiträge: 23
Answers: 0
Registriert: 16. Jan 2022 15:00

Re: Itemnamen aus Variablen zusammensetzen

Beitrag von MISPEZI »

Der Wert des Items "RS_EGEZ_10_REGEL" legt fest nach welcher Regel verfahren wird.
0 = manuell
1= Sonnensteuerung (Annahme: hier gesetzt)
2= Zeitsteuerung
in der Rule schaut ein Timecron nach ob die jeweiligen Zeiten errrreicht sind. (Annahme hier: Sonnenuntergangszeit)
Ist das der Fall werden alle REGEL-Items befragt ob sie den Wert 1 besitzen.
Wenn das so ist bekommen die zugerörigen Items, hier also das Item "RS_EGEZ_10_DWRE" den Wert 1.
Der wird per MQTT an das betreffende ESP-Modul im entsprechenden Rollo gegeben und das ESP entscheidet dann was zu tun ist.
Im Moment habe ich pro Rollo eine Rule für die Fahrbewegungen - also 10x das gleiche, nur mit andern Items.
Dazu eine Rule für die Zeitenermittlung und eine für die Steuerung. In dieser wird als "Bandwurm" über einzelne if-Zweige jeder Regelzustand abgefragt.

Das wollte ich jetzt etwas eleganter gestalten.
Dafür habe ich zB. die Gruppen "gRS_REGEL" mit "RS_EGEZ_10_REGEL" als Member und "gRS_DWRE" mit "RS_EGEZ_10_DWRE" als Member erstellt.
In der neuen Rule soll dann etwa folgendes passieren:

Code: Alles auswählen

rule "Zufahren mit Sonnensteuerung"
    when
        Item Auswahl_Steuerung changed to 1 // Schließzeit erreicht
    then
        gRS_REGEL.members.filter[i|i.state == 1]
        .forEach[j|
        var Myname = j.name
        var teil1 = Myname.split("_").get(0)  // das müßte Art sein  // RS
        var teil2 = Myname.split("_").get(1)  // das müßte Einbauort // EGEZ
        var teil3 = Myname.split("_").get(2)  // das müßte die Nummer sein // 10
        sendCommand(teil1 + "_" + teil2 + "_" + teil3 + "_DWRE",1)  // und das geht nicht, wegen der 1
        ]
end
Es müßte die Form [Item].sendCommand(1) haben - wahrscheinlich habe ich die Namen unglücklich gewählt...
Ich würde auch gern den Code in so einem schicken Fenster darstellen, weiß aber noch nicht wie das geht :roll:
Danke dir trotzdem für die promte Antwort

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

Re: Itemnamen aus Variablen zusammensetzen

Beitrag von udo1toni »

Wenn Du im Editor unten die Schaltfläche "Vollständiger Editor" oder "Vorschau" klickst (je nachdem, in welchem Kontext der Editor aufgerufen wurde...) erhältst Du oberhalb des Eingabefensters Knöpfe, mit denen Du die Steuercodes einfügen lassen kannst. Das funktioniert auch für bestehende Texte (Textblock markieren und gewünschtes Format klicken).
Du kannst die Tags aber auch einfach mit dazu schreiben. Tags werden in eckigen Klammern geschrieben [] und dann gibt es Schlüsselworte, für Code z.B. "code" :) Das Ende wird mit dem gleichen Tag versehen, nur steht dann vor dem Schlüsselwort noch ein /, also z.B. [/code]. Da hier bisher kein öffnendes Tag vorkam, wird das Schlüsselwort auch angezeigt, juhu...
Es handelt sich hier um BBCode, genaue Erläuterungen dazu unter diesem Link.

Kannst Du mal einen Regelsatz für einen Rollladen anzeigen, also so, wie er momentan ist?
MISPEZI hat geschrieben: 22. Jan 2022 10:02 In der neuen Rule soll dann etwa folgendes passieren:

Code: Alles auswählen

sendCommand(teil1 + "_" + teil2 + "_" + teil3 + "_DWRE",1)  // und das geht nicht, wegen der 1
Es müßte die Form [Item].sendCommand(1) haben - wahrscheinlich habe ich die Namen unglücklich gewählt...
Du verwendest die Action sendCommand(string,string). Diese erwartet als Parameter zwei Strings. 1 ist kein String. Du kannst also leicht

Code: Alles auswählen

sendCommand(teil1 + "_" + teil2 + "_" + teil3 + "_DWRE","1")
schreiben, aber eleganter ist es, aus der zweiten Gruppe das passende Item herauszusuchen:

Code: Alles auswählen

rule "Zufahren mit Sonnensteuerung"
when
    Item Auswahl_Steuerung changed to 1 // Schließzeit erreicht
then
    gRS_REGEL.members.filter[i|i.state == 1].forEach[j|
        val StringBuilder strName = new StringBuilder    // die "ordentliche" Art, einen String zusammenzusetzen ;)
        val Myname = j.name.split("_")                   // eine Liste
        strName.append(Myname.get(0))
        strName.append("_")
        strName.append(Myname.get(1))
        strName.append("_")
        strName.append(Myname.get(2))
        gRS_DWRE.members.filter[k|
            k.name.startsWith(strName.toString)
        ].head.sendCommand(1)                            // .head -> das erste Item der Ergebnisliste
    ]
end
was ich immer noch nicht verstanden habe, ist, wie die eigentliche Steuerung abläuft. Das Item RS_EGEZ_10_REGEL gibt es für jeden Rollladen? Das Item RS_EGEZ_10_DWRE gibt es ebenfalls für jeden Rollladen? Aber wo kommt da sie Steuerung ins Spiel? Hast Du die Schaltzeiten jeweils im ESP hinterlegt? Das bedeutet dann ja, dass Du (Gruppensteuerung mal außen vor gelassen) für jeden Rollladen einzeln die Zeiten eingeben musst? Die Sonnenstandssteuerung erfolgt auch vom ESP? Und openHAB teilt dem ESP lediglich mit, in welchem Modus der Laden gesteuert wird? Dafür bräuchte es dann doch überhaupt keine Rule, Du müsstest lediglich das Regel-Item mit dem entsprechenden Channel verbinden.

Meine Rollläden werden alle absolut positioniert (neun Stück ebenfalls per ESP8266, mit Tasmota im Rollershutter Mode, weitere 20 über knx). Ich habe dann Regeln, welche zur bestimmten Uhrzeit die Läden verfahren.

Hätte ich also einen Schalter, mit dem ich zwischen Manuell, Zeit- und Sonnenstandsautomatik umschaltete, sähe die Sonnenuntergangsregel bei mir so aus:

Code: Alles auswählen

rule "Zufahren mit Sonnensteuerung"
when
    Channel 'astro:sun:local:civilDusk#event' triggered START // Sonnenuntergang, bürgerliche Dämmerung
then
    gRS_Position.members.filter[i|
        var String strName = i.name.split("_").get(0) + "_"
        strName = strName + i.name.split("_").get(1) + "_"
        strName = strName + i.name.split("_").get(2) + "_"
        gRS_REGEL.members.filter[j|j.name.startsWith(strName)].head.state == 1
    ].forEach[k|
        k.sendCommand(100) // Rollladen schließen
    ]
end
Die Rule filtert aus allen Rollladensteuerungen diejenigen Items heraus, deren Pendant aus der Betriebsartwahl den Status 1 aufweist. Ich filtere also andersrum.
Ich bräuchte für diesen Ansatz dann eine Regel pro Automatik-Zeitpunkt. Ich habe keine Deaktivierung der Automatik vorgesehen, allerdings habe ich dann doch an einer Stelle so etwas nachgerüstet, falls wir mal Übernachtungsgäste im Wohnzimmer haben, damit die dann nicht von sieben Rollladenmotoren geweckt werden. Das ist aber nur in den entsprechenden Regeln drin, die potentiell davon betroffen sind, also alle Öffnungszeiten vor 9 Uhr. Danach haben die Kinder eh dafür gesorgt, dass alle wach sind...

Ich habe meine Itemnamen außerdem anders aufgebaut, so dass der identifizierende Teil des Namens (also der, anhand derer eine Rule Paare aus Items aus zwei Gruppen bilden kann) immer ein einziger Teilstring ist, der am ende oder am Anfang des Itemnamens steht. Deshalb benötige ich weder StringBuilder noch Zusammensetzen von Teilstrings :)
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

MISPEZI
Beiträge: 23
Answers: 0
Registriert: 16. Jan 2022 15:00

Re: Itemnamen aus Variablen zusammensetzen

Beitrag von MISPEZI »

Danke dir.
also dann: Hier eine Rollosteuerung:

Code: Alles auswählen

// Variablen für die Rollosteuerung R10
var Integer R10_UP_Time = 28      // Fahrzeit nach oben in Sec
var Integer R10_DW_Time = 23      // Fahrzeit nach unten in Sec
var Number R10_T_Step                // Schrittzähler
var Timer R10_UP_Timer = null       // Timer für Hochfahren
var Timer R10_DW_Timer = null       // Timer für Runterfahren
var Integer R10_LWT_OFF = 1         // Zähler für Off-Schleife
var Number R10_LWT_ON
//-- Regel für das Rollo im Flur R10
rule "R10-Normalsteuerung per Rollershutter-Item"
when
    Item RS_EGEZ_10_ALL received command   // Hoch, Stop oder Runter
then
    switch(receivedCommand.toString.toUpperCase) {
        case "UP" : {                     // es wurde Hoch gewählt
            RS_EGEZ_10_ALL.postUpdate(25)
            RS_EGEZ_10_UPTA.sendCommand(1)
        }  
        case "STOP": {
            // Prüfen ob Rollo fährt, damit nicht versehendlich Fahrt ausgelöst wird
            if (RS_EGEZ_10_ESP.state == 100) {  //ESP fährt
                RS_EGEZ_10_UPTA.sendCommand(1) //Kurzes Signal für Stopp
                Thread::sleep(500)
                RS_EGEZ_10_UPTA.sendCommand(0)
            }
        }
        case "DOWN": {                       // es wurde runter gewählt
            RS_EGEZ_10_ALL.postUpdate(75)
            RS_EGEZ_10_DWTA.sendCommand(1)
        }  
    }
end

// Regel 1 Übermittlung aller Werte von OH an ESP
rule "R10 - ESP schickt 100 (braucht Position)"
    when 
        Item RS_EGEZ_10_FAK changed to 100   //ESP fragt ob OH da ist
    then 
        RS_EGEZ_10_FAK.postUpdate(60)       // Zurücksetzen der Meldung 
        logInfo("R10-Down","Übermittlung von ESP bei OH angefragt (FAKTOR=100)")
        RS_EGEZ_10_OUT.sendCommand("event,openhabControl=101")                   // OH liefer Werte
        Thread::sleep(1000)
        RS_EGEZ_10_OUT.sendCommand("event,ShutterControl=" + R10_T_Step.toString) // Sende Wert
        logInfo("R10-Down","Übermittlung Rollostand: " + R10_T_Step.toString)
        RS_EGEZ_10_OUT.sendCommand("event,ShutterUpTime=" + R10_UP_Time.toString) // Sende Wert            
        logInfo("R10-Down","Übermittlung UP_Time: " + R10_UP_Time.toString)
        RS_EGEZ_10_OUT.sendCommand("event,ShutterDwTime=" + R10_DW_Time.toString) // Sende Wert            
        logInfo("R10-Down","Übermittlung DW_Time: " + R10_DW_Time.toString)
        RS_EGEZ_10_FAK.postUpdate(102)       // Dialogende setzten 
end 

// Regel 2 --- ESP sendet Rollostand
rule "R10 - ESP sendet Rollostand"
    when
        Item RS_EGSZ_10_RS changed          // ESP sendet neuen Rollostand
    then 
        R10_T_Step = RS_EGSZ_10_RS.state as Number // Rolloposition übernehmen
        logInfo("R10-Sendebetrieb","ESP hat Rollostand " + R10_T_Step.toString + " gesendet")
        sendTelegram("bot1", "R10 - Rollostandänderung auf: "+ R10_T_Step.toString + " durch ESP")
        //if (R10_T_Step > 9) {          // Rollo unten
        //    R10_T_Step = 10
        //}
        //if (R10_T_Step < 1) {          // Rollo oben
        //    R10_T_Step = 0
        //}
        RS_EGEZ_10_ALL.postUpdate(R10_T_Step * 10)    // % an sitemap
end 

// Regel 3 - OH-Neustart
rule "R10 - OH war down"
    when 
        System started         // wenn OH neu startet oder Rule neugelesen
    then 
        R10_T_Step = RS_EGSZ_10_RS.state as Number     //T_Step aus Datenbank
        logInfo("Werte Rollostand aus Datenbank","R10_T-Step " + R10_T_Step.toString)
        RS_EGEZ_10_ALL.postUpdate(R10_T_Step * 10)    // % an sitemap
end                 

// Regel 4 - Hochfahren abschalten und ggf. wiederholen
rule "R10 - UP-Befehl erhalten"
    when
        Item RS_EGEZ_10_UPTA changed to 1  // Befehl UP gegeben
    then 
        Thread::sleep(500)              // warte 500 millis
        RS_EGEZ_10_UPTA.sendCommand(0)     // Abschalten ==> nur Impuls erforderlich
        if (RS_EGSZ_10_LWT.state == "OFFLINE" && RS_EGEZ_10_REGEL.state != 0) { // R10 ist OFFLINE und nicht mauell
            if (R10_UP_Timer !== null) R10_UP_Timer.cancel
            R10_UP_Timer = createTimer(now.plusSeconds(60), [ | //Timer auf eine Minute
                RS_EGEZ_10_UPTA.sendCommand(1)   // Hochfahren erneut starten
                logInfo("R10-Befehlwiederholung","Timer wiederholt Fahrbefehl")
            ])        
        }
end
// Regel 5 - Runterfahren abschalten und ggf. wiederholen
rule "R10 - DW-Befehl erhalten"
    when
        Item RS_EGEZ_10_DWTA changed to 1  // Befehl DW gegeben
    then 
        Thread::sleep(500)              // warte 500 millis
        RS_EGEZ_10_DWTA.sendCommand(0)     // Abschalten ==> nur Impuls erforderlich
        if (RS_EGSZ_10_LWT.state == "OFFLINE" && RS_EGEZ_10_REGEL.state != 0) {  // R10 ist OFFLINE und nicht mauell
            if (R10_LWT_OFF < 11) {           // 10 Versuche zugelassen
                R10_LWT_OFF = R10_LWT_OFF + 1
                if (R10_DW_Timer !== null) R10_DW_Timer.cancel
                R10_DW_Timer = createTimer(now.plusSeconds(60), [ | //Timer auf eine Minute
                    RS_EGEZ_10_DWTA.sendCommand(1)   // Runterfahren erneut starten
                    logInfo("R10-Befehlwiederholung","Timer wiederholt Fahrbefehl")
                ])        
            }
            else {
        //        R10_LWT_OFF = 1  ==> das geht so nicht
                logInfo("R10-Befehlswiederholung"," nach 10 Versuchen abgebrochen")     
                sendTelegram("bot1", "R10 ist dauerhaft OFFLINE, bitte prüfen")
                Echo_Text.sendCommand("R10 ist dauerhaft OFFLINE, bitte prüfen") // Text der gesagt werden soll
            }
        }
end

dazu brauchst du noch den Auslöser: (die Teile mit gRS_REGEL ist die Zukunft :D )

Code: Alles auswählen

// ---- Fahrregel für die Rollos
// Aufahren mit Zeitsteuerung
rule "Auffahren mit Zeitsteuerung"
    when
        Item Auswahl_Steuerung changed to 1
    then
        gRS_REGEL.members.filter[i|i.state == 1]
        .forEach[j|
        var Myname = j.name
        var teil1 = Myname.split("_").get(0)  // das müßte Art sein
        var teil2 = Myname.split("_").get(1)  // das müßte Einbauort
        var teil3 = Myname.split("_").get(2)  // das müßte die Nummer sein
        sendCommand(teil1 + "_" + teil2 + "_" + teil3 + "_ALL","UP")
        ]

           
// MyGroup.members.filter[i|i.name.contains("Living") && i.getStateAs(OnOffType) != OFF].forEach[j|j.sendCommand(OFF)]

        if (Regel_Flur.state == 2) {
            logInfo("R1-Steuerung", "Zeisteuerung fährt hoch")
            DG_R1_GPIO14.sendCommand(1)
        }
        if (Regel_AZ.state == 2) {
            logInfo("R2-Steuerung", "Zeisteuerung fährt hoch")
            AZ_R2_GPIO14.sendCommand(1)
        }
        if (Regel_KU_FE.state == 2) {
            logInfo("R3-Steuerung", "Zeitsteuerung fährt hoch")
            KU_R3_GPIO14.sendCommand(1)
        }
        if (Regel_KU_TR.state == 2) {
            logInfo("R4-Steuerung", "Zeitsteuerung fährt hoch")
            KU_R4_GPIO14.sendCommand(1)
        }
        if (Regel_KL_NO.state == 2) {
            logInfo("R5-Steuerung", "Zeitsteuerung fährt hoch")
            DG_R5_GPIO14.sendCommand(1)
        }
        if (Regel_KL_WE.state == 2) {
            logInfo("R6-Steuerung", "Zeitsteuerung fährt hoch")
            DG_R6_GPIO14.sendCommand(1)
        }
        if (Regel_GR_LI.state == 2) {
            logInfo("R7-Steuerung", "Zeitsteuerung fährt hoch")
            DG_R7_GPIO14.sendCommand(1)
        }
        if (Regel_GR_RE.state == 2) {
            logInfo("R8-Steuerung", "Zeitsteuerung fährt hoch")
            DG_R8_GPIO14.sendCommand(1)
        }
        if (Regel_SZ.state == 2) {
            logInfo("R9-Steuerung", "Zeitsteuerung fährt hoch")
            DG_R9_GPIO14.sendCommand(1)
        }
        Auswahl_Steuerung.postUpdate(0)
end

// Zufahren mit Zeitsteuerung
rule "Zufahren mit Zeitsteuerung"
    when
        Item Auswahl_Steuerung changed to 2
    then
        gRS_REGEL.members.filter[i|i.state == 2]
        .forEach[j|
        var Myname = j.name
        var teil1 = Myname.split("_").get(0)  // das müßte Art sein
        var teil2 = Myname.split("_").get(1)  // das müßte Einbauort
        var teil3 = Myname.split("_").get(2)  // das müßte die Nummer sein
        sendCommand(teil1 + "_" + teil2 + "_" + teil3 + "_ALL","DOWN")
        ]
        if (Regel_Flur.state == 2) {
            logInfo("R1-Steuerung", "Zeisteuerung fährt runter")
            DG_R1_TA_DW.sendCommand(1)
        }
        if (Regel_AZ.state == 2) {
            logInfo("R2-Steuerung", "Zeisteuerung fährt runter")
            AZ_R2_TA_DW.sendCommand(1)
        }
        if (Regel_KU_FE.state == 2) {
            logInfo("R3-Steuerung", "Zeitsteuerung fährt runter")
            KU_R3_TA_DW.sendCommand(1)
        }
        if (Regel_KU_TR.state == 2) {
            logInfo("R4-Steuerung", "Zeitsteuerung fährt runter")
            KU_R4_TA_DW.sendCommand(1)
        }
        if (Regel_KL_NO.state == 2) {
            logInfo("R5-Steuerung", "Zeitsteuerung fährt runter")
            DG_R5_TA_DW.sendCommand(1)
        }
        if (Regel_KL_WE.state == 2) {
            logInfo("R6-Steuerung", "Zeitsteuerung fährt runter")
            DG_R6_TA_DW.sendCommand(1)
        }
        if (Regel_GR_LI.state == 2) {
            logInfo("R7-Steuerung", "Zeitsteuerung fährt runter")
            DG_R7_TA_DW.sendCommand(1)
        }
        if (Regel_GR_RE.state == 2) {
            logInfo("R8-Steuerung", "Zeitsteuerung fährt runter")
            DG_R8_TA_DW.sendCommand(1)
        }
        if (Regel_SZ.state == 2) {
            logInfo("R9-Steuerung", "Zeitsteuerung fährt runter")
            DG_R9_TA_DW.sendCommand(1)
        }
        Auswahl_Steuerung.postUpdate(0)
end

// Aufahren mit Sonnensteuerung
rule "Auffahren mit Sonnensteuerung"
    when
        Item Auswahl_Steuerung changed to 3
    then
        gRS_REGEL.members.filter[i|i.state == 1]
        .forEach[j|
        var Myname = j.name
        var teil1 = Myname.split("_").get(0)  // das müßte Art sein
        var teil2 = Myname.split("_").get(1)  // das müßte Einbauort
        var teil3 = Myname.split("_").get(2)  // das müßte die Nummer sein
        sendCommand(teil1 + "_" + teil2 + "_" + teil3 + "_ALL","UP")
        ]
        if (Regel_Flur.state == 1) {
            logInfo("R1-Steuerung", "Sonnensteuerung fährt hoch")
            DG_R1_GPIO14.sendCommand(1)
        }
        if (Regel_AZ.state == 1) {
            logInfo("R2-Steuerung", "Sonnensteuerung fährt hoch")
            AZ_R2_GPIO14.sendCommand(1)
        }
        if (Regel_KU_FE.state == 1) {
            logInfo("R3-Steuerung", "Sonnensteuerung fährt hoch")
            KU_R3_GPIO14.sendCommand(1)
        }
        if (Regel_KU_TR.state == 1) {
            logInfo("R4-Steuerung", "Sonnensteuerung fährt hoch")
            KU_R4_GPIO14.sendCommand(1)
        }
        if (Regel_KL_NO.state == 1) {
            logInfo("R5-Steuerung", "Sonnensteuerung fährt hoch")
            DG_R5_GPIO14.sendCommand(1)
        }
        if (Regel_KL_WE.state == 1) {
            logInfo("R6-Steuerung", "Sonnensteuerung fährt hoch")
            DG_R6_GPIO14.sendCommand(1)
        }
        if (Regel_GR_LI.state == 1) {
            logInfo("R7-Steuerung", "Sonnensteuerung fährt hoch")
            DG_R7_GPIO14.sendCommand(1)
        }
        if (Regel_GR_RE.state == 1) {
            logInfo("R8-Steuerung", "Sonnensteuerung fährt hoch")
            DG_R8_GPIO14.sendCommand(1)
        }
        if (Regel_SZ.state == 1) {
            logInfo("R9-Steuerung", "Sonnensteuerung fährt hoch")
            DG_R9_GPIO14.sendCommand(1)
        }
        Auswahl_Steuerung.postUpdate(0)
end

// Zufahren mit Sonnensteuerung
rule "Zufahren mit Sonnensteuerung"
    when
        Item Auswahl_Steuerung changed to 4
    then
        gRS_REGEL.members.filter[i|i.state == 1]
        .forEach[j|
        var Myname = j.name
        var teil1 = Myname.split("_").get(0)  // das müßte Art sein
        var teil2 = Myname.split("_").get(1)  // das müßte Einbauort
        var teil3 = Myname.split("_").get(2)  // das müßte die Nummer sein
        sendCommand(teil1 + "_" + teil2 + "_" + teil3 + "_ALL","DOWN")
        ]
        if (Regel_Flur.state == 1) {
            logInfo("R1-Steuerung", "Sonnensteuerung fährt runter")
            DG_R1_TA_DW.sendCommand(1)
        }
        if (Regel_AZ.state == 1) {
            logInfo("R2-Steuerung", "Sonnensteuerung fährt runter")
            AZ_R2_TA_DW.sendCommand(1)
        }
        if (Regel_KU_FE.state == 1) {
            logInfo("R3-Steuerung", "Sonnensteuerung fährt runter")
            KU_R3_TA_DW.sendCommand(1)
        }
        if (Regel_KU_TR.state == 1) {
            logInfo("R4-Steuerung", "Sonnensteuerung fährt runter")
            KU_R4_TA_DW.sendCommand(1)
        }
        if (Regel_KL_NO.state == 1) {
            logInfo("R5-Steuerung", "Sonnensteuerung fährt runter")
            DG_R5_TA_DW.sendCommand(1)
        }
        if (Regel_KL_WE.state == 1) {
            logInfo("R6-Steuerung", "Sonnensteuerung fährt runter")
            DG_R6_TA_DW.sendCommand(1)
        }
        if (Regel_GR_LI.state == 1) {
            logInfo("R7-Steuerung", "Sonnensteuerung fährt runter")
            DG_R7_TA_DW.sendCommand(1)
        }
        if (Regel_GR_RE.state == 1) {
            logInfo("R8-Steuerung", "Sonnensteuerung fährt runter")
            DG_R8_TA_DW.sendCommand(1)
        }
        if (Regel_SZ.state == 1) {
            logInfo("R9-Steuerung", "Sonnensteuerung fährt runter")
            DG_R9_TA_DW.sendCommand(1)
        }
        Auswahl_Steuerung.postUpdate(0)
end

// --- Regeln für Steuerung Küchenfenster mit HUE-Dimmer-Schalter
rule "Küchenfensterrollo auffahren"
    when 
        Channel "hue:0820:ecb5fa84df30:36:dimmer_switch_event" triggered 1002.0  //Taste mit Strich
    then 
        KU_R3_GPIO14.sendCommand(1)
end 
rule "Küchenfensterrollo zufahren"
    when 
        Channel "hue:0820:ecb5fa84df30:36:dimmer_switch_event" triggered 4002.0  //Taste mit O
    then 
        KU_R3_TA_DW.sendCommand(1)
end 
// --- Regeln für Steuerung Küchentür mit HUE-Dimmer-Schalter
rule "Küchentürrollo auffahren"
    when 
        Channel "hue:0820:ecb5fa84df30:36:dimmer_switch_event" triggered 2002.0  //Taste mit großer Sonne
    then 
        KU_R4_GPIO14.sendCommand(1)
end 
rule "Küchentürrollo zufahren"
    when 
        Channel "hue:0820:ecb5fa84df30:36:dimmer_switch_event" triggered 3002.0  //Taste kleiner Sonne
    then 
        KU_R4_TA_DW.sendCommand(1)
end 

// --- Regeln für Steuerung Großes Zimmer LINKS mit HUE-Dimmer-Schalter
rule "Linkes Rollo auffahren"
    when 
        Channel "hue:0820:ecb5fa84df30:40:dimmer_switch_event" triggered 1002.0  //Taste mit Strich
    then 
        DG_R7_GPIO14.sendCommand(1)
end 
rule "Linkes Rollo zufahren"
    when 
        Channel "hue:0820:ecb5fa84df30:40:dimmer_switch_event" triggered 4002.0  //Taste mit O
    then 
        DG_R7_TA_DW.sendCommand(1)
end 
// --- Regeln für Steuerung Großes Zimmer RECHTS HUE-Dimmer-Schalter
rule "Rechtes Rollo auffahren"
    when 
        Channel "hue:0820:ecb5fa84df30:40:dimmer_switch_event" triggered 2002.0  //Taste mit großer Sonne
    then 
        DG_R8_GPIO14.sendCommand(1)
end 
rule "Linkes Rollo zufahren"
    when 
        Channel "hue:0820:ecb5fa84df30:40:dimmer_switch_event" triggered 3002.0  //Taste kleiner Sonne
    then 
        DG_R8_TA_DW.sendCommand(1)
end 



//----Regeln für Alexa (Workarount)
// Furrollo
rule "Alexa ändert Flurrollozustand"
    when 
        Item AL_DG_FL_FE changed 
    then 
        if (AL_DG_FL_FE.state == 100) {
            DG_FL_FE.sendCommand(DOWN)
        }    
        else if (AL_DG_FL_FE.state == 0) {
            DG_FL_FE.sendCommand(UP)
        }
        else 
            DG_FL_FE.sendCommand(STOP)
end 
// Arbeitszimmerrollo
rule "Alexa ändert Flurrollozustand"
    when 
        Item AL_EG_AZ_FE changed 
    then 
        if (AL_EG_AZ_FE.state == 100) {
            EG_AZ_FE.sendCommand(DOWN)
        }    
        else if (AL_EG_AZ_FE.state == 0) {
            EG_AZ_FE.sendCommand(UP)
        }
        else 
            EG_AZ_FE.sendCommand(STOP)
end 
// Küchenfensterrollo
rule "Alexa ändert Küchenfensterrollozustand"
    when 
        Item AL_EG_KU_FE changed 
    then 
        if (AL_EG_KU_FE.state == 100) {
            EG_KU_FE.sendCommand(DOWN)
        }    
        else if (AL_EG_KU_FE.state == 0) {
            EG_KU_FE.sendCommand(UP)
        }
        else 
            EG_KU_FE.sendCommand(STOP)
end 
// Küchentürrollo
rule "Alexa ändert Küchentürrollozustand"
    when 
        Item AL_EG_KU_TR changed 
    then 
        if (AL_EG_KU_TR.state == 100) {
            EG_KU_TR.sendCommand(DOWN)
        }    
        else if (AL_EG_KU_TR.state == 0) {
            EG_KU_TR.sendCommand(UP)
        }
        else 
            EG_KU_TR.sendCommand(STOP)
end 
// Kleines Zimmer Nord
rule "Alexa ändert kleines Zimmer Nord Rollozustand"
    when 
        Item AL_DG_KL_NO changed 
    then 
        if (AL_DG_KL_NO.state == 100) {
            DG_KL_NO.sendCommand(DOWN)
        }    
        else if (AL_DG_KL_NO.state == 0) {
            DG_KL_NO.sendCommand(UP)
        }
        else 
            DG_KL_NO.sendCommand(STOP)
end 
// Kleines Zimmer Nord
rule "Alexa ändert kleines Zimmer West Rollozustand"
    when 
        Item AL_DG_KL_WE changed 
    then 
        if (AL_DG_KL_WE.state == 100) {
            DG_KL_WE.sendCommand(DOWN)
        }    
        else if (AL_DG_KL_WE.state == 0) {
            DG_KL_WE.sendCommand(UP)
        }
        else 
            DG_KL_WE.sendCommand(STOP)
end 

// Großes Zimmer LINKS
rule "Alexa ändert großes Zimmer LINKS Rollozustand"
    when 
        Item AL_DG_GR_LI changed 
    then 
        if (AL_DG_GR_LI.state == 100) {
            DG_GR_LI.sendCommand(DOWN)
        }    
        else if (AL_DG_GR_LI.state == 0) {
            AL_DG_GR_LI.sendCommand(UP)
        }
        else 
            AL_DG_GR_LI.sendCommand(STOP)
end 
// Großes Zimmer RECHTS
rule "Alexa ändert großes Zimmer RECHTS Rollozustand"
    when 
        Item AL_DG_GR_RE changed 
    then 
        if (AL_DG_GR_RE.state == 100) {
            DG_GR_RE.sendCommand(DOWN)
        }    
        else if (AL_DG_GR_RE.state == 0) {
            AL_DG_GR_RE.sendCommand(UP)
        }
        else 
            AL_DG_GR_RE.sendCommand(STOP)
end 

// Schlafzimmer
rule "Alexa ändert Schlafzimmerrollozustand"
    when 
        Item AL_DG_SZ changed 
    then 
        if (AL_DG_SZ.state == 100) {
            DG_SZ.sendCommand(DOWN)
        }    
        else if (AL_DG_SZ.state == 0) {
            AL_DG_SZ.sendCommand(UP)
        }
        else 
            AL_DG_SZ.sendCommand(STOP)
end 

und den Trigger für die Auswahl: (hier ist die rule "Anstoss der Fahrbewegungen" die wichtige)

Code: Alles auswählen

// Regeln für die Rollosteuerung
var Number Auf_So_h
var Number Auf_So_m
var Number Zu_So_h = 0
var Number Zu_So_m
var Number Auf_akt_minuten
var Number Zu_akt_minuten = 481
var Number Zu_last_minuten = 0
var Number Auf_h = 0
var Number Auf_m = 0
var Number Zu_h = 0
var Number Zu_m = 0
var String zwischen
var String Ausgabe
var Number zw1 = 0
var Number zw2 = 0
var Number zw3 = 0
var Number zw4 = 0
var Number zw5 = 0
var Number zw0
//zum testen
var Number STD_Auf
var Number MIN_Auf
var String Ausg

rule "Startrule"
when
    System started 
then
// Helfer ausschalten 
    MyHelper.postUpdate(OFF) 
    MyHelper1.postUpdate(OFF)
// Regelschalter setzen
    zw0 = Regel_Flur.state as Number 
    zw1 = zw0.intValue
    Regel_Flur.postUpdate(zw1)
    zw0 = Regel_AZ.state as Number 
    zw1 = zw0.intValue
    Regel_AZ.postUpdate(zw1)
    zw0 = Regel_KU_FE.state as Number 
    zw1 = zw0.intValue
    Regel_KU_FE.postUpdate(zw1)
    zw0 = Regel_KU_TR.state as Number 
    zw1 = zw0.intValue
    Regel_KU_TR.postUpdate(zw1)
    zw0 = Regel_KL_NO.state as Number 
    zw1 = zw0.intValue
    Regel_KL_NO.postUpdate(zw1)
    zw0 = Regel_KL_WE.state as Number 
    zw1 = zw0.intValue
    Regel_KL_WE.postUpdate(zw1)
    zw0 = Regel_GR_LI.state as Number 
    zw1 = zw0.intValue
    Regel_GR_LI.postUpdate(zw1)
    zw0 = Regel_GR_RE.state as Number 
    zw1 = zw0.intValue
    Regel_GR_RE.postUpdate(zw1)
    zw0 = Regel_SZ.state as Number 
    zw1 = zw0.intValue
    Regel_SZ.postUpdate(zw1)
    
    // Zeitsteuerung setzen 
    if (Start_WECKER_H.state as Number == NULL) Start_WECKER_H.postUpdate(5)
    if (Start_WECKER_M.state as Number == NULL) Start_WECKER_M.postUpdate(0)
    if (End_WECKER_H.state as Number == NULL) End_WECKER_H.postUpdate(12)
    if (End_WECKER_M.state as Number == NULL) End_WECKER_M.postUpdate(0)
  logInfo("Werte abfrage nach Neustart","Aufzeitkorrektur Sonnenzeit " + Auf_Korrek.state.toString)
  logInfo("Werte abfrage nach Neustart","Aufzeit Stundenanteil Sonnenzeit " + Auf_h_It.state.toString)
  logInfo("Werte abfrage nach Neustart","Aufzeit Minutenanteil Sonnenzeit " + Auf_m_It.state.toString)
  logInfo("Werte abfrage nach Neustart","Zuzeitkorrektur Sonnenzeit " + Zu_Korrek.state.toString)
  logInfo("Werte abfrage nach Neustart","Zuzeit Stundenanteil Sonnenzeit " + Zu_h_It.state.toString)
  logInfo("Werte abfrage nach Neustart","Zuzeit Minutenanteil Sonnenzeit " + Zu_m_It.state.toString)
    Auswahl_Steuerung.postUpdate(0)
// Sonnensteuerung setzen
   //Abweichungen setzen
    zw0 = Auf_Korrek.state as Number
    Auf_Korrek.postUpdate(zw0)
    zw0 = Zu_Korrek.state as Number
    Zu_Korrek.postUpdate(zw0)

   //----- Auf_h und Auf_m bestimmen
    Auf_h = Auf_h_It.state as Number 
    Auf_m = Auf_m_It.state as Number 
    Zu_h = Zu_h_It.state as Number 
    Zu_m = Zu_m_It.state as Number 
    //---- errechneten Werte ausgeben
    STD_Auf =((Auf_h_It.state as DecimalType).floatValue)
    MIN_Auf =((Auf_m_It.state as DecimalType).floatValue)
    if (Auf_m < 10) {
        Ausgabe = String::format("%.0f:0%.0f",STD_Auf,MIN_Auf)
    }
    else {
        Ausgabe = String::format("%.0f:%.0f",STD_Auf,MIN_Auf)
    }
    Auf_Startzeit.postUpdate(Ausgabe)
    STD_Auf =((Zu_h_It.state as DecimalType).floatValue)
    MIN_Auf =((Zu_m_It.state as DecimalType).floatValue)
    if (Zu_m < 10) {
        Ausgabe = String::format("%.0f:0%.0f",STD_Auf,MIN_Auf)
    }
    else {
        Ausgabe = String::format("%.0f:%.0f",STD_Auf,MIN_Auf)
    }
    Zu_Startzeit.postUpdate(Ausgabe)
    zw2 = Auf_Korrek.state as Number 
    zw4 = Zu_Korrek.state as Number 
    zw1 = Auf_m 
    zw3 = Zu_m 
end

// Zurücksetzten der Abweichungswerte
rule "Werte zurücksetzen"
when 
    Item Anz_korr_Startzeit changed to ON
then           
    var str = Sunrise_Time.state.toString
    var newValue1 = transform("REGEX", "s/(.{11})(.{2})/$2/g*", str)
    var newValue2 = transform("REGEX", "s/(.{2})(.{15})/$1/g*", newValue1)
    Auf_h = Integer::parseInt(newValue2)
    newValue1 = transform("REGEX", "s/(.{14})(.{2})/$2/g*", str)
    var newValue3 = transform("REGEX", "s/(.{2})(.{12})/$1/g*", newValue1)
    Auf_m = Integer::parseInt(newValue3)
    logInfo("Rücksetzter Ermittlung Sonnenaufgang","Stunde: "+ Auf_h + " Min: " + Auf_m)
   //----- Zu_h und Zu_m bestimmen
    str = Sunset_Time.state.toString
    newValue1 = transform("REGEX", "s/(.{11})(.{2})/$2/g*", str)
    newValue2 = transform("REGEX", "s/(.{2})(.{15})/$1/g*", newValue1)
    Zu_h = Integer::parseInt(newValue2)
    newValue1 = transform("REGEX", "s/(.{14})(.{2})/$2/g*", str)
    newValue3 = transform("REGEX", "s/(.{2})(.{12})/$1/g*", newValue1)
    Zu_m = Integer::parseInt(newValue3)
    logInfo("Rücksetzter Ermittlung Sonnenuntergang","Stunde: "+ Zu_h + " Min: " + Zu_m)
    zw1 = Auf_m
    zw3 = Zu_m
    Auf_Korrek.postUpdate(0)
    Zu_Korrek.postUpdate(0)
    Anz_korr_Startzeit.postUpdate(OFF)
        // Werte in Datenbank schreiben
    Auf_h_It.postUpdate(Auf_h)
    Auf_m_It.postUpdate(Auf_m)
    Zu_h_It.postUpdate(Zu_h)
    Zu_m_It.postUpdate(Zu_m)
    //---- errechneten Werte ausgeben
    STD_Auf =((Auf_h_It.state as DecimalType).floatValue)
    MIN_Auf =((Auf_m_It.state as DecimalType).floatValue)
    if (Auf_m < 10) {
        Ausgabe = String::format("%.0f:0%.0f",STD_Auf,MIN_Auf)
    }
    else {
        Ausgabe = String::format("%.0f:%.0f",STD_Auf,MIN_Auf)
    }
    Auf_Startzeit.postUpdate(Ausgabe)
    STD_Auf =((Zu_h_It.state as DecimalType).floatValue)
    MIN_Auf =((Zu_m_It.state as DecimalType).floatValue)
    if (Zu_m < 10) {
        Ausgabe = String::format("%.0f:0%.0f",STD_Auf,MIN_Auf)
    }
    else {
        Ausgabe = String::format("%.0f:%.0f",STD_Auf,MIN_Auf)
    }
    Zu_Startzeit.postUpdate(Ausgabe)
end 

//---- Regeln für die Zeitsteuerung -------
rule "Zeitsteuerung - Zeiten berechnen"
    when 
        Item Start_WECKER_H changed or  
        Item End_WECKER_H changed or 
        Item Start_WECKER_M changed or 
        Item End_WECKER_M changed
    then 
        Auf_akt_minuten = Start_WECKER_H.state as Number * 60 + Start_WECKER_M.state as Number - 240 //Berechnung Startzeit
        Zu_akt_minuten = End_WECKER_H.state as Number * 60 + End_WECKER_M.state as Number - 720 //Berechnung Endzeit
end 

rule "Zeitsteuerung - Werte übernehmen"
    when 
        Item MyHelper changed to ON 
    then 
        logInfo("Rollosteuerung","Manuelle Zeitberechnung abgeschlossen")
        logInfo("Rollosteuerung","AUF Timervorlauf beträgt: {} Minten",Auf_akt_minuten)
        logInfo("Rollosteuerung","ZU Timervorlauf beträgt: {} Minten",Zu_akt_minuten)
        MyHelper.postUpdate(OFF)
end 

rule "Anstoss der Fahrbewegungen"
    when 
        Time cron "0 0/1 * 1/1 * ? *"  //minütliche Abfrage
    then 
    //----- fahren mit Zeitsteuerung
        if ((now.getHourOfDay() == Start_WECKER_H.state as Number) && 
           (now.getMinuteOfHour == Start_WECKER_M.state as Number)) {  //Startzeit erreicht 
           Auswahl_Steuerung.postUpdate(1)
            logInfo("Zeitabhängige Rollosteuerung","Öffnungszeit erreicht")
        }
        if ((now.getHourOfDay() == End_WECKER_H.state as Number) && 
           (now.getMinuteOfHour ==  End_WECKER_M.state as Number)) {   //Endzeit erreicht 
           Auswahl_Steuerung.postUpdate(2)
            logInfo("Zeitabhängige Rollosteuerung","Schließzeit erreicht")
        }
    //------ fahren mit Sonnensteuerung    
        if ((now.getHourOfDay() == Auf_h) && 
           (now.getMinuteOfHour == Auf_m)) {     //Sonnenaufgang korrigiert 
           Auswahl_Steuerung.postUpdate(3)
            logInfo("Sonnenabhängige Rollosteuerung","Öffnungszeit erreicht")
        }
        if ((now.getHourOfDay() == Zu_h) && 
           (now.getMinuteOfHour ==  Zu_m)) {   //Sonnenuntergang korrigiert 
           Auswahl_Steuerung.postUpdate(4)
            logInfo("Sonnenabhängige Rollosteuerung","Schließzeit erreicht")
        }
// Test für Alexa
//Echo_Text.sendCommand("Ich wurde von Peter programmiert") // Text der gesagt werden soll
end 

//----- Regeln für die Sonnensteuerung

rule "trigger Sonnenaufgang"
    when
        Channel 'astro:sun:local:rise#event' triggered END  //Sonnenaufgang
    then
        // Berechnungen durchführen
        Auf_h = now.getHourOfDay()
        Auf_m = now.getMinuteOfHour + Auf_Korrek.state as Number 
        if (Auf_m > 0 ) {   // Es besteht eine Korrekturzeit > 0
            while (Auf_m >= 60) {
                Auf_h = Auf_h + 1
                Auf_m = Auf_m - 60
            }
        }
        if (Auf_m < 0 ) {   // Es besteht eine Korrekturzeit < 0
            while (Auf_m < 0) {
                Auf_h = Auf_h - 1
                Auf_m = 60 + Auf_m
            }
        }
        zw1 = Auf_m
        MyHelper1.sendCommand(ON)
        logInfo("Sonnensteuerung","neue Aufgangszeit korrigiert ist " + Auf_h +":"+ Auf_m )
    //---- errechneten Werte ausgeben
        STD_Auf =Auf_h.floatValue
        MIN_Auf =Auf_m.floatValue
        if (Auf_m < 10) {
            Ausgabe = String::format("%.0f:0%.0f",STD_Auf,MIN_Auf)
        }
        else {
            Ausgabe = String::format("%.0f:%.0f",STD_Auf,MIN_Auf)
        }
        Auf_Startzeit.postUpdate(Ausgabe)
end

rule "trigger Sonnenuntergang"
    when
        Channel 'astro:sun:local:set#event' triggered END  //Sonnenuntergang
        //Item Overrule1 changed to ON 
    then
        // Berechnungen durchführen
        Zu_h = now.getHourOfDay()
        Zu_m = now.getMinuteOfHour + Zu_Korrek.state as Number 
        if (Zu_m > 0 ) {   // Es besteht eine Korrekturzeit > 0
            while (Zu_m >= 60) {
                Zu_h = Zu_h + 1
                Zu_m = Zu_m - 60
            }
        }    
        if (Zu_m < 0 ) {   // Es besteht eine Korrekturzeit > 0
            while (Zu_m < 0) {
                Zu_h = Zu_h - 1
                Zu_m = 60 + Zu_m
            }
        }    
        zw3 = Zu_m
        MyHelper1.sendCommand(ON)
        logInfo("Sonnensteuerung","neue Untergangszeit korrigiert ist " + Zu_h +":"+ Zu_m )
        // Berechnungen ausgeben
        STD_Auf = Zu_h.floatValue
        MIN_Auf = Zu_m.floatValue
        if (Zu_m < 10) {
            Ausgabe = String::format("%.0f:0%.0f",STD_Auf,MIN_Auf)
        }
        else {
            Ausgabe = String::format("%.0f:%.0f",STD_Auf,MIN_Auf)
        }
        Zu_Startzeit.postUpdate(Ausgabe)
end

rule "Sonnenzeit Auf-Abweichung ändert sich"
    when 
        Item Auf_Korrek changed  
    then 
        if (Auf_Korrek.state > zw2 ) {                      //zählt hoch
            zw1 = zw1 + 10
//        Sonderfall 1 : Wert geht über 60
            if (zw1 >= 60) {
//                Anz_korr_Startzeit.postUpdate(zw1.toString)
                zw1 = zw1 - 60
                Auf_h = Auf_h +1
            }       
        }    
        if (Auf_Korrek.state < zw2 ) {                      //zählt runter
            zw1 = zw1 - 10
//       Sonderfall 2 : 0-Durchgang von Oben
            if (zw1 < 0) {
//                Anz_korr_Startzeit.postUpdate(zw1.toString)
                zw1 = 60 + zw1 
                Auf_h = Auf_h - 1
            }
        }
        zw2 = Auf_Korrek.state as Number 
    //---- errechneten Werte ausgeben
        STD_Auf = Auf_h.floatValue
        MIN_Auf =zw1.floatValue
        if (zw1 < 10) {
            Ausgabe = String::format("%.0f:0%.0f",STD_Auf,MIN_Auf)
        }
        else {
            Ausgabe = String::format("%.0f:%.0f",STD_Auf,MIN_Auf)
        }
        Auf_Startzeit.postUpdate(Ausgabe)
end 

rule "Sonnenzeit Zu-Abweichung"
    when 
        Item Zu_Korrek changed  
    then 
        if (Zu_Korrek.state > zw4 ) {                      //zählt hoch
            zw3 = zw3 + 10
//        Sonderfall 1 : Wert geht über 60
            if (zw3 >= 60) {
                zw3 = zw3 - 60
                Zu_h = Zu_h +1
            }       
        }    
        if (Zu_Korrek.state < zw4 ) {                      //zählt runter
            zw3 = zw3 - 10
//       Sonderfall 2 : 0-Durchgang von Oben
            if (zw3 < 0) {
                zw3 = 60 + zw3 
                Zu_h = Zu_h - 1
            }
        }
        zw4 = Zu_Korrek.state as Number
        // Berechnungen ausgeben
        STD_Auf =Zu_h.floatValue
        MIN_Auf =zw3.floatValue
        if (zw3 < 10) {
            Ausgabe = String::format("%.0f:0%.0f",STD_Auf,MIN_Auf)
        }
        else {
            Ausgabe = String::format("%.0f:%.0f",STD_Auf,MIN_Auf)
        }
        Zu_Startzeit.postUpdate(Ausgabe)
end 

rule "Sonnenzeitabweichung übernehmen"
    when 
        Item MyHelper1 changed to ON 
    then     
        logInfo("Rollosteuerung","Sonnenzeitberechnung abgeschlossen")
        logInfo("Rollosteuerung","AUF Aktion startet um: "+ Auf_h.toString +":"+ zw1.toString)
        logInfo("Rollosteuerung","ZU Aktion startet um: "+ Zu_h.toString +":"+ zw3.toString)
        Auf_m = zw1
        Zu_m = zw3
        MyHelper1.sendCommand(OFF)
        // Werte in Datenbank schreiben
        Auf_h_It.postUpdate(Auf_h)
        Auf_m_It.postUpdate(Auf_m)
        Zu_h_It.postUpdate(Zu_h)
        Zu_m_It.postUpdate(Zu_m)
end 

Die Festlegung welches Rollo wie fahren soll wird in der Admin-Sitemap festgelegt.

Ich hoffe, ich hab dich jetzt nicht erst richtig verwirrt. Ich weiß das man einiges besser und anders machen kann...

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

Re: Itemnamen aus Variablen zusammensetzen

Beitrag von udo1toni »

:o


Oh.

Mein.

Gott.

:o

Wäre es nicht einfacher, ein komplettes Betriebssystem samt GUI zu schreiben? /Sarkasmus aus/ ;)

Was nutzt Du denn für eine Hardware? Ich habe z.B. die Sonoff T1 2Ch verbaut. Zwei Taster (Sensorbedienung, na ja...) und zwei Relais. Mit Tasmota geflasht, Betriebsart auf Rollershutter gesetzt, parametriert (gegenseitige Verriegelung der Relais, Laufzeit hoch, Laufzeit runter, Korrekturfaktor für Mittelposition). Danach reicht ein Rollershutter Channel, um den Rolladen mittels UP,DOWN,STOP sowie den Zahlen 0 - 100 wie gewünscht zu steuern. Bis dahin keine einzige Zeile Code in openHAB.

Ich nutze für die Sonnenstandssteuerung die bürgerliche Dämmerung mit fix im Channel hinterlegten Zeiten für den frühesten und spätesten Zeitpunkt sowie den Versatz zum echten Zeitpunkt. Passt bei uns zu 99%, lediglich das Wetter hat dann noch Einfluss (wolkenlos, wolkig, Regen...) auf die Helligkeit zum Fahrzeitpunkt, damit können wir aber gut leben.
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

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

Re: Itemnamen aus Variablen zusammensetzen

Beitrag von udo1toni »

Ergänzung:

Ich denke, ein Großteil der Komplexität Deiner Rules rührt daher, dass Du die Steuerung über unterschiedliche Items erledigst. Du solltest Dir eine Methode überlegen, wie Du einen einzelnen Rollladen über ein paar Rules so abgebildet bekommst, dass Du nur ein Rollershutter Item für diesen Rollladen brauchst. Jegliche Steuerung erfolgt dann ausschließlich über dieses Rollershutter Item.

Wenn Du also an dieses Rollershutter Item den Befehl UP sendest, greift eine Rule zu, die diesen Befehl erkennt, prüft ob der Laden gerade fährt, bei Bedarf den Laden anhält und anschließend die Fahrt startet. Diese Rule kümmert sich dabei aber um alle Einzelheiten der Steuerung, also z.B. Sende 1 und nach 500 mSec 0.
Dieselbe(!) Rule kümmert sich dann auch um DOWN und STOP (so wie Deine Rule "R10-Normalsteuerung per Rollershutter-Item"

So wie es aussieht, hast Du die Itemnamen ja schon ganz gut aufgebaut. Ich habe oben ja erläutert, dass ich es bevorzuge, den Geräte identifizierenden Teil als einen Teilstring zu haben. Die "echten" Steueritems können dann alle in eine Gruppe, über den Identifier kann man den Rollladen selektieren, über die Endung, welchen Teil des Geräts man ansprechen möchte.
Möchte man in diesem Zusammenhang mit Timern arbeiten, wird es etwas komplexer, man muss dann zu einem Array greifen, welches für alle Rollläden dimensioniert ist. Weiterhin braucht man dann vermutlich noch Hashmaps, um innerhalb der Timer die korrekten Namen erzeugen zu können, denn der Timer läuft unabhängig von der startenden Rule und hat keine Kenntnis, welches Item eine Aktion getriggert hat. Ist aber alles lösbar...

Auch so eine Sache: Du prüfst (vermutlich aus der Not geboren), ob das Gerät OFFLINE ist. Da das LWT unmittelbar umschaltet, brauchst Du dazu keine Zähler oder Ähnliches. Schau einfach, ob Offline gemeldet wird und logge das, unternimm erst gar keinen Versuch, den Laden zu steuern.
Oder hast Du die Erfahrung gemacht, dass das Gerät trotz Offline auf Befehle reagiert? das wäre eher nicht so gut...
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

MISPEZI
Beiträge: 23
Answers: 0
Registriert: 16. Jan 2022 15:00

Re: Itemnamen aus Variablen zusammensetzen

Beitrag von MISPEZI »

Ich danke dir vielmals für die schnelle und umfassende Antwort.
Es war mir schon klar, dass das nicht der einfachste Weg war ;) , aber ich bastle nun mal gerne. Meine Steuerungselemente sind ESP8266 mit ESPEASY geflasht. Das hat den Scharm, dass man dort eigene rules schreiben kann. Die ESP,s steuern handelsübliche 2Relaismodule zusätzlich sind noch Taster für die "Handsteuerung" angeschlossen, die in den alten Wicklerkästen untergebracht sind.
In einigen Fällen ging das nicht, da habe ich HUE-Taster angebunden. Die Platinen für das Ganze sind selbstgebaut.
was ich immer noch nicht verstanden habe, ist, wie die eigentliche Steuerung abläuft. Das Item RS_EGEZ_10_REGEL gibt es für jeden Rollladen? Das Item RS_EGEZ_10_DWRE gibt es ebenfalls für jeden Rollladen? Aber wo kommt da sie Steuerung ins Spiel?
Die führende Instanz ist das OH (deshalb holen sich die ESP's nach deren Neustart die Informationen Rollostand, Fahrzeit Auf und Fahrzeit Ab dort ab).
Nur wenn das OH ausfällt fragt es die ESP's ab welchen Rollostand sie haben. Ansosten übertragen die ESP's nach Fahrt ihren Rollostand.
Die Werte werden dann in einer RR4DJ-Datenbank festgehalten und stehen nach einen Systemausfall zur Verfügung.

Ich kann im OH über die Regel-Items für jedes Rollo festlegen ob es vom Sonnenstand (mit Korrekturzeit), mit fester Zeitsteuerung oder manuell betrieben wird. Also ja RS_EGZ_10_REGEL gibt es als RS_DGKZ_9_REGEL usw. für jedes Rollo ebenso wie die Down, Up und Kommunikations-Items.
Hier kommt deiner Bemerkung
ch habe meine Itemnamen außerdem anders aufgebaut, so dass der identifizierende Teil des Namens (also der, anhand derer eine Rule Paare aus Items aus zwei Gruppen bilden kann) immer ein einziger Teilstring ist, der am ende oder am Anfang des Itemnamens steht. Deshalb benötige ich weder StringBuilder noch Zusammensetzen von Teilstrings
eine besondere Bedeutung für mich zu! Hast du dazu mal ein Beispiel?
Wenn ich das Problem schon angehe möchte ich mir das Leben auch ein wenig einfacher machen :) und ich habe erkannt, dass Namen wichtig sind.

MISPEZI
Beiträge: 23
Answers: 0
Registriert: 16. Jan 2022 15:00

Re: Itemnamen aus Variablen zusammensetzen

Beitrag von MISPEZI »

Auch so eine Sache: Du prüfst (vermutlich aus der Not geboren), ob das Gerät OFFLINE ist. Da das LWT unmittelbar umschaltet, brauchst Du dazu keine Zähler oder Ähnliches. Schau einfach, ob Offline gemeldet wird und logge das, unternimm erst gar keinen Versuch, den Laden zu steuern.
Oder hast Du die Erfahrung gemacht, dass das Gerät trotz Offline auf Befehle reagiert? das wäre eher nicht so gut...
Ha, da gibt es alle möglichen Schweinereien... LWT ist soweit ich weiss ja die Kommunikation ESP - MQTT. Da hatte ich der Tat die Situation eines häufigen Ausfalls in Milli-Bereich. Deshalb die Wiederholungen. Dann hab ich aber festgestellt bei bestimmten Situationen ist es tatsächlich so, dass der ESP noch steuerbar ist obwohl LWT OFFLINE ist. Ich kann ihn dann per Brouser und natürlich mit den angeschlossenen Tastern steuern. Mit viel Pech funkt mit dann der MQTT-Befehl vom OH dazwischen wenn er wieder ONLINE geht. Deshalb der Versuch der Begenzung der Versuche. Ist aber auch nicht sooo toll.

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

Re: Itemnamen aus Variablen zusammensetzen

Beitrag von udo1toni »

MISPEZI hat geschrieben: 22. Jan 2022 14:22 Hier kommt deiner Bemerkung

ch habe meine Itemnamen außerdem anders aufgebaut, so dass der identifizierende Teil des Namens (also der, anhand derer eine Rule Paare aus Items aus zwei Gruppen bilden kann) immer ein einziger Teilstring ist, der am ende oder am Anfang des Itemnamens steht. Deshalb benötige ich weder StringBuilder noch Zusammensetzen von Teilstrings

eine besondere Bedeutung für mich zu! Hast du dazu mal ein Beispiel?
Na, zum Beispiel habe ich Raumtemperaturregler bei mir, da folgen die Item dem Namensschema

Code: Alles auswählen

//Temperaturen ist
Number TS2plusBadEG_TempIs  "BadEG ist"        (GHeat_Is,GTempEG) {channel="knx:device:bridge:GiraTSplus1_1_120:tempIs"}
//Temperaturen soll
Number TS2plusBadEG_TempSet "BadEG soll"       (GHeat_Soll)       {channel="knx:device:bridge:GiraTSplus1_1_120:tempSet"}
//RTR Betriebsart ist
Number TS2plusBadEG_OpMode  "Betriebsart ist"  (GHeat_Mode)       {channel="knx:device:bridge:GiraTSplus1_1_120:opMode"}
//RTR Betriebsart soll
Number TS2plusBadEG_OpSet   "Betriebsart soll" (GHeat_Set)        {channel="knx:device:bridge:GiraTSplus1_1_120:opSet"}
//RTR Heat
Switch TS2plusBadEG_Heat    "Heizen"           (HeatingNow)       {channel="knx:device:bridge:GiraTSplus1_1_120:heat"}
Jeder Typ ist in einer eigenen Gruppe (Ist-Temperatur in zwei Gruppen, weil eine davon der Darstellung in einem Graphen dient).
Ich habe insgesamt neun Heizkreise, weil wir keine Fußbodenheizung haben :) ein hydraulischer Abgleich ist somit eine Herausforderung. Stattdessen hat jeder Raum seinen eigenen RTR. Nun gibt es in knx mit dem verwendeten Tastsensor von Gira das Problem, dass die Betriebsart über ein Byte gesteuert wird, welches aber anders funktioniert als die Rückmeldung des Zustands der Betriebsart. Also brauche ich eine Rule, mit der beides aneinander angeglichen wird:

Code: Alles auswählen

rule "Betriebsart RTR"
 when
    Member of GHeat_Mode changed
 then
    var Integer newMode 
    val mode = (triggeringItem.state as DecimalType).toBigDecimal.toBigInteger
    val iName = triggeringItem.name.split("_").get(0).toString
    logDebug("rtr","Name is: {}, Mode is: {}", iName, mode)
    switch (mode) {
        case mode.testBit(0) : newMode = 1
        case mode.testBit(2) : newMode = 3
        case mode.testBit(3) : newMode = 4
        default : newMode = 2
    }
    val myItem = GHeat_Set.members.filter[ f | f.name.startsWith(iName) ].head
    var Integer oldMode = 0
    if(myItem.state instanceof Number) oldMode = (myItem.state as Number).intValue
    if(oldMode != newMode) {
        logDebug("rtr","Name is: {}, oldMode is: {}, newMode is: {}", myItem.name, oldMode, newMode)
        myItem.postUpdate(newMode)
    }	
end
GHeat_Mode enthält alle Items, die die aktuelle Betriebsart zurückmelden. Ändert sich eines davon, triggert die Rule. in der lokalen Konstanten mode wird der Status gespeichert, und zwar als BigInteger. Dieses Format bringt die Funktion testBit() mit, welche ich im Verlauf der Rule verwende.
Aus dem Namen des Triggernden Items extrahiere ich den ersten Teilstring, der zum Identifizieren des RTR ausreicht (wie oben zu sehen, handelt es sich sogar um den Klartextnamen des Raums)
Per switch(mode) teste ich die Bits ab. Der RTR liefert über die Bits die verschiedenen Betriebsarten und Betriebszustände, das ist Heizen/Kühlen, aber auch Komfort, Nachtabsenkung, Standby und Frostschutz. Die letzten vier Bits sind dabei die interessanten. mode enthält also eine Zahl x + 1, x + 2, x + 4 oder x + 8, wobei x ohne Rest durch 16 teilbar ist. Es ist auf jeden Fall eines der Bits gesetzt. Falls aber irgendwo was schief geht, (z.B. ist kein gültiger Status vorhanden) soll die Rule dennoch ein eindeutiges Ergebnis liefern, entsprechend habe ich als default Wert hier 2 genommen.
Mein Item in der Steuerung sendet 1,2,3 oder 4 (das sind die Steuerwerte, die der RTR erwartet, entsprechend Bit 0, 1, 2 und 3... ;)
Nach dem switch suche ich aus der Gruppe das passende Item heraus, welches zum Steuern des RTR gedacht ist. das gehört natürlich der Gruppe GHeat_Set an und der erste Teilstring ist identisch mit dem, den ich oben extrahiert habe.
Jetzt ermittle ich den aktuellen Status. Falls das Item noch nicht initialisiert ist, bekommt es den Status 0.
Danach prüfe ich, ob der aktuelle Status vom neuen Status abweicht, und falls das der Fall ist, setze ich den Status entsprechend.

Die log-Befehle geben nur dann einen Output, wenn ich den Log-Level auf Debug setze (das geht im laufenden Betrieb für jeden Logger einzeln...)
openHAB4.3.3 stable in einem Debian-Container (bookworm) (Proxmox 8.3.5, LXC), mit openHABian eingerichtet

Antworten