
This article may contain affiliate links. If you buy through these links, the price is the same for you and the store pays me a small commission that helps keep Tecnoyfoto running.
The automation from the previous chapter turns on the light every time the door opens. It meets that requirement exactly, but a real home probably should not behave the same way at noon, at night, and when nobody is home.
We will extend it in stages. First, we will add conditions so it continues only when it is night and someone is home. Then we will examine what happens when a condition fails. Finally, we will use choose to express several possible outcomes without introducing Jinja templates.
The distinction between a trigger and a condition is central to this chapter. Both can examine states, but they serve different purposes: a trigger responds to a change and starts a run; a condition examines the current situation after that run has begun.
From a simple requirement to a conditional one
Our current automation can be summarized as follows:
When the door opens, turn on the light.
The new requirement is:
When the door opens, turn on the light if it’s night and there’s someone at home.
The door opening remains the event that starts the automation. Nighttime and presence do not need to begin at that exact moment; they simply must both be true when the door opens.
We therefore separate:
- Trigger: the door changes from closed to open.
- First condition: Night mode is active.
- Second condition: someone is home.
- Action: turn on the light.
The practice environment allows you to change both conditions manually using:
input_boolean.course_night_mode
input_boolean.course_someone_home
The corresponding entities are:
binary_sensor.course_night
binary_sensor.course_someone_home
These virtual controls let us test every path at any time. In a real installation, you might use sun.sun, an illuminance reading, a time window, or a combination appropriate for that home.
Add two state conditions
The automation now looks like this:
alias: "YAML Course - Light the entryway at night"
description: >-
Turn on the light when the door opens while night mode is active
and someone is home.
triggers:
- trigger: state
entity_id: binary_sensor.course_front_door
from: "off"
to: "on"
conditions:
- condition: state
entity_id: binary_sensor.course_night
state: "on"
- condition: state
entity_id: binary_sensor.course_someone_home
state: "on"
actions:
- action: light.turn_on
target:
entity_id: light.course_living_room
mode: single
conditions contains a list of two maps. Home Assistant evaluates them in order after the trigger has started the automation.
Several conditions mean AND by default
The two conditions must be true:
course_night is on
AND
course_someone_home is on
If either condition is false, Home Assistant stops the run before reaching the actions. We do not need an and key because a normal list of conditions already uses AND behavior.
The complete case table helps you see it:
| Night | Someone home | Light turns on? |
|---|---|---|
| No | No | No |
| No | Yes | No |
| Yes | No | No |
| Yes | Yes | Yes |
Only the last combination satisfies both conditions.
A condition does not wait for something to happen
This is one of the most frequent conceptual errors. Imagine the door opens during the day. The trigger starts the automation, but binary_sensor.course_night is off. The condition fails, and the run ends.
If night falls five hours later, that run does not resume. The condition was not waiting; it only took a snapshot of the situation at the moment it was evaluated.
For an automation to start when night comes, the night would have to be part of its triggers. That would describe another event:
When night begins, do something.
In our requirement, opening the door remains the relevant event. Nighttime only determines whether the action is appropriate at that moment.
This difference can be summarized as follows:
Trigger: detects an event and starts a run.
Condition: checks the current situation within that run.
A condition can check how long a state has held
The fact that a condition does not wait does not limit it to checking only the current value. With for, it can also check how long an entity has been in that state:
conditions:
- condition: state
entity_id: binary_sensor.course_hallway_motion
state: "off"
for:
seconds: 30
When Home Assistant evaluates this block, it checks two things: whether the sensor is off and whether it has been off for at least thirty seconds. If only twenty seconds have elapsed, the condition fails immediately. It does not wait for the remaining ten seconds or resume the run later.
Therefore, for does not turn the condition into a wait. It adds a duration requirement to the state at the moment of evaluation. In the final project, we will use this distinction to prevent a safety shutdown from running immediately after motion ends.
Test all four combinations
Before adding more logic, systematically test the table above.
For each case:
- Close the virtual door.
- Turn off the light.
- Adjust
course_night_modeandcourse_someone_home. - Open the door.
- Check the light and open the trace.
When a condition fails, the trace should show where the path stopped. That is not an execution error; it is the expected behavior.
If you click Run actions, Home Assistant skips the triggers and conditions and may turn on the light in daylight. To test the conditions, cause the real trigger to fire or start the automation with a method that evaluates them.
Defining nighttime in a real home: sun, time, or light
The practice night switch gives us repeatable tests, but “night” can mean different things in different homes.
State of the sun
Home Assistant maintains the entity sun.sun. A common condition is:
- condition: state
entity_id: sun.sun
state: "below_horizon"
This condition is true from sunset until sunrise and requires no template.
Time window
If the household rule depends on the time rather than outdoor light:
- condition: time
after: "22:00:00"
before: "07:00:00"
The window crosses midnight. after includes the initial time and before excludes the final time.
Illuminance sensor
An illuminance sensor may better represent the actual darkness at a particular entrance, but you must inspect its readings and choose an appropriate threshold for that installation.
No option is universally best. The right question is what “night” means in the actual requirement. We will keep using binary_sensor.course_night because it gives us controlled tests and lets us focus on structure.
When do we need OR?
Suppose we want to turn on the light when it is night or when an illuminance sensor reports darkness. A normal list would require both conditions. To accept either one, we need an explicit OR condition.
conditions:
- condition: or
conditions:
- condition: state
entity_id: binary_sensor.course_night
state: "on"
- condition: numeric_state
entity_id: sensor.example_illuminance
below: 20
The outer condition is type or. It contains another list under conditions, and only one inner condition needs to be true.
We will not use this fictitious sensor in the exercise because it is not part of the practice environment. The fragment shows how the structure changes when the requirement changes from “and” to “or.”
You should first write the rule in a sentence and mark its connectors:
Someone is home AND (it is night OR illuminance is below 20 lux).
The logical hierarchy should also appear in YAML. If we misgroup the conditions, we can create a valid configuration that responds to another rule.
Top-level conditions only allow the automation to continue or stop
With top-level conditions, the automation has two possible outcomes:
All pass → run the actions.
Any one fails → end without running the actions.
This is enough when there is only one useful answer, but imagine a more complete need:
- If you open the door at night and there’s someone at home, turn on the light.
- If it opens at night and there is no one, create a persistent alert.
- If it opens in the day, do nothing.
We no longer want a top-level condition to discard every case except one. We want the run to reach the actions and then select a sequence based on the situation. That is what choose provides.
choose: several branches, one selected
Automation can be written as follows:
alias: "YAML Course - Respond when the door opens"
description: >-
Decide what to do when the door opens based on nighttime and presence.
triggers:
- trigger: state
entity_id: binary_sensor.course_front_door
from: "off"
to: "on"
conditions: []
actions:
- choose:
- alias: "At night and with someone at home"
conditions:
- condition: state
entity_id: binary_sensor.course_night
state: "on"
- condition: state
entity_id: binary_sensor.course_someone_home
state: "on"
sequence:
- action: light.turn_on
target:
entity_id: light.course_living_room
- alias: "At night and with no one at home"
conditions:
- condition: state
entity_id: binary_sensor.course_night
state: "on"
- condition: state
entity_id: binary_sensor.course_someone_home
state: "off"
sequence:
- action: persistent_notification.create
data:
title: "YAML Course - Entry Notice"
message: "The door has been opened at night and no one is home."
default: []
mode: single
The top-level conditions list is empty because we do not want to stop the automation before it can select a branch.
Inside actions, one list item contains choose. It holds a list of options, and each option has:
conditions: when the branch is eligible.sequence: which actions run when the branch is selected.
Home Assistant evaluates the options in order and runs the first one whose conditions pass. It then exits that choose; later branches are not evaluated.
Branch aliases explain intent
alias: "At night and with someone at home"
This alias does not affect the outcome. It makes the configuration and trace easier to understand. For a branch with several conditions, the alias should summarize the entire situation rather than repeat only the first condition.
default is the fallback path
default: []
default runs when no option matches. Here it contains an empty list, so opening the door during the day produces no action.
We could omit default, but showing it makes the decision explicit. In other automations, it may contain a real sequence equivalent to “if none of the options above match.”
choose selects the first match
Order matters when two branches could match at the same time. A broad condition placed first may prevent a more specific branch from ever being reached.
Our example’s branches are mutually exclusive because course_someone_home cannot be both on and off. Suppose instead you created:
- A branch for “it’s night”.
- Another one for “it’s night and there’s someone.”
If the first branch came first, the second would never run: “it is night” would already have matched. Put the more specific rule first, or redesign the conditions.
Trigger IDs: identify which event started the run
In the previous chapter we created an automation to open the door and another to close it. We can combine them when they belong to the same responsibility and use trigger identifiers.
triggers:
- trigger: state
entity_id: binary_sensor.course_front_door
from: "off"
to: "on"
id: "opened"
- trigger: state
entity_id: binary_sensor.course_front_door
from: "on"
to: "off"
id: "closed"
Either trigger starts the automation. Multiple automation triggers behave like OR; only one needs to occur.
Within choose we can check which one started it:
actions:
- choose:
- conditions:
- condition: trigger
id: "opened"
sequence:
- action: light.turn_on
target:
entity_id: light.course_living_room
- conditions:
- condition: trigger
id: "closed"
sequence:
- action: light.turn_off
target:
entity_id: light.course_living_room
The trigger condition does not inspect the door’s current state. It compares the ID of the trigger that started this run.
One automation is not always better than two. If behaviors have different purposes, responsibilities, or maintenance needs, keeping them separate may be clearer. Combine them when the relationship improves understanding, not merely to reduce the automation count.
Exercise: join opening and closing with night conditions
Build an automation that follows these rules:
- When the door opens, identify the trigger as
opened. - When the door closes, identify the trigger as
closed. - If the door opened, it is night, and someone is home, turn on the light.
- If the door closed, turn off the light regardless of time or presence.
- In any other case, don’t do anything.
Try at least these paths:
- Open the door at night with someone home.
- Open the door during the day with someone home.
- Open the door at night with nobody home.
- Close the door with the light on.
The trace should show which trigger started the run and which branch of choose was selected.
See the explained solution
alias: "YAML Course - Control light with door"
description: >-
Turn on the light when the door opens at night and someone is home; turn it off when the door closes.
triggers:
- trigger: state
entity_id: binary_sensor.course_front_door
from: "off"
to: "on"
id: "opened"
- trigger: state
entity_id: binary_sensor.course_front_door
from: "on"
to: "off"
id: "closed"
conditions: []
actions:
- choose:
- alias: "Open at night with someone at home"
conditions:
- condition: trigger
id: "opened"
- condition: state
entity_id: binary_sensor.course_night
state: "on"
- condition: state
entity_id: binary_sensor.course_someone_home
state: "on"
sequence:
- action: light.turn_on
target:
entity_id: light.course_living_room
- alias: "Door closed"
conditions:
- condition: trigger
id: "closed"
sequence:
- action: light.turn_off
target:
entity_id: light.course_living_room
default: []
mode: single
The first branch contains three conditions and therefore uses AND: the run must come from the opened trigger, it must be night, and someone must be home.
The second branch only needs to check for closed. Turning off the light does not depend on its current state; calling light.turn_off when it is already off does not change the intended result.
When the door opens during the day or nobody is home, no branch matches and default runs no actions.
What should you take from this chapter?
The trigger responds to the event that starts a run. A condition checks the current situation after that run has started; it does not wait for the state to come true.
Several conditions form an AND by default. When we need alternatives, we use an explicit OR structure. When we do not want top-level conditions to limit the entire automation to one path, choose pairs conditions with sequences and runs the first matching branch.
Trigger IDs help combine related events without templates. They do not automatically make a large automation clear; the grouped behavior must still represent one understandable responsibility.
In the next chapter we will add time to the sequences. We will compare a fixed delay with an event wait and see what happens if an automation starts again while the previous run is still waiting.

