Measure duration of time between sensor states

I am attempting to measure the cycle time of my sump pump. I have a binary_sensor working with a float so I can already track exactly when the float device is “off” and thus the pump just finished running.

The template sensor “Sump Pump Last Off” below is working. The cycle time should be a calculation between this sensor turning off, and the prior time this same sensor turned off. I’m not sure the best way to do this in HA?

The cycle time code below is not what I want as it tells me the time the time the sensor has gone from “on” to “off”.

template:
  - trigger:
      - platform: state
        entity_id: binary_sensor.water_level_sensor
        from: 'on'
        to: 'off'
    sensor:
      - name: "Sump Pump Last Off"
        unique_id: sump_pump_last_off
        state: "{{ now().timestamp() | timestamp_custom('%I:%M %p %a') }}"

      - name: "Sump Pump Cycle Time"
        unique_id: sump_pump_cycle_time
        state: "{{ (trigger.to_state.last_changed|as_timestamp - trigger.from_state.last_changed|as_timestamp) | int }}"
        unit_of_measurement: "Seconds"
template:
  - trigger:
      - platform: state
        entity_id: binary_sensor.water_level_sensor
        from: 'on'
        to: 'off'
    sensor:
      - name: "Sump Pump Last Off"
        unique_id: sump_pump_last_off
        state: "{{ now().timestamp() | timestamp_custom('%I:%M %p %a') }}"

  - trigger:
      - platform: state
        entity_id: sensor.sump_pump_last_off
        not_from: 
          - unknown
          - unavailable
    sensor:
      - name: "Sump Pump Cycle Time"
        unique_id: sump_pump_cycle_time
        state: >
          {{ (trigger.to_state.state | as_datetime 
          - trigger.from_state.state | as_datetime).total_seconds() }}
        unit_of_measurement: "Seconds"
1 Like

Thanks!

I see the first thing is I was triggering off binary_sensor.water_level_sensor instead of sensor.sump_pump_last_off. Makes sense.

I am still having an issue with the cycle time and I think it has to do with the date formats in that subtraction? As written above, the cycle time stays at “unavailable” forever even though the sump_pump_last_off time is updating properly.

Yep, I just realized that too… the quick fix would be to change the state of the first sensor to {{ now() }}. If that’s out of the question, I can figure out the template in a little bit.

EDIT:

template:
  - trigger:
      - platform: state
        entity_id: binary_sensor.water_level_sensor
        from: 'on'
        to: 'off'
    sensor:
      - name: "Sump Pump Last Off"
        unique_id: sump_pump_last_off
        state: "{{ now().timestamp() | timestamp_custom('%I:%M %p %a') }}"

  - trigger:
      - platform: state
        entity_id: sensor.sump_pump_last_off
        not_from: 
          - unknown
          - unavailable
    sensor:
      - name: "Sump Pump Cycle Time"
        unique_id: sump_pump_cycle_time
        state: >
          {% set to = trigger.to_state.state %}
          {% set from = trigger.from_state.state %}
          {%- macro str_to_dt(x) %}
          {{- (strptime(now().date()~' '~x~' '~now().strftime('%z'), 
          '%Y-%m-%d %I:%M %p %a %z', 0 | as_datetime )) }}
          {%- endmacro %}
          {{ (str_to_dt(to) | as_datetime - str_to_dt(from) | as_datetime).total_seconds() }}
        unit_of_measurement: "Seconds"

Sorry, I should have added a comment that I do NOT need to keep the current time formatting in the sump_pump_last_off sensor. I see that is making this more difficult than it needs to be.

I tried your latest code and it seems to be working! I thought it wasn’t but it was just that it took 2 runs to clear out the last times.

I think I’m gonna keep at it until I can just do a basic timestamp comparison though.

Minor fix of changing now().timestamp() | as_datetime made it work with your first set of code. Thanks a bunch!!!

template:
    sensor:
      - name: "Sump Pump Last Off"
        unique_id: sump_pump_last_off
        state: "{{ now().timestamp() | as_datetime }}"
        
  - trigger:
      - platform: state
        entity_id: sensor.sump_pump_last_off
        not_from: 
          - unknown
          - unavailable
    sensor:
      - name: "Sump Pump Cycle Time"
        unique_id: sump_pump_cycle_time
        state: >
          {{ (trigger.to_state.state | as_datetime 
          - trigger.from_state.state | as_datetime).total_seconds() | int }}
        unit_of_measurement: "Seconds"
1 Like

FWIW, now() on its own already returns a properly formatted datetime string, so there’s no need for the .timestamp() | as_datetime

1 Like

Really appreciate your help with this. I’ve checked this one off my “HA To-Do” list finally! :grinning_face_with_smiling_eyes: