Ankündigung

Einklappen
Keine Ankündigung bisher.

sleep hier fehl am Platz?

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

    sleep hier fehl am Platz?

    Huhu und guten Abend
    Ich hab mich gerade dafür entschieden mich hier zu registrieren weil hier scheinbar viele Profis unterwegs sind.
    Darum auch gleich mal meine erste Frage:
    Ich habe eine Regel erstellt die mir jede viertel Stunde eine E-Mail schicken soll wenn im Bad vergessen wurde das Licht auszuschalten.
    Das funktioniert soweit auch, bloss hab ich öfter das Problem dass schon eine Mail raus geht wenn das Licht gerade eingeschaltet wurde...
    Kann es sein dass sleep mit der Regel pausiert wird, also sprich, wenn sagen wir 14 Minuten um sind und das Licht ausgeschaltet wurde und später wieder eingeschaltet wird er bei den 14 Minuten weiter zählt?
    Wie kann ich das Problem lösen?

    rule "Bad Licht Erinnerung"
    when
    Item Deckenleuchte_Bad changed to ON
    then
    Thread::sleep(900000)
    while(Deckenleuchte_Bad.state == ON) {
    sendMail("meinemail@gmail.com", "Badlicht", "Da hat wohl mal wieder wer vergessen das Licht aus zu machen...")
    Thread::sleep(900000)
    }
    end

    #2
    Die Vorgehensweise ist etwas unglücklich, denn Deine Schleife läuft ja auch wenn das Licht ausgeschaltet wurde weiter. Wenn dann vor Ablauf der 15 Minuten das Licht wieder eingeschaltet wird, wird die Mail aus der alten Schleife gesendet - und zum eigentlich korrekten Zeitpunkt noch eine.
    Nehmen wir an, Du schaltest das Licht eine Viertelstunde lang jede Minute einmal kurz aus und wieder an und lässt das Licht dann brennen, dann bekommst Du aus jeder Schleife eine Nachricht, also einmal pro Minute, denn es gibt dann 15 aktive Threads.
    Abgesehen davon ist natürlich Thread::sleep() für so lange Zeiträume ein ineffizientes Werkzeug. Besser geht's so:
    Code:
    import org.joda.time.DateTime
    var Timer t_bath = null
    
    rule "Bad Licht Erinnerung"
    when
        Item Deckenleuchte_Bad changed
    then
        if (Deckenleuchte_Bad.state == ON) {
            if (t_bath != null) {
                t_bath.cancel
                t_bath = null
            }
            t_bath = createTimer(now.plusMinutes(15))[|
                sendMail("meinemail@gmail.com", "Badlicht", "Da hat wohl mal wieder wer vergessen das Licht aus zu machen...")
                t_bath.reschedule(now.plusMinutes(15))
            ]
        }
        else {
            t_bath.cancel
            t_bath = null
        }
    end
    Für das Versenden der Mail wird also ein Timer angelegt, der 15 Minuten in der Zukunft endet. Läuft der Timer bis zum Ende, wird die Mail gesendet und der Timer anschließend erneut gestartet. Falls zwischenzeitlich das Licht ausgeschaltet wird, wird der Timer abgebrochen und zurückgesetzt. Im Unterschied zum Thread::sleep() wird hier auch kein zusätzlicher Thread gestartet, der den Speicher zumüllt (der Timer landet im ohnehin laufenden Scheduler), ebenso kann es nicht mehr passieren, dass übriggebliebene Threads rumdümpeln und zu seltsamem Verhalten führen.
    Es ist immer eine gute Idee, Timer darauf zu überprüfen, ob sie schon initialisiert sind, nur für den Fall deshalb das eigentlich unnötige if (t_bath != null)

    Kommentar


      #3
      Genial Danke!
      Da sieht man mal wieder was hier für kompetente Leute sind! *Daumen hoch*
      Musste die ganze Sache noch ein bisschen anpassen da ich Errors im Log hatte.
      Erst diesen hier:
      Code:
      [ERROR] [o.o.c.s.ScriptExecutionThread ] - Error during the execution of rule 'Bad Licht Erinnerung': The name '<XFeatureCallImplCustom>.cancel' cannot be resolved to an item or type.
      Dann diesen:
      Code:
      [ERROR] [o.o.c.s.ScriptExecutionThread ] - Error during the execution of rule 'Bad Licht Erinnerung': The name '<XFeatureCallImplCustom> != <XNullLiteralImpl>' cannot be resolved to an item or type.
      Und nach Ändern von import org.joda.time.DateTime auf import org.openhab.model.script.actions.* diesen:
      Code:
      [ERROR] [o.o.c.s.ScriptExecutionThread ] - Error during the execution of rule 'Bad Licht Erinnerung': cannot invoke method public abstract boolean org.openhab.model.script.actions.Timer.cancel() on null
      So sieht das ganze jetzt aus:
      Code:
      import org.openhab.model.script.actions.*
      var Timer Timer_Bad = null
      
      rule "Bad Licht Erinnerung"
      when
          Item Deckenleuchte_Bad changed
      then
          if (Deckenleuchte_Bad.state == ON) {
              if (Timer_Bad != null) {
                  Timer_Bad.cancel
                  Timer_Bad = null
              }
              Timer_Bad = createTimer(now.plusMinutes(15)) [|
                  sendMail("meinemail@gmail.com", "Badlicht", "Da hat wohl mal wieder wer vergessen das Licht aus zu machen...")
                  Timer_Bad.reschedule(now.plusMinutes(15))
              ]
          } else {
              if (Timer_Bad != null) {
                  Timer_Bad.cancel
                  Timer_Bad = null
              }
          }
      end
      Edit:
      Kann man den Item Namen auch durch eine Gruppe ersetzen so dass er auch startet wenn der Spiegelschrank eingeschaltet wird?

      Edit2:
      Hab das jetzt so gelöst:
      Code:
      import org.openhab.model.script.actions.*
      var Timer Timer_Bad = null
      
      rule "Bad Licht Erinnerung"
      when
          Item Deckenleuchte_Bad changed or
          Item Spiegelschrank_Bad changed
      then
          if (Deckenleuchte_Bad.state == ON || Spiegelschrank_Bad.state == ON) {
              if (Timer_Bad == null) {
                  Timer_Bad = createTimer(now.plusMinutes(15)) [|
                      sendMail("meinemail@gmail.com", "Badlicht", "Da hat wohl mal wieder wer vergessen das Licht aus zu machen...")
                      Timer_Bad.reschedule(now.plusMinutes(15))
                  ]
              }
          } else {
              if (Timer_Bad != null) {
                  Timer_Bad.cancel
                  Timer_Bad = null
              }
          }
      end
      Kann man doch so machen oder?
      Zuletzt geändert von Wired Life; 11.05.2016, 21:50.

      Kommentar


        #4
        Hmm... also die org.openhab.model.script.actions.* kann ich nachvollziehen, die wirst Du für sendMail benötigen, aber ohne org.joda.time.DateTime geht es definitiv nicht.

        Eine Gruppe könntest Du für den Trigger auch verwenden, allerdings musst Du aufpassen. Wenn Du die Gruppe als
        Code:
        Group:Switch:OR(ON, OFF) Licht_Bad "Lichter im Bad [(%d)]"
        definierst, sollte es aber funktionieren. Über das Switch:OR(ON, OFF) wird erreicht, dass die Gruppe auf ON wechselt, sobald mindesten ein Member ON ist, das entspricht ja dann Deinem Wunsch. Mit mehreren Einzelitems als Trigger funktioniert es erstmal auch, allerdings wird die erste Mail erst 15 Minuten nach dem letzten Schaltvorgang verschickt, bei dem mindestens ein Licht an blieb, während die Mail mit Gruppentrigger verschickt wird, falls ohne Unterbrechung mindestens ein Licht eingeschaltet war. Zur Verdeutlichung diese Tabelle:
        Zeit Aktion Gruppe Einzeln
        0 Min Licht 1 an Trigger Trigger
        5 Min Licht 2 an Trigger
        7 Min Licht 1 aus Trigger
        15 Min Mail
        22 Min Mail
        Das Label zeigt dann die Anzahl der eingeschalteten Lichter an.
        Zuletzt geändert von udo1toni; 12.05.2016, 11:56.

        Kommentar


          #5
          Doch es geht genauso wie gepostet, für sendMail braucht man nichts importieren.
          Mal eine Frage Offtopic:
          Wie kann ich ein aktuellen state noch mal setzen?
          Bei sendCommand(Deckenleuchte_Flur, Deckenleuchte_Flur.state) kommt immer:
          Code:
          [ERROR] [o.o.c.s.ScriptExecutionThread ] - Error during the execution of rule 'Light Intruder': Could not invoke method: org.openhab.model.script.actions.BusEvent.sendCommand(org.openhab.core.items.Item,java.lang.Number) on instance: null

          Kommentar


            #6
            also abgesehen davon, dass Dein Beispiel einfach den aktuellen Status auf den Bus schicken würde, empfehle ich dringend die objektorientierte Schreibweise:
            Code:
            Deckenleuchte_Flur.sendCommand(Deckenleuchte_Flur.state)
            Methode und Action sind tatsächlich zwei Paar Schuhe, und das Blöde dabei ist, dass die Actions sendCommand(Item,State) und postUpdate(Item,State) zumindest in der aktuellen Version OH 1.8.2 buggy sind.

            Kommentar


              #7
              So hab ich das auch schon probiert, kommt auch ein Fehler mit null

              Kommentar


                #8
                Naja, wie schon erwähnt, schreibst Du ja ohnehin nur den schon vorhandenen Status, vielleicht ist Dein Status in dem Moment auch noch uninitialized, dann wäre die Fehlermeldung korrekt

                Kommentar


                  #9
                  Lustigerweise kann ihn die if Abfrage auslesen also wird er ja gesetzt sein oder? Will mir die ganzen if Abfragen sparen und einfach gleich setzen

                  Kommentar


                    #10
                    Also machen wir es mal andersrum. Was willst Du denn eigentlich erreichen?

                    Kommentar


                      #11
                      Meine Aktoren sind unidirektional und unverschlüsselt und wenn ich am Rfxtrx433 etwas auf meinen IDs empfange möchte ich da drauf reagieren.
                      Ich würde die Regel bloss so kurz wie möglich halten.
                      Code:
                      rule "Light Intruder"
                      when
                          Item Licht_Komplett_R received update or
                          Item Deckenleuchte_Flur_R received update or
                          Item Spiegelschrank_Bad_R received update or
                          Item Deckenleuchte_Wohnzimmer_R received update or
                          Item Stehlampe_Wohnzimmer_R received update or
                          Item Deckenleuchte_Schlafzimmer_R received update or
                          Item Nachttischlampe_Schlafzimmer_R received update
                      then
                          if (Deckenleuchte_Flur.state == ON) {
                              sendCommand(Deckenleuchte_Flur, ON)
                          } else {
                              sendCommand(Deckenleuchte_Flur, OFF)
                          }
                          if (Spiegelschrank_Bad.state == ON) {
                              sendCommand(Spiegelschrank_Bad, ON)
                          } else {
                              sendCommand(Spiegelschrank_Bad, OFF)
                          }
                          if (Deckenleuchte_Wohnzimmer.state == ON) {
                              sendCommand(Deckenleuchte_Wohnzimmer, ON)
                          } else {
                              sendCommand(Deckenleuchte_Wohnzimmer, OFF)
                          }
                          if (Stehlampe_Wohnzimmer.state == ON) {
                              sendCommand(Stehlampe_Wohnzimmer, ON)
                          } else {
                              sendCommand(Stehlampe_Wohnzimmer, OFF)
                          }
                          if (Deckenleuchte_Schlafzimmer.state == ON) {
                              sendCommand(Deckenleuchte_Schlafzimmer, ON)
                          } else {
                              sendCommand(Deckenleuchte_Schlafzimmer, OFF)
                          }
                          if (Nachttischlampe_Schlafzimmer.state == ON) {
                              sendCommand(Nachttischlampe_Schlafzimmer, ON)
                          } else {
                              sendCommand(Nachttischlampe_Schlafzimmer, OFF)
                          }
                          sendMail("meinemail@gmail.com", "!Light Intruder!", "Da wollte wohl jemand dein Licht schalten...")
                      end
                      
                      rule "Remote Intruder"
                      when
                          Item Funksteckdosen_Komplett_R received update or
                          Item Technik_Kueche_R received update or
                          Item TV_Schlafzimmer_R received update
                      then
                          if (Technik_Kueche.state == ON) {
                              sendCommand(Technik_Kueche, ON)
                          } else {
                              sendCommand(Technik_Kueche, OFF)
                          }
                          if (TV_Schlafzimmer.state == ON) {
                              sendCommand(TV_Schlafzimmer, ON)
                          } else {
                              sendCommand(TV_Schlafzimmer, OFF)
                          }
                          sendMail("meinemail@gmail.com", "!Remote Intruder!", "Da wollte wohl jemand deine Steckdosen schalten...")
                      end

                      Kommentar


                        #12
                        Ich verstehe immer noch nicht, was Du da tun willst, Deine Rules ergeben keinen Sinn.

                        1. Nehmen wir an, Du hast ein Item, welches mit einem Aktor verbunden ist. Wie wird das Item geschaltet? Hast Du einen Schalter an der Wand, oder schaltest Du das Item in der UI? In beiden Fällen benötigst Du gar keine Rule, um den Aktor zu schalten, ein Betätigen eines Schalters in der UI bewirkt direkt ein sendCommand, wenn ein Hardware-Schalter mit einem Item verbunden ist, wird der Befehl von Binding zu Binding weitergeleitet, ebenfalls ohne Rule.

                        2. Ich hab ja schon darauf hingewiesen, dass die Action fehlerhaft ist, ich verstehe nicht, warum Du sie unbedingt verwenden willst.

                        3. Weiter hast Du Dir da eine böse Schleife gebaut, denn jedes sendCommand bewirkt gleichzeitig ein update des Items, Du triggerst also innerhalb Deiner Rule die Rule selbst.

                        Kommentar


                          #13
                          Oh man... Ich schalte die Aktoren via UI. Die Rules funktionieren so einwandfrei, die Empfang Items haben ein _R dahinter und die zum Senden nicht. Dadurch dass ich mit der gleichen Hardware sende wie auch empfange kann ich sehen ob jemand in mein System einbricht und meine Aktoren schaltet. Wenn das passiert, schaltet ja nur der entsprechende Aktor, nicht aber das Item. Ich empfange "jemand schaltet Aktor" und sende danach meinen Item.state an den Aktor zurück damit z.b. Die Lampe wieder aus ist. Soweit verstanden? Ich würde bloss gerne den State gleich senden, ohne vorher mit if abzufragen.

                          Kommentar


                            #14
                            Ah. Sorry, das _R hatte ich irgendwie übersehen. Mag vielleicht an der Menge Text liegen

                            Aber wie schon obern erwähnt, ein
                            Code:
                            TV_Schlafzimmer.sendCommand(TV_Schlafzimmer.state)
                            funktioniert bei mir einwandfrei und ohne Fehlermeldung. die Items heißen bei mir anders, klar.
                            Vorausetzung ist außerdem, dass jedes Item einen definierten Zustand hat, ein Stauts uninitialized führt zu einem Fehler - dies fängst Du aktuell mit der if-clause ab, weil Du ja nur auf ON testest. Falls der Status eines der Items zu diesem Zeitpunkt uninitialized ist, wird er nach Ausführung der Rule also OFF sein. Wenn Du aber ohne if-clause arbeitest, wird ein Status uninitialized zu dem Fehler führen.

                            Die Action sendCommand(Item,string) möchte tatsächlich normalerweise einen String haben, da könntest Du also mit
                            Code:
                            sendCommand(TV_Schlafzimmer,TV_Schlafzimmer.state.toString)
                            weiter kommen, allerdings gäbe es im beschriebenen Fall trotzdem einen Fehler - uninitialized ist kein gültiger Wert für sendCommand(), egal ob als State oder als String
                            Weil Du etliche Items in einer Rule abfrühstückst (was natürlich in Ordnung geht), kann jedes einzelne Item da querschießen.

                            Tipp am Rande: Du kannst die ganzen _R-Items in einer Gruppe zusammenfassen und dann auf Gruppe received update triggern, sollte genauso funktionieren.

                            Kommentar


                              #15
                              Sollte man nun eigentlich besser Item.sendCommand oder sendCommand(Item, State) verwenden?

                              Kommentar

                              Lädt...
                              X