Betriebsstundenzähler

Hallo Gemeinde,
hat jemand schonmal einen “echten” Betriebstundenzähler in Home Assistant realisiert? Ich möchte die Betriebsstunden meiner Zisternenpumpe mitzählen. ON bekomme ich über den Shelly und einem template sensor > 30 W raus.

Wenn ich alles richtig bei History Stats gelesen habe, benötige ich hier einen start: Parameter … der liegt aber hier unendlich in der Vergangenheit (solange das Gerät lebt). Anscheinend gibt es hier auch ein recorder: Problem mit der Unendlichkeit.
Bin ich hier mit dem Ansatz History Stats auf dem Holzweg?
Andere Ansätze und Ideen?

Danke und Gruß
Frank

Lustigerweise habe ich 2 verschiedene Betriebsstunden Sensoren erstellt, als ich mit dem ganzen Spaß hier angefangen habe, quasi zum lernen, evtl gehts auch deutlich einfacher…

Wenn du die Betriebsstunden kennst, kannst du folgends machen.

als erstes brauchst du, wie du schon sagst, einen History Sensor.
Hier tracke ich die Zeit, wie lang der tv “on” ist. Start ist 0Uhr, der Sensor wird also immer um Mitternacht auf 0 gestellt, damit hab ich die tägliche tv_on_time_false. ich nenne sie false weil die ausgegebene zeit falsch angezeigt wird (2.77std) und später nochmal formatiert wird.

- platform: history_stats
    name: tv_on_time_false
    entity_id: media_player.lg_webos
    state: 'on'
    type: time
    start: '{{ now().replace(hour=0, minute=0, second=0) }}'
    end: "{{ now() }}"

nun einen Nummer Helfer erstellen, max anpassen wenn nötig,
nach dem er erstellt wurde draufklicken und man kann die bekannten betriebsstunden eingeben.
Nun eine Automation erstellen.

sie löst jeden tag um 23:59:59uhr aus, nimmt den aktuellen tageswert von tv_on_time_false und den aktuellen total wert des helfers, total_tv_time, der ja täglich mehr wird, zählt sie zusammen und schreibt den neuen wert wieder in den Nummern Helfer

alias: Update TV total on time
trigger:
  - platform: time
    at: "23:59:59"
action:
  - service: input_number.set_value
    data:
      entity_id: input_number.tv_time_total
      value: "{{ total_tv_time + tv_on_time }}"
variables:
  total_tv_time: "{{ states('input_number.tv_time_total') | float(0) }}"
  tv_on_time: "{{ states('sensor.tv_on_time_false') | float(0) }}"

weil der nummern helfer in der ui ■■■■■■■ ausieht hab ich noch einen “kombiniere sensor …” helfer erstellt und zeige den dann an :upside_down_face:

Version 2, hier beginnt die zeit speicherung erst mit erstellen der sensoren
Ich benutze mariaDB und speichere 32 Tage, damit kann ich einen Monat an Daten anzeigen.

Tägliche play time, woche, monat

- platform: history_stats
    name: ps5_play_time_false
    entity_id: sensor.ps5_activity
    state: 'playing'
    type: time
    start: '{{ now().replace(hour=0, minute=0, second=0) }}'
    end: "{{ now() }}"
      
  - platform: history_stats
    name: ps5_play_time_week_false
    entity_id: sensor.ps5_activity
    state: 'playing'
    type: time
    start: "{{ as_timestamp( now().replace(hour=0, minute=0, second=0, microsecond=0) ) - now().weekday() * 86400 }}"
    end: "{{ now() }}"
    
  - platform: history_stats
    name: ps5_play_time_month_false
    entity_id: sensor.ps5_activity
    state: 'playing'
    type: time
    start: "{{ now().replace(day=1, hour=0, minute=0, second=0, microsecond=0 ) }}"
    end: "{{ now() }}"

Wie oben schon erwähnt, muss man die Ausgabe nochmal formatieren.

