Home Assistant skill for Claude Code
Automations that fire right and explain themselves. Claude writes Home Assistant automations in the post-2024.10 schema with stable IDs, the right mode, debounced triggers and guards against unavailable states. Templates get defaults and availability checks, repeated logic becomes blueprints or scripts with fields, configs are split into packages with secrets kept out of git, and missed automations are diagnosed from their traces.
- name
home-assistant - size259 lines · ≈2,250 tokens
- files1
- licenseMIT
- updated
What Claude sees before loading it
This description is the only part of the skill that sits in context all the time. Claude reads it to decide when to load the full playbook below.
description: Writes and debugs Home Assistant configuration — automations, scripts, and scenes in current YAML syntax (triggers, conditions, actions), template sensors and helpers, blueprints with inputs, trigger IDs with choose, modes, packages, secrets, and integration setup — and troubleshoots with traces, the template editor, and config checks. Use when creating or fixing a Home Assistant automation, writing Jinja templates for sensors, building a blueprint, organizing configuration.yaml, migrating old service/platform syntax, or figuring out why an automation did not fire. Try asking
- Write an automation that turns on the hallway light on motion after sunset and off 2 minutes later
- My garage door alert automation never fires, here is the YAML, find out why
- Convert my old service and platform automations to the current Home Assistant syntax
Use it when
- Creating or fixing Home Assistant automations or scripts
- Writing template sensors or Jinja templates
- Building a reusable blueprint
- Reorganizing a large configuration.yaml
Skip it when
- You are writing firmware for the sensor device itself — use esp32-firmware
- You are designing the MQTT topic layout for devices — use mqtt-iot
How to check the result
The configuration check passes, the automation's trace shows every step as intended on a real trigger, and a restart does not fire it from unavailable-to-on transitions.
The common mistake it prevents
Triggering on to: "on" without a from state, so devices recovering from unavailable after a restart fire the automation.
Done well means: automations fire exactly when intended, survive restarts and devices
going unavailable, use the current YAML schema, keep secrets in secrets.yaml, pass
the configuration check before reload, and can be explained from their trace.
Hard rules
- Check configuration before every restart or reload (Developer Tools -> YAML -> Check
configuration, or
ha core checkon HA OS). A YAML error can stop integrations from loading. - Secrets (API keys, passwords, tokens, lat/long if sharing config) go in
secrets.yamlreferenced with!secret name; keep it out of git. - Locks, garage doors, alarms, heating, and anything safety-related: require explicit
user confirmation of the logic, guard against
unavailable/unknown, and prefer notifications with actionable confirmation over silent automatic unlocks. - Back up before large refactors (Settings -> System -> Backups) and keep
/configin git (with a.gitignoreforsecrets.yaml,.storage/, databases, and logs).
Current syntax (2024.10 and later)
Old configs use platform: inside triggers, service: for actions, and singular
trigger:/condition:/action: block keys. Current syntax:
- id: hallway_motion_light # stable id enables UI editing and traces
alias: Hallway light on motion
description: Turn on hallway light at night on motion; off 2 min after motion stops
mode: restart # re-trigger restarts the timer
triggers:
- trigger: state
entity_id: binary_sensor.hallway_motion
from: "off"
to: "on"
conditions:
- condition: state
entity_id: sun.sun
state: below_horizon
actions:
- action: light.turn_on
target:
entity_id: light.hallway
data:
brightness_pct: 60
- wait_for_trigger:
- trigger: state
entity_id: binary_sensor.hallway_motion
to: "off"
for: "00:02:00"
- action: light.turn_off
target:
entity_id: light.hallway
Old syntax still loads, but write new code in the current form and convert files you touch.
Workflow
- [ ] 1. State the behavior as "when X, if Y, do Z, unless W"
- [ ] 2. Inspect entities: Developer Tools -> States (exact entity_id, states, attributes)
- [ ] 3. Choose trigger(s), conditions, mode
- [ ] 4. Write YAML (or UI editor, then review YAML); prototype templates in the template editor
- [ ] 5. Check configuration; reload automations (no restart needed)
- [ ] 6. Test: run actions manually, then trigger for real; read the trace
- [ ] 7. Handle edge cases: unavailable, restart, rapid re-triggers
Triggers and modes
| Need | Trigger |
|---|---|
| Device changes state | trigger: state with from/to; add for: to debounce |
| Numeric threshold | trigger: numeric_state with above/below (fires on crossing only) |
| Time | trigger: time (at: "07:00:00" or an input_datetime) / time_pattern |
| Sun | trigger: sun with event: sunset and offset |
| Presence | trigger: zone or state of person.* |
| Button / remote event | trigger: event or device trigger (device triggers use device IDs that change if re-paired) |
| HA start | trigger: homeassistant with event: start |
| Complex condition becomes true | trigger: template (fires when the template turns true) |
Avoid to: "on" without from when the entity can go unavailable -> on after a
restart or network blip; use from: "off" or not_from: [unavailable, unknown].
| Mode | Behavior | Use for |
|---|---|---|
single (default) | Ignore new triggers while running (logs a warning) | One-shot actions |
restart | Stop the running instance and start over | Motion lights with timers |
queued | Run in order (max: default 10) | Sequential notifications |
parallel | Run concurrently | Independent per-entity actions |
Trigger IDs and choose
triggers:
- trigger: state
entity_id: binary_sensor.front_door
to: "on"
id: opened
- trigger: state
entity_id: binary_sensor.front_door
to: "off"
for: "00:00:30"
id: closed
actions:
- choose:
- conditions:
- condition: trigger
id: opened
sequence:
- action: light.turn_on
target: { entity_id: light.porch }
- conditions:
- condition: trigger
id: closed
sequence:
- action: light.turn_off
target: { entity_id: light.porch }
Templates
Prototype every template in Developer Tools -> Template first.
template:
- sensor:
- name: "Power cost today"
unique_id: power_cost_today
unit_of_measurement: "EUR"
state_class: total
state: >
{{ (states('sensor.energy_today') | float(0) * states('input_number.kwh_price') | float(0)) | round(2) }}
availability: >
{{ has_value('sensor.energy_today') and has_value('input_number.kwh_price') }}
- binary_sensor:
- name: "Anyone home"
unique_id: anyone_home
state: "{{ states.person | selectattr('state', 'eq', 'home') | list | count > 0 }}"
- Always give
float(0)/int(0)defaults;states()returns strings andunknown. - Use
availability:so a broken source makes the sensorunavailableinstead of0. unique_idmakes entities editable in the UI.- Prefer
states('sensor.x')overstates.sensor.x.state(the former handles missing entities).
Scripts with fields
script:
notify_and_flash:
alias: Notify and flash
mode: queued
fields:
message:
description: Text to send
required: true
selector: { text: {} }
sequence:
- action: notify.mobile_app_pixel
data:
message: "{{ message }}"
- action: light.turn_on
target: { entity_id: light.living_room }
data: { flash: short }
Call with action: script.notify_and_flash and data: { message: "..." }.
Blueprints
blueprint:
name: Motion light with timeout
domain: automation
input:
motion_sensor:
name: Motion sensor
selector: { entity: { filter: { domain: binary_sensor, device_class: motion } } }
target_light:
name: Light
selector: { target: { entity: { domain: light } } }
delay:
name: Off delay
default: 120
selector: { number: { min: 10, max: 1800, unit_of_measurement: seconds } }
mode: restart
triggers:
- trigger: state
entity_id: !input motion_sensor
from: "off"
to: "on"
actions:
- action: light.turn_on
target: !input target_light
- wait_for_trigger:
- trigger: state
entity_id: !input motion_sensor
to: "off"
- delay: !input delay
- action: light.turn_off
target: !input target_light
Store under config/blueprints/automation/<author>/<name>.yaml. To use an input
inside a template, assign it to a variable first (variables: { d: !input delay }).
Organization
- Split config with packages:
homeassistant: { packages: !include_dir_named packages }, one file per room or feature containing its automations, scripts, helpers, and templates. - UI-created automations live in
automations.yaml; do not hand-edit while the UI editor is open. - Helpers (
input_boolean,input_number,input_datetime, timers) make thresholds adjustable without editing YAML.
Debugging an automation that did not fire
- Settings -> Automations -> the automation -> Traces. No trace means the trigger never
matched: check the entity ID and the exact state values in Developer Tools -> States
(
"on"vsonvs"open"). - Trace exists but stopped: the condition step shows which condition failed and why.
mode: singlewarnings in the log mean it was already running.- Numeric state triggers fire only when crossing the threshold, not if already above it.
- Is the automation enabled? Was it renamed (new entity ID) or disabled after errors?
- Raise logging temporarily:
logger:
default: warning
logs:
homeassistant.components.automation: debug
Verification
- Configuration check passes; automations reload without errors in the log.
- Run the automation’s actions manually (Run actions) to confirm targets work.
- Trigger it for real and read the trace step by step.
- Restart HA and confirm nothing fires unexpectedly from
unavailable -> ontransitions. - For time-based automations, temporarily set the time trigger a few minutes ahead.
Gotchas
- YAML booleans: quote
"on"/"off"/"yes"in state comparisons. - Device triggers and device actions reference device IDs that change when a device is re-added; entity-based triggers survive better.
delayinside amode: singleautomation blocks re-triggers for the whole delay.- Template triggers only fire on false -> true transitions; a template that is already true at reload does not fire.
- Restarting HA cancels running automations and delays; use timers (
timer.start) and restore-state helpers for long waits.
About this skill
Written and maintained by the Claude Skills editors to the same editorial standard as every skill in the directory: a selective trigger, a real workflow, known pitfalls and a verification step. First published , last updated . MIT licensed.