Presence-Aware Lighting in Home Assistant Using a YAML Blueprint
Tired of lights turning off too soon? This is how I built a presence-aware lighting system in Home Assistant using a blueprint.
I’ve automated my home with Home Assistant for years, but motion-sensor-based lighting always annoyed me — it turns off too soon. You know the feeling. Walking into a room, the light turns on, but it turns off at the first quiet moment even if you’re still sitting there reading, listening to music, or watching TV.
So I decided to build a proper presence-aware lighting system right in Home Assistant as a blueprint. The idea is simple:
- Each room has a set of sensors that define “presence” (motion sensors, media players, PCs, whatever)
- Lights turn on automatically based on time of day and room occupancy
- Lights turn off after a configurable timeout, but with a flash warning before turning off
- Manual light control is respected — if you turn on a light yourself, the automation will not override it (but it will still turn it off after timeout)
- Occupancy is exposed via input booleans, so other automations can use it
- The blueprint is reusable across all rooms through simple UI configuration
I’ll walk you through how I set it up, what it does, and how you can extend it.
My First Attempt
When I first installed Home Assistant, many tutorials online recommended using Node-RED for automations. Admittedly, the visual flow-based approach is appealing, but it quickly became unwieldy for anything non-trivial.
Here is what my Node-RED flow looked like for my home’s presence lighting:

