Scripts
A script is a named bundle of actions that WoowTech runs on demand. Starting the script — by turning it on, calling it from an automation, or pressing it in the dashboard — fires its action list from top to bottom. Each script you create shows up as its own entity, so you can trigger it, watch its state, and reference it anywhere entities are accepted.
You can author scripts either in YAML or through the visual editor; both produce the same thing.
Writing a script
Scripts are built from WoowTech's action syntax. The smallest useful one looks like this:
script:
announce_humidity:
sequence:
- action: notify.notify
data:
message: "Humidity is at {{ states('sensor.bathroom_humidity') }}%"
One naming rule matters: the key you give a script (the slug, here announce_humidity) may contain only lowercase letters and underscores. Capital letters and hyphens are not allowed.
The options a script accepts
| Key | Type | Role |
|---|---|---|
alias |
string | A human-friendly name for the interface. |
icon |
string | The icon shown for the script. |
description |
string | A short note about what the script is for; surfaces in Developer Tools. |
variables |
map | Values computed up front and made available to every template inside the script. |
fields |
map | Declares the inputs the script expects, which the editors then render as form fields. |
mode |
string | What happens if the script is started again while already running (defaults to single). |
max |
integer | The cap on simultaneous or queued runs (defaults to 10) for the queued and parallel modes. |
max_exceeded |
string | Severity of the log message emitted when max is hit (defaults to warning); set to silent to suppress it, or any standard log level. |
sequence |
list | The ordered list of actions to perform. This one is required. |
How re-triggering behaves
The mode decides what a second start does while the script is still busy:
| Mode | Behavior |
|---|---|
single |
Refuses the new request and logs a warning; the running instance is left alone. |
restart |
Abandons the current run and begins again from the top. |
queued |
Lines the new run up and executes them one after another in arrival order. |
parallel |
Lets the new run proceed at the same time as the existing one. |
Feeding data into a script
Scripts become reusable when you parameterize them. There are two ways to supply values, and both land in your templates by their field key. Declaring fields makes those inputs appear in the script and automation editors:
script:
send_pushover:
description: "Push a one-off message to Pushover"
fields:
heading:
description: "Headline of the notification"
body:
description: "Main text of the notification"
sequence:
- action: notify.pushover
data:
title: "{{ heading }}"
message: "{{ body }}"
You then call it and hand over the field values:
automation:
- alias: "Notify on door open"
triggers:
- trigger: state
entity_id: binary_sensor.front_door
to: "on"
actions:
- action: script.send_pushover
data:
heading: "Front door"
body: "The front door just opened"
Inside a script's templates, the this variable holds that script's own state object as a dictionary, which is handy when a script needs to inspect itself.
Calling scripts and waiting (or not)
How you invoke a script changes whether the caller pauses for it:
- Calling it by entity (for example
action: script.send_pushover) makes the caller block until the script finishes. If the called script errors out, that error stops the caller too. - Calling
script.turn_ondoes not block. The script is kicked off and the caller carries straight on to its next action. An error in the started script stays contained and won't abort the caller.
If you need to launch something with script.turn_on yet still wait for it to wrap up, pair it with a wait_template that watches for the script's state to settle.
A fuller example
This "Gentle Wake" script pulls together variables, a field with a selector, a non-default mode, a templated delay, and several actions:
script:
gentle_wake:
alias: "Gentle Wake"
icon: "mdi:weather-sunset-up"
description: "Brings the bedroom up slowly, then the kitchen after a pause"
mode: restart
fields:
pause_minutes:
name: Pause (minutes)
description: "How long to wait before lighting the kitchen"
selector:
number:
min: 0
max: 45
variables:
morning_level: 90
sequence:
- action: light.turn_on
target:
entity_id: light.bedroom_ceiling
data:
brightness: "{{ morning_level }}"
- delay:
minutes: "{{ pause_minutes }}"
- action: light.turn_on
target:
entity_id: light.kitchen_strip
data:
brightness: 180
Scripts
A script is a named bundle of actions that WoowTech runs on demand. Starting the script — by turning it on, calling it from an automation, or pressing it in the dashboard — fires its action list from top to bottom. Each script you create shows up as its own entity, so you can trigger it, watch its state, and reference it anywhere entities are accepted.
You can author scripts either in YAML or through the visual editor; both produce the same thing.
Writing a script
Scripts are built from WoowTech's action syntax. The smallest useful one looks like this:
script:
announce_humidity:
sequence:
- action: notify.notify
data:
message: "Humidity is at {{ states('sensor.bathroom_humidity') }}%"
One naming rule matters: the key you give a script (the slug, here announce_humidity) may contain only lowercase letters and underscores. Capital letters and hyphens are not allowed.
The options a script accepts
| Key | Type | Role |
|---|---|---|
alias |
string | A human-friendly name for the interface. |
icon |
string | The icon shown for the script. |
description |
string | A short note about what the script is for; surfaces in Developer Tools. |
variables |
map | Values computed up front and made available to every template inside the script. |
fields |
map | Declares the inputs the script expects, which the editors then render as form fields. |
mode |
string | What happens if the script is started again while already running (defaults to single). |
max |
integer | The cap on simultaneous or queued runs (defaults to 10) for the queued and parallel modes. |
max_exceeded |
string | Severity of the log message emitted when max is hit (defaults to warning); set to silent to suppress it, or any standard log level. |
sequence |
list | The ordered list of actions to perform. This one is required. |
How re-triggering behaves
The mode decides what a second start does while the script is still busy:
| Mode | Behavior |
|---|---|
single |
Refuses the new request and logs a warning; the running instance is left alone. |
restart |
Abandons the current run and begins again from the top. |
queued |
Lines the new run up and executes them one after another in arrival order. |
parallel |
Lets the new run proceed at the same time as the existing one. |
Feeding data into a script
Scripts become reusable when you parameterize them. There are two ways to supply values, and both land in your templates by their field key. Declaring fields makes those inputs appear in the script and automation editors:
script:
send_pushover:
description: "Push a one-off message to Pushover"
fields:
heading:
description: "Headline of the notification"
body:
description: "Main text of the notification"
sequence:
- action: notify.pushover
data:
title: "{{ heading }}"
message: "{{ body }}"
You then call it and hand over the field values:
automation:
- alias: "Notify on door open"
triggers:
- trigger: state
entity_id: binary_sensor.front_door
to: "on"
actions:
- action: script.send_pushover
data:
heading: "Front door"
body: "The front door just opened"
Inside a script's templates, the this variable holds that script's own state object as a dictionary, which is handy when a script needs to inspect itself.
Calling scripts and waiting (or not)
How you invoke a script changes whether the caller pauses for it:
- Calling it by entity (for example
action: script.send_pushover) makes the caller block until the script finishes. If the called script errors out, that error stops the caller too. - Calling
script.turn_ondoes not block. The script is kicked off and the caller carries straight on to its next action. An error in the started script stays contained and won't abort the caller.
If you need to launch something with script.turn_on yet still wait for it to wrap up, pair it with a wait_template that watches for the script's state to settle.
A fuller example
This "Gentle Wake" script pulls together variables, a field with a selector, a non-default mode, a templated delay, and several actions:
script:
gentle_wake:
alias: "Gentle Wake"
icon: "mdi:weather-sunset-up"
description: "Brings the bedroom up slowly, then the kitchen after a pause"
mode: restart
fields:
pause_minutes:
name: Pause (minutes)
description: "How long to wait before lighting the kitchen"
selector:
number:
min: 0
max: 45
variables:
morning_level: 90
sequence:
- action: light.turn_on
target:
entity_id: light.bedroom_ceiling
data:
brightness: "{{ morning_level }}"
- delay:
minutes: "{{ pause_minutes }}"
- action: light.turn_on
target:
entity_id: light.kitchen_strip
data:
brightness: 180
Start writing here...