Loading...
Author Cloudapp
E.G.

KNX Motion-Sensor Automations in Home Assistant

June 9, 2026
Table of Contents

The first time motion-controlled lighting actually worked in my place, it didn't feel clever. It felt obvious — I walked into a dark hallway and the light was already on by the time I'd registered it was dark. That's the bar. Not smart, just attentive. Getting there with seven KNX motion sensors took me less code than I expected and one insight I wish I'd had on day one.

This is Part 05 of the series. The earlier parts cover the boring-but-load-bearing groundwork: running Home Assistant in Docker and wiring up HACS. Here I'm assuming HA is up, talking KNX, and you just want the lights to behave.

One sensor, two jobs, two addresses

Here's the mistake I made, and it's the whole reason this post exists. KNX exposes each motion sensor to Home Assistant as a binary_sensor with device_class: motion, fed by a KNX group-address state object you configure in knx.yaml with a state_address per sensor. Simple enough. So I wired all seven sensors with one group address each and pointed both the lighting automation and the presence logic at the same signal.

That works right up until you want the two to behave differently. A light should react to the smallest twitch, instantly, generously. Presence and security want the opposite: a debounce, a grace window, some scepticism before they commit. When both ride the same group address, every change you make to one quietly deforms the other. I spent an evening forking conditions in Home Assistant trying to make one signal mean two things.

The fix isn't in Home Assistant at all. It's in ETS: give each physical PIR a second group address. One drives comfort lighting, the other feeds presence and the alarm path. I use a flat convention — 5/4/x for lighting, 5/5/x for the security path, 5/6/x reserved for generic presence. Now "the light reacts" and "security reacts" are genuinely separate events. The lighting automations below never touch the alarm side, which is exactly how I want it — this post is strictly about lights and presence, and the alarm internals stay out of it on purpose.

The dumb version first

Start with the on/off automation that everyone writes. Motion goes from off to on, turn the light on. Motion goes off, turn the light off. Two automations, a sensor and a light:

# Motion ON -> light on; motion OFF for 5 min -> light off
- alias: "Hallway light on motion"
  triggers:
    - trigger: state
      entity_id: binary_sensor.flur_motion
      from: "off"
      to: "on"
  actions:
    - action: light.turn_on
      target: { entity_id: light.flur }
      data: { brightness_pct: 100 }
  mode: single

- alias: "Hallway light off after 5 min"
  triggers:
    - trigger: state
      entity_id: binary_sensor.flur_motion
      from: "on"
      to: "off"
      for: { minutes: 5 }
  actions:
    - action: light.turn_off
      target: { entity_id: light.flur }
  mode: single

Two things are doing quiet work here. mode: single keeps the automation from re-triggering itself into a storm when a sensor chatters — pair it with max_exceeded: silent so the overlap is swallowed without filling your log. And the off side triggers on the sensor going to off with a for: of five minutes, not immediately. That for: is the single most important number in the whole setup.

The honest failure: lights dropping while you're still there

Every motion-lighting setup fails the same way the first week: you're standing perfectly still reading something, the sensor stops seeing you, and the room goes dark. It's the classic failure and it's infuriating because it makes the house feel like it's sulking at you.

The instinct is to fight the sensor — chase faster polling, a more sensitive PIR, fancier presence detection. Don't. The fix is almost always to lengthen the off-delay. I settled on a small taxonomy that maps to how long people actually linger in a space: short hold of about 30 seconds to a minute for small rooms you pass through, medium of 3 to 5 minutes for halls and stairs, and long of 10 to 15 minutes for living rooms and offices where you sit still. A hallway gets five minutes. A reading chair does not get thirty seconds.

I also give the trigger a 2 to 5 second grace window before acting, so a single flicker on the wire doesn't strobe the room. Cheap insurance.

The touches that make it feel intentional

Once the lights stop misbehaving, you can add the bits that make it feel like the house was designed rather than scripted. None of these are hard; they're just thoughtful.

Night-only stairs. The stairwell and hallway lights only auto-fire in the dark. A condition: sun with after sunset / before sunrise gates them, so they don't pointlessly switch on at noon when there's plenty of daylight.

Time-of-day brightness. A fixed brightness is a tell that a machine wrote your house. Full blast at 3am is hostile. I drive brightness with a choose: block keyed on time windows — roughly 30% late at night (22:00 to 06:00), 70% in the early morning (06:00 to 08:00), and 100% during the day:

# Time-of-day brightness with choose:
actions:
  - choose:
      - conditions:
          - condition: time
            after: "22:00:00"
            before: "06:00:00"
        sequence:
          - action: light.turn_on
            target: { entity_id: light.stairs }
            data: { brightness_pct: 30 }
    default:
      - action: light.turn_on
        target: { entity_id: light.stairs }
        data: { brightness_pct: 100 }

Pathway lighting up the stairs. My favourite trick. The stair automation chains two lights with a delay: of about three seconds between them — the lower light first, then the floor above a beat later — so the light walks up the stairs ahead of you instead of flooding the whole shaft at once. It's a tiny thing that gets noticed every single time.

A whole-zone energy cutoff. The thing I'm proudest of, because it's where the naive version quietly wastes power. Instead of each light timing out alone, an energy-saving automation triggers on a list of motion sensors all going to off for a hold time — I use ten minutes across the group — and then re-asserts in its conditions that every single sensor in the zone is still off before it drops anything. That AND-of-all guard matters: one sensor flapping back to on shouldn't keep a whole floor lit, and one sensor going quiet shouldn't plunge an occupied zone into darkness. Lights only drop when the zone is genuinely empty. Driving it by area_id rather than enumerating every fixture means one automation can switch off a whole zone at once.

A cheap presence value, almost for free

Here's a small one I keep reaching for. You don't always need a real presence-detection platform to answer "was anyone in the kitchen recently?". Give each area an input_datetime helper, and add a one-line automation per motion sensor that, on going to on, stamps the current time into it. Now you have a per-area "last motion seen" value you can read anywhere — in conditions, on a dashboard, in a notification — without installing anything.

It's not occupancy in the rigorous sense; it's a timestamp. But "last seen two minutes ago" answers nine out of ten of the questions I actually ask my house, and it costs one helper and one tiny automation per room.

To tune any of this, put the sensors on a Lovelace type: entities card so you can watch live motion state per area while you fiddle with the off-delays. Seeing a sensor sit on off a full second before you expected it to is how you learn which room needs a longer for:.

What I'd tell past me

Two things. First: split the signal at the bus, not in YAML. A second group address per sensor is five minutes in ETS and it saves you from building a tower of conditions that tries to make one event mean two contradictory things. Second: the entire quality of motion lighting lives in the off-delay, not the on-trigger. Turning a light on is trivial; turning it off at the right moment, after the right hold, only when the room is really empty, is the whole craft.

Throughout this I've kept entity names generic on purpose — flur, stairs, hallway — and the group-address scheme abstract. The real reason a lighting signal and a security signal get separate addresses is the alarm path that lives on the other one, and that's a story for a part of this series that very deliberately leaves out the internals. For lights, the recipe above is the whole thing. Next part picks up where the second group address leads.

Related articles