Home Assistant

HVAC health monitor

When the thermostat is actually calling for heat or cool, check that room temperature moves the right way within a set time; send a critical alert if it does not — failed equipment, a frozen coil, or a dirty filter.

Difficulty · IntermediateSetup · 45–90 minutesHA · current stable (blueprint)
Get the pack · from $19Have us set it up

Some hardware links on this page are affiliate links. As an Amazon Associate I earn from qualifying purchases. We may earn a commission if you buy through them, at no extra cost to you. See the affiliate disclosure.

A thermostat that says heating is not the same as a room that is getting warmer. A dirty flame sensor, a frozen coil, or a filter that has gone solid will run the fan for an hour while the temperature sits still — or walks the wrong way. This workflow starts a clock when hvac_action becomes heating or cooling, snapshots the room temperature, waits a dwell you pick, and pages critically if the number did not move far enough in the right direction.

Entity ids are blueprint inputs. Do not publish a live thermostat name.

If an open sash is the more likely reason heat is “on” and the room is not warming, pause the system first with window-open climate pause so this monitor does not treat a propped door as failed equipment.

What problem it solves

You want to know the equipment is doing work — not that the setpoint is armed — before a space sits at the wrong temperature for a whole afternoon.

How it works

  1. Call starts — climate hvac_action goes to heating or cooling (not fan or idle). The pack records start temperature in an input_number and, for cool, a start timestamp.
  2. Dwell — wait long enough that a healthy system would have moved the room. Defaults in the pack: about 30 minutes for heat, about 90 minutes for cool. Short cycles that hit setpoint and stop before the dwell are a success, not a miss.
  3. Direction + magnitude — after the wait, if the thermostat is still calling, the room must have dropped (cool) or risen (heat) by at least the tolerance (default about 0.4 °C / 0.7 °F). The tolerance must sit under the thermostat’s deadband or every normal cycle looks like a failure.
  4. Failure counting — cool: increment a consecutive-failure counter; reset on a good cycle; alert when it hits the limit (pack default 2). Heat: increment a weekly counter (flame sensors fail intermittently); reset Sunday; alert when the week’s count crosses the limit.
  5. Runaway cool — if cooling has been continuous past a long-runtime helper (hours, not minutes), fire a separate critical notify. That is the dirty-filter / low-refrigerant shape.
  6. Critical notify — Companion interruption-level critical (iOS) or high (Android), plus a persistent card. Separate actions for heat, cool, and long runtime so the message names the failure mode.

This is a performance check, not a service manual. A page means “look at the equipment,” not a diagnosis of which part failed.

Hardware notes

  • Climate entity. Must expose hvac_action of heating / cooling / idle. Confirm in Developer Tools → States before you import. Some Wi-Fi stats only report hvac_mode (what you asked for), not what the equipment is doing — those will not trigger.
  • Temperature. The thermostat’s current-temperature attribute is enough if it tracks the room. A separate sensor in the same space is better when the stat sits in a hallway.
  • No extra hub. Helpers plus a notify service. Power-draw clamps are useful later; they are not required for this pack.
  • Smart stats. Nest-class predictive deadbands confuse a naive “did it move?” check. The pack can disable deadband warnings for those.

Snippet

The pack ships a blueprint. Inputs replace real entity ids:

trigger:
  - platform: state
    entity_id: !input climate_entity
    attribute: hvac_action
    to: "cooling"
    id: cool_start
  - platform: state
    entity_id: !input climate_entity
    attribute: hvac_action
    to: "heating"
    id: heat_start
action:
  - service: input_number.set_value
    target:
      entity_id: !input start_temp
    data:
      value: "{{ state_attr(climate_entity, 'current_temperature') }}"
  - delay:
      minutes: !input cool_runtime
  - condition: state
    entity_id: !input climate_entity
    attribute: hvac_action
    state: "cooling"
  - condition: template
    value_template: >
      {{ (start | float - current | float) < (tolerance | float) }}
  - service: notify.notify
    data:
      title: "HVAC — cooling not moving the room"
      data:
        push:
          interruption-level: critical
  # heat branch + counters: full blueprint in the pack

Setup outline

  1. Confirm hvac_action on the climate entity. Create the pack helpers (start temp, two failure counters, cooling start datetime, long-runtime threshold).
  2. Import the blueprint. Point it at the climate entity (and optional room sensor). Leave defaults for the first week.
  3. Watch traces on a normal heat and a normal cool cycle. If a healthy run increments a failure counter, drop the tolerance or raise the dwell — do not chase the notify yet.
  4. Test the alert path without touching the equipment. For one cycle, set the tolerance higher than a healthy system can reach in the dwell (for example 5 °C / 9 °F) and shorten the dwell to about 10 minutes. Then raise the setpoint a few degrees (heat) or lower it (cool) so the thermostat calls. Confirm one critical push, then put the tolerance, dwell, and setpoint back.

Troubleshooting

  • Never triggers. The integration does not publish hvac_action, or it uses heat / cool instead of heating / cooling. Fix the attribute mapping; do not trigger on hvac_mode alone.
  • False alarm every cycle. Tolerance is larger than the deadband, or the dwell is longer than a short winter cycle. Lower tolerance first; then shorten dwell.
  • Missed a real dead unit. Dwell is shorter than the room’s thermal mass, or you are reading a sensor in a different space than the stat. Move the sensor or lengthen cool dwell toward 90 minutes.
  • Heat pages on an open window. The room is dumping heat on purpose. Use window-open climate pause so hvac_action goes idle while the opening is actually open.

Credits

Based on the community blueprint HVAC Health Monitor — detect system performance issues. This write-up is an original overview of the call-then-measure pattern.

Changelog

v1.0 · Oct 16, 2026: First publish.