blueprint: name: HVAC Failure Monitor description: > Detects HVAC underperformance and hard failure by monitoring temperature trends when heating or cooling is active. Uses differential between setpoint and outdoor temp to dynamically adjust expectations. domain: automation input: thermostat: name: Thermostat description: The climate entity to monitor (must support hvac_action and setpoint attributes). selector: entity: domain: climate heating_temp_sensors: name: Heating Temperature Sensors description: One or more temperature sensors to monitor during heating (e.g. upstairs). default: [] selector: target: entity: domain: sensor device_class: temperature cooling_temp_sensors: name: Cooling Temperature Sensors description: One or more temperature sensors to monitor during cooling (e.g. downstairs). default: [] selector: target: entity: domain: sensor device_class: temperature outdoor_sensor: name: Outdoor Temperature Source description: Outdoor temperature source (e.g. from a weather entity). selector: entity: domain: weather monitoring_interval: name: Monitoring Interval (minutes) description: How long after HVAC starts to evaluate temperature change. default: 20 selector: number: min: 5 max: 120 unit_of_measurement: minutes mode: slider notify_target: name: Notification Target description: Who to notify on potential HVAC failure (e.g. mobile app). default: [] selector: target: entity: domain: notify mode: single trigger: - platform: state entity_id: !input thermostat attribute: hvac_action to: - heating - cooling variables: thermostat: !input thermostat heating_temp_sensors: !input heating_temp_sensors cooling_temp_sensors: !input cooling_temp_sensors outdoor_sensor: !input outdoor_sensor interval: !input monitoring_interval hvac_action: "{{ state_attr(thermostat, 'hvac_action') }}" direction: > {{ 'rising' if hvac_action == 'heating' else 'falling' }} selected_sensors: > {{ heating_temp_sensors if hvac_action == 'heating' else cooling_temp_sensors }} condition: [] action: - variables: indoor_start: > {{ expand(selected_sensors) | map(attribute='state') | map('float') | select('defined') | list | average }} - delay: minutes: "{{ interval }}" - variables: indoor_now: > {{ expand(selected_sensors) | map(attribute='state') | map('float') | select('defined') | list | average }} outdoor_now: > {{ state_attr(outdoor_sensor, 'temperature') | float }} setpoint: > {{ state_attr(thermostat, 'temperature') | float }} delta: > {{ abs(setpoint - outdoor_now) }} required_rate: > {% set d = delta %} {{ [0.01, [0.10, 0.10 - (d * 0.004)] | min] | max }} observed_rate: > {{ ((indoor_now - indoor_start) / interval) | round(3) }} trend_ok: > {% if direction == 'rising' %} {{ observed_rate >= required_rate }} {% else %} {{ observed_rate <= -required_rate }} {% endif %} hard_failure: > {% if direction == 'rising' %} {{ observed_rate < 0 }} {% else %} {{ observed_rate > 0 }} {% endif %} hvac_state_icon: > {% if hard_failure %} mdi:close-circle-outline {% elif not trend_ok %} mdi:alert-circle-outline {% else %} mdi:check-circle-outline {% endif %} hvac_state_text: > {% if hard_failure %} HVAC Failure {% elif not trend_ok %} Possible HVAC underperformance {% else %} Normal operation {% endif %} - choose: - conditions: "{{ not trend_ok }}" sequence: - choose: - conditions: "{{ notify_target | length > 0 }}" sequence: - service: notify.{{ notify_target }} data: message: > HVAC '{{ hvac_action }}' action for {{ interval }} minutes showed ineffective operation. Indoor temp started at: {{ indoor_start }}°, now: {{ indoor_now }}° Outdoor temp: {{ outdoor_now }}° Setpoint: {{ setpoint }}° Required rate: {{ required_rate }}°/min Observed rate: {{ observed_rate }}°/min Status: {{ hvac_state_text }} {{ hvac_state_icon }} default: - service: persistent_notification.create data: title: HVAC Alert message: > HVAC '{{ hvac_action }}' action for {{ interval }} minutes showed ineffective operation. Indoor temp started at: {{ indoor_start }}°, now: {{ indoor_now }}° Outdoor temp: {{ outdoor_now }}° Setpoint: {{ setpoint }}° Required rate: {{ required_rate }}°/min Observed rate: {{ observed_rate }}°/min Status: {{ hvac_state_text }} {{ hvac_state_icon }}