Stopwatch with start/stop/resume, lap and reset

Miguel - this is really good work and you’ve come up with a short term solution to a simple stopwatch helper as the original poster requested. This is surely a huge amount of code compared to implementing a stopwatch helper for anyone interested in timing how long an entity is in a certain state.
I think your work here gives the developers a framework with which to implement a permanent stopwatch helper so the rest of us non-developers can accomplish this simple task without writing and debugging a lot of code. I’d like to keep track of how long my water heater is on whenever it fires and graph it. This has proven to be impossible,but may be possible after seeing your solution.

Again, nice work and thanks for the interim solution. If I try to implement this, you might see me back here asking for debugging help. I would prever a built in helper though.
Cheers

1 Like

Great to hear you.
If you need help to improve it, let me know.

Simple, yet effective creation! I use it to visually display the approximate status of a non-exposed timer running outside of HomeAssistant at this time. I added it 2 days ago and it was working great, but for some reason now it won’t show a continual elapsed time. It shows 00:00:00, even though the running attribute shows on. The state only seems to update when I stop the stopwatch. No change in the code from initial implementation. Has anyone run across this?

1 Like

In my case I haven’t had that problem. I’ve just tested and it works OK.

Try to show the state of sensor.stopwatch in Developer Tools → Template while the watch is running with the next code and check that its value updates every second. If so, it’s kind of a problem of Lovelace updating or visualization.

Template:

{{states('sensor.stopwatch')}}

You can also click on the card where the value is shown while running and the elapsed time should also be updated every second.

It just shows 00:00:00 everywhere, regardless of the status. It’s running (per the attribute) but the lovelace entity and the entity in Dev Tools both just show 00:00:00. It’s quite strange.

Does the input_boolean.tictac_stopwatch toggle? It’s the trigger that forces the value of the sensor updates every second. If not, you can check the traces of tic_tac_stopwatch automation in Settings → Automation and scenes → Tic tac stopwatch. If you start the stopwatch you should see that the “Last triggered” value updates every second. You can also check the traces. It should execute the toggle service on the input_boolean.

The problem with the stopwatch sensor is that there’s no way to look at its trace, I think.

You can also try to change the state of the sensor to something simpler as now(value) to check that sensor value updates when input_boolean.tictac_stopwatch toggles. To do this, change:

    sensor:
      - name: "Stopwatch"
        state: >-
          {% if is_state('input_boolean.reset_stopwatch','on') %}
              {{ '00:00:00' }}
          {% elif  is_state_attr('sensor.stopwatch','running','on') %}
              {% set value = as_timestamp(now()) - state_attr('sensor.stopwatch','initial_time') + state_attr('sensor.stopwatch','elapsed_time') %}
              {{ value|float|timestamp_custom("%H:%M:%S", False) + '.' + ((value|float*100)%100)|round(0)|string }}
          {% else %}
              {{ states('sensor.stopwatch') }}
          {% endif %}

with

    sensor:
      - name: "Stopwatch"
        state: "{{ now() }}"

Now stopwatch should show a complete date that updates every second.

1 Like

I’ve added animated gifs in the initial post to show it running.

So I found the error, and it was (obviously) a user error. When I initially integrated the yaml, I split the sections up into their respective files instead of doing a package. After it was working (flawlessly, I might add), I somehow ended up commenting my automations.yaml file out of my config, so they weren’t even loading. I didn’t even realize it until I dove into my config since I use NodeRed for 99% of my automations. It’s usually a mistyped or missing character that causes things to fail for me. It’s like looking for a needle in a haystack. Once again it’s working! I appreciate the help!

1 Like

Great news!

Thank you for your feedback.

I had to float(0) in line 66:

{{ as_timestamp(now()) - (state_attr('sensor.stopwatch','initial_time') | float(0) ) + (state_attr('sensor.stopwatch','elapsed_time') | float(0) ) }}

…or it failed to work, giving errors in the log and sensor.stopwatch not available.

sensor.stopwatch shows to milliseconds, which I don’t need for my application - I only need hours/minutes… is there an easy way to tweak to that? EDIT - saw the post above which had the same question, fixed.
Thanks for the stopwatch - I’m using it to track how long my pool pump runs on solar energy :slight_smile:

In my case, it works without casting to float(0). I don’t know why, really.

The stopwatch shows hundredths of a second if you use my code. If you only need hours:minutes, put this in the state of the sensor:

        state: >-
          {% if is_state('input_boolean.reset_stopwatch','on') %}
              {{ '00:00' }}
          {% elif  is_state_attr('sensor.stopwatch','running','on') %}
              {% set value = as_timestamp(now()) - state_attr('sensor.stopwatch','initial_time') + state_attr('sensor.stopwatch','elapsed_time') %}
              {{ value|float|timestamp_custom("%H:%M", False)|string }}
          {% else %}
              {{ states('sensor.stopwatch') }}
          {% endif %}

