My Home Assistant blueprint Klimaanlage Smart Control drives a split AC fully automatically: heating, cooling, window-open-stop, presence and room presence, vacation mode, adaptive cooling target, minimum cycle against short cycling, and floor-heating coordination. Code, docs, one-click import button, and CI validation are now on GitHub. I'll walk through every design decision, show the Jinja templates, three real days from my telemetry, and the sensor lessons I learned over two summers of iteration.
What's the deal? 🧐
I have a split air conditioner mounted in my home office. In summer it cools, and during shoulder seasons it heats faster and cheaper than the underfloor heating. The problem without automation: it either runs forever or I forget to turn it on at all. Neither is great, one costs me money, the other my focus, because after three hours of coding in a 28-degree oven I'm producing typos like a first-day intern.

So I built the blueprint that does exactly one thing right: drive an AC intelligently so I never have to think about it again. Safety checks come first (window open, nobody home, vacation on: AC stays off). Comfort comes next. Efficiency is baked in everywhere: adaptive targets, minimum cycle, hysteresis. The finished blueprint, including README, MIT license, issue templates, and CI validation, is now public on GitHub:
My setup context: why AC in a home office? 🏗️
Quick context, because the defaults in the blueprint won't make full sense without it. My office is a top-floor room with three exterior walls, a large west-facing window, and an underfloor heating system fed by a condensing boiler. Which means:
- In summer it gets unbearable after 2 pm, even when "only" 28 °C outside. Solar gain plus roof slope plus three exterior walls equals a thermally unfortunate room.
- In shoulder seasons (March/April, September/October) the underfloor heating doesn't pay off because it takes 4 hours to lift the room from 17 to 21 °C. The AC in heating mode does it in 15 minutes.
- In deep winter (below −5 °C outside) the heat-pump COP drops so far that the underfloor heating becomes the better option again. So I need an outdoor-temperature-dependent decision on which system heats.
These three points are why the blueprint isn't "AC on when warm, off when cold" but rather the tangled condition net you'll see below. If your room is thermally unproblematic, you can leave many inputs on null/default and the logic falls back gracefully to a simple variant.
The backstory: why the old blueprint wasn't enough 📜
My first AC blueprint was smart-ac-automation.yaml, a monolithic 40 KB beast based on a single trigger sensor plus time window. Worked for 90 % of cases, but:
- No heating mode. Come April I didn't feel like manually swapping between two blueprints.
- No room presence. When I briefly went to the bathroom, the AC stayed on. Sounds harmless but adds up to 30 to 60 minutes of unnecessary runtime per day. At 800 W inverter load that's 0.4 to 0.8 kWh per day, just because I needed a pee break.
- No vacation mode. On a 10-day trip in August the AC ran for four days before I noticed I'd forgotten to disable it. Electricity bill shock.
- Static target. 26 °C or 36 °C outside, the cooling target was stuck on 21 °C. Result at 36 °C outside: continuous compressor full-tilt operation. The inverter whine eventually got so loud I had to put headphones on.
- Short-cycle chaos without hysteresis. With jittery sensor values the AC was clicking every one or two minutes. After two years the compressor started whistling. The service tech said: "Switching cycles count more than runtime."
Point 5 was the trigger. I sat down, listed all the problems, and made a clean restart: not patching the old blueprint but writing a new one that bakes in the lessons learned from day one. The result is what's now in the repo.
Why not just use HA's Climate Scheduler? 🤔

