Create or Update Automation
ha_config_set_automationDefine automations with triggers, conditions, and actions to control smart home devices automatically.
Instructions
Create or update a Home Assistant automation.
MUST call ha_get_skill_guide OR refer to your locally installed skills first.
PREFER NATIVE SOLUTIONS OVER TEMPLATES (read this before writing any {{ ... }}):
Native triggers/conditions/actions are validated at config load, fail loudly, and
do not bypass HA's schema. Templates fail silently at runtime and obscure intent.
condition: numeric_stateinstead of{{ states('x') | float > N }}condition: state(withstate:list) instead of{{ is_state(...) }}/{{ states(x) in [...] }}condition: timeinstead of{{ now().hour ... }}or{{ now().weekday() ... }}condition: suninstead of{{ is_state('sun.sun', ...) }}Native
for:field onstate/numeric_statetriggers andstateconditions over{{ now() - X.last_changed > timedelta(...) }}duration math.wait_for_triggerinstead ofwait_templatechooseaction instead of template-based service namesFor one-shot date firing, use a
timetrigger plusautomation.turn_offon a hardcoded entity_id — not{{ now().date() ... }}.Hardcode
target.entity_idliterals — never{{ this.entity_id }}. Templates are appropriate ONLY indata.*fields, notification message/title,event_data, andvariables. The reactive best-practice checker on this tool will surface anything in a logic position that should be native; consult thebest_practice_warningsfield on the response and fix before re-submitting. The relevant skill section is auto-embedded underskill_contenton warnings, and the fullautomation-patterns.md+template-guidelines.mdreferences ship underskill_contentproactively by default. For comprehensive guidance beyond that, callha_get_skill_guide.
The returned automation_id is the resolved entity_id (canonical
form, e.g. automation.morning_routine) when entity registration
succeeds, falling back to the input identifier (update path) or
the generated unique_id from the upsert response (fresh create
when no identifier was passed).
Before reaching for ha_config_set_automation, consider whether a
dedicated tool fits the use case better:
State snapshot of one or more entities (capture-then-replay, no trigger needed) -> ha_config_set_scene
State-derived value that recomputes when its inputs change (template sensor / binary sensor / number / select) -> ha_config_set_helper(helper_type='template')
Stateful counter / timer / schedule / boolean / etc. -> ha_config_set_helper(helper_type='counter' | 'timer' | ...)
Supports two modes: full config replacement OR Python transformation.
WHEN TO USE WHICH MODE:
python_transform: RECOMMENDED for edits to existing automations. Surgical updates.
config: Use for creating new automations or full restructures.
IMPORTANT: python_transform requires 'identifier' and 'config_hash' from ha_config_get_automation().
PYTHON TRANSFORM EXAMPLES (operate on the fetched config, which uses HA's canonical plural root keys 'triggers'/'actions'/'conditions'):
Update action: python_transform="config['actions'][0]['data']['brightness'] = 255"
Add trigger: python_transform="config['triggers'].append({'trigger': 'state', 'entity_id': 'binary_sensor.motion', 'to': 'on'})"
Remove last action: python_transform="config['actions'].pop()"
Creates a new automation (if identifier omitted) or updates existing automation with provided configuration.
AUTOMATION TYPES:
Regular Automations - Define triggers and actions directly
Blueprint Automations - Use pre-built templates with customizable inputs
REQUIRED FIELDS (Regular Automations):
alias: Human-readable automation name
triggers: List of triggers (time, state, event, etc.)
actions: List of actions to execute
REQUIRED FIELDS (Blueprint Automations):
alias: Human-readable automation name
use_blueprint: Blueprint configuration
path: Blueprint file path (e.g., "motion_light.yaml")
input: Dictionary of input values for the blueprint
OPTIONAL CONFIG FIELDS (Regular Automations):
description: Detailed description of the user's intent (RECOMMENDED: helps safely modify implementation later)
category: Category ID for organization (use ha_config_get_category to list, ha_config_set_category to create)
conditions: Additional conditions that must be met
mode: 'single' (default), 'restart', 'queued', 'parallel'
max: Maximum concurrent executions (for queued/parallel modes)
initial_state: Whether automation starts enabled (true/false)
variables: Variables for use in automation
BASIC EXAMPLES:
Simple time-based automation: ha_config_set_automation(config={ "alias": "Morning Lights", "description": "Turn on bedroom lights at 7 AM to help wake up", "triggers": [{"trigger": "time", "at": "07:00:00"}], "actions": [{"action": "light.turn_on", "target": {"area_id": "bedroom"}}] })
Motion-activated lighting — for: on the off-transition replaces action-delay:
ha_config_set_automation(config={
"alias": "Motion Light",
"triggers": [
{"trigger": "state", "entity_id": "binary_sensor.motion", "to": "on", "id": "motion_on"},
{"trigger": "state", "entity_id": "binary_sensor.motion", "to": "off",
"for": {"minutes": 5}, "id": "motion_off"}
],
"actions": [
{"choose": [
{"conditions": [
{"condition": "trigger", "id": "motion_on"},
{"condition": "sun", "after": "sunset"}
],
"sequence": [{"action": "light.turn_on", "target": {"entity_id": "light.hallway"}}]},
{"conditions": [{"condition": "trigger", "id": "motion_off"}],
"sequence": [{"action": "light.turn_off", "target": {"entity_id": "light.hallway"}}]}
]}
]
})
Update existing automation: ha_config_set_automation( identifier="automation.morning_routine", config={ "alias": "Updated Morning Routine", "triggers": [{"trigger": "time", "at": "06:30:00"}], "actions": [ {"action": "light.turn_on", "target": {"area_id": "bedroom"}}, {"action": "climate.set_temperature", "target": {"entity_id": "climate.bedroom"}, "data": {"temperature": 22}} ] } )
BLUEPRINT AUTOMATION EXAMPLES:
Create automation from blueprint: ha_config_set_automation(config={ "alias": "Motion Light Kitchen", "use_blueprint": { "path": "homeassistant/motion_light.yaml", "input": { "motion_entity": "binary_sensor.kitchen_motion", "light_target": {"entity_id": "light.kitchen"}, "no_motion_wait": 120 } } })
Update blueprint automation inputs: ha_config_set_automation( identifier="automation.motion_light_kitchen", config={ "alias": "Motion Light Kitchen", "use_blueprint": { "path": "homeassistant/motion_light.yaml", "input": { "motion_entity": "binary_sensor.kitchen_motion", "light_target": {"entity_id": "light.kitchen"}, "no_motion_wait": 300 } } } )
TRIGGER TYPES: time, time_pattern, sun, state, numeric_state, event, device, zone, template, and more CONDITION TYPES: state, numeric_state, time, sun, template, device, zone, and more ACTION TYPES: action calls, delays, wait_for_trigger, wait_template, if/then/else, choose, repeat, parallel
For comprehensive automation documentation with all trigger/condition/action types and advanced examples:
Use: ha_get_skill_guide
TROUBLESHOOTING:
Use ha_get_state() to verify entity_ids exist
Use ha_search() to find correct entity_ids
IF you must use Jinja2 and have no native alternative, test it first with ha_eval_template() before embedding it in the automation config — catches syntax errors and unresolved entity_ids before they fail silently at runtime
Use ha_search(domain_filter='automation') to find existing automations
create update modify edit automation triggers conditions actions new automation write save
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| wait | No | Wait for automation to be queryable before returning. Default: True. Set to False for bulk operations. | |
| config | No | Complete automation configuration with required fields: 'alias', 'triggers', 'actions'. Optional: 'description', 'conditions', 'mode', 'max', 'initial_state', 'variables'. Purpose-specific triggers/conditions (HA 2026.7+ default: 'trigger': '<domain>.<name>' with 'target'/'options') are valid config. Mutually exclusive with python_transform. | |
| category | No | Category ID to assign to this automation. Use ha_config_get_category(scope='automation') to list available categories, or ha_config_set_category() to create one. | |
| identifier | No | Automation entity_id or unique_id for updates. Required for python_transform. Omit to create new automation with generated unique_id. | |
| config_hash | No | Config hash from ha_config_get_automation for optimistic locking. REQUIRED for python_transform (validates automation unchanged). Optional for config updates (validates before full replacement if provided). | |
| MandatoryBPS | No | ||
| BestPracticeKey | No | Read-receipt for the home-assistant-best-practices skill; required when strict best-practices mode is enabled. Not a secret or credential: the current value is an attestation phrase published openly at the top of the skill content served by ha_get_skill_guide. Read that content, then pass the value back verbatim — this round-trip is the server's designed protocol confirming the practices were read before writing. | |
| python_transform | No | Python expression to transform existing automation config. Mutually exclusive with config. Requires identifier and config_hash for validation. WARNING: Expressions with infinite loops will hang the server. Examples: Simple: python_transform="config['actions'][0]['data']['brightness'] = 255" Pattern: python_transform="for a in config['actions']: if a.get('alias') == 'My Step': a['data']['value'] = 100" PYTHON TRANSFORM SECURITY: ✅ ALLOWED: - Dictionary/list access: config['views'][0]['cards'][1] - Slicing: config['views'][0]['cards'][1:3] - Assignment: config['key'] = 'value' - Deletion: del config['key'] or config.pop('key') - List methods: append, insert, pop, remove, clear, extend - Dict methods: update, get, setdefault, keys, values, items - Loops: for, if/else, pass, break, continue - Comprehensions: [x for x in ...], {k: v for ...}, (x for x in ...) - Ternary: x if condition else y - Iterable unpacking (* in calls/literals): f(*xs), [*xs, y] - Dict unpacking (**) in calls and dict literals: {**d, 'k': v} - Keyword arguments: func(key=value) - Lambdas (e.g. for `key=`): sorted(items, key=lambda x: x['score']) - String methods: startswith, endswith, lower, upper, strip, split, join, replace - Safe builtins: isinstance, len, range, enumerate, zip, sorted, reversed, min, max, sum, abs, any, all, round, str, int, float, bool, list, dict, tuple, set ❌ FORBIDDEN: - Imports: import, from, __import__ - File operations: open, read, write - Dunder access: __class__, __bases__, __subclasses__ - Dangerous builtins: eval, exec, compile, getattr, setattr, delattr, hasattr - Function definitions: def, class - Exception handling: try/except (validate with isinstance/in/.get() instead) - While loops: use bounded for loops or comprehensions instead 🎯 PATTERNS: - Filter cards: cards = [c for c in cards if keep(c)] - Skip in a loop: prefer `continue` over an empty `pass` branch (clearer) - Conditionally include: build a new list and `.append(x)` only the cards you want, instead of iterating the original and using if/pass branches to drop entries - Modify in place when possible (single pass, fewer surprises) over reconstructing the entire list |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||