If you use the lap feature, and you also want values in hours:minutes, do the same change there.

1 Like

Thank you mate for sharing. I was looking for this feature to track how long my dish washer, washing machine and so on have been working and display it in dashboard. :slight_smile:

Would be cool anyway to have this feature as helper natively integrated.

2 Likes

Thanks for your work! Since history stats aren‘t working properly I used your stopwatch for counting some states. Like Someone mentioned above I had to reset the watches after I added them to Homeassistant to get them to work. But no problem.
Is there an easy way to geht the Sensor in an hour format (1,54 h for example) instead of 00:00:00:00? I am just tracking long term.

1 Like

You have to change the state of the sensor with:

        state: >-
          {% if is_state('input_boolean.reset_stopwatch','on') %}
              {{ '0:00 h' }}
          {% elif  is_state_attr('sensor.stopwatch','running','on') %}
              {% set value = as_timestamp(now()) - state_attr('sensor.stopwatch','initial_time') + state_attr('sensor.stopwatch','elapsed_time') %}
              {{ value|float|timestamp_custom("%H:%M h", False) |string }}
          {% else %}
              {{ states('sensor.stopwatch') }}
          {% endif %}

and in the button:

      name: >-
        {% if is_state('input_boolean.start_stopwatch','off') %}
          {% if is_state('sensor.stopwatch','0:00 h') %}
            Start
          {% else %}
            Resume
          {% endif %}
        {% else %}
          Stop/Pause
        {% endif %}

If you use the laps, and you also want it in the same format:

          laps: >-
            {% if is_state('input_boolean.reset_stopwatch','on') %}
              {{[]}}
            {% elif is_state('input_boolean.lap_stopwatch','on') and is_state_attr('sensor.stopwatch','running','on') %}
              {% set data = namespace(laps=state_attr('sensor.stopwatch','laps')) %}
              {% set value = as_timestamp(now()) - state_attr('sensor.stopwatch','initial_time') + state_attr('sensor.stopwatch','elapsed_time') %}
              {% set data.laps = (data.laps + [value|float|timestamp_custom("%H:%M h", False) |string]) %}
              {{ data.laps }}
            {% else %}
              {{ state_attr('sensor.stopwatch','laps')}}
            {% endif %}  

I’ve changed the code to show only hundreds of second when the stopwatch is stopped.

Thank you for your reply.

For my usecase (doing some graphs with plotly interactive graph card). I need a decimal point. So that instead of 01:54 h sensor should have the value 1.90 h is this possible?

In that case, state should be:

        unit_of_measurement: 'h'
        state: >-
          {% if is_state('input_boolean.reset_stopwatch','on') %}
              {{ '0,00' }}
          {% elif  is_state_attr('sensor.stopwatch','running','on') %}
              {% set value = as_timestamp(now()) - state_attr('sensor.stopwatch','initial_time') + state_attr('sensor.stopwatch','elapsed_time') %}
              {{(value|float/3600)|round(2)}}
          {% else %}
              {{ states('sensor.stopwatch') }}
          {% endif %}

Thank you sooooo much! This really helps me a lot :slight_smile:

1 Like

Thanks very much for providing this solution, its hopefully just what I’m looking for! Does anyone have any examples of how they have utilised this stopwatch into a front end display of state time?

What I’m hoping to achieve is to start this stopwatch when my clothes dryer enters a state of ‘running’, which will let me display the running duration of the drying cycle on a card. I would like tge stopwatch to stop, probably using the ‘lap’ function, when my dryer changes to the anti-crease cycle. I would need the last cycle run duration to remain visible while the machine is in the anti-crease cycle, kind of like a ‘split’ in a regular stopwatch.
Then when the anti-crease cycle ends, to stop the stopwatch and display that cycles run duration, and possibly a total combined run time. I could probably add a door sensor so that the dryer door is opened, it triggers a reset, ready for the next load of drying.

I’m not sure if I can achieve this but this stopwatch code seems like it should do what I need, along with some automations on top, but if anyone can help I would really appreciate it.

1 Like

You can create automations with triggers, the sensors in your clothes dryer, and the actions would be setting on and off the input_booleas: start_stopwatch, reset_stopwatch, and lap_stopwatch.

For instance, to start the stopwatch you can create an automation similar to this one:

description: "..."
mode: single
trigger:
  - platform: state
    entity_id:
      - binary_sensor.clothes_dryer
    from: "off"
    to: "on"
condition: []
action:
  - service: input_boolean.turn_on
    data: {}
    target:
      entity_id: input_boolean.start_stopwatch