Fixing Motion Automation Race Conditions in Home Assistant
A guide to solving common race conditions in motion-activated lighting automations, where lights turn on and then immediately off.
Search results
Understanding the Race Condition
A race condition in motion-activated lighting typically occurs when the automation logic for turning lights on and
turning them off overlap or execute too quickly in succession. In Home Assistant, a motion sensor changing state from
on (motion detected) to off (no motion detected) often triggers the ’lights off’ sequence. If a person moves just
enough to briefly clear the sensor’s field of view, the sensor might flip to off and immediately back to on.
If the ’lights off’ automation is triggered by the brief off state, it starts running. If the sensor immediately flips
back to on, the ’lights on’ automation might also run. The result is often that the lights turn on, and then almost
immediately turn off, leading to a frustrating user experience.
We can solve this by introducing timing checks and conditional logic to ensure the automations only run when appropriate.
Solution 1: Debouncing the Off Trigger with for:
The most effective way to prevent lights from turning off prematurely is to require the motion sensor to remain in the
off state for a specific duration before the ’lights off’ action is executed. This is known as debouncing.
In Home Assistant, you achieve this by adding a for: statement to the off trigger. This ensures the trigger only fires
if the state change persists for the specified time (e.g., 60 seconds).
automation:
- alias: 'Motion Light - Turn Off'
trigger:
- platform: state
entity_id: binary_sensor.hallway_motion
to: 'off'
for: '00:01:00' # Must be off for 60 seconds
action:
- service: light.turn_off
target:
entity_id: light.hallway_light
Solution 2: Using choose: for Conditional Execution
Sometimes, you want an automation to run only under specific environmental conditions. For instance, there is no need to
turn on lights if the sun is up or if the room is already bright. Using the choose: action allows you to implement
complex conditional logic within a single automation.
This technique is particularly useful for the ’lights on’ automation, preventing unnecessary execution.
automation:
- alias: 'Motion Light - Turn On Conditionally'
trigger:
- platform: state
entity_id: binary_sensor.hallway_motion
to: 'on'
action:
- choose:
- conditions:
# Condition 1: Only run if the sun is below the horizon
- condition: state
entity_id: sun.sun
state: 'below_horizon'
# Condition 2: Only run if illuminance is below 50 lux
- condition: numeric_state
entity_id: sensor.hallway_illuminance
below: 50
sequence:
- service: light.turn_on
target:
entity_id: light.hallway_light
default: []
Solution 3: Managing Automation Behavior with mode:
The mode: setting controls how Home Assistant handles multiple simultaneous executions of the same automation.
Understanding this setting is crucial for managing race conditions, especially when motion sensors rapidly switch states.
- mode: single (Default): If the automation is triggered while it is already running, the new trigger is ignored. This is the safest default for most lighting automations, as it prevents the ’lights off’ sequence from being interrupted by a new ’lights on’ trigger, or vice versa.
- mode: restart: If the automation is triggered while it is already running, the current execution is stopped and restarted from the beginning. This is particularly useful for motion lighting where you want the automation to respond immediately to new motion, even if it’s currently in a delay or cooldown period.
- mode: queued: If the automation is triggered while running, the new trigger is added to a queue and executed sequentially after the current run finishes. This is generally not recommended for motion lighting as it can lead to delayed or unexpected behavior.
For motion lighting, mode: restart is often preferred over mode: single when using a single automation with
choose blocks, as it ensures rapid response to new motion events.
Complete YAML Automation Examples
Here are two complete examples combining the techniques above for robust motion lighting.
Example 1: Hallway Light Automation (On/Off with Debounce and Sun Condition)
This example uses two separate automations for clarity, incorporating for: on the off trigger and a condition check on
the on trigger.
# Automation 1: Turn ON the light
- alias: 'Hallway Motion Light ON'
id: 'hallway_motion_on_2025'
mode: single
trigger:
- platform: state
entity_id: binary_sensor.hallway_motion
to: 'on'
condition:
# Only turn on if it is dark
- condition: state
entity_id: sun.sun
state: 'below_horizon'
action:
- service: light.turn_on
target:
entity_id: light.hallway_light
# Automation 2: Turn OFF the light (Debounced)
- alias: 'Hallway Motion Light OFF'
id: 'hallway_motion_off_2025'
mode: single
trigger:
- platform: state
entity_id: binary_sensor.hallway_motion
to: 'off'
# Wait 90 seconds before turning off
for: '00:01:30'
action:
- service: light.turn_off
target:
entity_id: light.hallway_light
Example 2: Bathroom Light Automation (Single Automation with choose: and mode: restart)
This example combines the logic into a single automation using choose: to handle both the on and off states,
ensuring the off action is debounced. The choose block ties specific sequences to trigger IDs, and mode: restart
ensures immediate response to new motion events.
- alias: 'Bathroom Motion Light Combined'
id: 'bathroom_motion_combined_2025'
mode: restart # Restart on new motion for immediate response
trigger:
# Trigger on motion start (no delay to avoid bounce)
- platform: state
entity_id: binary_sensor.bathroom_motion
to: 'on'
id: 'motion_on'
# Trigger on motion end (must persist for 2 minutes)
- platform: state
entity_id: binary_sensor.bathroom_motion
to: 'off'
for: '00:02:00'
id: 'motion_off'
action:
# Using choose keeps on/off logic in one automation and ties sequences to specific trigger ids
- choose:
# Case 1: Motion started (turn on)
- conditions:
- condition: trigger
id: 'motion_on'
- condition: numeric_state
entity_id: sensor.bathroom_illuminance
below: 75
sequence:
- service: light.turn_on
target:
entity_id: light.bathroom_light
# Case 2: Motion ended (turn off)
- conditions:
- condition: trigger
id: 'motion_off'
sequence:
- service: light.turn_off
target:
entity_id: light.bathroom_light
default: []
Advanced Technique: PIR with mmWave Presence Sensor
For more reliable motion detection, consider pairing a PIR sensor with an mmWave presence sensor. The PIR provides immediate motion detection, while the mmWave sensor detects subtle presence (breathing, small movements) to prevent false offs.
Create a binary sensor group that requires both sensors to report ‘off’ before considering the room clear:
binary_sensor:
- platform: group
name: Bathroom Presence
unique_id: bathroom_presence_group
device_class: motion
entities:
- binary_sensor.bathroom_pir_motion
- binary_sensor.bathroom_mmwave_presence
Then use this group sensor in your automation:
- alias: 'Bathroom Motion with Dual Sensors'
id: 'bathroom_dual_sensors_2025'
mode: restart
trigger:
- platform: state
entity_id: binary_sensor.bathroom_presence
to: 'on'
id: 'motion_on'
- platform: state
entity_id: binary_sensor.bathroom_presence
to: 'off'
for: '00:03:00' # Longer timeout with dual sensors
id: 'motion_off'
action:
- choose:
- conditions:
- condition: trigger
id: 'motion_on'
- condition: numeric_state
entity_id: sensor.bathroom_illuminance
below: 75
sequence:
- service: light.turn_on
target:
entity_id: light.bathroom_light
- conditions:
- condition: trigger
id: 'motion_off'
sequence:
- service: light.turn_off
target:
entity_id: light.bathroom_light
default: []
Last modified October 21, 2025: docs: Fixing motion automation race conditions (878e0bd)