Ankündigung

Einklappen
Keine Ankündigung bisher.

Zufallsaktionen / Anwesenheitssimulation in "rules"

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

    Zufallsaktionen / Anwesenheitssimulation in "rules"

    Moin moin,

    kennt jemand die korrekte Syntax für "random actions", die man in rules verwenden könnte?

    Ich würde gerne eine simple Anwesenheitssimulation erstellen, die mir zwischen bestimmten Uhrzeiten bestimmte Aktoren ein- und ausschaltet.
    Wäre natürlich toll, wenn man die Dauer des Einschaltens auch noch bestimmen könnte, aber ich wäre schon für die einfache Variante dankbar.


    #2
    Deine Frage kann ich nicht beantworten, aber es gibt auch Lösungen zur Anwesenheitssimulation per Kalender (Google-Calender oder calDav Binding). Damit werden Aktionen überwacht und im Kalender eingetragen. Diese Kalendereinträge steuern dann die Aktoren (ein/aus schalten).

    Kommentar


      #3
      Die Geschichte mit dem Google Calendar kenne ich, passt aber leider nicht, da wir bisher keine Beleuchtung nutzen, deren Verhalten aufgezeichnet werden kann.

      Ich habe es mit (math::random) versucht, bekomme es aber leider nicht hin, dazu reichen mir die Programmierkenntnisse leider nicht aus.

      Werde einfach mehrere verschieden timecron Einträge erstellen, die mehr oder weniger zufällig erscheinen.

      Kommentar


        #4
        Hi,
        math::random liefert einen Wert zwischen 0 und 1, also z.b. 0.7
        Wenn du diesen mit 10 multiplizierst also 0-10.
        Jetzt kannst du dir einen cron Job erzeugen der z.b. 19 Uhr auslöst und dann einen Timer mit der Verzögerung startet.
        Das könnte z.b.so aussehen:
        Code:
        rule "zufall licht"
        when    Time cron "0 0 19 * *  ?"
        then
                var Integer rand
                rand = 1+ (Math::random * 10.0).intValue
                println("rand:" + rand.toString())
                createTimer(now.plusMinutes(rand)) [|
                            {
                               // .. licht an...
                            }
                    ]
        
        end
        Du kannst auch mit 100 multiplizieren und hast dann 0-100 Minuten in 10er Schritten.
        Über einen zweiten Random Wert kann man auch feiner auflösen.

        Holger
        Zuletzt geändert von HolgerW; 22.04.2015, 19:45.

        Kommentar


          #5
          Hallo Holger,

          Vielen Dank für Deinen Tipp, die Lampe wird eingeschaltet!
          Code:
          rule "zufall licht"
          when    Time cron "0 11 21 * *  ?"
          then
                  var Integer rand
                  rand = 1+ (Math::random * 1.0).intValue
                  println("rand:" + rand.toString())
                  createTimer(now.plusMinutes(rand)) [|
                  sendCommand(RandomLamp, ON)           {
                                 // .. licht an...
                              }
                      ]
          
          end
          Wie schalte ich sie wieder aus? Eine zweite "feste" TimeCron mit dem Code von oben, diesmal "OFF"?


          Kommentar


            #6
            Ja entweder zweite rule oder gleich zweiten Timer starten in xx Minuten oder auch zufällig mit einem Offset von z.b. 30 Minuten.

            Holger

            PS: * 1.0 ist natürlich nicht ganz sinnvoll in deiner rule ...

            PS2: dein sendCommand(RandomLamp, ON) sollte dort hin wo mein kommentar steht: // .. licht an
            Innerhalb der Klammern kannst du dann auch mehrere Befehle rein schreiben
            Zuletzt geändert von HolgerW; 23.04.2015, 20:50.

            Kommentar


              #7
              * 1.0 ist nur zum Testen, damit ich auf das Ergebnis nicht so lange warten muss

              Habe es jetzt so gemacht, würde das funktionieren? Die Rule soll nur laufen, wenn ich sie aktiviere.
              Code:
              rule "zufall licht"
              when    Item Abwesenheitssimulation received update ON
              and     Time cron "0 11 21 * *  ?"
              or      Time cron "0 0 22 * * ?"
              then
                      var Integer rand
                      rand = 1+ (Math::random * 10.0).intValue
                      println("rand:" + rand.toString())
                      createTimer(now.plusMinutes(rand)) [|
                                {
                                     // .. licht an...
                          sendCommand(RandomLamp, ON)         }
                          ]
                      createTimer(now.plusMinutes(rand)) [|
                                {
                                     // .. licht aus...
                          sendCommand(RandomLamp, OFF)         }
                          ]  
                       createTimer(now.plusMinutes(rand)) [|
                                {
                                     // .. licht an zum zweiten Mal...
                          sendCommand(RandomLamp, ON)         }
                          ]
                      createTimer(now.plusMinutes(rand)) [|
                                {
                                     // .. licht aus zum zweiten Mal...
                          sendCommand(RandomLamp, OFF)         }
                          ]  
              
              end
              BTW: wie setze ich einen Offset oder eine Zeitspanne zwischen "Licht AUS zum ersten Mal" und "Licht AN zum zweiten Mal"?


              Danke!
              Zuletzt geändert von Alex22; 24.04.2015, 09:01.

              Kommentar


                #8
                Da Du rand nur einmal am Anfang initialisierst, wird das so nicht funktinoieren, Du legst nur vier Timer an, die alle zur gleichen (besser gar selben) Zeit versuchen, die Lampe ein bzw. auszuschalten. Nur die Tatsache, dass die Befehle eine gewisse Abarbeitungszeit haben, bewahrt Dich davor, dass die Lampe danach in einem undefinierten Zustand ist (weil man nicht vorhersagen könnte, ob nun der letzte abgelaufene Timer ein- oder ausgeschaltet hat). Besser wäre also so etwas:
                Code:
                createTimer(now.plusMinutes(rand)) [|sendCommand(RandomLamp, ON)]
                createTimer(now.plusMinutes(rand*2)) [|sendCommand(RandomLamp, OFF)]
                oder
                Code:
                createTimer(now.plusMinutes(rand)) [|
                   {
                    sendCommand(RandomLamp, ON)        
                    createTimer(now.plusMinutes(rand)) [|sendCommand(RandomLamp, OFF)]
                   }
                ]
                die zweite Variante legt den Timer in dem Moment an, wenn das Licht eingeschaltet wird. now ist dann der Einschaltzeitpunkt. Noch besser wäre natürlich, rand auch zwischendurch neu zu initialisieren, damit das Licht unregelmäßig geschaltet wird, dann musst Du aber zwingend mit der 2. Variante arbeiten, weil rand ja nicht streng monoton wachsend ist.

                Kommentar


                  #9
                  bei der zweiten Variante bringt OH Designer die Meldung "Cannot refer to a non-final variable rand from within a closure"
                  muss die variable neu innerhalb der Klammern des zweiten "createTimer" erneut deklariert werden?

                  Auch das "AND" aus meinem Beispiel oben scheint nicht zu funktionieren. Die Rule soll nur aktiv werden, wenn ich den Schalter dazu betätige.


                  PS: Danke für Eure Geduld und sorry für die vielen Fragen, ich bin zwar selbst aus der IT-Welt, aber leider kein Programmierer, kann den Code halbwegs interpretieren, selbst schreiben jedoch nicht


                  Code:
                  rule     "zufall licht"
                  when
                           Time cron "0 11 21 * *  ?"
                  or      Time cron "0 0 22 * * ?"
                  then
                          var Integer rand
                          rand = 1+ (Math::random * 10.0).intValue
                          println("rand:" + rand.toString())
                          createTimer(now.plusMinutes(rand)) [|
                              {
                      sendCommand(RandomLamp, ON)        
                      createTimer(now.plusMinutes(rand)) [|sendCommand(RandomLamp, OFF)]
                     }
                  ]
                  end

                  Kommentar


                    #10
                    Also rand * 1.0 bringt garnichts, da ja rand nur Werte von 0.1 biss 0.9 (oder 1) ausgibt, das Ergebnis kannst du dir ja sicher selber ausrechnen.
                    In der Regel der Rule geht kein "and", nur ein "or" Wenn du die Ausführung von einem Schalter abhängig machen willst dann muss der in der Regel aussen herum.
                    Offset machst du indem du einen festen Wert dazurechnest.
                    Also ich würde es in etwa so machen, ist aber ungetestet....

                    Code:
                    rule     "zufall licht"
                    when
                            Time cron "0 11 21 * *  ?" or
                            Time cron "0 0 22 * * ?"
                    then
                            var Integer rand1
                            var Integer rand2
                            
                            var Integer offset = 30 // solange soll die Lampe mindestens leuchten
                            
                            if (Abwesenheitssimulation.state == ON
                            {
                            
                                rand1 = 1 + (Math::random * 10.0).intValue
                                rand2 = 1 + (Math::random * 10.0).intValue
                            
                            
                                createTimer(now.plusMinutes(rand1)) [|  sendCommand(RandomLamp, ON) ]              
                    
                                createTimer(now.plusMinutes(rand1 + rand2 + offset)) [|sendCommand(RandomLamp, OFF)]
                            }
                    end

                    Wenn das ganze noch realitätsnaher sein soll vielleicht folgender Ansatz:

                    Über das Astro Binding die Zeit für den Sonnenuntergang bestimmen und einen Switch entsprechend auslösen lassen.
                    Dazu können die die Astro-User bestimmt etwas sagen, ich verwende noch wonderground.
                    Kommt das Ereignis "Sonnenuntergang" dann eine zufällige Wartezeit über rand erzeugen (z.b. 1-30 Minuten) und dann Licht an.
                    Im Winter ist der Sonnenuntergang recht zeitig, wenn du da normalerweise nicht da bist müsste man einen variablen Offset dazurechnen.

                    Meine Gewohnheit ist es gg. 22 Uhr zu Bett zu gehen, also eine Regel um 22 Uhr auslösen lassen und
                    wieder eine zufällige Wartezeit über rand erzeugen (z.b. 1-30 Minuten) und dann Licht aus.
                    Freitags oder am Wochenende (Stichwort dayofweek) z.b. Offset von einer Stunde dazurechnen.

                    Man kann sich also richtig auslassen bei der Sache :-)


                    Holger
                    Zuletzt geändert von HolgerW; 24.04.2015, 18:42.

                    Kommentar


                      #11
                      Ah, ja, das mit den Triggern hatte ich glatt übersehen. Trigger für Rules können nicht mit and verknüpft werden.
                      Das ist auch logisch, denn der Trigger wird ja nur ausgelöst, wenn das entsprechende Ereignis gerade stattfindet.
                      Im Beispiel mit dem Schalter müsstest Du den Schalter also genau in dem Moment betätigen, in dem einer der beiden Time cron-trigger auslöst, und das ist sicher nicht das gewünschte Verhalten.

                      Korrekt musst Du nach dem 1. then eine weitere if-Abfrage einbauen nach dem Schema
                      Code:
                      if(Abwesenheitssimulation.state==ON) {//ab hier der normale Code}
                      Weiterhin gibt es bei der Verknüpfung speziell mehrerer Time cron-Trigger wohl einen Bug, so dass nur der erste Trigger berücksichtigt wird. Dazu gibt's hier im Forum auch ein paar Threads. Am einfachsten baust Du mehrere Trigger-Rules, die jeweils nur auf eine Time cron triggern und nur ein Dummy Item updaten. Dann kannst Du die eigentliche Zufalls-Rule auf dieses Dummy Item triggern lassen (aber nicht vergessen, das Dummy Item auch zu definieren).

                      Kommentar


                        #12
                        @HolgerW:
                        Der OH-Designer meckert bei
                        Code:
                        createTimer(now.plusMinutes(rand1 + rand2 + offset)) [|sendCommand(RandomLamp, OFF)]
                        mit "Incompatible types. Expected int or java.lang.Integer but was java.math.BigDecimal"

                        Ich habs ignoriert und trotzdem laufen lassen:
                        2015-04-24 23:14:00.848 [ERROR] [.o.m.r.i.engine.ExecuteRuleJob] - Error during the execution of rule zufall licht
                        java.lang.IllegalStateException: Could not invoke method: org.joda.time.DateTime.plusMinutes(int) on instance: 2015-04-24T23:14:00.658+02:00
                        at org.eclipse.xtext.xbase.interpreter.impl.XbaseInte rpreter.invokeOperation(XbaseInterpreter.java:738) ~[na:na]
                        at org.eclipse.xtext.xbase.interpreter.impl.XbaseInte rpreter._featureCallOperation(XbaseInterpreter.jav a:713) ~[na:na]

                        etc.

                        und trotzdem sehe ich ne Minute später im Log "RandomLamp received command ON"
                        ...wird aber kein OFF mehr geschickt.

                        Hat die Fehlermeldung evtl. was mit diesem "offset" zu tun? Er kann wohl die beiden "rand1" und "rand2" nicht zu "offset" addieren?

                        Kommentar


                          #13
                          @udo1toni: Danke! Das hat Holger in der Rule oben auch eingebaut. Jetzt verstehe ich die Logik mit dem "...state=ON" als Alternative zu "...when recieved command..."

                          Kommentar


                            #14
                            Zitat von Alex22 Beitrag anzeigen
                            @udo1toni: Danke! Das hat Holger in der Rule oben auch eingebaut. Jetzt verstehe ich die Logik mit dem "...state=ON" als Alternative zu "...when recieved command..."
                            Jepp. Wobei .state=ON keine Alternative ist, sondern etwas ganz anderes als recieved command

                            Kommentar


                              #15
                              mit "Incompatible types. Expected int or java.lang.Integer but was java.math.BigDecimal"
                              Ich schätze, es liegt an einem fehlenden typecast. Bei mir sieht das folgendermaßen aus:

                              Code:
                              randomOffsetLamps = (Math::random()*1800).intValue()
                                      createTimer(now.plusSeconds(randomOffsetLamps)) [|
                                          sendCommand(Licht_Kueche_Regal_Schalten,   ON)
                                          logInfo("timer_lampes rules", "Switch kitchen lamp on")
                                      ]

                              Kommentar

                              Lädt...
                              X