Seite 1 von 2

Rule läuft manchmal nicht !

Verfasst: 1. Okt 2020 21:19
von Baumtasche
Hallo zusammen,

ich bin noch relativ neu in der Materie Openhab, deswegen kann es sein, dass meine Frage für euch vielleicht lächerlich ist.
Ich habe seid Tagen ein Problem das ich nicht lösen kann. Ich habe eine Rule die vom Lichtwert eines Lichtsensors ausgelöst wird. Diese funktioniert aber komischerweise nur, wenn ich kurz vorher eine Änderung und wenn sich auch noch so unbedeutend ist (z.B. Kommentar einfügen) vornehme.
Konkret sieht das so aus. Die Helligkeit fällt unter 10, es passiert nichts, ich nehme eine Änderung vor, und bei nächsten Zyklus, wo der Lichtsensor erneut eine Helligkeit unter 10 misst, funktioniert die rule :cry: .
Um einen Zufall auszuschließen habe ich das jetzt über 3 Tage beobachtet und getestet.

Wenn man eine Änderung in der Rule vornimmt dann erscheint im LOG

19:07:58.942 [INFO ] [del.core.internal.ModelRepositoryImpl] - Loading model 'Rollo.rules'
19:08:07.755 [INFO ] [del.core.internal.ModelRepositoryImpl] - Refreshing model 'Rollo.rules'

Sieht fast so aus, dass durch die Änderung erst die rule geladen wird und deswegen dann funktioniert.
Ich habe auch berücksichtigt das Openhab nur 5 rules gleichzeitig bearbeiten kann, aber ich aber nur zwei rules, die auf den Lichtsensor reagieren, also daran kann es auch nicht liegen, oder?
Ich hoffe einer von euch, hat einen guten Tipp für mich , ich verzweifle schon :oops:



Anbei ein Auszug aus der rule

Code: Alles auswählen


rule "React on Aktuelle Helligkeit (Lichtsensor_1_CurrentIllumination) change/update"

when
   Item Lichtsensor_Aussen changed 
then
    if((Lichtsensor_Aussen.state as Number)  < 10)  { 
            Rollo_Bad_Level.sendCommand(100)
            Thread::sleep(15000)
            Rollo_SchlafzKleider_Level.sendCommand(100)
            Thread::sleep(7000) 
            Rollo_SchlafzGarage_Level.sendCommand(100)
            Thread::sleep(2000)
            Rollo_SchlafzBalkon_Level.sendCommand(32)
            Thread::sleep(3000)
......

Re: Rule läuft manchmal nicht !

Verfasst: 1. Okt 2020 21:44
von peter-pan
...also mal abgesehen davon, dass das mit dem "Thread::sleep(xxxx)" suboptimal ist, bist du dir sicher, dass der Vergleich richtig ist ? Wie sieht denn das Item aus ?

Vielleicht hilft:

Code: Alles auswählen

if((Lichtsensor_Aussen.state as Number).floatValue  < 10)

Re: Rule läuft manchmal nicht !

Verfasst: 1. Okt 2020 22:04
von Baumtasche
ja, ich bin mir sicher da sie eigentlich funktioniert, sobald ich eine Änderung mache, auch wenn ich die Änderung wieder zurücknehme. Es sieht so aus, das durch die Änderung die rule bei Openhab erst bekannt wird.
Zum besseren Verständnis, wenn die Helligkeit z.B auf 9 fällt, passiert nichts, ich mache eine Änderung, die Helligkeit fällt weiter auf 8 und dann funktioniert es :cry:

Warum ist das mit dem Thread::sleep(xxxx) suboptimal? Ich will nicht das alle Rollos gleichzeitig runtergehen, sie sollen versetzt runtergehen, gibt es da eine bessere Lösung?

Re: Rule läuft manchmal nicht !

Verfasst: 1. Okt 2020 22:19
von peter-pan
Das geht mit einem Timer sicher besser, da kann dir vielleicht @udo1toni einiges dazu sagen bzw. du suchst hier mal im Forum nach "createTimer".
Baumtasche hat geschrieben: 1. Okt 2020 22:04 ja, ich bin mir sicher da sie eigentlich funktioniert
Das kann man nun so oder so sehen, denn eigentlich funktioniert sie ja nicht ;)

Re: Rule läuft manchmal nicht !

Verfasst: 1. Okt 2020 22:41
von hannahgrf
Wie du ja schon gesagt hast, kann openHAB nur 5 parallel bearbeiten. Um nun die Lichteinstellung zu ändern, brauchst du einen Timer. Den stellst du mit time cron + create timer ein. Anschließend gibst du die Bedingungen für den Timer ein.

Re: Rule läuft manchmal nicht !

Verfasst: 1. Okt 2020 23:07
von OliverCJ
Nur mal so als Idee (auch wenn Du das nicht möchtest): Lass doch mal die Thread:sleep weg. Dann gehen halt mal alle Rollos gleichzeitig runter. Aber dann weißt Du zumindest, ob die Rule ansonsten so funktioniert wie sie soll. Kannst du nachher immer noch wieder einbauen,
Außerdem wäre es wahrscheinlich hilfreich, die Rule tatsächlich komplett zu posten und nicht mit "..." den weiteren Verlauf anzudeuten. Könnte ja sein, dass in dem weggelassenen Teil noch ein Fehler ist...

Re: Rule läuft manchmal nicht !

Verfasst: 2. Okt 2020 06:58
von udo1toni
Also, die Rule ist ja nun nicht vollständig, insofern ist die Schwere Deines Vergehens nicht abschätzbar ;) aber Deine Aussage, dass Du ja "nur zwei Rules" hast, welche auf das Item Lichtsensor_Aussen reagieren, und deshalb könnte die grenze von fünf gleichzeitig laufenden Rules nicht überschritten sein, zeigt, dass Du noch nicht vollständig verstanden hast, wie openHAB funktioniert.

Eine Rule (eine!) kann theoretisch hunderte Male gleichzeitig ausgeführt werden, wenn sie nur oft genug getriggert wird und lang genug läuft (und man die Anzahl gleichzeitig ausführbarer Rules entsprechend hochgesetzt hat - tu das nicht!)
Die Threads beziehen sich auf alle Rules insgesamt. Wenn Du also viele Rules hast, die ähnlich gegen die grundsätzlichen Regeln der Programmierung verstoßen wie der Teil der gezeigten Rule, ist es im Gegenteil sogar sehr wahrscheinlich, dass Deine Rules sich gegenseitig blockieren.

Der erste Punkt ist, dass man es grundsätzlich vermeiden sollte, Rules zu definieren, die identische Trigger aufweisen. Es gibt nur wenige Situationen, in denen das ok ist, und man sollte genau überlegen, ob die Rule Engine sich dann tatsächlich immer korrekt verhalten wird (z.B. welche der Rules wurde als erstes gestartet).

Der zweite Punkt ist die Sache mit dem Thread::sleep(). Es ist eine ganz schlechte Idee, Rules zu schreiben, die wesentlich länger als einige hundert Millisekunden(!) laufen.
Was die konkrete Steuerung der Rollläden betrifft: Gibt es wichtige Gründe, ganz bestimmte Abstände zwischen den einzelnen Rollladenfahrten zu verwenden? Ein automatisches Schließen ist sicherlich ok, auch dass bestimmte Läden auf eine Lüftungsposition gefahren werden, aber das macht es natürlich etwas schwerer, die Rule effizient zu gestalten. Aber mal als Beispiel:

Code: Alles auswählen

// globale Variablen zu Beginn der Datei definieren!
var Timer tShutter = null
var Integer iShutter = 0

rule "Rollläden schließen"
when
    Item Lichtsensor_Aussen changed
then
    if(tShutter !== null) {                                                                                  // Timer läuft schon
        logInfo("shutter","Rule getriggert, aber Timer bereits aktiv. Abbruch!")
        return;
    }
    if(!(Lichtsensor_Aussen.state instanceof Number)) {                                                      // ist der Status eine Zahl?
        logWarn("shutter","Lichtsensor liefert ungültigen Status ({}). Abbruch!",Lichtsensor_Aussen.state)
        return;
    }
    val Number nPrev = if(previousState instanceof Number) (previousState as Number).floatValue else 20      // alten Wert auslesen
    if((Lichtsensor_Aussen.state as Number).floatValue < 10 && nPrev > 10) {                                 // Falls Schwellwert unterschritten und vorher nicht unterschritten
        iShutter = 0                                                                                         // Zähler zurücksetzen
        tShutter = createTimer(now.plusMillis(10),[|                                                         // Timer anlegen und starten
            iShutter = iShutter + 1                                                                          // Zähler erhöhen
            switch(iShutter) {                                                                               // Abhängig vom Zähler
                case 1: {                                                                                    // 1. Schritt
                    Rollo_Bad_Level.sendCommand(100)
                    tShutter.reschedule(now.plusSeconds(15))                                                 // Timer erneut ausführen in 15 Sekunden
                }
                case 2: {                                                                                    // 2. Schritt
                    Rollo_SchlafzKleider_Level.sendCommand(100)
                    tShutter.reschedule(now.plusSeconds(7))
                }
                case 3: {                                                                                    // 3. Schritt
                    Rollo_SchlafzGarage_Level.sendCommand(100)
                    tShutter.reschedule(now.plusSeconds(2))
                }
                case 4: {                                                                                    // 4. Schritt
                    Rollo_SchlafzBalkon_Level.sendCommand(32)
                    tShutter.reschedule(now.plusSeconds(3))
                }
                case 5: ...                                                                                  // 5. Schritt
                default: {                                                                                   // letzter Schritt
                    tShutter = null
                }
            }
        ])
    }
end
Allein die große Menge an gleichartigen Befehlen sieht nicht schön aus. Gegenbeispiel:

Code: Alles auswählen

// globale Variablen zu Beginn der Datei definieren!
var Timer tShutter = null
var Integer iShutter = 0

val lShutter      = newArrayList('Bad', 'SchlafzKleider', 'SchlafzGarage', 'SchlafzBalkon')
val lShutterClose = newArrayList(100, 100, 100, 32)
val lShutterTime  = newArrayList(15, 7, 2, 3)


