home-assistant-best-practices

Native Home Assistant constructs for automations, helpers, scripts, and Lovelace dashboards. Prioritizes built-in conditions, triggers, and helpers over Jinja2 templates; includes decision workflow for choosing between native state conditions, numeric_state, time triggers, and template helpers Covers automation modes (single, restart, queued, parallel) with scenarios, entity_id vs device_id usage, and Zigbee button/remote patterns for ZHA and Zigbee2MQTT Provides safe refactoring workflow for entity renames, helper replacements, and trigger restructuring to prevent silent breakage across dashboards and scripts Documents anti-patterns (template conditions, wait_template polling, device_id brittleness) with native alternatives and reasoning

INSTALLATION
npx skills add https://github.com/homeassistant-ai/skills --skill home-assistant-best-practices
Run in your project or agent environment. Adjust flags if your CLI version differs.

SKILL.md

Home Assistant Best Practices

Core principle: Use native Home Assistant constructs wherever possible. Templates bypass validation, fail silently at runtime, and make debugging opaque.

Decision Workflow

Follow this sequence when creating any automation:

0. Gate: modifying existing config?

If your change affects entity IDs or cross-component references — renaming entities, replacing template sensors with helpers, converting device triggers, or restructuring automations — read references/safe-refactoring.md first. That reference covers impact analysis, device-sibling discovery, and post-change verification. Complete its workflow before proceeding.

Steps 1-5 below apply to new config or pattern evaluation.

1. Check for native condition/trigger

Before writing any template, check references/automation-patterns.md for native alternatives.

