Loading...
Author Cloudapp
E.G.

Window Open, Heating Off: Auto-Switch Each KNX Thermostat to Frost Protection in Home Assistant

July 7, 2026
Table of Contents

In winter I heat against the open window. Every time I tilt a window for a quick airing, the KNX thermostat below dutifully ramps up and blasts heating energy straight outside — for minutes, until someone notices the room going cold and closes it again. Across a heating season that adds up to real money going out the window, literally.

The fix is a simple, per-room duplicable automation: window contact opens → that room's thermostat goes to frost protection; window closes → back to comfort. The one trick almost every tutorial leaves out is a 5-second debounce against false triggers. Here's my setup, step by step.

Why building_protection and not just "off"

The obvious reflex is to switch the thermostat fully off while the window is open (hvac_mode off or preset standby). That's dangerous: with a thermostat you forget or a window contact that gets stuck, the room can then cool down indefinitely — in the worst case below freezing on an exterior wall. So I switch to the building_protection preset (frost guard, typically ~7 °C). The radiator stays supervised and kicks in if it genuinely gets cold, but it never heats the open window. That's the whole difference between "saving energy" and "a burst pipe in January".

Step 1 — the window contact as a KNX binary_sensor

Every window I want to watch gets a binary_sensor with device_class window. That matters because Home Assistant derives the correct "open/closed" state and the right icons from it. The state address is the KNX group address your window contact reports on — shown here as X/X/X placeholders; fill in your own. sync_state: false avoids needless polling of the bus, since the contact sends its state on its own.

binary_sensor:
  - name: "Fenster Buero Status Sensor"
    state_address: "X/X/X"
    sync_state: false
    device_class: window

  - name: "Fenster Wohnzimmer Status Sensor"
    state_address: "X/X/X"
    sync_state: false
    device_class: window

  - name: "Fenster Kinderzimmer 1 Status Sensor"
    state_address: "X/X/X"
    sync_state: false
    device_class: window

  - name: "Fenster Kueche Status Sensor"
    state_address: "X/X/X"
    sync_state: false
    device_class: window

  - name: "Fenster Kinderzimmer 2 Status Sensor"
    state_address: "X/X/X"
    sync_state: false
    device_class: window

One entry per window. The names are just examples — generic room names like "Buero" (office) or "Wohnzimmer" (living room) keep the automations readable later on.

Step 2 — the per-room automation pair

For each room I need two automations: one disables the heating on open, one re-enables it on close. Both hang off the same window contact and control the same thermostat. Here's the pair for the office:

- alias: Heizung Buero Deaktivieren
  triggers:
  - trigger: state
    entity_id: [binary_sensor.fenster_buro_status_sensor]
    from: 'off'
    to: 'on'
    for: {seconds: 5}
  actions:
  - action: climate.set_preset_mode
    data: {preset_mode: building_protection}
    target: {entity_id: climate.thermostat_buro}
  mode: single

- alias: Heizung Buero Aktivieren
  triggers:
  - trigger: state
    entity_id: [binary_sensor.fenster_buro_status_sensor]
    from: 'on'
    to: 'off'
    for: {seconds: 5}
  actions:
  - action: climate.set_preset_mode
    data: {preset_mode: comfort}
    target: {entity_id: climate.thermostat_buro}
  mode: single

On open it sets building_protection; on close, back to comfort. Which preset modes your KNX thermostat actually supports, and how they map onto the bus, is covered in detail in my post on KNX thermostat preset modes.

Step 3 — understanding the 5-second debounce

The for: {seconds: 5} is the real trick and the reason this automation doesn't drive you mad in daily use. Without it, every micro-movement of the contact fires immediately: a reed contact sometimes bounces on closing, the window rattles in its frame during airing, and the KNX bus occasionally delivers brief flutter telegrams. Each of those glitches would otherwise trigger a pointless mode switch.

With the 5-second filter, the automation only fires once the window has actually been open (or closed) for five seconds. Short rattling is ignored, real airing is detected. Five seconds is short enough that no noticeable heating energy is lost, and long enough to mask all the flutter junk.

The mapping scales per room

The nice thing about the pattern: it's bluntly duplicable. One window-contact binary_sensor plus one climate thermostat per room, and the automation pair gets copied once with its two entity_ids swapped out. Here's my mapping table:

# Raum            Fensterkontakt                              Thermostat
# Buero           binary_sensor.fenster_buro_status_sensor    climate.thermostat_buro
# Wohnzimmer      binary_sensor.fenster_wohnzimmer_...        climate.thermostat_wohnzimmer
# Kueche          binary_sensor.fenster_kueche_...            climate.thermostat_kueche
# Kinderzimmer 1  binary_sensor.fenster_kinderzimmer_1_...    climate.thermostat_kinderzimmer_1
# Kinderzimmer 2  binary_sensor.fenster_kinderzimmer_2_...    climate.thermostat_kinderzimmer_2

If you have several windows per room, you can list them all in the trigger's entity_id and express "at least one window open" via a group or a template condition — the logic stays the same.

Verifying it works

After reloading I test each room once by hand: open the window, wait a moment, then check in the thermostat overview that the preset jumped to building_protection (the list with secondary_info "last-changed" shows the timestamp). Close the window, wait five seconds, back to comfort. If the switch happens but too early or too late, the for duration is almost always the knob to turn.

Frequently asked questions

Why not hvac_mode off instead of building_protection?

Because off disables all frost protection. If a window is accidentally left open overnight or the contact gets stuck, the room cools down without limit — on an exterior wall a burst pipe is the worst-case outcome. building_protection holds a safety minimum (~7 °C) but doesn't heat against the open window. That's the entire point of the exercise.

What if my thermostat doesn't have a building_protection preset?

Then check the climate entity's more-info dialog for which preset_modes it reports. On some KNX actuators the frost guard is called "frost", or it's done via a low target temperature with climate.set_temperature instead of a preset. The trigger logic stays identical — you only swap the action in the disable block.

Do I really need two automations per room?

Not strictly — you can also solve it in a single automation with two triggers and a choose block. I deliberately use two separate ones because they're instantly readable in the automation UI ("Heizung Buero Deaktivieren/Aktivieren") and can each be disabled individually when I'm testing something in one room. For a maintainable setup the small redundancy is worth it.

Do I lose heating energy during airing because of the 5-second delay?

Practically none. In five seconds a radiator gives off barely measurable heat, and the inertia of a water-based system is far larger anyway. Those five seconds buy you the reliability that not every rattle and bus glitch triggers a mode switch — an excellent trade.

Related articles