| Requirement | HA Climate Scheduler | Klimaanlage Smart Control |
|---|---|---|
| Fixed schedule | ✅ | ✅ |
| Window-open stop | ❌ (separate automation) | ✅ built in, with restart logic |
| House-level presence | ❌ | ✅ |
| Room presence with grace time | ❌ | ✅ configurable |
| Vacation mode | ❌ | ✅ via input_boolean |
| Adaptive cooling target | ❌ | ✅ (Δ indoor-outdoor capped) |
| Minimum cycle (compressor protection) | ❌ | ✅ configurable |
| Hysteresis | ❌ (single setpoint) | ✅ separate for cooling/heating |
| Floor-heating coordination | ❌ | ✅ |
| Allow AC self-regulation | ❌ | ✅ optional |
The HA scheduler is fine for "on at 7, off at 22". The moment you need contextual decisions, you start gluing ten little automations around it, each with its own trigger, its own condition, its own race condition. That mess is exactly what the blueprint avoids.
What the blueprint does 🧠
- Heating and cooling in a single automation. No swapping blueprints between seasons.
- Window logic: contact open → AC off immediately. Window closed again → AC waits for the next regular trigger, not an instant restart. Ventilation should stay ventilation.
- Presence on two levels: house (anyone home?) and room (someone actually in the office?). Room presence has a configurable grace period so a quick bathroom break doesn't kill the AC.
- Vacation mode: a single
input_boolean.urlaublocks everything down. Frost protection stays with the thermostat itself. - Adaptive cooling target: 18 °C inside with 32 °C outside is a shock to the system (and your body). The Δ between inside and outside is capped, 7 °C default.
- Minimum cycle: after switching off, at least X minutes pause before the compressor can restart. Inverters don't enjoy 90-second cycles.
- Self-regulation: if your AC has a decent inverter, let it handle fine target tracking and have the automation only flip ON/OFF.
- Floor heating coordination: turned off when the AC kicks in, switched back to
heatwhen the AC stops, but only if it's actually heating weather. - Defensive against sensor failures:
unavailableorunknownon a required sensor → automation aborts instead of switching blindly.
Inputs at a glance 📋
All inputs are grouped into sections in the HA UI, with defaults that fit a normal German home office out of the box:
| Section | Input | Default |
|---|---|---|
| Device | climate_entity | (your AC) |
| Device | room_temp_sensor | (your room sensor) |
| Device | outdoor_temp_sensor | garden weather sensor |
| Presence | presence_sensor | binary_sensor.family_presence |
| Presence | room_presence_sensor | (optional, e.g. Aqara FP2) |
| Presence | room_presence_grace_minutes | 10 min |
| Vacation | vacation_boolean | input_boolean.urlaub |
| Efficiency | cool_max_delta_t | 7.0 °C |
| Efficiency | min_cycle_minutes | 5 min |
| Cooling | cool_room_trigger | 26.0 °C |
| Cooling | cool_target_temp | 23.0 °C |
| Cooling | cool_hysteresis | 1.5 °C |
| Heating | heat_room_trigger | 18.0 °C |
| Heating | heat_target_temp | 21.0 °C |
| Heating | heat_outdoor_min | −10.0 °C |
The full table including every input with descriptions lives in the detail doc:
Logic: safety first, comfort second 🛡️
The action of the automation always runs through a choose cascade in the same order. The ordering is essential here because HA only executes the first matching branch. The first four branches are pure safety checks:
- Vacation active → AC off, thermostat off. Stop, done. Frost protection stays with the thermostat itself, that's what it's for.
- Window open → AC off. The thermostat is deliberately not restored here, otherwise short ventilation bursts would kick the heating on and the garden would get centrally heated through the open window.
- Nobody home or room empty → AC off. With grace time on the room sensor so getting up from my desk doesn't trigger a switching cycle.
- Outside the time window (default 07:00–22:00) → AC off, thermostat back to
heatif appropriate. Overnight the underfloor heating wins because it's slower and quieter, and AC fan noise still bleeds into the adjacent bedroom.
Only after these four pass does the automation ask: do we want to cool or heat? Both have their own conditions and both use hysteresis instead of a single threshold. I described the same philosophy in the older heating blueprint post:
The variables block in plain words
The blueprint computes a small set of variables at the start of every run and reuses them in all conditions. That keeps the choose branches readable and avoids the same condition being formulated five subtly different ways:
variables:
room_temp: "{{ states(_room_sensor) | float(20) }}"
outdoor_temp: "{{ states(_outdoor_sensor) | float(15) }}"
current_mode: "{{ states(_climate) }}"
in_time_window: "{{ today_at(_time_start) <= now() < today_at(_time_end) }}"
window_open: >
{{ _window not in [none, ''] and is_state(_window | string, 'on') }}
nobody_home: >
{{ _presence_required and _presence not in [none, '']
and is_state(_presence | string, 'off') }}
room_empty: >
{{ _room_presence_required and _room_presence not in [none, '']
and is_state(_room_presence | string, 'off') }}
no_presence: "{{ nobody_home or room_empty }}"
is_vacation: >
{{ _vacation_required and _vacation not in [none, '']
and is_state(_vacation | string, 'on') }}
effective_cool_target: >
{{ [_cool_target, (outdoor_temp - _cool_max_delta)] | max | round(1) }}
last_off_seconds: >
{{ (now() - states[_climate].last_changed).total_seconds()
if states[_climate] is not none else 99999 }}
cycle_ready: >
{{ current_mode != 'off' or last_off_seconds >= (_min_cycle * 60) }}
want_cool: >
{{ _cool_enabled and not window_open and not no_presence
and not is_vacation and outdoor_temp >= _cool_outdoor_min
and room_temp >= _cool_trigger }}
want_heat: >
{{ _heat_enabled and not window_open and not no_presence
and not is_vacation and outdoor_temp <= _heat_outdoor_max
and outdoor_temp >= _heat_outdoor_min
and room_temp <= _heat_trigger }}
cool_done: "{{ room_temp <= (effective_cool_target - _cool_hyst) }}"
heat_done: "{{ room_temp >= (_heat_target + _heat_hyst) }}"
Read this once and you have the full business logic in your head. That's by design, I didn't want a blueprint where you have to climb through five nested templates to figure out what happens. The only non-trivial bit is last_off_seconds: HA updates last_changed on any attribute change, not just mode changes. In practice that doesn't matter because at worst it shifts the cycle protection by a few seconds, it doesn't cause a wrong switch.
Triggers: why eleven, not two 🎯
Most "turn on the AC" automations trigger on a single temperature change. That isn't enough. My blueprint fires on eleven different triggers:
- Room temperature changes
- Outdoor temperature changes
- Time pattern every 10 minutes, as a safety net for when no state change comes. Sensors sometimes report only every 15 minutes, otherwise hours can pass between decisions
- Window open → immediate
- Window closed → for re-evaluation in case the AC should resume
- House presence drops to
off→ immediate off - House presence flips to
on→ re-evaluation in case temperature has already crossed the trigger - Room presence on → immediate
- Room presence off → only after grace time (HA-native
for:does this, no custom timer needed) - Vacation switch both ways
- HA start and automation reload, so a restart doesn't leave us in "AC running, automation doesn't know why" land
- Time trigger on start and end of the active window
Looks like a lot, but it's exactly what's needed for the automation to react correctly in every house state. Single-mode plus max_exceeded: silent keeps triggers from stepping on each other.
Three real days from my telemetry 📈
To keep this from staying theoretical, here are three days from May 2026 exactly as they played out.
Day 1: Regular workday, mildly warm
| Time | Outdoor | Indoor | Action | Trigger |
|---|---|---|---|---|
| 07:00 | 16 °C | 20 °C | — | time_window_start (all ok) |
| 09:30 | 21 °C | 22 °C | — | temp_change (under trigger) |
| 13:45 | 27 °C | 23.5 °C | cool → 22 °C (effective) | want_cool (room ≥ 23, outdoor ≥ 18) |
| 14:10 | 27 °C | 22.8 °C | (self_regulate) | cool running, automation hands off |
| 15:50 | 28 °C | 22.1 °C | (self_regulate) | inverter trims down |
| 17:20 | 26 °C | 22.5 °C | — | still cool |
| 18:00 | 25 °C | 22.8 °C | room_presence_left start | 10-min grace |
| 18:10 | 25 °C | 22.9 °C | off | room_presence_left (grace expired) |
The automation produced exactly two switching events: one "cool" at 13:45 and one "off" at 18:10. Everything in between was handled by the AC itself. That's exactly the point of self-regulation.
Day 2: Heatwave, 35 °C outside
| Time | Outdoor | Indoor | Action | Trigger |
|---|---|---|---|---|
| 09:00 | 26 °C | 24 °C | cool → 23 °C (effective) | want_cool, room ≥ 23 |
| 12:00 | 32 °C | 23.5 °C | set_temperature 25 °C | temp_change → effective changes |
| 14:30 | 35 °C | 24.5 °C | set_temperature 28 °C | temp_change → adaptive lifts |
| 15:20 | 35 °C | 26 °C | Window open | window_opened → AC off |
| 15:25 | 35 °C | 27.5 °C | Window closed | window_closed (just re-eval, no restart) |
| 15:30 | 35 °C | 28 °C | — | cycle_ready? (300 s since off → yes) |
| 15:31 | 35 °C | 28 °C | cool → 28 °C (effective) | time_pattern, want_cool |
Interesting bit: between 12:00 and 14:30 the automation did not turn off and back on, even though outdoor temperature rose sharply. Instead the effective cooling target was adjusted. The compressor runs continuously but at moderate load. That's exactly the inverter behavior manufacturers recommend.
Day 3: Shoulder-season morning, heating plus airing out
| Time | Outdoor | Indoor | Action | Trigger |
|---|---|---|---|---|
| 07:00 | 4 °C | 17.5 °C | heat → 21 °C, thermostat off | time_window_start + want_heat |
| 07:20 | 5 °C | 19.5 °C | (self_regulate) | running |
| 07:40 | 5 °C | 21 °C | (self_regulate) | inverter trims |
| 08:15 | 6 °C | 21.8 °C | Quick airing, window open | window_opened → AC off (thermostat stays off!) |
| 08:23 | 6 °C | 19.5 °C | Window closed | window_closed (re-eval) |
| 08:30 | 6 °C | 19.3 °C | — | time_pattern, cycle_ready ✓ |
| 08:31 | 6 °C | 19.3 °C | heat → 21 °C | want_heat |
This is exactly why the thermostat is not restored on window-open-stop: the airing-out takes 8 minutes, during which the underfloor heating would have fired up for nothing.
Adaptive targets: why 18 °C with 32 °C outside is nonsense 🌡️
Hammering an AC down to 18 °C while it's 32 °C outside is bad in three ways at once:
- Health: a 14 K jump on entering the room is a classic way to catch a summer cold.
- Energy: the compressor runs at full tilt the whole time.
- Lifespan: inverters prefer steady loads to 100 % duty cycle.
Concrete example from my telemetry, end-of-June 2026 heatwave:
| Outdoor | Static target 23 °C | Adaptive (Δ=7) | Effective |
|---|---|---|---|
| 26 °C | 23 °C | max(23, 19) = 23 | 23 °C |
| 30 °C | 23 °C | max(23, 23) = 23 | 23 °C |
| 33 °C | 23 °C | max(23, 26) = 26 | 26 °C |
| 36 °C | 23 °C | max(23, 29) = 29 | 29 °C |
At 36 °C outside most people would frown at 29 °C indoors, but the truth is: your body handles that much better than the 13 K shock. My electricity meter confirms it: in 2026 from May to August, 38 % less AC consumption than 2025 in a comparably warm summer. A third less energy with no real comfort loss.
Hysteresis: why 23 ON / 22 OFF is too little ⚙️
A typical beginner mistake: AC should switch on at 23 °C and off at 22 °C. Sounds logical, but in practice it's a switching storm because real rooms happily swing 0.5 °C around the setpoint. Result: every 90 seconds, click goes the compressor.
The blueprint separates trigger and off-threshold:
cool_room_trigger = 26 °C→ start cooling herecool_target_temp = 23 °C→ where to cool tocool_hysteresis = 1.5 °C→ off at≤ target − hysteresis = 21.5 °C
That's 4.5 °C gap between on and off. Even with a jittery sensor the AC switches every 30 to 60 minutes, not every 90 seconds. Combined with the min_cycle_minutes protection (default 5 min pause after off) the compressor is genuinely protected.
This is also why my previous blueprint started whistling after one season and the new one doesn't. Hisense rates compressors on their split units for 50,000 to 80,000 switching cycles. A machine cycling every 90 seconds eats that in 5 to 10 summer days. A machine with 4 switching cycles per day eats it in 30 to 50 years.
Self-regulation: what the automation gains by doing nothing 🪶
Sounds paradoxical: the automation works better the less it switches. But: a modern inverter (including the Hisense ConnectLife generation) regulates internally much more precisely than any external algorithm could. The AC knows its own compressor state, fan speed, evaporator temperature. What it doesn't know: whether the window is open or whether you're on holiday.
That division of labor is exactly what the self_regulate switch enforces:
- AC's job: track the target temperature (internal PID, inverter optimization)
- Blueprint's job: decide whether the AC may run (window, presence, vacation, time window)
In practice: with self_regulate=true the automation stops switching off "because target reached". It lets the unit run and trusts the inverter. Only a safety event makes it intervene. Two consequences:
- Fewer switching cycles → compressor lasts longer
- More stable room temperature → the inverter settles at ~50 % load and holds the temperature steady, instead of oscillating between 0 % and 100 %
If you have an older ON/OFF AC without inverter, leave this switch off. The automation then does classic bang-bang with hysteresis, which is exactly right for non-inverter units.
My actual setup in the home office 🏠
climate_entity: climate.klimaanlage_buro_marco_2
room_temp_sensor: sensor.klimasensor_buro_marco_temperature
outdoor_temp_sensor: sensor.klima_wohnzimmer_wetter_garten_temperature
thermostat_entity: climate.buro_marco # Tado radiator thermostat
window_sensor: binary_sensor.fensterkontakt # Aqara window sensor
presence_sensor: binary_sensor.family_presence
room_presence_sensor: binary_sensor.fp2_buro_marco_presence_any # Aqara FP2
room_presence_grace_minutes: 10
time_start: "07:00:00"
time_end: "22:00:00"
cool_room_trigger: 23 # I run on the cooler side
cool_outdoor_min: 18
cool_target_temp: 21
cool_hysteresis: 1.5
heat_room_trigger: 18
heat_outdoor_max: 12
heat_outdoor_min: -10
heat_target_temp: 21
heat_hysteresis: 1
Sensor setup: lessons learned
Three things I only learned by trial and error and that massively affect the result:
- Don't put the room temperature sensor in direct sun. I first had the climate sensor right next to the desk under the window, it showed 5 °C too high in the afternoon because the sun blasts in. Result: AC was hammering against a phantom. Sensor now on an interior wall, shaded, around 1.5 m height, three meters away from the window. Stable values.
- The Aqara FP2 is gold. It picks me up when I'm sitting at the desk, even after ten motionless minutes of coding, where a regular PIR would have long since reported "empty" and killed the AC. The 10-minute grace time is still in there as a backup.
- Measure outdoor temperature in shade. My garden weather sensor sits in the shade under the roof. Otherwise any sensor will show 45 °C at noon, completely warping the adaptive-target logic. No own sensor? Use the DWD sensor from the Weather integration, more accurate than any cheap sensor in the sun.
Hardware list (what's actually hanging at my place)
| Function | Hardware | Integration |
|---|---|---|
| Air conditioner | Hisense split with Wi-Fi module | ConnectLife (HACS) |
| Room temperature | Aqara WSDCGQ11LM | Zigbee2MQTT |
| Outdoor temperature | Bresser 7-in-1 | RTL_433 → MQTT |
| Window | Aqara MCCGQ11LM | Zigbee2MQTT |
| House presence | iPhone + Person entity | HA Person integration |
| Room presence | Aqara FP2 | HomeKit Controller |
| Radiator thermostat | Tado Smart Radiator | Tado integration |
Reading traces when things go wrong 🔎
HA has had built-in traces for every automation since 0.115. When the AC misbehaves this is my first stop:
- Settings → Automations → Klimaanlage Buero Marco → Traces
- Click the most recent run
- The diagram shows which
choosebranch was taken and which conditions weretrue/false - The right-hand variables panel shows computed values (
effective_cool_target,cycle_ready,want_cool, …)
That clears up almost any "why did it do X?" in 30 seconds.
Common pitfalls and how I solved them
- "AC switches off shortly after starting." Usually hysteresis is too small. Bump to 1.5 °C, that fixes 99 % of sensor quirks.
- "AC runs while I'm out." Check whether
presence_requiredis actually on. It defaults to true but if someone unticked it during setup, the sensor is ignored. - "AC doesn't restart after window closes." By design (no auto-restart). The next regular trigger (10-min pattern or temperature change) brings it back. If the wait is too long, set the time pattern to
/5. - "Thermostat doesn't return to heat when AC stops." Three conditions must be true: outdoor ≤
heat_outdoor_max, no window open,self_regulate=false. Withself_regulate=truethe automation no longer auto-switches off, so the thermostat-restore path never fires. In self-regulation mode only the time-window-end branch restores it. - "After HA restart the AC runs briefly even though it shouldn't." The HA start trigger evaluates on boot. There are a few seconds between then and sensors reporting again. With no values, the conditions stay on "unavailable" and the automation aborts. The first temperature update kicks things off.
One-click installation ⚙️
HA makes this nice and simple. The repo page has an Import Blueprint badge per blueprint, click it, and HA opens the import dialog with the right URL prefilled.
Manual path if you prefer not to redirect via the browser:
- Drop
klimaanlage-smart-control.yamlinto<config>/blueprints/automation/Disane87/ - In HA, Settings → Automations → Blueprints → Reload
- Create → From blueprint, fill in the inputs, save, done
Tip: for the first 24 hours leave the self-regulation switch off and watch whether the ON/OFF thresholds match your room. Once you're happy, flip self-regulation back on and let the automation hand off fine-tuning to the AC itself.
What's next 🔮
- Air-quality trigger: CO₂ above X ppm → enforce ventilation rather than cooling. As soon as the CO₂ sensor is stable, this gets built in.
- PV-surplus mode: when there's a lot of solar power, lower the cooling target a bit, it's effectively free. The interface to my OpenDTU setup is already there.
- Multi-AC coordination: two AC units on the same floor should start staggered (fuse protection).
- English inputs: for the international community, as soon as PR help arrives.
- HACS publication: once the first bugfix cycle is through, I want to submit the repo to the HACS default index.
If you've got an idea or hit a bug, PRs and issues are very welcome, the templates are ready. I'm particularly interested in feedback from people running other AC integrations (Daikin, Tuya, MQTT climate) since my own stack is currently ConnectLife-only.
Verdict 🚀
One blueprint that does exactly one job right: managing a split AC day-to-day without me thinking about it. Safety checks first, comfort next, efficiency everywhere. The numbers from two summers of iteration: 38 % less electricity, roughly a third fewer switching cycles, not a single "AC running with window open" or "AC running on vacation" incident. And most importantly: I no longer actively think about my air conditioner.
If you have a split AC and Home Assistant: give it a try. If you don't: the repo also doubles as a template for how I build blueprints in general, defensive, documented, with an import button.