Seite 1 von 1

Wo ist der Fehler in meiner Rule?

Verfasst: 7. Jul 2022 09:54
von Grandlhuber
Habe mal wieder ein kleines Problem und komme nicht weiter. Habe diese Rule hier zum herunterfahren der Rollladen wenn es dunkel wird. Zudem werden je nach Sommer/Winter andere Rolladengruppen herunter gefahren:

Code: Alles auswählen

configuration: {}
triggers:
  - id: "1"
    configuration:
      event: END
      channelUID: astro:sun:local:set#event
    type: core.ChannelEventTrigger
conditions: []
actions:
  - inputs: {}
    id: "13"
    configuration:
      type: application/vnd.openhab.dsl.rule
      script: >-
        if(Dummy_alle_geschlossen.state == ON)
        return;

        if(now.getMonthValue >= 4 && now.getMonthValue() <= 9)
        Rolladen.members.forEach[ r | r.sendCommand(DOWN) Thread::sleep(900)]
        Dummy_alle_geschlossen.postUpdate(ON)

        else if(now.getMonthValue >= 10 && now.getMonthValue() <= 3)
        Rollladen_Winter.members.forEach[ r | r.sendCommand(DOWN) Thread::sleep(900)]
        Dummy_alle_geschlossen.postUpdate(ON)
        
    type: script.ScriptAction
So funktioniert die DSL-Rule. Ich möchte aber einen Timer mit einbauen. Mache ich dieses, funktioniert die Rule nicht mehr:

Code: Alles auswählen

if(Dummy_alle_geschlossen.state == ON)

return;

if(now.getMonthValue >= 4 && now.getMonthValue() <= 9)
createTimer(now.plusMinutes(10), [|
Rolladen.members.forEach[ r | r.sendCommand(UP) Thread::sleep(900)]
])
 
Dummy_alle_geschlossen.postUpdate(ON)

else if(now.getMonthValue >= 10 && now.getMonthValue() <= 3)
Rollladen_Winter.members.forEach[ r | r.sendCommand(DOWN) Thread::sleep(900)]
Dummy_alle_geschlossen.postUpdate(ON)
Frage an die Spezialisten: Wo ist hier der Fehler damit es mit dem createTimer nicht mehr geht?
Ich habe z.B. dieses hier und da funktioniert das auch mit dem Timer:

Code: Alles auswählen

if(Brunnen.state == ON)

return;

createTimer(now.plusMinutes(60), [|              

Brunnen.sendCommand(ON)

])
Oli

Re: Wo ist der Fehler in meiner Rule?

Verfasst: 7. Jul 2022 11:36
von udo1toni
Die Rule kann nicht funktionieren :), egal ob mit oder ohne Timer.
Deutlich wird das, wenn man die Rule etwas ordentlicher formatiert. Nur der relevante Teil:

Code: Alles auswählen

if(Dummy_alle_geschlossen.state == ON)
    return;
if(now.getMonthValue >= 4 && now.getMonthValue <= 9)
    Rolladen.members.forEach[ r | 
        r.sendCommand(DOWN)
        Thread::sleep(900)
    ]
Dummy_alle_geschlossen.postUpdate(ON)
else // <-------------------------------------------------- else ohne if!
    if(now.getMonthValue >= 10 && now.getMonthValue() <= 3) // a > 9 UND a < 4 niemals erfüllt!
        Rollladen_Winter.members.forEach[ r |
            r.sendCommand(DOWN)
            Thread::sleep(900)
        ]
Dummy_alle_geschlossen.postUpdate(ON)
if() als bedingte Verzweigung wirkt ausschließlich auf den nächsten Befehl. Damit ist Dummy_alle_geschlossen.postUpdate(ON) nicht Teil der bedingten Verzweigung. Entsprechend hat else auch kein vorgeordnetes if()
Eine Zahl (oder auch der Inhalt einer Variablen) kann niemals gleichzeitig größer als 9 UND kleiner als 4 sein.
Korrekt:

Code: Alles auswählen

if(Dummy_alle_geschlossen.state == ON)
    return;
if(now.getMonthValue > 3 && now.getMonthValue < 10) { // einfacher
    Rolladen.members.forEach[ r | 
        r.sendCommand(DOWN)
        Thread::sleep(900)
    ]
    Dummy_alle_geschlossen.postUpdate(ON)
} else
    if(now.getMonthValue > 9 || now.getMonthValue() < 4) { // einfacher
        Rollladen_Winter.members.forEach[ r |
            r.sendCommand(DOWN)
            Thread::sleep(900)
        ]
        Dummy_alle_geschlossen.postUpdate(ON)
    }
Die geschweiften Klammern definieren einen Block, der von if() als eine Anweisung betrachtet wird. Nun gibt es auch ein vorgeordnetes if() und else funktioniert. In der zweiten if() Anweisung heißt es nun der Wert muss entweder größer als 9 ODER kleiner als 4 sein.
Allerdings ist die zweite if-Anweisung unnötig, entweder wir befinden uns innerhalb oder außerhalb des Sommer-Fensters (1.4. - 30.9.)
Außerdem wird Dummy_alle_geschlossen.postUpdate(ON) auf jeden Fall ausgeführt, sollte also nicht Bestandteil des if-Blocks sein. Praktischerweise können nun die geschweiften Klammern auch wieder entfallen. now.getMonthValue wird zweimal abgefragt, also einfach in einer lokalen Konstanten speichern. Der fertige Codeblock ohne Timer:

