Alert / template sensor to track if hvac fails to improve the temperature?

I’d like to set up an alert if my hvac takes too long to improve the temperature in my house I.e., too long heating without a significant rise in temperature or too long cooling without a significant fall in temperature.

If template sensors supported conditions, I could imagine writing the code below (ignoring startup for simplicity). Without conditions, I’m unsure what to write that isn’t messy and brittle. Any suggestions?

template:
  - binary_sensor:
      - name "temp fl2 expect improvement"
        # If temp goes over or under the setpoints, we expect the hvac to start working
        state: >
          {{ ( is_state('climate.nest_therm_fl2', 'heat') and
               states('sensor.nest_therm_fl2_temperature')|float < state_attr('climate.nest_therm_fl2', 'temperature')|float ) or
             ( is_state('climate.nest_therm_fl2', 'cool') and
               states('sensor.nest_therm_fl2_temperature')|float > state_attr('climate.nest_therm_fl2', 'temperature')|float ) }}
  - trigger:
      - platform: state
        entity_id: binary_sensor.temp_fl2_expect_improvement
        to: "on"
        id: "t1"
      - platform: state
        entity_id:
          - sensor.nest_therm_fl2_temperature
        id: "t2"
    condition: >
      {% set tempDiff = states('sensor.nest_therm_fl2_temperature')|float - this.attributes.last_improvement_temp|float %}
      {{ trigger.id == "t1" or
         ( trigger.id == "t2" and
           states('sensor.nest_therm_fl2_temperature')|is_number and
           ( ( is_state('climate.nest_therm_fl2', 'heat') and tempDiff >= 1 ) or
             ( is_state('climate.nest_therm_fl2', 'cool') and tempDiff <= -1 ) ) ) }}
    sensor:
      - name: "temp fl2 last improvement"
        state: {{ now().timestamp }}
        attributes:
          last_improvement_temp: >
              {{ states('sensor.nest_therm_fl2_temperature') }}

alert2:
  alerts:
    - domain: fl2 hvac
      name: not_improving_temp
      condition: "{{ states.binary_sensor.temp_fl2_expect_improvement and
                     (now().timestamp() - states.sensor.temp_fl2_last_improvement|int) | int > 3600 }}"
      message: "hvac mode is states('climate.nest_therm_fl2') and Last improvement was at {{ as_local(states.sensor.temp_fl2_last_improvement|int) }}"
      notifier: telegram

Thanks for any thoughts.
-Josh

You may want to consider using the hvac_action instead of the the state of the climate entity, since that will tell you if it’s actively heating or cooling.

Another thing to consider might be a Trend sensor.

Thanks for the suggestions. I think I finally got it working, yaml code below. I ended up using two template binary_sensor to capture whether I "expect " the temperature to improve and whether the temperature “has” improved. That enabled me to get rid of the reliance on any template conditions and have a simpler triggered template sensor measuring the last time the temp improved, which I then alert off of.

I wanted the alert to widely catch issues that prevent the temperature from improving, such as hvac short cycling. That’s why I use the state of the climate entity rather than the hvac_action attribute.

template:
  - binary_sensor:
      - name: "temp fl1 expect improvement"
        state: >
          {{ ( state_attr('climate.nest_therm_fl1', 'hvac_action') not in [ 'idle', 'fan', 'off', 'unknown', 'unavailable' ] ) or
             ( state_attr('climate.nest_therm_fl1', 'temperature')|is_number and
               states('sensor.nest_therm_fl1_temperature')|is_number and
               ( ( is_state('climate.nest_therm_fl1', 'heat') and
                   states('sensor.nest_therm_fl1_temperature')|float <= (state_attr('climate.nest_therm_fl1', 'temperature')|float - 1) ) or
                 ( is_state('climate.nest_therm_fl1', 'cool') and
                   states('sensor.nest_therm_fl1_temperature')|float >= (state_attr('climate.nest_therm_fl1', 'temperature')|float + 1) ) ) ) }}
      - name: "temp fl1 has improvement"
        state: >
          {% set tempDiff = states('sensor.nest_therm_fl1_temperature')|float(0) - state_attr('sensor.temp_fl1_last_improvement', 'last_improvement_temp')|float(0) %}
          {{ states('sensor.nest_therm_fl1_temperature')|is_number and
             ( (not state_attr('sensor.temp_fl1_last_improvement', 'last_improvement_temp')|is_number) or
               ( is_state('climate.nest_therm_fl1', 'heat') and tempDiff >= 1 ) or
               ( is_state('climate.nest_therm_fl1', 'cool') and tempDiff <= -1 ) ) }}
  - trigger:
      - platform: state
        entity_id: binary_sensor.temp_fl1_expect_improvement
        to: "on"
      - platform: state
        entity_id:
          - binary_sensor.temp_fl1_has_improvement
        to: "on"
    sensor:
      - name: "temp fl1 last improvement"
        state: "{{ now() }}"
        attributes:
          last_improvement_temp: >
              {{ states('sensor.nest_therm_fl1_temperature')  }}


alert2:
  alerts:
    - domain: thermostat_fl1
      name: not_improving_temp
      condition: "{{ states('binary_sensor.temp_fl1_expect_improvement') and
                     states.sensor.temp_fl1_last_improvement.last_changed.timestamp()|int > 0 and 
                     (now().timestamp() - states.sensor.temp_fl1_last_improvement.last_changed.timestamp()) | int > 3600 }}"
      message: "hvac mode is {{ states('climate.nest_therm_fl1') }} and Last improvement was at {{ as_local(states.sensor.temp_fl1_last_improvement.last_changed) }}, temp trying to go from {{ states('sensor.nest_therm_fl1_temperature') }} -> {{ state_attr('climate.nest_therm_fl1', 'temperature') }} and last improvement was to {{ state_attr('sensor.temp_fl1_last_improvement', 'last_improvement_temp') }}"