Ankündigung

Einklappen
Keine Ankündigung bisher.

Timer einbauen

Einklappen
X
 
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

    Timer einbauen

    Hallo zusammen,

    Wie kann ich in diesem Fall die Thread::sleep durch einen Timer ersetzen?

    Code:
    if(kinderbetreuung.state==ON) {
    
    Thread::sleep(20000)
    if(SQ_Samsung_Galaxy_S10.state==CLOSED && KB_Samsung_Galaxy_S8.state==CLOSED){
    Thread::sleep(20000)
    if(SQ_Samsung_Galaxy_S10.state==CLOSED && KB_Samsung_Galaxy_S8.state==CLOSED){
    Thread::sleep(20000)
    if(SQ_Samsung_Galaxy_S10.state==CLOSED && KB_Samsung_Galaxy_S8.state==CLOSED){
    Thread::sleep(20000)
    if(SQ_Samsung_Galaxy_S10.state==CLOSED && KB_Samsung_Galaxy_S8.state==CLOSED){
    prae_anwesenheit.sendCommand(ON)
    sendBroadcastNotification("Niemand ist zuhause, Kinderbetreuung an!")
    
    }
    }
    }
    }
    }
    Zuletzt geändert von SaschaQ; 15.10.2020, 11:33.

    #2
    Einfachste Variante:
    Code:
    // globale Variablen außerhalb der Rules zu Beginn der Datei definieren!
    var Timer tBetreuung = null
    var Integer iBetreuung = 0
    
    
    
    // Code in der Rule...
    if(kinderbetreuung.state==ON && tBetreuung === null) {                                  // Bedingung und kein Timer aktiv
        iBetreuung = 0                                                                      // Zähler auf 0
        tBetreuung = createTimer(now,[|                                                     // Timer anlegen und sofort ausführen
            if(SQ_Samsung_Galaxy_S10.state!=CLOSED || KB_Samsung_Galaxy_S8.state!=CLOSED) { // eines der Geräte anwesend, also
                tBetreuung = null                                                           // Timer löschen und
                return;                                                                     // Abbruch
            }
            iBetreuung = iBetreuung + 1                                                     // Zähler erhöhen
            if(iBetreuung < 5) {                                                            // Falls Grenzwert nicht erreicht
                tBetreuung.reschedule(now.plusSeconds(20))                                  // Timer erneut ausführen
            } else {                                                                        // sonst
                prae_anwesenheit.sendCommand(ON)                                            // Aktion ausführen
                sendBroadcastNotification("Niemand ist zuhause, Kinderbetreuung an!")
                tBetreuung = null                                                           // und abschließend Timer löschen
            }
        ])
    }
    Allerdings wird so nur zu exakt 4 Zeitpunkten geprüft, ob die Handies Online sind (ich gehe mal davon aus, dass sich diese Eigenschaft hinter den beiden Items verbirgt).
    Sinnvoller wäre es, das Ganze anders aufzubauen. Der Timer wird wie gehabt gestartet, falls eines der Handies erreichbar wird, löst eine Rule aus und bricht ihrerseits den Timer ab. Der Timer läuft dann einfach 80 Sekunden:
    Code:
    // globale Variablen außerhalb der Rules zu Beginn der Datei definieren!
    var Timer tBetreuung = null
    
    
    
    // Code in der Rule...
    if(kinderbetreuung.state==ON && tBetreuung === null && SQ_Samsung_Galaxy_S10.state==CLOSED && KB_Samsung_Galaxy_S8.state==CLOSED) {
        tBetreuung = createTimer(now.plusSeconds(80),[|
            prae_anwesenheit.sendCommand(ON)
            sendBroadcastNotification("Niemand ist zuhause, Kinderbetreuung an!")
            tBetreuung = null
        ])
    }
    //... Dieser Teil der Rule wird unmitelbar ausgeführt und wird nicht vom Timer beeinflusst!
    
    rule "Timer Abbrechen"
    when
        Item SQ_Samsung_Galaxy_S10 changed from CLOSED or
        Item KB_Samsung_Galaxy_S8  changed from CLOSED
    then
        tBetreuung?.cancel
        tBetreuung = null
    end
    Nun ist also der Zustand der beiden Items ebenfalls Bedingung zum Anlegen des Timers, dafür ist der Code aber simpel und die zweite Rule ist ebenso trivial...

    Kommentar


      #3
      Hallo Udo1toni,

      danke für deine Mühen.

      Ich hatte nur einen Teil der Gesamtrule hier reinkopiert, da ich nur wissen wollte, wie ich am einfachsten das
      Thread::sleep(20000) durch einen Timer ersetzen kann aber die Rule so lasse wie sie ist.

      Duch was muss ich das Thread::sleep(20000) also ersetzen in meinem Code um einen Timer zu bekommen.

      Danke trotzdem für deine riesige Mühe. Hatte mich vielleicht etwas falsch ausgedrückt.


      Kommentar


        #4
        So wie Du Dir das vorstellst, geht das eben nicht. Deine Rule ist falsch. Klingt vielleicht etwas besserwisserisch ist aber so.

        Die Rule Engine von openHAB mag Thread::sleep() nicht. openHAB bietet 5 + 2 Threads um Rules auszuführen, das heißt, dass maximal 7 Rules parallel zueinander ausgeführt werden können.
        Wenn man nun Rules baut (eine reicht schon!!!), welche weit über eine Minute zur Ausführung brauchen (Dein Beispielcode benötigt mehr als 80 Sekunden - nur der Ausschnitt), so steigt die Wahrscheinlichkeit, dass Rules gar nicht oder extrem verspätet ausgeführt werden.
        Je nach Trigger ist es leicht möglich, dass eine (1) Rule mehrfach parallel läuft. Nimm z.B. eine Rule, die auf MySwitch changed triggert. Die Rule braucht 80 Sekunden zur Ausführung, und jemand schaltet MySwitch drei mal ON und OFF. Macht 6 Rules, die parallel laufen, sich in die Quere kommen, und die letzte davon läuft erst, wenn die erste Rule fertig ist. Rules sollten grundsätzlich nur wenige Millisekunden für die Ausführung benötigen. Selbst sehr komplexe Rules brauchen gemeinhin unter eine Sekunde Ausführungszeit. Eine vergleichbare Rule mit Timer braucht nur wenige Millisekunden insgesamt und läuft dafür mehrfach. Aber es muss schon der gesamte Rule Code zur Verfügung stehen, um den Timer Code entsprechend zu erstellen.

        Kommentar


          #5
          Hallo Udo,

          alles klar Danke, jetzt habe ich noch diese Rule hier, die soll auch so bleiben aber er meckert immer:

          Code:
          
          2020-10-16 18:18:07.492 [WARN ] [el.core.internal.ModelRepositoryImpl] - Configuration model 'Praesenz.rules' has errors, therefore ignoring it: [76,2]: mismatched input 'else' expecting 'end'
          
          [112,2]: mismatched input 'else' expecting 'end'
          Ich möchte immer bevor er nochmals nach dem Open oder Closed prüft eine Verzögerung drin haben, falls das Mobiltelefon doch wieder online geht.

          Code:
          rule "Kerstin Anwesenheit Status"
          when
          Item KB_Samsung_Galaxy_S8 changed to OPEN or
          Item KB_Samsung_Galaxy_S8 changed to CLOSED
          
          then
          
          
          createTimer(now.plusSeconds(20), [ |
          if(KB_Samsung_Galaxy_S8.state==OPEN) {
          prae_kerstin.sendCommand(OPEN)
          sendBroadcastNotification("Kerstin ist zuhause!")
          echo_wohnzimmer_TTS_Volume.sendCommand(60)
          if (now.getHourOfDay() <= 20 && now.getHourOfDay() >= 7) {
          Thread::sleep(2500)
          echo_wohnzimmer_TTS.sendCommand('Willkommen zuhause Kerstin')
          Thread::sleep(2500)
          echo_wohnzimmer_TTS_Volume.sendCommand(30)
          }
          }
          ])
          
          else {
          
          createTimer(now.plusSeconds(60), [ |
          if(KB_Samsung_Galaxy_S8.state==CLOSED) {
          prae_kerstin.sendCommand(CLOSED)
          sendBroadcastNotification("Kerstin hat das Haus verlassen!")
          }
          ])
          }
          
          
          end
          Zuletzt geändert von SaschaQ; 16.10.2020, 17:29.

          Kommentar


            #6
            Ich formatiere die Rule mal etwas um:
            Code:
            rule "Kerstin Anwesenheit Status"
            when
                Item KB_Samsung_Galaxy_S8 changed to OPEN or
                Item KB_Samsung_Galaxy_S8 changed to CLOSED
            then
                createTimer(now.plusSeconds(20), [ |
                    if(KB_Samsung_Galaxy_S8.state==OPEN) {
                        prae_kerstin.sendCommand(OPEN)
                        sendBroadcastNotification("Kerstin ist zuhause!")
                        echo_wohnzimmer_TTS_Volume.sendCommand(60)
                        if (now.getHourOfDay() <= 20 && now.getHourOfDay() >= 7) {
                            Thread::sleep(2500)
                            echo_wohnzimmer_TTS.sendCommand('Willkommen zuhause Kerstin')
                            Thread::sleep(2500)
                            echo_wohnzimmer_TTS_Volume.sendCommand(30)
                        }
                    }
                ])
            else {
                createTimer(now.plusSeconds(60), [ |
                    if(KB_Samsung_Galaxy_S8.state==CLOSED) {
                        prae_kerstin.sendCommand(CLOSED)
                        sendBroadcastNotification("Kerstin hat das Haus verlassen!")
                    }
                ])
            }
            end
            Nun siehst Du, dass da etwas grundsätzlich schief läuft. Dein else bezieht sich auf das then. Das ist aber großer Quatsch, denn das then kennt kein else. Das hier ist nicht BASIC, das ist die Rules DSL.

            Was Du möchtest, ist innerhalb der Rule auf den Status des Items KB_Samsung_Galaxy_S8 reagieren. Also so:
            Code:
            var Timer tPresence = null
            
            rule "Kerstin Anwesenheit Status"
            when
                Item KB_Samsung_Galaxy_S8 changed
            then
                tPresence?.cancel
                if(KB_Samsung_Galaxy_S8.state == OPEN) {
                    tPresence = createTimer(now.plusSeconds(20), [ |
                        prae_kerstin.sendCommand(OPEN)
                        sendBroadcastNotification("Kerstin ist zuhause!")
                        echo_wohnzimmer_TTS_Volume.sendCommand(60)
                        if (now.getHourOfDay < 21 && now.getHourOfDay > 6) {
                            Thread::sleep(2500)
                            echo_wohnzimmer_TTS.sendCommand('Willkommen zuhause Kerstin')
                            Thread::sleep(2500)
                            echo_wohnzimmer_TTS_Volume.sendCommand(30)
                        }
                    ])
                } else {
                    tPresence = createTimer(now.plusSeconds(60), [ |
                        prae_kerstin.sendCommand(CLOSED)
                        sendBroadcastNotification("Kerstin hat das Haus verlassen!")
                    ])
                }
            end
            Ich habe oben schon erklärt, dass eine Rule durchaus mehrfach parallel ausgeführt werden kann. Deshalb ist es keine Option, auf die Timer Variable zu verzichten! Du möchtest kein wildes Durcheinander von Notifications, nur weil das Handy mal kurz mehrfach den Status gewechselt hat (z.B. weil das WLAN gestört war). Es ist schlimm genug, in einem solchen Fall eine (1) Meldung zu bekommen.

            Kommentar

            Lädt...
            X