Code: Alles auswählen

if(Dummy_alle_geschlossen.state == ON)
    return;
val Integer iMonth = now.getMonthValue 

if(iMonth > 3 && iMonth < 10)
    Rolladen.members.forEach[ r | 
        r.sendCommand(DOWN)
        Thread::sleep(900)
    ]
 else
    Rollladen_Winter.members.forEach[ r |
        r.sendCommand(DOWN)
        Thread::sleep(900)
    ]
Dummy_alle_geschlossen.postUpdate(ON)
Dein eigentliches Problem, das des Timers, ist allerdings noch ungelöst. Rein formal sollte der Timer funktionieren.
Es kann allerdings sein, dass Thread::sleep() in diesem Zusammenhang Probleme bereitet, weil es im Kontext des Lambdas definiert ist (sollte eigentlich keine Rolle spielen, aber trotzdem...).

Re: Wo ist der Fehler in meiner Rule?

Verfasst: 7. Jul 2022 14:21
von Grandlhuber
Hi!
Die Rule kann nicht funktionieren :), egal ob mit oder ohne Timer.
Komisch. Im Log von OpenHab gibt es keine Fehlermeldungen und die Rollladen fahren auch so runter wie sie sollen. Oder bezieht sich das nicht funktionieren auf den Sommer/Winter-Modus?

Dann erst mal danke für das Aufdröseln des Codes und dem erklären mit den Klammern. Da muss ich mal in mich gehen. Vielleicht verstehe ich dann irgendwann mal diese Sprache :) :idea: .
Dein eigentliches Problem, das des Timers, ist allerdings noch ungelöst. Rein formal sollte der Timer funktionieren.
Wäre es so richtig mit dem timer?

Code: Alles auswählen

if(Dummy_alle_geschlossen.state == ON)
    return;
val Integer iMonth = now.getMonthValue 

if(iMonth > 3 && iMonth < 10)
createTimer(now.plusMinutes(60), [|              
    Rolladen.members.forEach[ r | 
        r.sendCommand(DOWN)
        Thread::sleep(900)
  ]]) 
 else
    Rollladen_Winter.members.forEach[ r |
        r.sendCommand(DOWN)
        Thread::sleep(900)
    ]
Dummy_alle_geschlossen.postUpdate(ON)
Oli

Re: Wo ist der Fehler in meiner Rule?

Verfasst: 7. Jul 2022 14:42
von udo1toni
Ja, aber besser ist es, den Code (mindestens in der Testphase) ordentlich einzurücken:

Code: Alles auswählen

if(Dummy_alle_geschlossen.state == ON)
    return;
val Integer iMonth = now.getMonthValue 

if(iMonth > 3 && iMonth < 10)
    createTimer(now.plusMinutes(60), [|
        Rolladen.members.forEach[ r | 
            r.sendCommand(DOWN)
            Thread::sleep(900)
        ]
    ])
else
    Rollladen_Winter.members.forEach[ r |
        r.sendCommand(DOWN)
        Thread::sleep(900)
    ]
Dummy_alle_geschlossen.postUpdate(ON)
Einfach um zu erkennen, dass die erste schließende eckige Klammer zum Lambda des forEach gehört, während die zweite eckige Klammer zum Lambda des createTimer gehört (so wie auch die folgende schließend runde Klammer).
Man könnte den Code auch in eine einzige Zeile schreiben, mit jeweils einem Leerzeichen statt Zeilenumbruch, aber in dieser Form ist es doch wesentlich besser lesbar.

Re: Wo ist der Fehler in meiner Rule?

Verfasst: 8. Jul 2022 07:34
von Grandlhuber
Ok danke.

Habe ich die Klammern richtig verstanden (Habe sie der meiner Meinung nach in richtiger Reihenfolge eingefärbt):?

if(Dummy_alle_geschlossen.state == ON)
return;
val Integer iMonth = now.getMonthValue

if(iMonth > 3 && iMonth < 10)
createTimer(now.plusMinutes(60), [|
Rolladen.members.forEach[ r |
r.sendCommand(DOWN)
Thread::sleep(900)
]
])


else
Rollladen_Winter.members.forEach[ r |
r.sendCommand(DOWN)
Thread::sleep(900)
]
Dummy_alle_geschlossen.postUpdate(ON)
Konnte hier die Codeansicht mit dem Einrücken nicht aktivieren, da sonst die Einfärbungen weg wären :shock:

Kurz Frage: Was hat es eigentlich mit diesem " | " (ohne Gänsefüßchen) auf sich? Ist das dein angedeuteter Zeilenumbruch für den Code wie z.B. in VBA ( "& _")?

Oli

Re: Wo ist der Fehler in meiner Rule?

Verfasst: 8. Jul 2022 08:57
von udo1toni
Das ist nicht die Code-Ansicht, sondern ein Zitat. Innerhalb des Codes kannst Du hier keine Auszeichnungen vornehmen, da sie per Definition Bestandteil des Codes sind. Aber ja, die farbliche Zuordnung passt so.