I’m a big fan of clean, maintainable code, and this just wasn’t cutting it. So I decided to scrap Node-RED and implement the entire logic as a reusable blueprint (with the help of ChatGPT — seriously, it’s a game-changer for writing automations).
Prerequisites
Before we start, you should have:
- Home Assistant up and running
- (Optional) Input booleans for each room:
input_boolean.occupied_<room>andinput_boolean.auto_lights_<room> binary_sensor.sunsetandbinary_sensor.night_modehelpers (you can create these using the Time of Day) integration.
These can go in your configuration.yaml. The Night Mode sensor can be set up from the UI or in YAML, but the sunset sensor needs to be added in YAML like this:
binary_sensor:
- platform: tod
name: Sunset
after: sunset
after_offset: "-00:30"
before: sunrise
unique_id: sunset
- platform: tod
name: Night Mode
after: "22:00:00"
before: "05:00:00"
unique_id: night_modeWe’re going to use a blueprint, so it’s portable, maintainable, and reusable across all rooms.
Room Configuration
The blueprint lets you configure each room through the Home Assistant UI. When you create an automation from the blueprint, you’ll configure:
- Presence entities: Motion sensors, media players, or any device that indicates someone is present. I have an ICMP ping sensor for my PC that marks me as present when it’s on the network.
- Lights: Which lights to control (can be multiple)
- Scenes (optional): Which scene to use for sunset and night mode
- Timeouts: How long to wait before turning off lights
For example, my man cave configuration looks like this:
- Presence Sensors:
binary_sensor.man_cave_sensor_motion,media_player.man_cave_tv,sensor.man_cave_pc_ping - Lights:
light.man_cave - Sunset Scene:
scene.man_cave_stranger_things - Night Scene:
scene.man_cave_sleepy - Timeouts: 10 minutes (sunset), 5 minutes (night)
A few things to note:
presence_entitiescan include motion sensors, media players, PCs, or any device that can indicate someone is present. Media players are considered “active” when playing, paused, or on (but not idle, standby, or off).lightsis a list, so you can control multiple lights per room.sceneandscene_nightdefine which scene to use when lights turn on. If no scene is defined, we fall back to 80% brightness during the day and 5% at night.timeout_minutesandtimeout_minutes_nightcontrol how long the room waits before turning off the lights.
How It Works
The automation has two main branches:
1. Presence Detected
When any of the room’s presence entities turn on:
Mark the room as occupied (
input_boolean.occupied_<room>).Turn on the lights if auto-lighting is not disabled (using the optional
input_boolean.auto_lights_<room>) and all lights are currently off.Decide what to turn on based on the time of day:
- Night mode: either the night scene or very dim lights (5%).
- After sunset but not night: the default scene or 80% brightness.
- Daytime: do nothing; lights stay off (but will remain on if you manually turned them on as long as the room is occupied).
This ensures that lights never interrupt your manual adjustments and only turn on automatically when appropriate.
2. Presence Cleared
When all presence entities in a room are off/inactive:
- Start a timeout countdown (
timeout_minutes). - When the timeout expires, flash the lights gently to warn you (a soft brightness pulse).
- Wait 30 more seconds after the flash.
- If the room is still empty, turn off the lights and mark the room as unoccupied.
This handles the common problem of “lights turning off too early” while still conserving energy.
The flash is usually followed in our house by a flailing hand gesture to convince the IR sensor that we’re still there!
The Full Blueprint
Here’s the complete blueprint YAML. You can import this directly into Home Assistant or save it in your blueprints/automation/ folder:
blueprint:
name: Presence-Aware Lighting System
description: >
Robust presence-based lighting with sunset/night scenes, configurable timeouts,
manual override detection, and optional occupancy tracking.
Supports motion sensors (bursty), media players, door sensors, and static presence indicators.
domain: automation
author: James Harding
input:
presence_binary_sensors:
name: Binary Presence Sensors
description: Motion sensors, door sensors, or any binary_sensor that indicates presence when "on".
selector:
entity:
domain: binary_sensor
multiple: true
default: []
presence_media_players:
name: Media Players
description: >
Media players that indicate presence when playing/paused/on.
Room is considered occupied when state is not "off", "unavailable", "idle", or "standby".
selector:
entity:
domain: media_player
multiple: true
default: []
lights:
name: Lights
description: The lights to control in this room.
selector:
entity:
domain: light
multiple: true
sunset_scene:
name: Sunset Scene
description: >
Scene to activate from sunset until night mode begins.
If not set, lights will turn on at 80% brightness.
selector:
entity:
domain: scene
default: ""
night_scene:
name: Night Scene
description: >
Scene to activate during night mode (e.g., late evening/sleep time).
If not set, lights will turn on at 5% brightness.
selector:
entity:
domain: scene
default: ""
occupied_helper:
name: Occupied Helper (Optional)
description: >
An input_boolean to track room occupancy externally.
Useful for other automations or dashboards.
selector:
entity:
domain: input_boolean
default: ""
auto_lights_toggle:
name: Auto Lights Toggle (Optional)
description: >
An input_boolean that enables/disables automatic lighting.
When "off", lights won't turn on/off automatically, but occupancy tracking still works.
selector:
entity:
domain: input_boolean
default: ""
timeout_sunset:
name: Sunset Timeout (minutes)
description: How long to wait after presence clears before turning off lights (sunset period).
default: 10
selector:
number:
min: 1
max: 60
unit_of_measurement: minutes
mode: slider
timeout_night:
name: Night Timeout (minutes)
description: How long to wait after presence clears before turning off lights (night period).
default: 5
selector:
number:
min: 1
max: 60
unit_of_measurement: minutes
mode: slider
night_mode_sensor:
name: Night Mode Sensor
description: A binary_sensor that is "on" during night mode (e.g., late evening/sleep time).
selector:
entity:
domain: binary_sensor
default: binary_sensor.night
sunset_sensor:
name: Sunset Sensor
description: A binary_sensor that is "on" after sunset (typically sun.sun based).
selector:
entity:
domain: binary_sensor
default: binary_sensor.sunset
trigger:
- platform: state
entity_id: !input presence_binary_sensors
id: binary_sensor_change
- platform: state
entity_id: !input presence_media_players
id: media_player_change
variables:
presence_binary_sensors: !input presence_binary_sensors
presence_media_players: !input presence_media_players
lights: !input lights
sunset_scene: !input sunset_scene
night_scene: !input night_scene
occupied_helper: !input occupied_helper
auto_lights_toggle: !input auto_lights_toggle
timeout_sunset: !input timeout_sunset
timeout_night: !input timeout_night
night_mode_sensor: !input night_mode_sensor
sunset_sensor: !input sunset_sensor
brightness_sunset: 80
brightness_night: 5
transition_sunset: 2
transition_night: 3
condition: []
action:
- variables:
check_binary_presence: >
{{ presence_binary_sensors | default([]) | select('is_state', 'on') | list | length > 0 }}
check_media_presence: >
{{ presence_media_players | default([])
| reject('is_state', 'off')
| reject('is_state', 'unavailable')
| reject('is_state', 'unknown')
| reject('is_state', 'idle')
| reject('is_state', 'standby')
| list | length > 0 }}
presence_active: >
{{ check_binary_presence or check_media_presence }}
is_night: >
{{ is_state(night_mode_sensor, 'on') }}
is_after_sunset: >
{{ is_state(sunset_sensor, 'on') }}
auto_lights_enabled: >
{{ auto_lights_toggle == '' or auto_lights_toggle is none or is_state(auto_lights_toggle, 'on') }}
any_light_on: >
{{ lights | select('is_state', 'on') | list | length > 0 }}
timeout_minutes: >
{{ timeout_night if is_night else timeout_sunset }}
- choose:
- conditions:
- condition: template
value_template: "{{ presence_active }}"
sequence:
- if:
- condition: template
value_template: "{{ occupied_helper != '' and occupied_helper is not none }}"
then:
- service: input_boolean.turn_on
target:
entity_id: "{{ occupied_helper }}"
- condition: template
value_template: "{{ auto_lights_enabled }}"
- condition: template
value_template: "{{ not any_light_on }}"
- condition: template
value_template: "{{ is_after_sunset }}"
- choose:
- conditions:
- condition: template
value_template: "{{ is_night }}"
sequence:
- choose:
- conditions:
- condition: template
value_template: "{{ night_scene != '' and night_scene is not none }}"
sequence:
- service: scene.turn_on
target:
entity_id: "{{ night_scene }}"
default:
- service: light.turn_on
target:
entity_id: "{{ lights }}"
data:
brightness_pct: "{{ brightness_night }}"
transition: "{{ transition_night }}"
default:
- choose:
- conditions:
- condition: template
value_template: "{{ sunset_scene != '' and sunset_scene is not none }}"
sequence:
- service: scene.turn_on
target:
entity_id: "{{ sunset_scene }}"
default:
- service: light.turn_on
target:
entity_id: "{{ lights }}"
data:
brightness_pct: "{{ brightness_sunset }}"
transition: "{{ transition_sunset }}"
- conditions:
- condition: template
value_template: "{{ not presence_active }}"
sequence:
- delay:
minutes: "{{ [timeout_minutes | int, 1] | max }}"
- if:
- condition: template
value_template: "{{ auto_lights_toggle == '' or auto_lights_toggle is none or is_state(auto_lights_toggle, 'on') }}"
then:
- if:
- condition: template
value_template: "{{ lights | select('is_state', 'on') | list | length > 0 }}"
then:
- repeat:
count: 1
sequence:
- service: light.turn_on
target:
entity_id: "{{ lights }}"
data:
brightness_step_pct: 15
transition: 0.3
- delay:
milliseconds: 400
- service: light.turn_on
target:
entity_id: "{{ lights }}"
data:
brightness_step_pct: -15
transition: 0.3
- delay:
milliseconds: 600
- delay:
seconds: 30
- service: light.turn_off
target:
entity_id: "{{ lights }}"
data:
transition: "{{ transition_night if is_state(night_mode_sensor, 'on') else transition_sunset }}"
- if:
- condition: template
value_template: "{{ occupied_helper != '' and occupied_helper is not none }}"
then:
- service: input_boolean.turn_off
target:
entity_id: "{{ occupied_helper }}"
mode: restartExtending and Customizing
- Create a new automation from the blueprint for each room
- Adjust
timeout_minutesfor each room depending on usage (bedroom might need shorter timeouts than office) - Scenes can be swapped for different moods — golden hours in the evening, “stranger things” (my red and blue 80s theme) for night
- Other automations can use the
occupied_<room>helper to adjust heating, music, or notifications - The blueprint uses
mode: restartwhich means if new presence is detected during the timeout, it restarts — perfect for bursty motion sensors
Final Thoughts
This setup gives you presence-aware lighting without complicated integrations or scripting. Lights behave intuitively, flash to warn before turning off, and respect your manual overrides. It’s fully reusable across rooms and easy to configure through Home Assistant’s UI.
Give it a try in your Home Assistant setup, and let me know how it works for you or if you have any suggestions. Happy automating!