Ankündigung

Einklappen
Keine Ankündigung bisher.

Manuell getriggerte Logik nicht über return_next() ermittelbar?

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

    Manuell getriggerte Logik nicht über return_next() ermittelbar?

    Hallo,

    ich triggere eine Logik Manuell:
    Code:
    >>> sh.trigger(name= 'Logi_Wecker_Hoch_Wenn_Hell', dt=(sh.now()+datetime.timedelta(seconds=10)))
    Ein return_next() gibt mir aber nichts zurück
    Code:
    >>> sh.scheduler.return_next('Logi_Wecker_Hoch_Wenn_Hell')
    weil _next nicht befüllt ist
    Code:
    >>> sh.scheduler._scheduler['Logi_Wecker_Hoch_Wenn_Hell']
    {'obj': <lib.logic.Logic object at 0x7f693804cb90>, 'prio': 3, 'value': None, 'next': None, 'cron': None, 'active': True, 'cycle': None}
    Logik wird dennoch wie erwartet nach 10 sek ausgeführt:
    Code:
    2013-11-03 15:41:45,390 DEBUG    Main         Triggering Logi_Wecker_Hoch_Wenn_Hell - by: Logic source: None dest: None value: None at: 2013-11-03 15:41:55.389881+01:00 -- scheduler.py:trigger:174
    2013-11-03 15:41:55,453 DEBUG    Logi_Wecker_Hoch_Wenn_Hell Trigger {'dest': None, 'source': None, 'by': 'Logic', 'value': None} -- logi_wecker.py:<module>:7
    Wie kann ich herrausfinden ob eine Logik für einen späteren Zeitpunkt (dt) eingeplant ist?

    Ist ein
    Code:
    sh.scheduler.change('Logi_Wecker_Hoch_Wenn_Hell', active=False)
    geeignet um dieses geplante Ausführen zu unterbinden?

    LG

    Mode

    #2
    Zusatzfrage.

    Bisher dachte ich immer ein mit dt terminierter Aufruf einer Logik, wird durch einen Aufruf der vor dt liegt "überschrieben". Dies scheint nicht so zu sein:

    Code:
    >>> sh.trigger(name= 'Logi_Wecker_Hoch_Wenn_Hell', dest = 'Logi_Wecker_Hoch_Wenn_Hell', value = True, dt=sh.now() + datetime.timedelta(seconds=10))
    >>> sh.trigger(name= 'Logi_Wecker_Hoch_Wenn_Hell', dest = 'Logi_Wecker_Hoch_Wenn_Hell', value = False)
    Log:
    Code:
    2013-11-03 15:58:17,511 DEBUG    Main         Triggering Logi_Wecker_Hoch_Wenn_Hell - by: Logic source: None dest: Logi_Wecker_Hoch_Wenn_Hell value: True at: 2013-11-03 15:58:27.511285+01:00 -- scheduler.py:trigger:174
    2013-11-03 15:58:19,319 DEBUG    Main         Triggering Logi_Wecker_Hoch_Wenn_Hell - by: Logic source: None dest: Logi_Wecker_Hoch_Wenn_Hell value: False -- scheduler.py:trigger:162
    2013-11-03 15:58:19,320 DEBUG    Logi_Wecker_Hoch_Wenn_Hell Trigger {'dest': 'Logi_Wecker_Hoch_Wenn_Hell', 'source': None, 'by': 'Logic', 'value': False} -- logi_wecker.py:<module>:7
    2013-11-03 15:58:27,756 DEBUG    Logi_Wecker_Hoch_Wenn_Hell Trigger {'dest': 'Logi_Wecker_Hoch_Wenn_Hell', 'source': None, 'by': 'Logic', 'value': True} -- logi_wecker.py:<module>:7
    Warum ist das so?

    Edit: So stehts auch im manual:
    dt timezone aware datetime object, which specifies the triggering time But watch out, if something else triggers that logic before the given datetime, it will not be triggered at the specified time!
    LG

    Mode

    Kommentar


      #3
      Hallo,

      manuells triggern läuft autark zu den Triggern über crontab, cycle und items.

      May the source be with you.

      Edit: hab die Doku angepasst.

      Bis bald

      Marcus

      Kommentar


        #4
        Hi,

        also ein einmal mit dt terminierter Trigger kann weder überschrieben noch gelöscht werden?

        Und in welchen Fällen kann ich sh.scheduler.return_next() nutzen? Nur beim manuellen Triggern nicht?


        LG

        Mode

        Kommentar


          #5
          Hallo Daniel,

          eigentlich ist return_next() eigentlich keine offiziell API-Schnittstelle, sondern war nur das CLI-Plugin gedacht.
          Aus meiner Sicht sind manuelle Trigger schon advanced Logiken, da bin ich zuversichtlich das sich auch andere Lösungen finden lassen.

          Bis bald

          Marcus

          Kommentar


            #6
            Ok, dann bin ich wohl schon advanced Logic Programmer

            Vielleicht hast du eine Idee wie meine Aufgabenstellung ohne manuelle Trigger ausführen kann:

            Ich möchte eine Jalousie 5 Minuten nach dem Triggern einer Logik hochfahren (bis hier hin einfach mit item.timer zu realisieren) aber das nur wenn die Außenhelligkeit dann über 10 Lux liegt. Liegt die Helligkeit unter 10 Lux soll die Jalousie erst dann hochfahren wenn die Helligkeit die 10 Lux überschreitet.

            Eine mögliche Lösungwäre ein eigenes Item zu definieren, was nicht mit KNX verbunden ist. Dieses könnte ich mit item.timer() triggern. Mit einem watch_item auf dieses Item kann ich in meiner Logik dann feststellen ob es hell genug ist und die Jalousien hochfahren. Wäre das eine gute Lösung?

            Bei item.trigger() besteht ja auch noch die Möglichkeit einen Trigger zu überschreiben was ich oft sehr nützlich finde. Zudem funktioniert scheduler.return_next(). Praktisch wäre es außerdem wenn return_next() direkt vom item aus aufrufbar wäre. -> item.return_next()

            LG

            Mode

            Kommentar


              #7
              Warum nicht einfach eine eigene Logik? Helligkeit und Trigger beobachten und sich selbst nach 5min triggern und auswerten was Sache ist. Entweder direkt Action oder Zustand merken und auf 10lux warten. Zu einfach?

              Kommentar


                #8
                sich selbst nach 5min triggern
                Sind wir dann nicht schon wieder beim manuellen Triggern?
                Ein
                Code:
                sh.trigger(name= 'Logik_in_der_ich_mich_beim_Aufruf_befinde')
                und
                Code:
                 logic.trigger()
                bewirken doch das gleiche -> manuelles Triggern?!?

                Kommentar


                  #9
                  den Trigger kannst du dir doch mit "dt = now+5 Minuten" entsprechend stellen? Dann logik-intern "Eieruhr-gestellt" merken. Wenn zwischendurch halt was passiert und du in 5min nix mehr machen willst halt den Zustand auf "Manuelle Bedienung" stellen. Oder trickreicher: Über die entsprechenden ".age" ermitteln, ob zwischendurch ein Fahrbefehl ausgeführt wurde und dann nix machen. Oder verstehe ich dein Problem falsch?

                  Was genau soll denn passieren?

                  jalousie_automatic.py
                  cron = werktags um 6 = day | wochenende um 8 = day | abends sunset + 6 = night
                  watchitem = außenhelligkeit | manuelle-bedienung-GAs

                  if trigger['by'] == scheduler:
                  je nach trigger['value'] generell hoch- oder runterfahren aktivieren, evtl. schon direkt fahren wenn Helligkeit ok?

                  else if by = Item and source = Helligkeit
                  gucken ob fahrt freigegeben und fahren

                  else if by Item and source manuelle-Bedienung
                  automatik für x Minuten/bis zu gewissen Ereignis sperren (oder eben dies hier über .age() der Fahrobjekte realisieren.

                  Kommentar


                    #10
                    Hallo Robert,
                    danke für deine ausführliche Antwort.

                    Ungefähr so habe ich es auch umgesetzt und es funktioniert. Ich dachte nur, man sollte vom manuellen Triggern wegkommen.

                    Mein Posting ging eher in die Richtung die Logiken vom Design her "schön" zu machen.

                    Wie speicherst du eines Status innerhalb eine Logik ab, so dass er beim nächsten triggern der Logik noch erhalten ist? Ich nutze aktuell ein item oder ein item.conf[] dafür.

                    Kommentar


                      #11
                      Zitat von mode Beitrag anzeigen
                      Wie speicherst du eines Status innerhalb eine Logik ab, so dass er beim nächsten triggern der Logik noch erhalten ist? Ich nutze aktuell ein item oder ein item.conf[] dafür.
                      einfach ein/mehrere Attribute:

                      setzen: logic.foo = xxx (oder setattr(logic, 'foo') <- als String!)

                      abfragen ob vorhanden: hasattr(logic, 'foo')

                      abfragen: logic.foo == xxx (oder getattr(logic, 'foo') <- wenn man das aus Itemnamen zusammenbastelt!)

                      löschen (als Flag!): del logic.foo

                      Ansonsten gilt: EAFP: Easier to ask for forgiveness than permission


                      Beispiel:

                      Logik die die automatische Fahrt des Raffstores der jeweils offenen Terrassentür sperrt. Aus dem Trigger wird die jeweilige Tür extrahiert, ein eigenes Attribut zur Speicherung der Zustands erzeugt (könnte ja auch vorher schon gesperrt gewesen sein), und über das ebenfalls zusammengebastelte Sperr-Item die Fahrt gesperrt. Bei Verschluss wieder rückwärts. Zusätzlich kann manuell die Sperre natürlich geändert werden.

                      PHP-Code:
                      #!/usr/bin/env python

                      #logger.info('{}: trigger={}'.format(logic.name, trigger))

                      # check if triggered by lock/unlocking door
                      if trigger['source'].endswith('verriegelt'):
                          
                      # get blind which corresponds to the door (Sued or West)
                          
                      id_str trigger['source'].split('.')[-1].split('_')[-2]
                          
                      auto_item sh.return_item('Wohnzimmer.Raffstore.Essbereich_' id_str '.Automatik')
                          if 
                      not trigger['value']:
                              
                      # if door was unlocked, save auto-state and disable
                              
                      setattr(logic'save_state_' id_strauto_item())
                              
                      auto_item(0logic.name)
                          else:
                              
                      # if door was locked, restore previous state if possible
                              
                      try:
                                  
                      auto_item(getattr(logic'save_state_' id_str), logic.name)
                              
                      except:
                                  
                      pass

                      # else check if auto-state was changed by somebody while logic was active
                      elif trigger['source'].endswith('Automatik'):
                          
                      auto_item sh.return_item(trigger['source'])
                          
                      id_str trigger['source'].split('.')[-2].split('_')[-1]
                          
                      # ignore changes introduced by this logic
                          
                      if not auto_item.changed_by().startswith(logic.name):
                              
                      setattr(logic'save_state_' id_strtrigger['value']) 
                      logic.conf
                      Code:
                      # Raffstoren-Automatik wird bei geöffneter Tür deaktiviert (und hinterher ggfl. wieder aktiviert)
                      [raffstoren_automatiksteuerung]
                          name = 'Raffstoren-Automatiksteuerung'
                          filename = raffstoren_automatiksteuerung.py
                          watch_item = Wohnzimmer.Fenster.Schiebetuer_*_verriegelt | Wohnzimmer.Raffstore.Essbereich_*.Automatik

                      Kommentar


                        #12
                        Und wie es so ist: Guckt man sich die eigenen Logiken an, findet man immer noch schönere Versionen:

                        raffstoren_automatiksteuerung.py
                        PHP-Code:
                        #!/usr/bin/env python

                        #logger.info('{}: trigger={}'.format(logic.name, trigger))

                        # check if triggered by lock/unlocking door
                        # get blind which corresponds to the door (Sued or West)
                        id_str trigger['source'].split('.')[-1].split('_')[-2]
                        auto_item sh.return_item('Wohnzimmer.Raffstore.Essbereich_' id_str '.Automatik')
                        if 
                        not trigger['value']:
                            
                        # if door was unlocked, save auto-state and disable
                            
                        setattr(logic'save_state_' id_strauto_item())
                            
                        auto_item(0logic.name)
                        elif auto_item.changed_by().startswith(logic.name):
                            
                        # if door was locked, restore previous state if possible and item was changed by logic last
                            
                        try:
                                
                        auto_item(getattr(logic'save_state_' id_str), logic.name)
                            
                        except:
                                
                        pass 
                        logic.conf
                        Code:
                        # Raffstoren-Automatik wird bei geöffneter Tür deaktiviert (und hinterher ggfl. wieder aktiviert)
                        [raffstoren_automatiksteuerung]
                            name = 'Raffstoren-Automatiksteuerung'
                            filename = raffstoren_automatiksteuerung.py
                            watch_item = Wohnzimmer.Fenster.Schiebetuer_*_verriegelt

                        Kommentar


                          #13
                          Hallo Robert und Marcus,

                          vielen Dank für eure Tipps. Meine Logik läuft nun wie gewünscht! :-)

                          Eine aktuell theoretische Frage habe ich noch:

                          Angenommen ich möchte 5 Minuten nach dem ein Fenster geöffnet würde die Heizung ausschalten. Wird das Fenster kürzer als 5 Min geöffnet soll die Heizung dementsprechend nicht ausgeschaltet werden.

                          Diese Logik ermöglicht all dies:
                          Code:
                          # Fenster geöffnet
                          if trigger['source'] == 'fenster' and trigger['by'] == 'Item' and not trigger['value']:
                              logic.heizung_aus = True
                              logic.trigger(dest = 'Heizung_aus', value = True, dt=sh.now() + datetime.timedelta(minutes = 5))
                          
                          # Fenster geschlossen
                          if trigger['source'] == 'fenster' and trigger['by'] == 'Item' and trigger['value']:
                              logic.heizung_aus = False
                          
                          #Trigger
                          if trigger['by'] == 'Logic' and trigger['dest'] == 'Heizung_aus' and trigger['value']:
                              if hasattr(logic,'heizung_aus'):
                                  if logic.heizung_aus:
                                      logic.heizung_aus = False
                                      item.heizung(False)
                          Jedoch gibt es einen Schwachpunkt.
                          Öffnet man das Fenster läuft der terminierte Trigger in 5 Minuten. Schließe ich das Fenster nach einer Minute wieder, so würde der Trigger, der 4 Minuten später auslöst nichts tun, da logic.heizung_aus = False ist. Öffne ich aber in der 3. Minute das Fenster, würde schon 2 Minuten später die Heizung ausgeschaltet, da das erste Öffnen den Trigger gestartet hat und das zweite Triggern einen weiteren Trigger gestartet hat (der uns hier nicht interessiert) und logic.heizung_aus wieder auf True gesetzt hat.

                          Mir fallen 2 Lösungswege ein:
                          - Mit item.timer() da man hier den Timer auf dem Item überschreiben kann.
                          - Mit item.age() arbeiten und prüfen ob age vom Item => als dt vom Trigger ist.

                          Beides für mich keine besonders schöne Lösungen.
                          Für die erste wird ein Item benötigt, was ich an dieser Stelle nicht immer benötige. Und ein Item zu erzeugen nur um einen Trigger überschreiben zu können ist mehr als unschön.

                          Freue mich über jede Idee :-)

                          LG

                          Mode

                          Kommentar


                            #14
                            Ich habs nicht ganz durchdrungen, aber warum willst du nach 5 Minuten überhaupt die Logik noch mal triggern? Dein "ungewünschtes" Item hast du doch eh:

                            Fenster auf -> Logik -> Timer Heizungsitem in 5 Minuten auf AUS
                            Fenster zu -> Logik -> Timer Heizungsitem in 2 Sekunden auf Heizungsitem() (seinen eigenen Wert) -> Timer "gelöscht".

                            edit: Oder wenn du Angst vor einer Race-Condition hast: den Timer einfach ins nächste Jahrtausend setzen...

                            Kommentar


                              #15
                              Hallo Robert,

                              Schaffst Du mit logic.foo=xxx einen persistentes Attribut was die items (soweit ich verstanden habe) nicht zulassen? Ist logic an dieser Stelle durch den Namen der Logik zu ersetzen oder bleibt es bei logic?
                              Ähnlich dem plugin_info beim WireGate, eben nur nicht Neustart resistent? Müsste doch auch mit item gehen?

                              Dank und Gruß
                              Mirko
                              Umgezogen? Ja! ... Fertig? Nein!
                              Baustelle 2.0 !

                              Kommentar

                              Lädt...
                              X