A hallway light is the one people leave on, or walk through in the dark because the switch is at the far end. This recipe hands the job to the room. When any motion sensor you pick sees movement the light comes on, and once the hallway has been still for the grace period you set it goes back off on its own.
Five minutes is a middle-of-the-road grace period. Shorten it for a narrow passage that is only ever crossed, lengthen it for a landing where people stop to talk. The whole thing runs locally on your sensors and lights, with no phone and no cloud in the loop.
Only after dark
A hallway rarely needs a light in the middle of the day. Pick a light sensor as the optional illuminance role and the automation checks the brightness first, switching the light on only when the hallway is below the darkness level you set. Leave the sensor out and the light runs on motion around the clock.
Holding the light while someone lingers
A plain motion sensor sees movement, not presence, so it can drop a person who stands still to read a label or answer the phone. Add an mmWave presence sensor as the optional occupancy role and the light stays on until both the motion and the presence sensors are clear, so it does not switch off with someone still there.
Files Selora AI's pipeline reads to install this recipe. The manifest declares roles, inputs, and integrations; the package files are Jinja-templated YAML applied to Home Assistant.
# Motion Hallway Light — switch a hallway light on with motion and off again
# after a grace period, with two optional refinements.
#
# The recipe resolves one required motion role (multi-select, so several
# sensors can cover one hallway) and one required light role. Two optional
# roles refine it: an illuminance sensor gates the light to darkness, and an
# occupancy (mmWave presence) sensor holds it on while a still person is in
# the room. A third optional role adds dimmable lights brought up at a gentler
# level than the mains.
slug: motion-hallway-light
version: 1.0.0
title: Motion Hallway Light
tagline: Motion turns the hallway light on, and it turns itself off once the space has been still for a while.
description: >-
Switches the lights you pick on when any selected motion sensor fires and
off again once every sensor has been clear for the grace period. Add a light
sensor to run only after dark, a presence sensor to hold the light while
someone lingers, and dimmable lights that come up at a softer level.
author: Selora AI
released: "2026-08-28"
min_integration_version: "0.12.0"
tags: [lighting, motion, hallway, presence]
roles:
# Motion sensors — multi-select so several PIR or mmWave sensors can cover a
# long hallway with one install. binary_sensor + device_class motion is how
# they register. min_count 1: with no sensor there is nothing to trigger on.
- id: motion_sensors
title: Motion sensors
kind: binary_sensor
device_class: motion
min_count: 1
selection: required
description: >-
The motion sensors that switch the light on. Pick every one covering the
hallway; any of them firing turns the light on.
# Lights to control — multi-select. min_count 1: the recipe needs at least
# one light to switch.
- id: lights
title: Hallway lights
kind: light
min_count: 1
selection: required
description: >-
The light or lights the recipe switches on and off. Pick one or more and
they move together.
# Optional illuminance sensor. When picked, the on automation only runs
# while the reading is below the darkness threshold. max_count 1: a single
# reading decides light or dark. min_count 0: leave empty to run any hour.
- id: illuminance
title: Light level sensor
kind: sensor
device_class: illuminance
min_count: 0
max_count: 1
selection: required
description: >-
Optional. A light sensor so the automation only turns the light on when
the hallway is dark. Leave empty to run on motion at any hour.
# Optional occupancy / presence sensor that holds the light on while a still
# person is present. max_count 1. min_count 0: leave empty to switch off on
# the motion grace period alone.
- id: occupancy
title: Presence sensor
kind: binary_sensor
device_class: occupancy
min_count: 0
max_count: 1
selection: required
description: >-
Optional. An mmWave presence sensor that keeps the light on while someone
is standing still. Leave empty to rely on motion only.
# Optional dimmable lights brought up at a softer brightness than the mains.
- id: dimmers
title: Dimmable accent lights
kind: light
min_count: 0
selection: required
description: >-
Optional. Dimmable lights the recipe brings up at the accent brightness
instead of full, for a softer night-time crossing. Leave empty to skip.
inputs:
# Grace period, in minutes, the hallway must be clear of motion before the
# light turns off. Feeds the off trigger's for: block. 3 minutes clears a
# normal pass-through without dropping someone who paused.
- id: no_motion_minutes
type: number
label: Grace period (minutes)
description: >-
How long every motion sensor must be clear before the light turns off.
default: 3
min: 1
max: 60
# Darkness threshold in lux, used only when an illuminance sensor is picked.
# 40 lux is dusk indoors: bright enough to skip the light in daylight, dark
# enough to switch it on once the hallway dims.
- id: dark_lux
type: number
label: Darkness threshold (lux)
description: >-
With a light sensor picked, the light only comes on below this reading.
default: 40
min: 1
max: 1000
# Brightness percent for the optional dimmable accent lights.
- id: dim_brightness
type: number
label: Accent brightness (percent)
description: >-
Brightness the optional dimmable lights come up at.
default: 40
min: 1
max: 100
package_files:
- package/automations/hallway.yaml.j2
{# Motion Hallway Light: one automation to switch the lights on with motion,
one to switch them off after a grace period.
The on automation fires on any selected motion sensor going on. When an
illuminance sensor is picked it is gated to a below-threshold reading so
daylight does not trigger it. Optional dimmable lights come up at the accent
brightness in a second service call.
The off automation waits for every motion sensor to have been off for the
grace period, then confirms all of them are clear before switching off, so
one sensor still seeing movement keeps the light on. A picked occupancy
sensor adds a second hold for a person standing still.
Both automations use mode: restart so a fresh trigger resets the timing
rather than queuing a second run. #}
automation:
- id: selora_recipe_{{ slug | replace('-', '_') }}_on
alias: "Motion Hallway Light: on"
description: >-
When any selected motion sensor detects movement, switch the hallway
lights on, optionally only while the hallway is dark.
mode: restart
trigger:
{% for sensor in roles.motion_sensors %}
- platform: state
entity_id: {{ sensor }}
to: "on"
{% endfor %}
{% if roles.illuminance %}
condition:
- condition: numeric_state
entity_id: {{ roles.illuminance[0] }}
below: {{ inputs.dark_lux }}
{% endif %}
action:
- service: light.turn_on
target:
entity_id:
{% for light in roles.lights %}
- {{ light }}
{% endfor %}
{% if roles.dimmers %}
- service: light.turn_on
target:
entity_id:
{% for dimmer in roles.dimmers %}
- {{ dimmer }}
{% endfor %}
data:
brightness_pct: {{ inputs.dim_brightness }}
{% endif %}
- id: selora_recipe_{{ slug | replace('-', '_') }}_off
alias: "Motion Hallway Light: off"
description: >-
Once every motion sensor has been clear for the grace period, and any
presence sensor is clear too, switch the hallway lights off.
mode: restart
trigger:
{% for sensor in roles.motion_sensors %}
- platform: state
entity_id: {{ sensor }}
to: "off"
for:
minutes: {{ inputs.no_motion_minutes }}
{% endfor %}
{% for sensor in roles.occupancy %}
- platform: state
entity_id: {{ sensor }}
to: "off"
for:
minutes: {{ inputs.no_motion_minutes }}
{% endfor %}
condition:
# for: applies to every entity in the list, so all of them must have been
# clear for the full grace period. Without it the trigger firing for one
# sensor was enough, and the rest only had to be off at that moment: on a
# two-sensor hallway the lights could go out a minute after the second
# sensor last saw movement, well inside the period the homeowner set.
- condition: state
state: "off"
for:
minutes: {{ inputs.no_motion_minutes }}
entity_id:
{% for sensor in roles.motion_sensors %}
- {{ sensor }}
{% endfor %}
{% if roles.occupancy %}
# Same grace period as the motion sensors, matching this sensor's own
# trigger. Without it an occupancy sensor that cleared seconds ago lets a
# motion sensor whose delay has just expired switch the lights off well
# inside the period the homeowner set.
- condition: state
entity_id: {{ roles.occupancy[0] }}
state: "off"
for:
minutes: {{ inputs.no_motion_minutes }}
{% endif %}
action:
- service: light.turn_off
target:
entity_id:
{% for light in roles.lights %}
- {{ light }}
{% endfor %}
{% for dimmer in roles.dimmers %}
- {{ dimmer }}
{% endfor %}