Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. Deutsch
    3. Off Topic
    4. Microcontroller
    5. [Gelöst] EspHome: Zeit seit letztem State Wechsel

    NEWS

    • Wir empfehlen: Node.js 22.x

    • Neuer Blog: Fotos und Eindrücke aus Solingen

    • ioBroker goes Matter ... Matter Adapter in Stable

    [Gelöst] EspHome: Zeit seit letztem State Wechsel

    This topic has been deleted. Only users with topic management privileges can see it.
    • W
      WolfgangFB last edited by WolfgangFB

      Wie könnte man das realisieren? Ich hätte gerne einen Datenpunkt (State) in dem z.B. alle Minute aktualisiert wird, wann der Zustand von BinarySensor X zuletzt geändert worden ist.

      SBorg 1 Reply Last reply Reply Quote 0
      • SBorg
        SBorg Forum Testing Most Active @WolfgangFB last edited by

        @wolfgangfb Kommt darauf an was du genau mit dem Datenpunkt/Daten anstellen willst?
        Die letzte Änderung steht dir im entsprechenden Datenpunkt jederzeit zur Verfügung:
        Bild 001.png

        Da kommst du per "LC" (=last change) dran, zB. Javascript

        console.log (getState("esphome.0.xxxxxx.Sensor.xxxxx.state").lc);
        

        Du kannst jetzt natürlich auch ein Blockly nutzen welches auf "Änderung" triggert und dann den "LC" wieder in einen weiteren Datenpunkt schreibt.

        W 1 Reply Last reply Reply Quote 0
        • W
          WolfgangFB @SBorg last edited by

          @sborg
          Hi

          Ich möchte eigentlich gerade vermeiden, mit JS darauf reagieren zu müssen. Deshalb hätte ich gerne direkt aus dem ESP heraus die Info, wann z.B. ein Bewegungsmelder zuletzt ausgelöst hat (am besten in Sekunden).
          Im Moment scheiter ich aber gerade an der Syntax von Time_component und lambdas 😞

          1 Reply Last reply Reply Quote 0
          • W
            WolfgangFB last edited by

            @wolfgangfb
            So, ich habe es geschafft, vielleicht interessiert es ja auch andere, deshalb hier meine ausführliche Lösung.

            Mein Ziel war es, in der Vis auf einen Blick zu erkennen, wann z.B. eine Bewegungsmelder oder ein Türkontakt zuletzt ausgelöst hat.

            vis_movement.jpg

            Das ganze hatte ich ursprünglich in Javaskript realisiert, immerhin soll ja in de Regel auch irgendwas passieren, wenn der Bewegungsmelder auslöst 🙂 Aber mein Ehrgeiz war es, das ganze zu vereinfachen so dass der Sensor direkt die gewünschte Zeit ausgibt.
            Meine Sensoren sind in der Regel ESP8266 besiert, das ganze wird in ESPHome gemacht. Als Hardware verwende ich für den Bewegungmelder AM312 Sensor, der kostet bei Ali 40 Cent und ist meiner Meinung nach zuverlässiger als der HC-SR501

            Ein "nromaler" Bewegungsmelder sieht dort ja wie folgt aus:

            binary_sensor:
              - platform: gpio
                name: "Bewegung"
                pin: 
                  number: D5
            

            Damit wird ein Datenpunkt angelegt, der immer dann für ein paar Sekunden true wird, wenn der Bewegugsmelder auslöst. Damit kann man dann ein Licht steuern oder was auch immer.

            Jetzt zur Zeiterfassung und da habe ich eben gemerkt, dass C++ nicht meine (Programmier) Muttersprache ist. Hat mich einiges an Kopfzerbrechen gekostet bis ich da immer am Ende auf die richtige Syntax und die richtigen Typumwandlungen gekommen bin. C++ Experten dürfen mir hier auch gerne Vorschläge machen, wie der Code besser oder suaberer wird.

            Zunächst definiere ich mir eine Variale, in der die Sekunden seit dem letzten Auslösen gespeichert werden:

            globals:  
              - id: D5Last
                type: int
                restore_value: yes
                initial_value: '0'
            

            (id ist der Name der Variable, der Type eben, was darin gespeichert werden soll, restore_value sorgt dafür, dass der Wert bei einem Neustart erhalten bleibt und initial_value ist der Ausgangswert).

            Jetzt zur Zeit, hierfür wird die Time Komponente benötig:

            time:
              - platform: sntp
                timezone: Etc/GMT+1
                id: MySntp
                on_time:
                  - seconds: /5
                    then:
                      - lambda: |-
                          id(D5Last) += 5;
            

            Was macht dieser Teil: Es wird eine Echtzeituhr gestartet (die eigentliche Zeit werte ich hier garnicht aus) und alle 5 Sekunden wird ein Trigger ausgelöst, der auf die bisherige Zeit seit dem letzten Auslösen 5 (Sekunden) draufaddiert. Man könnte das ganze natürlich auch Sekündlich machen, bringt aber meiner Meinung nach nichts.
            Als nächstes muss die Zeit wieder auf 0 zurückgesetzt werden, wenn der Bewegungsmelder auslöst: Also den den Bewegungsmelder erweitern.

            binary_sensor:
              - platform: gpio
                name: "Bewegung"
                pin: 
                  number: D5
                on_state:
                  then:
                  - lambda: id(D5Last) = 0;
            

            Jetzt zum scvhwierigsten Teil, das ganze als fertig lesbaren Text mit Einheit "Sek" zu liefern so dass es dirket in die VIS eingebunden werden kann.

            Das ganze wird realisiert über einen sogenannten Textsensor. Die habe ich bisher dafür verwendet um beispielsweise die IP eines ESP anzuzeigen.

            text_sensor:
              - platform: template
                name: "IP"
                lambda: 'return {WiFi.localIP().toString().c_str()};'
            

            Jetzt musste ich ertmal kapieren, wie das mit den Lambdas und dem c_str etc. funktioniert.

            aber zunächst mal einen Datenpunkt anlegen:

              - platform: template
                name: "D5MotionLast"
                id: D5MotionLastID
                update_interval: never
            

            Das ist dann der Datenpunkt, der in Vis als "Text" eingebunden wird.
            (normalerweise wird so ein Textsensor alle 60 Seekunden aktualisiert, hier wird mit "never aber dafür gesorgt, dass er selbständig nie aktualisier, das will ich ja selbst steuern.)

            Also die Zeitkomponente erweitert:

            time:
              - platform: sntp
                timezone: Etc/GMT+1
                id: MySntp
                on_time:
                  - seconds: /5
                    then:
                      - lambda: |-
                          id(D5Last) += 5;
                      - text_sensor.template.publish:
                          id: D5LastId
                          state: !lambda return MyTime(id(D5Last));
            
            

            Mit text_sensor.template.publish kann man den Textsensor von außen mit einem neuen Wert versehen. Die Aufgabe war jetzt noch aus der nakten Zehl (int) eine schöne Ausgabe zu machen.
            Gehen würde das z.B. mit

            return str_sprintf("%02.0f sec",float(D5Last));
            

            aber ich wollte es schöner haben und 13565 Sekunden finde ich nicht sonderlich aussagekräftig.
            Also in der ersten Minute die Sekunden anzeigen, inder ersten Stunde die Minuten und am ersten Tag die Stunden, dann nur noch die Tage (wer will darf das ganze gerne auf Wochen, Monate etc. erweitern).
            Da ich das ganze nicht nur für einen Sensor mahen wollte habe ich mir überlegt, wie ich diese Funktion nicht bei jedem Sensor neu reinkopieren muss.
            Also die Funktion ausgelagert.
            Im gleichen Verzeichnis in dem die yaml Dateien sind eine Date "MyTime.h" angelgt und diese am Anfan in das yaml Projekt eingebunden:

            esphome:
              name: Testraum
              platform: ESP8266
              board: nodemcuv2
              includes:
                 - MyTime.h 
            

            die Datei "MyTime.h" sieht wie folgt aus:

            std::string MyTime(int secs){
              char Plural = ' ';
              if (secs > 60 * 60 * 24 *2 ) 
                {
                Plural = 'e';
                }
              if (secs < 60){
                return str_sprintf("%02.0f Sek", float(secs));
                } else
                {
                if (secs < 60 * 60){
                  return str_sprintf("%2.0f Min", abs(float(secs/60)));
                  } else
                  {
                  if (secs < 60 * 60 * 24){
                  	return str_sprintf("%2.0f Std", abs(float(secs/(60 * 60))));
                  	} else
                  	{
                  	return str_sprintf("%2.0f Tag%c", abs(float(secs/(60 * 60 * 24))), Plural);
                  	}
                  }
                }
              }
            

            (Das geht mit Sicherheit eleganter, Verbesserungsvorschläge nehme ich aber gerne an).

            Auf jeden Fall funktioniert das ganze und es wird sogar bei einem Tag nur "Tag" und ab dem zweiten Tag "Tage" ausgegeben 🙂

            Hier das ganze nochmal als komplettes yaml File das sich so auch übersetzen lassen sollte (wenn ich beim Copy&Paste keinen Fehler gemacht habe 🙂

            esphome:
              name: Testraum
              platform: ESP8266
              board: nodemcuv2
              includes:
                 - MyTime.h 
            
            # Enable logging
            logger:
            
            # Enable Home Assistant API
            api:
            
            ota:
              password: "xxxx"
            
            wifi:
              ssid: xxxx"
              password: "xxxx"
            
              # Enable fallback hotspot (captive portal) in case wifi connection fails
              ap:
                ssid: "xxxx"
                password: "xxxx"
            
            captive_portal:
            
            web_server:
              port: 80 
            
            globals:  
              - id: D5Last
                type: int
                restore_value: yes
                initial_value: '0'
            
            text_sensor:
              - platform: template
                name: D5Last
                id: D5LastId
                update_interval: never
            
            binary_sensor:
              - platform: gpio
                pin: 
                  number: D5
                on_state:
                  then:
                  - lambda: id(D5Last) = 0;
            
            time:
              - platform: sntp
                timezone: Etc/GMT+1
                id: MySntp
                on_time:
                  - seconds: /5
                    then:
                      - lambda: |-
                          id(D5Last) += 5;
                      - text_sensor.template.publish:
                          id: D5LastId
                          state: !lambda return MyTime(id(D5Last));
            
            
            1 Reply Last reply Reply Quote 0
            • K
              Kopterframe last edited by

              @wolfgangfb Servus, kann man auch z.B. bei

              time:
                - platform: sntp
                  timezone: Etc/GMT+1
                  id: MySntp
                  on_time:
                    - seconds: /5 # Wert aus einer Variable nehmen????
                      then:
              
              1 Reply Last reply Reply Quote 0
              • First post
                Last post

              Support us

              ioBroker
              Community Adapters
              Donate

              604
              Online

              32.0k
              Users

              80.4k
              Topics

              1.3m
              Posts

              3
              5
              836
              Loading More Posts
              • Oldest to Newest
              • Newest to Oldest
              • Most Votes
              Reply
              • Reply as topic
              Log in to reply
              Community
              Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen
              The ioBroker Community 2014-2023
              logo