- platform: template
    sensors:
      ps5_play_time:
        unique_id: PS5 Spielzeit
        value_template: >
          {% set play_time = states('sensor.ps5_play_time_false') | float(0) %}
          {% set hours = play_time | int %}
          {% set minutes = ((play_time - hours) * 60) | round %}
          {% if hours == 0 %}
          {% set text = '{} min'.format(minutes) %}
          {% else %}
          {% set text = '{} Std {} min'.format(hours, minutes) %}
          {% endif %}
          {% if play_time == 0 %}
            Off
          {% else %}
           {{ text }}
          {% endif %}
        
  - platform: template
    sensors:
      ps5_play_time_week:
        unique_id: PS5 Spielzeit (diese Woche)
        value_template: >
          {% set play_time = states('sensor.ps5_play_time_week_false') | float(0) %}
          {% set hours = play_time | int %}
          {% set minutes = ((play_time - hours) * 60) | round %}
          {% set days = 0 %}
          {% set weeks = 0 %}
          {% if hours >= 24 %}
          {% set days = hours // 24 %}
          {% set hours = hours % 24 %}
          {% endif %}
          {% if days >= 7 %}
          {% set weeks = days // 7 %}
          {% set days = days % 7 %}
          {% endif %}
          {% macro phrase(value, name) %}
          {%- set end = 'e' if value > 1 and name == 'Tag' else '' %}
          {%- set end = 'n' if value > 1 and name == 'Woche' else end %}
          {{- '{} {}{}'.format(value, name, end) if value > 0 else '' }}
          {%- endmacro %}
          {% set text = [phrase(weeks, 'Woche'), phrase(days, 'Tag'), phrase(hours, 'Std'), phrase(minutes, 'min')] | select('!=', '') | list | join(' ') %}
          {% if text == '' %}
            No Playtime
          {% else %}
          {{ text }}
          {% endif %}
         
  - platform: template
    sensors:
      ps5_play_time_month:
        unique_id: PS5 Spielzeit (dieser Monat)
        value_template: >
          {% set play_time = states('sensor.ps5_play_time_month_false') | float(0) %}
          {% set hours = play_time | int %}
          {% set minutes = ((play_time - hours) * 60) | round %}
          {% set days = 0 %}
          {% set weeks = 0 %}
          {% if hours >= 24 %}
          {% set days = hours // 24 %}
          {% set hours = hours % 24 %}
          {% endif %}
          {% if days >= 7 %}
          {% set weeks = days // 7 %}
          {% set days = days % 7 %}
          {% endif %}
          {% macro phrase(value, name) %}
          {%- set end = 'e' if value > 1 and name == 'Tag' else '' %}
          {%- set end = 'n' if value > 1 and name == 'Woche' else end %}
          {{- '{} {}{}'.format(value, name, end) if value > 0 else '' }}
          {%- endmacro %}
          {% set text = [phrase(weeks, 'Woche'), phrase(days, 'Tag'), phrase(hours, 'Std'), phrase(minutes, 'min')] | select('!=', '') | list | join(' ') %}
          {% if text == '' %}
            No Playtime
          {% else %}
          {{ text }}
          {% endif %}
        
  - platform: template
    sensors:
      ps5_play_time_year:
        unique_id: PS5 Spielzeit (dieses Jahr)
        value_template: >
          {% set play_time = states('sensor.ps5_play_time_year_false') | float(0) %}
          {% set hours = play_time | int %}
          {% set minutes = ((play_time - hours) * 60) | round %}
          {% set days = 0 %}
          {% set weeks = 0 %}
          {% if hours >= 24 %}
          {% set days = hours // 24 %}
          {% set hours = hours % 24 %}
          {% endif %}
          {% if days >= 7 %}
          {% set weeks = days // 7 %}
          {% set days = days % 7 %}
          {% endif %}
          {% macro phrase(value, name) %}
          {%- set end = 'e' if value > 1 and name == 'Tag' else '' %}
          {%- set end = 'n' if value > 1 and name == 'Woche' else end %}
          {{- '{} {}{}'.format(value, name, end) if value > 0 else '' }}
          {%- endmacro %}
          {% set text = [phrase(weeks, 'Woche'), phrase(days, 'Tag'), phrase(hours, 'Std'), phrase(minutes, 'min')] | select('!=', '') | list | join(' ') %}
          {% if text == '' %}
            No Playtime
          {% else %}
          {{ text }}
          {% endif %}

wie man sieht gibt es noch einen year sensor, das ist ein “verbrauchszähler” helfer der als eingangs sensor ps5_play_time_false hat und auf ein jahrliches rest gestellt ist. ich geh mal davon, dass es dadurch ein “long term” Sensor ist und dass die Daten auch über Jahre gespeichert werden.

I Love Data :crazy_face:

Ps: man könnt auch mit influx DB arbeiten, ich will aber nicht mit zwei DB arbeiten.

2 „Gefällt mir“

@meowmoo, mein außerordentlicher Respekt!
So viel Code als “Anfangsspaß” …

Herzlichen Dank für dieses umfangreiches Code Beispiel. Damit werde ich mich mal beschäftigen.
Deine Version 1 scheint auf dem ersten kurzen Blick für meine Zwecke, einfaches zählen der Pumpenstunden, ausreichend zu sein und als YAML Anfänger leichter nachvollziehbar als Version 2 :wink:.
Das “umformatieren” erschlägt mich geradezu :exploding_head:

Gruß
Frank

Hallo @meowmoo,
ich stehe vor einem Rätsel bei der Umsetzung Deiner Version 1
Der Sensor “sensor.3d_on_time_dezi” in Abhängingkeit funktioniert und liefert den aktuellenTageswert.
Der Helfer “input_number.3d_bstd_total_dezi” ist vorhanden und kann ich im Status setzen.
Die Automation ist über “neue Automation” kreiert, diesen Rumpf habe ich im Editor (automation.yaml) nachbehandelt mit der Addition und den Variablen. Diese zeigt sich auch in der Automation unter YAML Ansicht.


Dagegen hier unter Abläufe nicht!?!
grafik

Die Automation läßt sich manuell starten, aber verändert nichts.
Und sobald ich die YAML Konfiguration “Neuladen” ausführe, ist die Automation reproduzierbar gelöscht aber in der automation.yaml noch vorhanden !!!

automation.yaml:

 alias: 3D Drucker Bstd total
  description: Betriebstundenzähler 3D Drucker
  trigger:
  - platform: time
    at: '23:59:59'
  condition: []
  action:
  - service: input_number.set_value
    target:
      entity_id: input_number.3d_bstd_total_dezi
      data:
        value: "{{ total_3d_time + 3d_on_time }}" # addiere Tageswert zu Gesamtdauer
  variables:
   total_3d_time: "{{ states('input_number.3d_bstd_total_dezi') | float(0) }}" # Gesamt Betriebsdauer
   3d_on_time: "{{ states('sensor.3D_on_time_dezi') | float(0) }}" # Tages Betriebsdauer
  mode: single

Das neue @simon42 Video mit vielen Infos rund um Automationen liefert hier auch keine Hinweise
Gruß
Frank

Ne automation in der automation.yaml und in der gui zu bearbeiten, hat bei mir auch schon zu Probleme geführt.

Ich würde die automation nur über die HA gui erstellen. Also evtl nochmal aus der automation.yaml löschen und mit einem anderen Namen! Neu über die gui und Yaml mod erstellen. Ein reboot davor schadet nie

Um die automation zu testen kannst du diese Zeile von value: "{{ total_3d_time + 3d_on_time }}"

In

value: "{{ total_3d_time + 100 }}" 

Ändern dann sollte sich der total wert beim auslösen um 100 erhöhen.

Ansonst sehe ich auf den ersten Blick keine fehler.

Meine motivationskurve zeigt gerade abwärts :face_with_diagonal_mouth:
mit “100” geht die Automation!
grafik
dagegen kommt, sobald ich die Variable eintrage statt die 100, die Fehlermeldung:

Nach vielen Versuchen mit “try & error” bin ich nun hier und läßt sich zumindest fehlerfrei speichern:

alias: 3D Drucker BetriebsStd total
description: Betriebstundenzähler 3D Drucker
trigger:
  - platform: time
    at: "23:59:59"
condition: []
action:
  - service: input_number.set_value
    target:
      entity_id: input_number.3d_bstd_total_dezi
    data:
      value: >-
        {{ states('input_number.3d_bstd_total_dezi') +
        states('sensor.3D_on_time_dezi') }}
mode: single

Die Ausführung sagt aber:

Das versteht auch keiner hier eine “0”, dort eine 5,26:


grafik

Sorry @meowmoo, viel Input

Der Fehler tritt auf, weil states('input_number.3d_bstd_total_dezi und states('sensor.3D_on_time_dezi'') als Strings zurückgegeben werden und nicht als Float. ( wie der fehler ja sagt, klugscheiß modus)
In deinem Template test hast du es richtig gemacht, in der automation fehlt das float

value: >-
{{ (states('input_number.3d_bstd_total_dezi')|float +
states('sensor.3D_on_time_dezi')|float) }}

Und schon gehts :upside_down_face:

um die Motivation wieder zu steigern, mich hat das anfangs mehrere Tage wenn nicht wochen gekostet bis es funktioniert hat wie ich will :stuck_out_tongue:

@meowmoo
Yep, jetzt geht es mit den “|float” Ergänzungen und es läuft wie gewünscht.
Ich belasse es jetzt mal so, warum es mit den “variables: … |float” nicht ging eruiere ich nun nicht mehr. Ich denke, daß war genug unserer beider Zeit.

Herzlichen Dank
Gruß Frank

DANKE,

ich habe das Ding in der 1. Variante umgesetzt.

Das war schon eine schwerere Geburt am Ende und natürlich bin ich abgestürzt in die klar beschriebene Falle (in der Diskussion), dass config.yaml editieren und UI Geschichten sich beißen.
Wer daran arbeitet , der muss nach jedem yaml Schritt nicht nur speichern (hatte ich getan), sondern auch schließen und neu öffnen, ansonsten geht da was im Browser Cache fürchterlich daneben und produziert Folgefehler.

Ich habe Variante 1 genutzt, um die Betriebsstunden bei der Ölheizung zu messen, um daraus den Ölverbrauch am Tag herzuleiten, weil man bei der Betrachtung der flattrigen Leistungskurve erkennen kann, dass der Brenner ab 80 Watt Gas gibt und damit die Arbeitzeit zu laufen beginnt. Werden 80 Watt unterschritten, geht der Sensor auf 0. Da wir 33000 Liter Heizöl gekauft von vollem Tank zu vollem Tank gekauft haben, sind nun nach 15.000 Betriebsstunden und über 20 Winter sichere Daten für einen durchschnittlichen Winter da, sprich 2,06 Liter Öl / 2 h , denn das Gerät hat nur alle 2 Stunden weitergezählt.

Wird der Winter härter, springt sie halt öfter an, aber sie läuft mit konstantem Verbrauch an sich. Gute Übung, aber auch anstrengend bei den genannten Untiefen bzw. ich hab zu spät erkannt, was meine wachsenden Probleme verursachte.

Wer das auch bauen will, der schaut sich am besten zum Einstieg das Video hier an, weil es vieles erleichtert, ist allerdings english und auch in der original HA ANleitung eingebettet. Lohnt sich wirklich, um die hier eher knappe Anleitung auch in der Tiefe zu verstehen, was da alles abgeht. Wenige Zeilen, die es aber in sich haben.

Hut ab !

Hallo,
ich habe mir die Erklärungen von Dir mehrfach durchgelesen, kapiere es aber nicht so ganz. Ich möchte nur die Beriebsstunden meiner Geräte erfassen und im Dashboard anzeigen lassen.
Also habe ich erstmal diesen Code angelegt:

- platform: history_stats
    name: TV_heute
    entity_id: binary_sensor.tv_an_oder_aus
    unique_id: 'history_stats_tv_andy'
    state: "on"
    type: time
    start: '{{ now().replace(hour=0, minute=0, second=0) }}'
    end: '{{ now() }}'

Aber ich raffe es nicht, wie ich jetzt weiter machen muss um die Zeiten dann letztendlich im Dashboard anzeigen lassen zu können. Vielleicht kannst Du mir das kurz erklären?

Mach das mittlerweile damit

Macht es deutlich einfacher verschiedene Sensoren zu erstellen.

@Damrak2023
Tut mir leid, derzeit habe ich keine Antworten.
Momentan ist mein HA im Datenhimmel und arbeite noch an der Wiederherstellung.

Gruß
Frank

Hallo,
das scheint wirklich einfacher zu sei, aber momentan beiße ich mir an an der korrekten Konfiguration die Zähne aus.
Ich habe alle meine Geräte an Shelly Plug S hängen und möchte praktisch die Zeit messen wienlange ein Gerät insgesamt eingeschaltet war. Das mach ich anhand des erhöhten Stromverbrauchs.

So bin ich bis jetzt vorgegangen:

  1. Bei Measureit “Time” ausgewählt
    2.“Laufzeit Schreibtischlampe”

Mein bisheriger Code war so:

{% if float(states.sensor.shellyplusplugs_e465b893531c_switch_0_power.state) > 1.5%}
  on
{%else%}
  off
{%endif%}

Mir ist nicht ganz klar was bei “condition template” und im nächsten Step bei “value template” genau rein muss

Bei condition template musst du angeben wann/was gemessen wird z. B

{{ is_state('shellyplusplugs_e465b893531c_switch_0_power', 'on') }}

Wenn der state vom Shelly on ist wird angefangen zu messen.

Value template kannst du leer lassen, ausser du willst das Ausgabe Format ändern. Standart ist h:m:s

Ich muss nochmal nachfragen, da ich bei einigen Geräten folgende Meldung im Protokoll angezeigt bekomme.

Laufzeit Raspberry # Encountered a template error: ValueError: Template error: float got invalid input 'unavailable' when rendering template '{{ states('sensor.raspberry_power') | float > 3 }} Wh' but no default was specified. Could not start or stop measuring!
Laufzeit Router # Encountered a template error: ValueError: Template error: float got invalid input 'unavailable' when rendering template '{{ states('sensor.router_power') | float > 8 }} Wh' but no default was specified. Could not start or stop measuring!
Laufzeit Schreibtischlampe # Encountered a template error: ValueError: Template error: float got invalid input 'unavailable' when rendering template '{{ states('sensor.shellyplusplugs_e465b893531c_switch_0_power') | float > 8 }} Wh' but no default was specified. Could not start or stop measuring!
Laufzeit Hisense TV # Encountered a template error: ValueError: Template error: float got invalid input 'unavailable' when rendering template '{{ states('sensor.shelly_tv_hisense_switch_0_power') | float > 10 }} Wh' but no default was specified. Could not start or stop measuring!
Laufzeit Waschmaschine # Encountered a template error: ValueError: Template error: float got invalid input 'unavailable' when rendering template '{{ states('sensor.waschmaschine_power') | float > 5 }} Wh' but no default was specified. Could not start or stop measuring!

Bevor ich das “Wh” hinzugefügt habe, bekam ich einen Fehler das kein Wert definiert sei.
Ich habe in allen condition templates folgenden Code mit der jeweils passenden Entität eingegeben:

{{ states('sensor.shelly_tv_hisense_switch_0_power') | float > 10 }} Wh

Deine Sensoren sind unavailable daher kann die template nicht aufgelöst werden. Warum sinnd sie nicht verfügbar? Nur nach nem Neustart?

Habs grad damit versucht.
{{ states('sensor.smart_plug_links_power') | float > 10 }}

Also ohne Wh und das geht bei mir einwandfrei


Ah okay, mein System schmeisst mittlerweile soviel Fehler raus, das ich überlege nochmal von vorne anzufangen, denn ich kann mit den meisten Fehlermeldungen nichts anfangen.