Common substitutions:

  • {{ states('x') | float > 25 }}numeric_state condition with above: 25
  • {{ is_state('x', 'on') and is_state('y', 'on') }}condition: and with state conditions
  • {{ now().hour >= 9 }}condition: time with after: "09:00:00"
  • wait_template: "{{ is_state(...) }}"wait_for_trigger with state trigger (caveat: different behavior when state is already true — see references/safe-refactoring.md#trigger-restructuring)

2. Check for built-in helper or Template Helper

Before creating a template sensor, check references/helper-selection.md.

Common substitutions:

  • Sum/average multiple sensors → min_max integration
  • Binary any-on/all-on logic → group helper
  • Rate of change → derivative integration
  • Cross threshold detection → threshold integration
  • Consumption tracking → utility_meter helper

If no built-in helper fits, use a Template Helper — not YAML.

Create it via the HA config flow (MCP tool or API) or via the UI:

Settings → Devices & Services → Helpers → Create Helper → Template.

Only write template: YAML if explicitly requested or if neither path is available.

3. Select correct automation mode

Default single mode is often wrong. See references/automation-patterns.md#automation-modes.

Scenario

Mode

Motion light with timeout

restart

Sequential processing (door locks)

queued

Independent per-entity actions

parallel

One-shot notifications

single

4. Use entity_id over device_id

device_id breaks when devices are re-added. See references/device-control.md.

Exception: Zigbee2MQTT autodiscovered device triggers are acceptable.

5. For Zigbee buttons/remotes

  • ZHA: Use event trigger with device_ieee (persistent)
  • Z2M: Use device trigger (autodiscovered) or mqtt trigger

See references/device-control.md#zigbee-buttonremote-patterns.

Critical Anti-Patterns

Anti-pattern

Use instead

Why

Reference

condition: template with float > 25

condition: numeric_state

Validated at load, not runtime

references/automation-patterns.md#native-conditions

wait_template: "{{ is_state(...) }}"

wait_for_trigger with state trigger

Event-driven, not polling; waits for change (see references/safe-refactoring.md#trigger-restructuring for semantic differences)

references/automation-patterns.md#wait-actions

device_id in triggers

entity_id (or device_ieee for ZHA)

device_id breaks on re-add

references/device-control.md#entity-id-vs-device-id

mode: single for motion lights

mode: restart

Re-triggers must reset the timer

references/automation-patterns.md#automation-modes

enabled: false as a top-level key in automations.yaml

automation.turn_off (temporary) or entity registry disable (permanent)

Not a valid top-level key — rejected during schema validation; automation loads as unavailable

references/automation-patterns.md#disabling-automations

Template sensor for sum/mean

min_max helper

Declarative, handles unavailable states

references/helper-selection.md#numeric-aggregation

Template binary sensor with threshold

threshold helper

Built-in hysteresis support

references/helper-selection.md#threshold

Renaming entity IDs without impact analysis

Follow references/safe-refactoring.md workflow

Renames break dashboards, scripts, scenes, Config-Entry data, and storage dashboards silently

references/safe-refactoring.md#entity-renames

Renaming members of Config-Entry-based groups (UI groups) without updating membership

Update group membership via Options Flow after the registry rename

The entity registry rename does not update options.entities in the Config Entry — group silently breaks

references/safe-refactoring.md#config-entry-groups

Renaming entities used by Config-Entry integrations (Better/Generic Thermostat, Min/Max, Threshold) without patching Config-Entry data

Scan and patch core.config_entries data+options fields

These integrations store entity_ids in Config Entry — not updated by entity registry renames

references/safe-refactoring.md#config-entry-data--blind-spots-for-entity-registry-renames

template: sensor/binary sensor in YAML

Template Helper (UI or config flow API)

Requires file edit and config reload; harder to manage

references/template-guidelines.md

Editing .storage/ files or other HA internal state directly

Use the HA REST/WebSocket API to manage state and config entries

.storage/ files are HA's internal state database; direct edits bypass validation, risk corruption, and can be silently overwritten by HA

Writing raw YAML to configuration.yaml by hand for YAML-only integrations

Use managed YAML config editing with backup and validation

Unmanaged writes risk syntax errors, have no backup, and skip check_config — managed editing provides all three

references/yaml-only-integrations.md

Generating YAML snippets for automations/scripts/scenes

Use the HA config API to create automations/scripts programmatically

API calls validate config, avoid syntax errors, and don't require manual file edits or restarts

references/automation-patterns.md, references/examples.yaml

Telling user to edit configuration.yaml for integrations

Direct user to Settings > Devices & Services in the HA UI

Most integrations are UI-configured; YAML integration config is rare and integration-specific

Referring to HA "add-ons"

Use the term "Apps"

HA renamed add-ons to Apps in 2026.2 — "Apps are standalone applications that run alongside Home Assistant"

vacuum.send_command with vendor room IDs

vacuum.clean_area with HA area_id (if segments are mapped)

Uses native HA areas, works across integrations — but requires segment-to-area mapping in entity settings first

references/device-control.md#vacuum-control

Using color_temp (mireds) in light service calls

Use color_temp_kelvin

The color_temp parameter was removed in 2026.3; only Kelvin is supported

references/device-control.md#lights

Person/Device Tracker entered_home/left_home device triggers or is_home/is_not_home conditions

state trigger to: home / to: not_home, or state condition

These were removed in 2026.5 — state triggers and conditions are the correct replacements

references/automation-patterns.md#presence-and-person-triggers-and-conditions-removed-in-20265

Reference Files

Read these when you need detailed information:

File

When to read

Key sections

references/safe-refactoring.md

Renaming entities, replacing helpers, restructuring automations, or any modification to existing config

#universal-workflow, #entity-renames, #helper-replacements, #trigger-restructuring, #config-entry-data--blind-spots-for-entity-registry-renames, #storage-mode-dashboards-storagelovelace

references/automation-patterns.md

Writing triggers, conditions, waits, or choosing automation modes; disabling automations

#native-conditions, #trigger-types, #wait-actions, #automation-modes, #continue-on-error, #repeat-actions, #ifthen-vs-choose, #trigger-ids, #disabling-automations

references/helper-selection.md

Deciding whether to use a built-in helper vs template sensor

#menu-based-helpers, #numeric-aggregation, #rate-and-change, #time-based-tracking, #counting-and-timing, #scheduling, #entity-grouping, #data-smoothing, #random-values, #climate-control, #domain-conversion, #template-helpers, #decision-matrix

references/template-guidelines.md

Confirming templates ARE appropriate for a use case

#when-templates-are-appropriate, #when-to-avoid-templates, #template-sensor-best-practices, #common-patterns, #error-handling

references/yaml-only-integrations.md

Creating or editing YAML-only integrations that have no config flow (e.g. command_line, platform-based mqtt, rest)

#yaml-only-integration-types, #post-edit-actions

references/device-control.md

Writing service calls, Zigbee button automations, or using target:

#entity-id-vs-device-id, #service-calls-best-practices, #zigbee-buttonremote-patterns, #domain-specific-patterns

references/dashboard-guide.md

Designing or modifying Lovelace dashboards — layout, view types, sections, custom cards, CSS styling, HACS

#dashboard-structure, #view-types, #built-in-cards, #features, #custom-cards, #css-styling, #common-pitfalls

references/dashboard-cards.md

Looking up available card types or fetching card-specific documentation

references/domain-docs.md

Looking up integration or domain documentation for service calls, entity attributes, or configuration

references/examples.yaml

Need compound examples combining multiple best practices

BrowserAct

Let your agent run on any real-world website

Bypass CAPTCHA & anti-bot for free. Start local, scale to cloud.

Explore BrowserAct Skills →

Stop writing automation&scrapers

Install the CLI. Run your first Skill in 30 seconds. Scale when you're ready.

Start free
free · no credit card