Beyond Static: Mastering Dynamic Scripted Scenes in Home Assistant for Adaptive Ambiance
NGC 224
DIY Smart Home Creator
Intro
Smart home users often start with static scenes – "Movie Night" sets lights to 30% warm white, "Morning" turns them on at 100% cool white. While functional, these predefined snapshots quickly hit their limitations. What if "Movie Night" needs to adjust brightness based on the actual time of day, or "Morning" needs to consider if someone is actually present and still prefers a softer light on weekends? The problem is that static scenes lack context. They don't adapt to changing conditions like time, outdoor light levels, presence, or even personal preferences that shift throughout the day. This leads to rigid automations that feel less "smart" and more like glorified remote controls.
The solution lies in mastering dynamic scripted scenes within Home Assistant. By leveraging the power of Home Assistant's scripting engine, templates, and helpers, you can create scenes that are truly adaptive. Instead of fixed values, your scenes can calculate brightness, color temperature, and even which entities to control on the fly, responding intelligently to your environment. This guide will walk you through transforming your static scenes into powerful, context-aware experiences, making your smart home genuinely proactive and personalized.
Step-by-Step Setup: The Foundation – Crafting a Basic Scripted Scene
Before diving into dynamic parameters, let's establish how to encapsulate scene logic within a Home Assistant script. This provides a reusable wrapper and allows for more complex control flow than a simple scene entity.
1. Define Your Scene
First, create a standard scene. This will be the base for our script. In your scenes.yaml (or configuration.yaml):
# scenes.yaml
- name: "Living Room Base Dim"
id: "living_room_base_dim"
entities:
light.living_room_main:
state: "on"
brightness_pct: 40
color_temp: 350 # Kelvin (e.g., 350 = ~2857K)
light.living_room_accent:
state: "on"
brightness_pct: 20
rgb_color: [255, 100, 0] # Orange hue
This defines a scene called "Living Room Base Dim" that sets specific light states.
2. Create a Script to Activate the Scene
Now, create a script that calls this scene. This might seem redundant for a static scene, but it sets the stage for adding dynamic elements. In your scripts.yaml (or configuration.yaml):
# scripts.yaml
living_room_dimmed_mood:
name: "Activate Living Room Dimmed Mood"
sequence:
- service: scene.turn_on
target:
entity_id: scene.living_room_base_dim
You can now call script.living_room_dimmed_mood to activate your scene.
(Screenshot Placeholder: Home Assistant UI showing the created script and scene)
Step-by-Step Setup: Infusing Dynamics with Script Fields
The real power emerges when scripts accept parameters, making scenes flexible. We'll use script fields to pass dynamic values.
1. Modify the Script to Accept Parameters
Let's make our "Living Room Mood" script accept brightness, color temperature, and even optional entities. We'll define these as fields in the script's YAML.
# scripts.yaml
living_room_dynamic_mood:
name: "Activate Dynamic Living Room Mood"
fields:
brightness_percent:
description: "Brightness percentage (0-100)"
example: 75
selector:
number:
min: 0
max: 100
unit_of_measurement: "%"
color_temperature:
description: "Color temperature in Kelvin (e.g., 2700-6500)"
example: 4000
selector:
number:
min: 2000
max: 6500
unit_of_measurement: "K"
additional_lights:
description: "Optional list of additional lights to control"
example: "light.kitchen_spot_1, light.dining_room_light"
selector:
entity:
filter:
domain: light
multiple: true
sequence:
- variables:
# Default values if fields are not provided
_brightness: "{{ brightness_percent | default(50) }}"
_color_temp: "{{ color_temperature | default(3500) }}"
# Ensure additional_lights is a list, even if empty or single string
_extra_lights: >
{% if additional_lights is string %}
{{ additional_lights.split(', ') | map('trim') | list }}
{% elif additional_lights is not none %}
{{ additional_lights }}
{% else %}
[]
{% endif %}
- service: light.turn_on
target:
entity_id:
- light.living_room_main
- light.living_room_accent
- "{{ _extra_lights }}" # This will apply to the main lights and any extra ones
data:
brightness_pct: "{{ _brightness }}"
color_temp: "{{ _color_temp }}"
In this example, we've replaced the static scene.turn_on with a direct light.turn_on service call, allowing us to template the service data. The variables section provides default values and handles parsing for optional entity lists.
2. Calling the Dynamic Script from an Automation
Now, you can call this script from any automation, passing the desired parameters.
# automations.yaml
- id: '1678901234567'
alias: 'Evening Cozy Mood'
description: 'Set a cozy mood after sunset with specific brightness and color'
trigger:
- platform: sun
event: sunset
offset: "-00:30:00" # 30 minutes before sunset
condition: []
action:
- service: script.living_room_dynamic_mood
data:
brightness_percent: 60
color_temperature: 3000 # Warmer
additional_lights: "light.kitchen_lights"
mode: single
(Screenshot Placeholder: Home Assistant UI showing an automation calling the script with parameters)
Troubleshooting Section: When Your Dynamic Scenes Don't Dance
Dynamic scenes introduce more moving parts. Here are common issues and their solutions:
1. Script Fails to Trigger or Parameters Not Applied
- Check Logs: The Home Assistant log file (
home-assistant.log) is your best friend. Look for errors related toscript.living_room_dynamic_moodorlight.turn_on. - Template Errors: Invalid templates are a common culprit. Use the Home Assistant Developer Tools -> Template editor to test your Jinja2 templates (e.g.,
"{{ brightness_percent | default(50) }}"). Ensure variables are correctly defined and accessed. - Selector Mismatches: If you're using UI-based automations, ensure the
selectortype in your script fields matches the expected input (e.g., a number selector for a number input). - Service Call Data: Double-check that the service data in your
light.turn_oncall matches the expected format. For instance,brightness_pctexpects a number, not a string.
2. Entities Not Responding / Missing
- Entity ID Check: Verify all entity IDs in your script and automation are correct and exist. Typo in
light.living_room_main? - List vs. String for Entities: If passing multiple entities, ensure they are handled as a list. The example uses
additional_lights.split(', ') | map('trim') | listto correctly convert a comma-separated string from a selector into a proper list for the service call. - Integration Health: Ensure the underlying light integration (e.g., Zigbee, Z-Wave, Philips Hue) is functioning correctly and the devices are online.
Advanced Config / Optimization: Contextual Scene Activation
Let's make these dynamic scenes truly smart by integrating real-world context.
1. Leveraging Input Helpers for User Preferences
Use input_number and input_select helpers to allow users to set preferences that influence dynamic scenes without modifying YAML.
# configuration.yaml or helpers.yaml
input_number:
living_room_max_brightness:
name: "Living Room Max Brightness"
min: 10
max: 100
step: 5
unit_of_measurement: "%"
mode: slider
initial: 80
input_select:
current_ambiance_mode:
name: "Current Ambiance Mode"
options:
- "Bright White"
- "Warm & Cozy"
- "Vibrant"
initial: "Warm & Cozy"
Now, your automation can pull these values:
# automations.yaml
- id: '1678901234568'
alias: 'Dynamic Morning Scene with Preferences'
trigger:
- platform: time
at: "07:00:00"
condition:
- condition: state
entity_id: binary_sensor.living_room_motion # Only if motion detected
state: 'on'
action:
- service: script.living_room_dynamic_mood
data:
brightness_percent: "{{ states('input_number.living_room_max_brightness') | int }}"
color_temperature: >
{% if is_state('input_select.current_ambiance_mode', 'Bright White') %}
5500
{% elif is_state('input_select.current_ambiance_mode', 'Warm & Cozy') %}
2700
{% else %}
4000
{% endif %}
2. Time-Based and Sun-Aware Adjustments
Combine sun entity attributes and current time to dynamically calculate parameters.
# Example: Automation calling the script, adjusting for time of day
- id: '1678901234569'
alias: 'Contextual Living Room Entry'
trigger:
- platform: state
entity_id: binary_sensor.living_room_door_contact
to: 'on'
action:
- variables:
current_hour: "{{ now().hour }}"
is_daytime: "{{ states('sun.sun') == 'above_horizon' }}"
desired_brightness: >
{% if current_hour >= 22 or current_hour < 6 %} # Late night/early morning
20
{% elif current_hour >= 18 or not is_daytime %} # Evening/night
50
{% else %} # Daytime
80
{% endif %}
desired_color_temp: >
{% if current_hour >= 20 or current_hour < 6 %} # Evening/night
2500
{% elif current_hour >= 17 %} # Late afternoon
3000
{% else %} # Daytime
4500
{% endif %}
- service: script.living_room_dynamic_mood
data:
brightness_percent: "{{ desired_brightness }}"
color_temperature: "{{ desired_color_temp }}"
This automation uses a combination of the current hour and the sun's position to set a truly dynamic scene upon entry into the living room.
Real-World Example: An Adaptive "Good Night" Routine
Let's create a robust "Good Night" routine that not only turns things off but also sets a very low, warm light in the hallway if motion is detected shortly after, assisting with late-night trips to the bathroom without blinding anyone.
Goal: When "Good Night" is triggered: 1. Turn off all main lights and non-essential devices. 2. Set a low, warm light in the hallway for 5 minutes if motion is detected within 15 minutes of the routine starting.
1. The Core "Good Night" Script
# scripts.yaml
good_night_routine:
name: "Good Night Routine"
sequence:
- service: light.turn_off
data:
entity_id:
- light.living_room_main
- light.bedroom_main
- light.kitchen_main
- service: switch.turn_off
data:
entity_id:
- switch.tv_power
- switch.desk_lamp_plug
- service: automation.turn_on # Enable the delayed motion light automation
target:
entity_id: automation.hallway_late_night_light
- delay: "00:15:00" # Keep the automation active for 15 minutes
- service: automation.turn_off # Disable the automation after delay
target:
entity_id: automation.hallway_late_night_light
2. The "Late Night Hallway Light" Automation (initially disabled)
This automation will only be active when enabled by the "Good Night" script.
# automations.yaml
- id: '1678901234570'
alias: 'Hallway Late Night Light'
description: 'Soft hallway light if motion detected shortly after Good Night routine'
initial_state: 'off' # IMPORTANT: Start disabled
trigger:
- platform: state
entity_id: binary_sensor.hallway_motion_sensor
to: 'on'
condition:
- condition: state
entity_id: sun.sun
state: 'below_horizon' # Only at night
action:
- service: light.turn_on
target:
entity_id: light.hallway_light_strip
data:
brightness_pct: 10 # Very dim
color_temp: 2000 # Very warm
- delay: "00:05:00" # Light stays on for 5 minutes
- service: light.turn_off
target:
entity_id: light.hallway_light_strip
mode: restart # If motion is detected again, restart the 5-minute timer
This advanced example demonstrates how scripts can orchestrate not just light settings but also the behavior of other automations, creating a sophisticated, context-sensitive routine.
Best Practices / Wrap-up: Maintaining a Scalable, Smart Home
Building dynamic scenes introduces complexity, but following these best practices ensures a robust and maintainable system:
- Modularity: Break down complex scenes into smaller, reusable scripts. One script might handle "dimming to X%", another "setting color to Y." This makes debugging easier and logic more reusable.
- Default Parameters: Always provide sensible default values for script fields using the
| defaultfilter. This prevents errors if a calling automation doesn't provide all parameters. - Version Control: For any serious Home Assistant setup, especially with complex YAML, use Git. Store your configuration files in a Git repository. This allows you to track changes, revert to previous versions, and test new configurations safely.
- Comments: Document your scripts and automations liberally. Explain the purpose of complex templates, variables, and why certain decisions were made. Future you (or someone else) will thank you.
- Test Thoroughly: Use the Home Assistant Developer Tools to manually call scripts and services with different parameters to ensure they behave as expected before deploying them in critical automations.
- Performance Considerations: While Home Assistant is generally efficient, avoid overly complex templates that run constantly. Evaluate if a template sensor can pre-calculate a value rather than re-calculating it every time an automation triggers.
- UI Helpers for Control: Expose key script parameters or
input_selecthelpers on your dashboard. This empowers household members to influence the smart home's behavior without touching YAML.
By moving beyond static scenes and embracing dynamic scripted approaches, you unlock a new level of intelligence and responsiveness in your Home Assistant setup. Your smart home will no longer just react; it will proactively adapt to your life, creating truly personalized and seamless experiences.
NGC 224
Author bio: DIY Smart Home Creator