rule "Rollläden schließen"
when
    Item Lichtsensor_Aussen changed
then
    if(tShutter !== null) {                                                                                  // Timer läuft schon
        logInfo("shutter","Rule getriggert, aber Timer bereits aktiv. Abbruch!")
        return;
    }
    if(!(Lichtsensor_Aussen.state instanceof Number)) {                                                      // ist der Status eine Zahl?
        logWarn("shutter","Lichtsensor liefert ungültigen Status ({}). Abbruch!",Lichtsensor_Aussen.state)
        return;
    }
    val Number nPrev = if(previousState instanceof Number) (previousState as Number).floatValue else 20      // alten Wert auslesen
    if((Lichtsensor_Aussen.state as Number).floatValue < 10 && nPrev > 10) {                                 // Falls Schwellwert unterschritten und vorher nicht unterschritten
        iShutter = 0                                                                                         // Zähler zurücksetzen
        tShutter = createTimer(now.plusMillis(10),[|                                                         // Timer anlegen und starten
            if(lShutter.size >= iShutter) {
                tShutter = 0
                return;
            }
            sendCommand("Rollo_" + lShutter(iShutter) + "_Level",lShutterClose(iShutter).intValue)           // Shutternamen aus Liste berechnen und mit passendem Wert ansteuern
            tShutter.reschedule(now.plusSeconds(lShutterTime(iShutter).intValue))                            // Timer erneut planen
            iShutter = iShutter + 1                                                                          // Zähler erhöhen
        ])
    }
end
Hier werden die Namen, Sollhöhen und Wartezeiten aus drei Listen entnommen. Wird das Ende der Liste erreicht, stoppt der Timer.
Ich setze hier voraus, dass alle Rollläden dem Namensschema folgen. Auch wenn die Variante mit der Arraylist nicht optimal ist, kann man sehr schön sehen, dass der Code wesentlich effizienter ist. Die Rule wird nicht länger, egal, wie viele Rollläden auch in der Liste eingetragen sein mögen.

Das Wichtigste bei der Rule ist aber, sicherzustellen, dass der Code nur einmalig gestartet wird. das macht den weitaus größeren Teil der Rule aus :)
Der Timer sorgt dafür, dass die Threads minimal belegt sind - wenige Millisekunden bei Wertänderung des Sensors, wenige Millisekunden wenn ein Rollladen angesteuert wird.

Re: Rule läuft manchmal nicht !

Verfasst: 2. Okt 2020 19:28
von Baumtasche
Wow, ihr seid echt Klasse, vielen vielen Dank für eure Hilfe, insbesondere an udo1toni. Ist der Wahnsinn, was du du für Zeit investiert hast, mir als Anfänger, das so ausführlich zu erklären. Den Code dazu hast du auch gleich mitgeliefert. DAAAAAANNNKE
Ich werde berichten, ob es funktioniert hat.

Re: Rule läuft manchmal nicht !

Verfasst: 2. Okt 2020 19:44
von Baumtasche
Nachtrag: anbei der komplette ursprüngliche Code

Code: Alles auswählen


rule  "Aktuelle Helligkeit fällt unter 10" //"React on Aktuelle Helligkeit (Lichtsensor_1_CurrentIllumination) change/update"

when
   Item Lichtsensor_Aussen changed 
then
    if((Lichtsensor_Aussen.state as Number)  < 30 && (ItemRollo_Geschlossen== CLOSED)) { 
            Rollo_Bad_Level.sendCommand(100)
            Thread::sleep(8000)
            Rollo_SchlafzKleider_Level.sendCommand(100)
            Thread::sleep(7000) 
            Rollo_SchlafzGarage_Level.sendCommand(100)
            Thread::sleep(2000)
            Rollo_SchlafzBalkon_Level.sendCommand(32)
            Thread::sleep(3000)
            Rollo_KindLinks_Level.sendCommand(63)
            Thread::sleep(1000)
            Rollo_KindRechts_Level.sendCommand(100)
            Thread::sleep(1500)
            Rolle_Kueche_Level.sendCommand(100)
            Thread::sleep(3000)
            Rollo_Wohnzimmer_Level.sendCommand(100)
        
            if(DrehTerrasse_State == CLOSED)
                Rollo_Terrasse_Level.sendCommand(32)       
      
            ItemRollo_Geschlossen.postUpdate(ON)
        }
    
end



Re: Rule läuft manchmal nicht !

Verfasst: 2. Okt 2020 21:57
von Baumtasche
Hallo Udo1toni,

kannst du bitte noch Mal auf folgende Passage von dir schauen?

Code: Alles auswählen

            sendCommand("Rollo_" + lShutter(iShutter) + "_Level",lShutterClose(iShutter).intValue)           
            tShutter.reschedule(now.plusSeconds(lShutterTime(iShutter).intValue))                            
            iShutter = iShutter + 1                                                                          
        ])
VSCode meldet, dass lShutter --> invalid number of arguments. The field lShutter is not applicable for the arguments (Integer), dass gleiche bei lShutterClose