Scenes and scripts are tools for reusing states and sequences of actions in Home Assistant.
As our installation grows and we add dozens of automations, we will encounter a classic problem: configuration duplication.
Suppose we have a sequence of actions to “Turn off the house” (turn off all lights, lower the blinds to 0%, set the thermostat to 17°C, and arm the alarm).
If we want to execute this sequence when a physical button by the door is pressed, when telling a voice assistant, and automatically at midnight, we would end up copying and pasting the same block of actions into three different automations.
Home Assistant provides us with two fundamental tools to group and reuse logic: Scenes and Scripts.
Although to the eyes of a beginner user they may seem the same, at an architectural level they have radically different purposes. Let’s analyze them in depth.
Scenes: the snapshot of the state
A Scene in Home Assistant is, strictly speaking, a static capture of the state of a group of entities.
There is no logic, no delays, and no conditions. It is simply a declaration of how we want certain devices to be at a given moment. When we “activate” (scene.turn_on) a scene, Home Assistant simultaneously sends the necessary commands to all involved entities so they adopt that exact state.
Scenes fit very well for defining lighting environments or fixed configurations.
Example of a scene in YAML
If we look at the scenes.yaml file, we will see that its structure is a simple dictionary (mapping) of entity_id and their desired states:
- id: "scene_movie_night"
name: "Movie Night"
entities:
light.luz_techo_salon:
state: "off"
light.tira_led_tv:
state: "on"
brightness: 75
color_name: "blue"
cover.persiana_salon:
state: "closed"
media_player.amplificador:
state: "on"
volume_level: 0.45
Instead of writing this YAML by hand, the most efficient way to create a scene is to physically adjust the lights and devices in the room to your liking, go to the Home Assistant interface (Settings > Scenes), click add and select the devices. The system will read their current states and save them automatically.
Dynamic scenes (scene.create)
Here comes one of the most powerful technical tricks in Home Assistant. In addition to predefined scenes, we can create scenes on the fly in RAM during the execution of an automation.
Suppose we are watching a movie with dim lights and someone rings the doorbell. We want the living room light to flash white to alert us, and then return exactly to the state it was in.
To achieve this, we use the scene.create service before altering anything:
action:
# 1. Take a "snapshot" of the current state and save it to memory
- action: scene.create
data:
scene_id: estado_previo_salon
snapshot_entities:
- light.luz_techo_salon
- light.tira_led_tv
# 2. Execute our visual alert (white flash at 100%)
- action: light.turn_on
target:
entity_id: light.luz_techo_salon
data:
color_name: "white"
brightness_pct: 100
flash: short
# 3. Wait 3 seconds
- delay: "00:00:03"
# 4. Restore the original snapshot
- action: scene.turn_on
target:
entity_id: scene.estado_previo_salon
Scripts: logical sequences and functions
If a Scene is a static photograph, a Script is a moving picture.
Internally, a Script is exactly the same as the action block of an automation, but extracted into an independent entity (script.nombre_del_script).
Scripts support sequences, delays, loops, and conditions, as well as event waiting with wait_for_trigger. They are the equivalent of functions in a programming language.
Using variables with Jinja
What makes scripts especially useful is their ability to accept input parameters (variables) when called, using the Jinja2 template engine.
Imagine we want a standard script to send voice notifications to our smart speakers (TTS), but we want the volume to be adjusted dynamically, send the message, and then return the speaker to its original volume.
Instead of creating an automation for each message, we create a single reusable script (script.anuncio_voz_dinamico):
alias: "System: Dynamic Voice Announcement"
mode: queued # Prevents two announcements from overlapping on the same speaker
fields:
mensaje:
description: "The text to be played"
example: "Washing machine finished"
entidad_altavoz:
description: "The destination media_player"
example: "media_player.altavoz_cocina"
sequence:
# 1. Save the current volume in a Jinja2 variable
- variables:
volumen_previo: "{{ state_attr(entidad_altavoz, 'volume_level') }}"
# 2. Raise the volume to 70% for the announcement
- action: media_player.volume_set
target:
entity_id: "{{ entidad_altavoz }}"
data:
volume_level: 0.7
# 3. Launch the Text-to-Speech (TTS) engine
- action: tts.speak
target:
entity_id: tts.google_translate_es_es
data:
media_player_entity_id: "{{ entidad_altavoz }}"
message: "{{ mensaje }}"
# 4. Wait for the speaker to finish speaking
- wait_template: "{{ is_state(entidad_altavoz, 'idle') }}"
timeout: "00:00:10"
# 5. Restore the original volume
- action: media_player.volume_set
target:
entity_id: "{{ entidad_altavoz }}"
data:
volume_level: "{{ volumen_previo }}"
Now, from any automation in our home, we only need to invoke this script passing it the mensaje and entidad_altavoz arguments. We have encapsulated the complexity in one place. If tomorrow we change the voice engine from Google to Nabu Casa, we will only have to modify this script, and all automations in the house will inherit the change automatically.
When to use each tool
To maintain a clean codebase in Home Assistant, the design rule we should apply is as follows:
- Automations: They are responsible exclusively for deciding WHEN things happen (Triggers and Conditions). Their action block should be as short as possible.
- Scripts: They are responsible for deciding HOW dynamic processes happen (logical sequences, checks, loops, waits). Automations call scripts.
- Scenes: They are responsible for defining WHAT exact state static devices should have. Scripts (or direct automations) apply the scenes.
This separation of concerns is the difference between a chaotic configuration file with thousands of lines that breaks with every update, and a professional, maintainable, and scalable home automation system.
Helpers: small auxiliary states
Besides scenes and scripts, Home Assistant has another very useful tool to keep logic organized: Helpers. These are virtual entities that do not represent a physical device but allow us to store information.
For example, an input_boolean.modo_invitados can indicate there are guests at home and prevent all lights from turning off at midnight. An input_select.modo_casa can toggle between normal, cine, night, or vacation. And an input_number.temperatura_confort can store the preferred heating setpoint.
Helpers are great for separating configuration state from logic. Instead of hardcoding fixed values in ten automations, we store them in an entity editable from the interface.