Mastering Home Assistant Scripts: Building Reusable, Parameterized Automation Logic

NGC 224
DIY Smart Home Creator
Introduction: The Pitfall of Repetitive Automations
As your Home Assistant setup grows, you inevitably encounter a common challenge: repetitive automation logic. You might find yourself copying and pasting similar sequences of actions across multiple automations – perhaps a notification routine that sends alerts to different devices based on the trigger, or a series of steps to prepare your home for sleep. This practice, while functional initially, quickly leads to configuration bloat, maintenance nightmares, and a higher probability of introducing errors when updates are needed. If you've ever thought, "There has to be a better way to reuse this block of actions," you're ready to master Home Assistant's scripting capabilities.
Home Assistant scripts are powerful, reusable sequences of actions that can be called from automations, other scripts, or even directly from the UI. Unlike automations which are triggered by specific events or states, scripts are manually invoked and can accept parameters, making them incredibly versatile. By leveraging scripts, you can encapsulate complex logic, centralize common tasks, and drastically reduce the redundancy in your configuration, leading to a more maintainable, scalable, and robust smart home system.
Step-by-Step Setup: Creating Your First Parameterized Script
Let's begin by creating a simple, parameterized script that sends a customizable notification. This will illustrate how to define a script and pass data to it.
1. Define the Script in scripts.yaml
First, ensure you have a scripts.yaml
file included in your configuration.yaml
:
# configuration.yaml
script:
!include scripts.yaml
Now, open scripts.yaml
and add your first script:
# scripts.yaml
notify_with_title_and_message:
alias: Send a Dynamic Notification
sequence:
- service: notify.mobile_app_your_device # Replace with your notification service
data:
title: "{{ title | default('Home Assistant Notification') }}"
message: "{{ message | default('No message provided.') }}"
data:
tag: "{{ tag | default('home_assistant') }}"
color: "{{ color | default('blue') }}"
Explanation:
notify_with_title_and_message
: This is the unique ID of your script.alias
: A user-friendly name visible in the UI.sequence
: The list of actions the script will perform.service: notify.mobile_app_your_device
: The notification service call. Adjust this to your specific notification service (e.g.,notify.telegram
,notify.hass_mobile_app_iphone
).data:
: This section uses Jinja2 templating to access parameters passed to the script.{{ title | default('Home Assistant Notification') }}
: This expects atitle
variable. If not provided, it defaults to 'Home Assistant Notification'. The same applies tomessage
,tag
, andcolor
.
2. Call the Script from an Automation
Now, let's create an automation to trigger this script and pass it some data. Imagine you want to send a notification when your front door opens.
# automations.yaml
- id: '1678901234567'
alias: Front Door Opened Alert
trigger:
- platform: state
entity_id: binary_sensor.front_door
to: 'on'
action:
- service: script.notify_with_title_and_message
data:
title: "Security Alert!"
message: "The front door was opened."
tag: "security_alert"
color: "red"
Explanation:
service: script.notify_with_title_and_message
: This is how you invoke a script. The service domain isscript
, and the service name is the script's ID.data:
: This is where you pass parameters to your script. The keys (title
,message
,tag
,color
) correspond to the variables expected by the script.
Troubleshooting Common Script Issues
Scripts, while powerful, can be tricky. Here are common issues and how to troubleshoot them:
1. Script Not Running / No Notification
- Check Home Assistant Logs: Go to Settings > System > Logs. Look for errors related to
script
ornotify
services. - Verify Service Call: Ensure the
service: script.your_script_id
in your automation matches the script ID exactly. - Test Script Directly: Go to Developer Tools > Services, select your script (e.g.,
script.notify_with_title_and_message
), and manually enter data variables (e.g.,title: Test
,message: Manual Test
) to see if it runs.
2. Parameters Not Received / Templating Errors
- Variable Mismatch: Double-check that the variable names in the
data:
section of your automation exactly match the variable names used in your script's Jinja2 templates (e.g.,{{ title }}
). - Default Values: If you're using
| default('...')
, temporary remove the default to see if the template is truly evaluating toNone
. - Developer Tools > Template: Use the Template editor under Developer Tools to test your Jinja2 expressions. For instance, to simulate the script, you can temporarily define variables like this:
{% set title = 'My Custom Title' %} {% set message = 'Hello from the template editor!' %} Title: {{ title }} Message: {{ message }}
- Quote Strings: Ensure all string values in YAML are properly quoted, especially if they contain special characters.
Advanced Config / Optimization: Dynamic Script Invocation and Complex Logic
1. Dynamic Entity IDs and Lists
You're not limited to simple strings for parameters. You can pass full entity IDs, lists of entities, or complex objects.
# scripts.yaml
toggle_multiple_lights:
alias: Toggle a List of Lights
sequence:
- service: light.toggle
target:
entity_id: "{{ lights_to_toggle | default([]) }}"
# automation.yaml (calling the script)
- id: '1678901234568'
alias: Evening Light Toggle
trigger:
- platform: time
at: "18:00:00"
action:
- service: script.toggle_multiple_lights
data:
lights_to_toggle:
- light.living_room_lamp
- light.kitchen_counter_lights
2. Conditional Logic (choose
, if/then
) within Scripts
Scripts can contain advanced branching logic, making them truly powerful decision-makers.
# scripts.yaml
handle_door_event:
alias: Process Door Event
sequence:
- variables:
door_entity: "{{ entity_id }}"
event_type: "{{ to_state }}"
- choose:
- conditions:
- "{{ event_type == 'on' }}"
sequence:
- service: script.notify_with_title_and_message
data:
title: "Door Open!"
message: "{{ door_entity }} was opened."
color: "red"
- service: light.turn_on
target:
entity_id: light.hallway_light
- conditions:
- "{{ event_type == 'off' }}"
sequence:
- service: script.notify_with_title_and_message
data:
title: "Door Closed"
message: "{{ door_entity }} was closed."
color: "green"
- delay: "00:00:30"
- service: light.turn_off
target:
entity_id: light.hallway_light
default: []
# automation.yaml (calling the script from any door sensor)
- id: '1678901234569'
alias: Monitor All Doors with Script
trigger:
- platform: state
entity_id:
- binary_sensor.front_door
- binary_sensor.back_door
- binary_sensor.garage_door
action:
- service: script.handle_door_event
data:
entity_id: "{{ trigger.entity_id }}"
to_state: "{{ trigger.to_state.state }}"
This example demonstrates a single script handling both 'open' and 'close' events for multiple door sensors, significantly reducing automation redundancy.
3. Using repeat
for Iteration
Scripts can iterate through lists or perform actions a set number of times.
# scripts.yaml
pulse_light:
alias: Pulse a Light for Notifications
sequence:
- repeat:
count: "{{ count | default(3) }}"
sequence:
- service: light.turn_on
target:
entity_id: "{{ light_entity_id }}"
data:
brightness: 255
color_name: "{{ color | default('red') }}"
- delay: "00:00:01"
- service: light.turn_off
target:
entity_id: "{{ light_entity_id }}"
- delay: "00:00:01"
Real-World Example: A Comprehensive "Good Night" Routine
Let's build a robust "Good Night" script that prepares your home for the evening, encompassing various actions based on parameters.
# scripts.yaml
good_night_routine:
alias: Execute Good Night Routine
sequence:
- variables:
arm_alarm: "{{ arm_alarm | default(true) }}" # Default to arming
lights_off_area: "{{ lights_off_area | default('all') }}" # 'all', 'bedrooms', 'living_room'
set_hvac_mode: "{{ hvac_mode | default('auto') }}"
hvac_temp: "{{ target_temp | default(20) }}"
notify_if_issues: "{{ notify_issues | default(true) }}"
- service: system_log.write
data:
message: "Starting Good Night Routine with arm_alarm={{ arm_alarm }}, lights_off_area={{ lights_off_area }}"
level: info
# Step 1: Turn off lights based on area
- choose:
- conditions: "{{ lights_off_area == 'all' or lights_off_area == 'living_room' }}"
sequence:
- service: light.turn_off
target:
area_id: living_room
# Can also use entity_id list
- conditions: "{{ lights_off_area == 'all' or lights_off_area == 'bedrooms' }}"
sequence:
- service: light.turn_off
target:
area_id: bedrooms
default: []
# Step 2: Set HVAC mode and temperature
- service: climate.set_hvac_mode
target:
entity_id: climate.thermostat
data:
hvac_mode: "{{ set_hvac_mode }}"
- service: climate.set_temperature
target:
entity_id: climate.thermostat
data:
temperature: "{{ hvac_temp }}"
# Step 3: Arm security system if requested
- if: "{{ arm_alarm }}"
then:
- service: alarm_control_panel.alarm_arm_home
target:
entity_id: alarm_control_panel.home_alarm
- delay: "00:00:05" # Give alarm time to arm
- if: "{{ is_state('alarm_control_panel.home_alarm', 'armed_home') }}"
then:
- service: script.notify_with_title_and_message
data:
title: "Good Night!"
message: "Alarm armed. Home secure."
color: "green"
else:
- if: "{{ notify_if_issues }}"
then:
- service: script.notify_with_title_and_message
data:
title: "Alarm Arming Failed!"
message: "Check for open doors/windows."
color: "orange"
# Step 4: Final checks and notifications
- if:
- conditions:
- "{{ is_state('binary_sensor.garage_door', 'on') }}"
- "{{ notify_if_issues }}"
then:
- service: script.notify_with_title_and_message
data:
title: "Reminder!"
message: "Garage door is still open!"
color: "yellow"
- service: script.notify_with_title_and_message
data:
title: "Routine Complete"
message: "Good night routine finished. Sweet dreams!"
color: "blue"
Now, you can trigger this script from various sources:
- Bedside Button:
# automation.yaml
- id: 'bedside_button_good_night'
alias: Bedside Button - Good Night
trigger:
- platform: state
entity_id: sensor.bedside_button_action
to: 'single'
action:
- service: script.good_night_routine
data:
arm_alarm: true
lights_off_area: 'all'
target_temp: 19
notify_issues: true
# automation.yaml
- id: 'late_night_good_night'
alias: Automatic Late Night Shutdown
trigger:
- platform: time
at: "01:00:00"
action:
- service: script.good_night_routine
data:
arm_alarm: false # Don't arm if everyone is asleep
lights_off_area: 'all'
target_temp: 18
hvac_mode: 'heat'
notify_issues: false # Don't wake people up for minor issues
This demonstrates how a single, well-crafted script can serve multiple automation needs by simply varying the input parameters, making your Home Assistant configuration incredibly flexible and easy to manage.
Best Practices / Wrap-up
To ensure your script-driven automations are scalable, reliable, and secure, consider these best practices:
1. Organization and Naming Conventions
- Descriptive IDs: Use clear, lowercase, underscore-separated IDs for your scripts (e.g.,
notify_critical_alert
). - Aliases: Always provide a human-readable
alias
for easy identification in the UI. - Folder Structure: For large setups, consider breaking
scripts.yaml
into a directory structure (e.g.,scripts/notifications.yaml
,scripts/routines.yaml
) and using!include_dir_list
or!include_dir_named
.
2. Documentation and Comments
- Inline Comments: Use
#
to add comments within your scripts, explaining complex logic or variable usage. - Script Descriptions: Consider adding a
description
field to your script for more extensive documentation, especially for parameters.
3. Robustness and Error Handling
- Default Values: Always use
| default('...')
in your templates to provide fallback values if a parameter isn't passed, preventing template errors. - System Logs: Leverage
system_log.write
within critical scripts to log their execution and passed parameters, aiding debugging. - Conditions and Choices: Use
choose
andif/then
statements to handle different scenarios gracefully and prevent unintended actions.
4. Version Control (Git)
Treat your Home Assistant configuration, especially scripts and automations, as code. Use Git to track changes, revert to previous versions, and collaborate. This is invaluable for complex setups.
5. Testing and Validation
- Developer Tools > Services: Manually call scripts from Developer Tools to test different parameter combinations.
- Dedicated Test Automations: Create temporary automations specifically to trigger scripts with various inputs during development.
By embracing Home Assistant scripts, you move beyond basic automations to build a truly intelligent, efficient, and easily maintainable smart home. Start refactoring your repetitive actions into parameterized scripts today, and experience the power of modular automation.

NGC 224
Author bio: DIY Smart Home Creator