You have a routine that turns on the kitchen lights when motion is detected. You have another that dims them after 10 minutes if there is no motion. You walk into the kitchen, lights come on, you stand still, lights dim. You move slightly, lights go bright again. You stop moving for 10 minutes, lights dim. You move at the same moment the dimming routine starts, and end up with lights at 30% brightness instead of full. This is a race condition between two automations targeting the same device.
What is a race condition
A race condition occurs when two processes compete for the same resource and the outcome depends on the exact timing of each. Smart home automations can race when:
- Two automations target the same device at nearly the same time
- An automation’s actions take long enough that another can interrupt mid-execution
- The order of action execution within a single automation is not deterministic
The result is unpredictable behavior that is hard to debug because it does not happen consistently.
Diagnose by reproducing
If the race condition is reproducible (you can make it happen reliably by performing actions in a specific sequence), document the sequence. Note exactly what triggers, in what order, how much time between each, and what the final state is.
If it is not reproducible, watch for patterns. Does it happen more often at specific times of day (when other automations are also running)? Does it happen when the network is busy? These hints point to root causes.
Common race patterns
Pattern 1: motion on, dim off race. Motion automation sets lights to 100%. Idle automation dims to 30%. If both fire near simultaneously, the result depends on which one’s command arrives at the device last.
Fix: instead of two competing automations, build one combined automation. When motion is detected, set lights to 100% AND schedule a future dim. When motion ends, the dim is preserved. When motion resumes, cancel the scheduled dim and reset to 100%.
Pattern 2: scene transition race. Scene A sets the kitchen to warm white. Scene B sets the kitchen to cool white. Both triggered at nearly the same time. The lights end up in an indeterminate state with some warm and some cool.
Fix: scenes should be exclusive. Use a state machine where activating one scene explicitly cancels any in-progress scene transition before starting.
Pattern 3: device state read before write. Routine reads the current state of a device, decides what to do, then writes a new state. Between the read and the write, another routine changes the state. The first routine’s write is based on stale information.
Fix: use atomic operations where available. Avoid read-then-write logic in automations when the device may change state between operations.
The single source of truth principle
The cleanest design has exactly one automation that controls each device’s state at each moment. If two automations want to set the same device, design them to coordinate through an intermediary (a virtual switch, a state variable).
Example: instead of separate motion-on and idle-dim automations, build a single “kitchen brightness manager” automation that takes inputs from both motion sensor and idle timer and decides the appropriate brightness based on the combined inputs.
Add ordering with explicit delays
If two automations must run in a specific order, add an explicit delay to the second to ensure the first completes first.
Example: routine A sets the thermostat to away mode. Routine B turns off all lights. If both fire on “leaving home” trigger, add a 5-second delay to routine B to ensure routine A is fully committed before routine B starts.
This is fragile because the delay is fixed. If routine A is sometimes slow, the delay may not be enough.
Use mutual exclusion with virtual locks
A more robust approach: a virtual switch acts as a lock. Each routine that wants to control the device must first check the lock, set it, do its work, then release the lock. Other routines wait or skip.
Setup: create a virtual switch “kitchen-lock”. Each routine that controls kitchen lights starts with “if kitchen-lock is on, do nothing. Else, turn kitchen-lock on, do work, turn kitchen-lock off”.
This pattern works in any hub that supports conditional logic and virtual switches.
The acknowledgment race
Devices acknowledge commands at different speeds. A bulb may acknowledge in 200ms while a thermostat takes 5 seconds. If a routine fires a command and then immediately reads the device state, the state may not reflect the command yet.
Fix: avoid read-after-write patterns. If you must read after writing, wait long enough for the device to process the command (a few seconds is usually safe).
The cloud delay race
If your automation involves cloud-relayed commands (Alexa to manufacturer cloud to device), the cloud round trip adds variable latency. Two simultaneous routines may have their commands arrive at the device in either order.
Move to local execution where possible (Matter, native hub integration) to reduce variability.
The schedule overlap race
If two scheduled routines fire at the same time (both scheduled for 8:00 AM), they may interleave their actions. The result depends on the engine’s scheduling order, which is not always documented.
Stagger by 1 minute (8:00, 8:01) so they do not collide. The user-visible difference is negligible but the race is eliminated.
Test under load
Race conditions often only appear when the system is under load. Trigger multiple automations simultaneously and watch for unexpected behavior. If everything works at low load but breaks at high load, you have an engine throughput limit that exposes races.
The kitchen sink approach
If you cannot eliminate the race condition through design, the kitchen sink fix is to add explicit reconciliation. After all routines complete, a final routine reads the current state and sets it to whatever the correct final state should be.
This is robust but inelegant. The routine acts as a janitor cleaning up any indeterminate state.
When the race is benign
Some races do not actually cause user-visible problems. Two routines both turning a light on results in the light being on, even if the second command was redundant. As long as the end state is correct, the race is harmless.
Focus your debugging on races that cause incorrect final states or visible glitches, not on races that just produce redundant commands.