Ankündigung

Einklappen
Keine Ankündigung bisher.

Sauberer Code für "Sofort und alle 5 Minuten"

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

    Sauberer Code für "Sofort und alle 5 Minuten"

    Hallo Leute,

    irgendwie habe ich einen Knoten im Gehirn auch wenn ich denke, dass es eigentlich ganz einfach gehen müsste.

    Also ich will, dass bei Eintreten eines "Auslösers" (z.B. es regnet gerade in die Bude) sofort eine "Reaktion" ausgelöst wird (Ansage oder was auch immer). Und diese soll alle 5 Minuten wiederholt werden solange der Auslöser weiter besteht.

    Klingt nicht kompliziert, oder? Bei zyklisch denkt man sofort an cycle, aber der kann nicht "sofort" sondern erst, wenn zufällig gerade sein 5-Minuten-Zyklus erreicht ist.
    Bisher hatte ich das mit einer Hilfsvariablen etwa so gelöst:
    Code:
    varJetztReagieren = AUS;
    if "Ausloeser-1/1/1" then varJetztReagieren = EIN endif;
    if varJetztReagieren then write("Reaktion-1/1/2", EIN); varJetztReagieren = AUS endif;
    if after(varJetztReagieren == AUS, 300000u64) and "Ausloeser-1/1/1" then varJetztReagieren = EIN endif;
    Kommt mir aber sperrig vor. Jetzt ist mir eingefallen, dass es ohne Hilfsvariable und dafür mit afterc auch gehen müste. Also etwa so:
    Code:
    Restzeit = 0;
    if afterc("Ausloeser-1/1/1", 300000u64, Restzeit) then Restzeit = 300000 endif;
    if Restzeit > 299000u64 then write("Reaktion-1/1/2", EIN) endif;
    if "Ausloeser-1/1/1" == AUS then Restzeit = 0u64 endif; // Timer beenden
    Elegant und schlank ist aber was anderes. Welche Variante resourcen-schonender ist, weiß ich schon gar nicht.
    Kann jemand den Knoten lösen? Bin für jede Anregung dankbar,
    Jens.

    #2
    Deine 1. Lösung sieht gut aus.

    Evtl. gefällt dir ja so etwas:
    Code:
    varAlarmEvent = 0u08;
    if "Ausloeser-1/1/1" or ( after(change(varAlarmEvent), 300000u64) and "Ausloeser-1/1/1" ) then write("Reaktion-1/1/2", EIN); varAlarmEvent++  endif;




    BR
    Marc

    Kommentar


      #3
      Danke, Marc!
      Dein Code ist meinem ersten ja etwas ähnlich, aber nochmal gut komprimiert.

      Allerdings funktioniert sowohl meiner als auch deiner nicht - habe es ausprobiert. Es wird einmal die Reagieren-GA bedient und dann nicht mehr.
      Bei meinem ersten Code liegt es wohl daran, dass die lokale Variable im gleichen Zyklus hin und her geändert wird. Daher greift das change nicht mehr.
      Habe es wie folgt umgebaut, dann geht es. Aber noch ein zweiter Timer :-(
      Code:
      varJetztReagieren = AUS;
      if "Ausloeser-1/1/1" then varJetztReagieren = EIN endif;
      if varJetztReagieren then write("Reaktion-1/1/2", EIN) endif;
      if after(varJetztReagieren, 500u64) then varJetztReagieren = AUS endif;
      if after(varJetztReagieren == AUS, 300000u64) and "Ausloeser-1/1/1" then varJetztReagieren = EIN endif;
      Gute Nacht,
      Jens.

      Kommentar


        #4
        Ohne Timer sollte es auch gehen:

        Code:
        varWdhMin = 255u08;
        if change(Ausloeser) and Ausloeser then {[INDENT]varWdhMin = mod(minute()/5);[/INDENT]} else {[INDENT]varWdhMin = 255;[/INDENT]} endif;
        if change(minute()) and varWdhMin < 60 and mod(minute(),5) == varWdhMin then {[INDENT]write(Reaktion, EIN);[/INDENT]} endif;
        (Leider bringe ich es irgendwie nicht auf die Reihe, den Code in eine größere "CODE"-Box zu bringen - wisst Ihr zufällig, ob man da noch was einstellen muss? ) Drum wiederhole ich hier zur besseren Übersicht:

        varWdhMin = 255u08;
        if change(Ausloeser) and Ausloeser then {
        varWdhMin = mod(minute(),5);
        } else {
        varWdhMin = 255;
        } endif;
        if change(minute()) and varWdhMin < 60 and mod(minute(),5) == varWdhMin then {
        write(Reaktion, EIN);
        } endif;

        So sparst Du Timer ein, hast jedoch nicht exakt auf die Millisekunde 5 Minuten, sondern nur zum Minutenwechsel, was aber für die meisten Fälle reichen sollte. Code ist aus dem Bauch heraus und nicht getestet, allerdings mache ich den Vergleich auf Minuten mittels Modulorechnung in meinen Anwendungen gerne...
        Zuletzt geändert von klaus_kraemer; 05.07.2015, 13:59. Grund: Syntaxfehler...

        Kommentar


          #5
          Zitat von DerRenovator Beitrag anzeigen
          Allerdings funktioniert sowohl meiner als auch deiner nicht - habe es ausprobiert. Es wird einmal die Reagieren-GA bedient und dann nicht mehr.
          Bei meinem ersten Code liegt es wohl daran, dass die lokale Variable im gleichen Zyklus hin und her geändert wird. Daher greift das change nicht mehr.
          Hm, habe meinen Code eigentlich nur an deine Namen angepasst und die Bedingungen vereinfacht. Dass es dann nicht mehr geht, wundert mich.

          Das change() sollte ja auch erst im folgenden Zyklus ausgewertet werden ... und selbst im gleichen Zyklus müsste der Timer ja starten ... versteh ich grad nicht, schau ich mir aber an.

          Naja, so ist es halt, wenn man es nicht testet
          BR
          Marc

          Kommentar


            #6
            Cool, ihr seid ja total fleißig, danke!
            Es gab doch mal neulich einen Thread über Code-Review, der dann aber wohl wieder eingeschlafen ist. Dieser hier lebt es :-)

            Deine Lösung, Klaus, gefällt mir sehr gut. Kommt völlig ohne Timer aus. Dürfte damit den EibPC weniger belasten, auch wenn die EibPC-Statistik eine etwas höhere Anzahl an Verarbeitungsobjekten ausgibt.

            Allerdings funktioniert sie auch nicht. Na gut, man muss nur das erste "change" weglassen ;-)

            Die Anforderung mit dem "Sofort" wird allerdings nicht erfüllt. Bei den nächsten Zyklen ist mir das Warten auf einen Minutenwechsel egal. So habe ich die letzte Bedingung etwas erweitert, und schon geht auch das:
            Code:
            if varWdhMin@ < 60u08 and (change(varWdhMin@) or (change(minute()) and mod(minute(), InZyklus) == varWdhMin@)) then {

            Kommentar


              #7
              Na, das freut einen doch!

              Kommentar


                #8
                Zitat von saft6luck Beitrag anzeigen
                ... und selbst im gleichen Zyklus müsste der Timer ja starten ...
                Der "Ausloeser" vor dem "or" scheint dazu zu führen, dass die Bedingung nach dem "or" nicht mehr ausgewertet wird. (So wie das bei anderen Sprachen ja auch ist.) Daher wird der Timer wohl nie gestartet.
                Interessanterweise ist das auch dann der Fall wenn man die Bedingungen vor und nach dem "or" vertauscht. (Was in anderen Sprachen funktionieren würde.)

                Nimmt man die beiden Bedingungen vor und nach dem "or" auseinander in separate Anweisungen, dann funktioniert es:
                Code:
                    varLokalCount@ = 0u08;
                    if InAusloeser then write(OutGA, OutWert); varLokalCount@ = varLokalCount@ + 1u08 endif;
                    if after(change(varLokalCount@), InZyklus) and InAusloeser then write(OutGA, OutWert); varLokalCount@ = varLokalCount@ + 1u08 endif;

                Kommentar


                  #9
                  Zitat von DerRenovator Beitrag anzeigen
                  ...

                  Deine Lösung, Klaus, gefällt mir sehr gut. Kommt völlig ohne Timer aus. Dürfte damit den EibPC weniger belasten, auch wenn die EibPC-Statistik eine etwas höhere Anzahl an Verarbeitungsobjekten ausgibt.
                  ...
                  @enertegus: Könntest Du hierzu mal eine Einschätzung abgeben?

                  Kommentar


                    #10
                    Zitat von DerRenovator Beitrag anzeigen
                    Der "Ausloeser" vor dem "or" scheint dazu zu führen, dass die Bedingung nach dem "or" nicht mehr ausgewertet wird. (So wie das bei anderen Sprachen ja auch ist.) Daher wird der Timer wohl nie gestartet.
                    Interessanterweise ist das auch dann der Fall wenn man die Bedingungen vor und nach dem "or" vertauscht. (Was in anderen Sprachen funktionieren würde.)
                    Sehr interessant, zumal eine derartige Optimierung beim eibPC schlicht falsch ist, also ein klarer Bug wäre, denn if GA then "expandiert" ja quasi zu if change(GA) and (GA == EIN) then.
                    Der entsprechende expandierte Wert ist aber nicht wahr und somit wäre es auch nicht zu "optimieren".

                    Da könnte aber auch der Unterschied liegen, denn für alle meine Logiken verwende ich in diesem Fall ein Makro GA_change(GA,EIN), welches zu change(GA) and (GA == EIN) wird. Finde ich einfach sicherer und besser zu lesen.

                    Falls dies also tatsächlich ein Problem der Optimierung sein sollte, sollte folgender Code laufen:

                    Code:
                    varAlarmEvent = 0u08;
                    if (change("Ausloeser-1/1/1") and "Ausloeser-1/1/1") or ( after(change(varAlarmEvent), 300000u64) and "Ausloeser-1/1/1" ) then write("Reaktion-1/1/2", EIN); varAlarmEvent++  endif;
                    NB:
                    Die Variante ohne Timer gefällt mir persönlich nicht.

                    Wieso soll ich mir einen eibPC anschaffen, der mein Haus automatisiert, wenn der dann generell Probleme mit Timern hat(?), wegen denen ich dann solchen unleserlichen Code produzieren muss?
                    Zumal hinter einem Cycle() sicher auch ein Timer steckt. Die Frage bleibt aber, ob hier ein "globaler" Timer verwendet oder auch nur wieder ein eigener Timer erzeugt wird.

                    Woher kommt eigentlich die Idee, dass Timer "Teufelszeug" sind? Ich habe nur einen Thread über die problematische Verwendung von cycle() gefunden.
                    Beim eibPC gilt wohl allgemein: Zuviel ist schlecht, egal wovon. Wenn du tatsächlich so viele Timer hast, die alle auch noch gleichzeitig laufen, dann erzeugt dir das cycle() auch jede Menge Lastspitzen (hier konzentriert sich die Ausführung ja auf die vollen Minuten). Und wenn du derlei Events selten und sowieso in geringen Mengen verarbeitest, dann sollte ein Timer ja der richtige Weg sein.

                    Only my 2 Cents.
                    Zuletzt geändert von saft6luck; 05.07.2015, 22:00.
                    BR
                    Marc

                    Kommentar


                      #11
                      Das hätte ich nicht gedacht. Mit dem zusätzlichen "change(Ausloeser)" funktioniert es tatsächlich!

                      Den Ausloeser habe ich jetzt noch "ausgeklammert", dann sieht das Makro doch ganz sprechend aus:
                      Code:
                      :begin JetztUndZyklischMarc(InAusloeser, InZyklus, OutGA, OutWert)
                      :info $Schreibt den OutWert auf die OutGA, sobald InAusloeser erfuellt ist. Dies wird zyklisch wiederholt solange InAusloeser erfuellt bleibt.$ \\
                          $Ausloesender Status (b01, GA oder Variable)$\\
                          $Zyklus in dem das Schreiben wiederholt werden soll (u64 in Millisekunden, Konstante)$\\
                          $GA auf die der Wert geschrieben wird$\\
                          $Wert der auf die GA geschrieben wird (GA oder Variable oder Konstante)$
                      :shortinfo $Event sofort senden und zyklisch wiederholen$
                      :var varLokalCount@
                          varLokalCount@ = 0u08;
                          if InAusloeser and (change(InAusloeser) or after(change(varLokalCount@), InZyklus)) then {
                              write(OutGA, OutWert);
                              varLokalCount@ = varLokalCount@ + 1u08;
                          } endif;

                      Kommentar


                        #12
                        Woher kommt eigentlich die Idee, dass Timer "Teufelszeug" sind?
                        Weiß nicht. Es gab mal einen Fall, dass jemand über 1500 Timer aktiv hatte. Dann hat man eine Verzögerung im Webserver gemerkt (ich glaub, das war noch V2).
                        An sich ist es dabei auch egal, ob man cycle, after, utc ... nutzt. Diese leiten sich alle vom Systemtimer ab und werden wie eine Verarbeitungsliste an diesem pro Zyklus angeheftet. Ich selbst habe hier auch schon über 2500 Timer im Einsatz gehabt, allerdings sollte dann natürlich nicht jeder Timer in jedem Zyklus was machen, sodass ständig alle Variablen neu verarbeitet werden müssen. In so einem Fall ist der EibPC dann irgendwann auch "lahm"....
                        offizielles Supportforum für den Enertex® EibPC: https://knx-user-forum.de/eibpc/
                        Enertex Produkte kaufen

                        Kommentar


                          #13
                          Na, das ist doch mal eine Aussage!

                          Irgendwie hat sich aus dem von Dir angesprochenen Thread im Hinterkopf festgesetzt, dass Timer besoders ressourcenhungrig wären - das wäre ja wohl hiermit ausgeräumt.

                          Kommentar


                            #14
                            und das Verhalten:
                            Sehr interessant, zumal eine derartige Optimierung beim eibPC schlicht falsch ist, also ein klarer Bug wäre, denn if GA then "expandiert" ja quasi zu if change(GA) and (GA == EIN) then.
                            Der entsprechende expandierte Wert ist aber nicht wahr und somit wäre es auch nicht zu "optimieren".
                            Konntet ihr das nachvollziehen?
                            EPIX
                            ...und möge der Saft mit euch sein...
                            Getippt von meinen Zeigefingern auf einer QWERTZ Tastatur

                            Kommentar


                              #15
                              Zitat von klaus_kraemer Beitrag anzeigen
                              Irgendwie hat sich aus dem von Dir angesprochenen Thread im Hinterkopf festgesetzt, dass Timer besoders ressourcenhungrig wären
                              Na was dahinter steht: Ein Timer muss jedesmal in der Liste abgearbeitet werden, reine Logik braucht überhaupt keinen Overhead. Daher sind dann eben 2000 Timer zu "spüren", 15000 Verarbeitungsobjekte nicht.
                              Code:
                              [FONT=inherit][FONT=inherit][FONT=inherit][FONT=inherit][FONT=inherit]if "Ausloeser-1/1/1" or ( after(change(varAlarmEvent), 300000u64) and "Ausloeser-1/1/1" )[/FONT][/FONT][/FONT][/FONT][/FONT]
                              hat keinen Bug: Wenn Ausloeser auf EIN steht, dann ist die or- Verknüpfung immer auf EIN, dann wird if auch nicht mehr "getriggert" (Validierung):
                              offizielles Supportforum für den Enertex® EibPC: https://knx-user-forum.de/eibpc/
                              Enertex Produkte kaufen

                              Kommentar

                              Lädt...
                              X