Subtracting two sensors containing time values

Hi folks

Been staring myself blind here…
I have two sensors containing a time value in the format HH:MM which I am trying to subtract from each other. This doesn’t work as the result of the template is 0 and not the actual result I am expecting of the sensors subtracted.

I am using the template editor, and it looks like this:

{{states('sensor.cradle_off_time') | float(0) - states('sensor.cradle_on_time') | float(0)}}

I am not entirely sure I need the float(0), but without it I get:

TypeError: unsupported operand type(s) for -: ‘str’ and ‘str’

When using:
{{states('sensor.cradle_off_time')}}
I get the value eg. 20:00

My sensor.cradle_off_time looks like this (the on-sensor is the same):

  - trigger:
      - platform: state
        entity_id: binary_sensor.cradle_in_use
        to: 'off'
    sensor:
      - name: cradle_off_time
        state: "{{ now().timestamp() | timestamp_custom('%H:%M') }}"

I hope that someone can help me out here. It is probably pretty simple when you know how.

Regards

Use as_timestamp to convert from datetime to epoch seconds. You then have the difference in seconds and can convert as needed.

  sensor:
    - name: "My Uptime"
      unique_id: "My Uptime"
      state: >-
        {% set boot = as_timestamp(states('sensor.ha_uptime'))|int %}
        {% set duration = as_timestamp(utcnow())|int - boot %}
        {{ timedelta(seconds=duration) }}

This is from my templates.yaml

Thanks for your reply!
Shouldn’t this be working then ?

{{as_timestamp(states('sensor.cradle_off_time'))|float - as_timestamp(states('sensor.cradle_on_time'))|float}}

Getting this error:

ValueError: Template error: as_timestamp got invalid input ‘20:00’ when rendering template ‘{{as_timestamp(states(‘sensor.cradle_off_time’))|float - as_timestamp(states(‘sensor.cradle_on_time’))|float}}’ but no default was specified

{{ '15:42:33' | as_timedelta }}

Since you have hh:mm suffix the string with ~ ':00'.

No, because there’s no date component. Use today_at in that case.

Hi Pieter
I feel that I quite close to something here. Just can’t grasp it completely.
Can you elaborate on where I would suffix the string with ~’:00’ ?

You can probably help me with the following too.
I would like to subtract current time from the sensor “sensor.cradle_off_time” last changed state to know for how long the state has been changed, in the format HH:MM. Currently the .last_changed gives me something like “1 hour ago” instead of 01:00 as I wish.

I have tried this:

{{ (as_timestamp(now())) - as_timestamp(states.sensor.cradle_off_time.last_changed)}}

Which gives something like: 6700.577723026276
Then I was thinking that I could convert it back to HH:MM with custom_timestamp like this:

{{ (as_timestamp(now())) - as_timestamp(states.sensor.cradle_off_time.last_changed) | timestamp_custom('%H:%M') }}

Which gives the error: TypeError: unsupported operand type(s) for -: ‘float’ and ‘str’

Any idea of how to convert/show the .Last_changed as HH:MM ?

Thanks!

You said your sensor gives HH:MM. The issue for as_timedelta is that if you give that to it, it will interpret it as MM:SS. So, you need to do this:

{{ (states('sensor.cradle_off_time') ~ ':00') | as_timedelta }}

I’ll check the rest tomorrow when I’m at a PC again. What card will you use to display this?

This is enough:

{{ now() - states.sensor.cradle_off_time.last_changed }}

The UI automatically interprets results like that depending on the card, card settings and device class used (e.g. if you set it as a duration).

But, you can force it with:

sensor:
  - platform: template
    sensors:
      your_sensor_as_hours_and_minutes:
        value_template: >-
          {% set delta = now() - states.sensor.cradle_off_time.last_changed %}
          {% set total_seconds = delta.total_seconds() %}
          {% set hours = total_seconds // 60 // 60 %}
          {% set minutes = (total_seconds) // 60 - (hours * 60)%}
          {{ '%02i:%02i' % (hours, minutes) }}

PS: datetime and timedelta objects are different and the functions of one won’t work on the other.

Man! You’re a wizard! :wink:

That results in: 0:08:56.264515
I thought there was a one-liner to omit “:56.264515” and add a character in the hour-field to result in: 00:08, which was my goal. But anyway your way of forcing it works great, it just adds more lines. But I guess that’s the way of doing it then.

My last goal now is to subtract the time when my babys cradle is off with the on time, to show the length of his nap.

Currently I have built the sensors to show the timestamp when the cradle was either on or off in two ways, which currently both works to show the time in HH:MM. You might be able to tell me which sensor is the easiest to work with, in order to subtract the timestamps.

type 1 (template under configuration.yaml)

  - trigger:
      - platform: state
        entity_id: binary_sensor.cradle_in_use
        to: 'off'
    sensor:
      - name: cradle_off_time
        state: "{{ now().timestamp() | timestamp_custom('%H:%M') }}"

type 2 (template under configuration.yaml. Updated via an automation which triggers on binary_sensor.cradle_in_use state change)

  - sensor:
      - name: cradle_off_time_test_sensor
#        device_class: timestamp (sensor not working if this line is not commented)
        state: "{{ state_attr('input_datetime.cradle_off_time_test', 'timestamp') | timestamp_custom('%H:%M', false) }}"
        icon: "mdi:calendar-clock"

The cradle_on_time sensors looks the same as above.

Which of the two types would be easiest to subtract and display as HH:MM ?
Eg on time: 01:00, off time: 02:15, nap: 01:15.

Thanks in advance!

I’ve been thinking about my lastest reply about the creation of the nap time duration sensor.
I believe I could just reuse your proposal for the value template to force-show sensor as HH:MM, as I now have a “baby asleep for” sensor based on that.

I would then have to save the HH:MM as a sensor value right before the cradle is turned off (indicating the nap has ended). I have an idea of how to do that using a automation.

What would be the best way of saving the HH:MM from the sensor, to display the value in my entity-card also as HH:MM? I am thinking of writing it to an input_datetime, but I think It has to have the format of HH:MM:SS to do that ? there might be a smarter way to store it for display ?

Store it in an input_text instead.

General comment:
All of this is basically working around the built-in mechanisms, since one has no option to display a time without seconds. Ideally, you’d store the full datetime object. Don’t confuse data with presentation. One should store the full thing and then display it as needed. For example, the entities card (but not the entity card) has an entity format option to display date, time, datetime, etc. One can display the input helper directly. One can also set the helper to store only a date, time or datetime.

Thanks. Will try input_text instead !
And thanks for the comment. It makes sense. I will try to adapt my HASS to it. Still a learning curve for me here :slight_smile: