Calculate endtime for a washing cycle

I want to display the end-time for a washing cycle on my dashboard. The washingmachine gives me a ‘time left’ as an attribute which I have converted to a sensor for ease of use and other display purposes on my dashboard.

But I am a bit stuck on how to calculate an endtime based on the current time and the time left.

I can fetch the time remaining either as

{{ state_attr('sensor.wasmachine', 'remain_time') }}

or

states('sensor.wash_timeleft')

This gives me a string as such “0:30:00”, “1:02:00”, “0:00:00”… etc.
What I want to do to is add this time to a now() (using now().strftime("%H:%M:%S") for example) and get a time that displays when the washingmachine will be done. So if it’s now 12:00 and the timeleft is “0:30:00” the finnish time should be 12:30 (30 minutes later).

Any help will be much appreciated!

Interesting case, this required a lot of fumbling. :slight_smile:

For this to work, I had to convert the string to a DateTime object and then convert that to a TimeDelta object in order to be able to add it to now(). remaining here is the DateTime object of the remaining time.

{% set remaining = strptime('00:12:30', '%H:%M:%S') %}
{{ now() + timedelta(hours=remaining.hour, minutes=remaining.minute, seconds=remaining.second) }}

This returns just the DateTime object in text. If you want to convert it back to a specific format, you can use srftime to convert it back. Also, you’d want to replace my placeholder text 00:12:30 to your sensor. The end result might look something like this:

{% set remaining = strptime(state_attr('sensor.wasmachine', 'remain_time'), '%H:%M:%S') %}{{ (now() + timedelta(hours=remaining.hour, minutes=remaining.minute, seconds=remaining.second)).strftime('%H:%M:%S') }}

Good luck! :slight_smile:

If you want to do some more with time calculations, I’d recommend this documentation.

1 Like

Wow @TomWis97 that worked like a charm! I did not expect it to take so much convertions. At least I get why I couldn’t figure this out! Thank you a lot!

One step closer to recreating all the features of the LG ThinQ app into my HA Dashboard! :smiley:

1 Like

It doesn’t require all that.

{% set h, m, s = "00:12:30".split(":") | map("int") %}
{{ now() + timedelta(hours=h, minutes=m, seconds=s) }}
1 Like

I chose for the option I went with because it’s a lot more flexible with other date notations (for other people finding this topic. I do agree that your answer might be a bit better readable.

What do you mean with “all that”? The only difference is that you interpret the input differently. You’d still need to read the state and convert it back to a more “friendly” string (resulting in the same long output as my reply).

There’s no reason to create a datetime object. There’s unnecessary attributes that come with it and it can be confusing if you don’t know how to use it. For example, your object has a date associated with it and a timezone. It’s easy to misuse.

Where as a tuple of 3 integers has no overhead and it’s hard to misuse them when you name them h, m, s.

Thanks both of you!

I’m only using it in a sensor and the first solution worked for me. I did forget one thing. If the washingmachine is turned off the calculation still happens and causes the current time to be displayed.

This probably isn’t the prettiest solution. But seems to work to display a “-” when the machine is done. And the time when it is running.

{% set remaining = strptime(state_attr('sensor.wasmachine', 'remain_time'), '%H:%M:%S') %}
{%- if now().strftime("%H:%M:%S") == (now() + timedelta(hours=remaining.hour, minutes=remaining.minute, seconds=remaining.second)).strftime('%H:%M:%S') -%}
   -
{%- else -%}
   {{ (now() + timedelta(hours=remaining.hour, minutes=remaining.minute, seconds=remaining.second)).strftime('%H:%M:%S') }}
{%- endif -%}

FWIW, there’s a chance for that template to fail, however it’s very low. Basically, if it’s executed slightly before 00 seconds it has a chance to fail. You should guard against that. This can be done by assigning now() to a variable so that you aren’t accessing it multiple times in your template. Each time you access it, it’s a new “now()” which means its slightly different from the last time you accessed it.

{% set t = now() %}
{% set h, m, s = (state_attr('sensor.wasmachine', 'remain_time') or '0:0:0').split(':') | map('int') %}
{% set remaining = timedelta(hours=h, minutes=m, seconds=s) %}
{% if t + remaining > t %}
  {{ (t + remaining).strftime("%H:%M:%S") }}
{% else %}
  -
{% endif %}

If you want a condensed version…

{% set t = now() %}
{% set h, m, s = (state_attr('sensor.wasmachine', 'remain_time') or '0:0:0').split(':') | map('int') %}
{% set remaining = timedelta(hours=h, minutes=m, seconds=s) %}
{{ (t + remaining).strftime("%H:%M:%S") if t + remaining > t else '-' }}

EDIT: The benefit of this is that you only convert to and from a timedelta or datetime object once. I.e. it’s optimzed well. You could optimize it a bit more by altering it this way.

{% set t = now() %}
{% set h, m, s = (state_attr('sensor.wasmachine', 'remain_time') or '0:0:0').split(':') | map('int') %}
{% set end = t + timedelta(hours=h, minutes=m, seconds=s) %}
{{ end.strftime("%H:%M:%S") if end > t else '-' }}

This only computes the difference once.

2 Likes

Wow thanks!