Expertise·Lifestyle & Local·v25

Home Assistant Best Practices

Best practices for Home Assistant automations, helpers, scripts, and dashboards.

You say
Buy it · $49 Read it before you buy $49 Written by homeassistant-ai · unverified publisher
Context cost
64.9k tokensestimated from the bundle, loaded when it triggers
Bundle
15 files · 259.5 kBtext throughout, nothing executable
Licence
MITpaid listing
Last change
v25
Servers it uses
Noneruns standalone

What it does

Best practices for HA automations, helpers, scripts, and dashboards. TRIGGER THIS SKILL WHEN: - Creating or editing automations, scripts, scenes, dashboards, blueprints - Choosing template sensors, helpers, or Jinja macros - Restructuring triggers, conditions, or modes; button, remote, or event-entity automations - Renaming entities or migrating device_id to entity_id - Looking up card types or domain docs; writing AppDaemon apps - Deleting or restoring a backup, or upgrading Core or the OS SYMPTOMS: - Jinja2 templates where native options exist - device_id used instead of entity_id - Entity…

Installed, it changes the agent in these ways.

What this skill changes about the agent is not written down here yet. The listing was collected from its source, and the description is in its own SKILL.md.

Expertise

Domain judgement the base model does not have.

smart-homehome-assistantautomationhousehold

The skill itself

This is the whole product. A skill is instructions the model reads, so there is nothing behind the listing you cannot see first — the front matter loads with every session, and the body below it loads when the skill triggers.

SKILL.md17.2 kB · 150 lines
--- name: home-assistant-best-practices description: > Best practices for HA automations, helpers, scripts, and dashboards. TRIGGER THIS SKILL WHEN: - Creating or editing automations, scripts, scenes, dashboards, blueprints - Choosing template sensors, helpers, or Jinja macros - Restructuring triggers, conditions, or modes; button, remote, or event-entity automations - Renaming entities or migrating device_id to entity_id - Looking up card types or domain docs; writing AppDaemon apps - Deleting or restoring a backup, or upgrading Core or the OS SYMPTOMS: - Jinja2 templates where native options exist - device_id used instead of entity_id - Entity IDs changed without checking consumers - Wrong automation mode chosen - Raw sensor or hard-coded value used where a helper belongs - Direct .storage edits, or generated YAML snippets - User told to edit configuration.yaml for UI integrations - Hardcoded Blueprint entities or skipped selectors - Existing state changed with no recovery path - Jinja copy-pasted between templates metadata: version: "25" ---
29# Home Assistant Best Practices
30
31**Core principle:** Use native Home Assistant constructs wherever possible. Templates bypass validation, fail silently at runtime, and make debugging opaque.
32
33## Decision Workflow
34
35Follow this sequence when creating any automation:
36
37### 0. Gate: modifying existing config?
38
39If your change affects entity IDs or cross-component references — renaming entities, replacing template sensors with helpers, converting device triggers, or restructuring automations — read [safe-refactoring](references/safe-refactoring.md) first. That reference covers impact analysis, device-sibling discovery, and post-change verification. Complete its workflow before proceeding.
40
41Steps 1-5 below apply to new config or pattern evaluation.
42
43### 1. Check for a purpose-specific, then generic native, trigger/condition
44Since 2026.7 the default building blocks are purpose-specific triggers/conditions — <domain>.<name> keys (motion detected, battery low, door opened) with area/floor/label targets. Check for one that matches the intent first, then a generic native trigger/condition, and only then a template. See [automation-patterns #purpose-specific-triggers--conditions-default-since-20267](references/automation-patterns.md#purpose-specific-triggers--conditions-default-since-20267).
45
46**Common substitutions:**
47- List of individual sensor entities in a trigger → one purpose-specific trigger with an area/floor/label target:
48- {{ states('x') | float > 25 }}numeric_state condition with above: 25
49- {{ is_state('x', 'on') and is_state('y', 'on') }}condition: and with state conditions
50- {{ now().hour >= 9 }}condition: time with after: "09:00:00"
51- wait_template: "{{ is_state(...) }}"wait_for_trigger with state trigger (caveat: different behavior when state is already true — see [safe-refactoring #trigger-restructuring](references/safe-refactoring.md#trigger-restructuring))
52
53### 2. Check for built-in helper or Template Helper
54Before creating a template sensor, check [helper-selection](references/helper-selection.md).
55
56**Common substitutions:**
57- Sum/average multiple sensors → min_max integration
58- Binary any-on/all-on logic → group helper
59- Rate of change → derivative integration
60- Cross threshold detection → threshold integration
61- Consumption tracking → utility_meter helper
62
63**If no built-in helper fits, use a Template Helper — not YAML.**
64Create it via the HA config flow (programmatically or in the UI:
65Settings → Devices & Services → Helpers → Create Helper → Template). A flow-created helper
66is UI-editable; a template: YAML entry needs a template.reload and is not.
67
68Write template: YAML when the user asks for it, when neither path is available, or when
69the config needs a key the flow has no field for — trigger-based templates and attributes:
70are the common ones. Then use managed YAML editing ([yaml-only-integrations](references/yaml-only-integrations.md)), not a hand-edit.
71
72### 3. Select correct automation mode
73Default single mode is often wrong. See [automation-patterns #automation-modes](references/automation-patterns.md#automation-modes).
74
75| Scenario | Mode |
76|----------|------|
77| Motion light with timeout | restart |
78| Sequential processing (door locks) | queued |
79| Independent per-entity actions | parallel |
80| One-shot notifications | single |
81
82### 4. Use entity_id over device_id
83device_id breaks when devices are re-added. See [device-control](references/device-control.md).
84
85**Exception:** Zigbee2MQTT autodiscovered device triggers are acceptable.
86
87### 5. For buttons and remotes
88- **Any integration exposing an event.* entity:** Use event.received targeting that entity — a normal entity, so it can be renamed and survives a re-add when the integration keeps a stable unique ID
89- **ZHA:** No event entities — use an event trigger with device_ieee (persistent)
90- **Z2M:** Event entities are experimental and off by default — use a device trigger (autodiscovered) or mqtt trigger
91
92See [device-control #buttonremote-patterns](references/device-control.md#buttonremote-patterns).
93
94---
95
96## Critical Anti-Patterns
97
98| Anti-pattern | Use instead | Why | Reference |
99|--------------|-------------|-----|-----------|
100| condition: template with float > 25 | condition: numeric_state | Validated at load, not runtime | [automation-patterns #native-conditions](references/automation-patterns.md#native-conditions) |
101| wait_template: "{{ is_state(...) }}" | wait_for_trigger with state trigger | Event-driven, not polling; waits for *change* (see [safe-refactoring #trigger-restructuring](references/safe-refactoring.md#trigger-restructuring) for semantic differences) | [automation-patterns #wait-actions](references/automation-patterns.md#wait-actions) |
102| device_id in triggers | entity_id (or device_ieee for ZHA) | device_id breaks on re-add | [device-control #entity-id-vs-device-id](references/device-control.md#entity-id-vs-device-id) |
103| mode: single for motion lights | mode: restart | Re-triggers must reset the timer | [automation-patterns #automation-modes](references/automation-patterns.md#automation-modes) |
104| 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 | [automation-patterns #disabling-automations](references/automation-patterns.md#disabling-automations) |
105| Template sensor for sum/mean | min_max helper | Declarative, handles unavailable states | [helper-selection #numeric-aggregation](references/helper-selection.md#numeric-aggregation) |
106| Template binary sensor with threshold | threshold helper | Built-in hysteresis support | [helper-selection #threshold](references/helper-selection.md#threshold) |
107| Renaming entity IDs without impact analysis | Follow [safe-refactoring](references/safe-refactoring.md) workflow | Renames break dashboards, scripts, scenes, Config-Entry data, and storage dashboards silently | [safe-refactoring #entity-renames](references/safe-refactoring.md#entity-renames) |
108| 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 | [safe-refactoring #config-entry-groups](references/safe-refactoring.md#config-entry-groups) |
109| 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 | [safe-refactoring #config-entry-data--blind-spots-for-entity-registry-renames](references/safe-refactoring.md#config-entry-data--blind-spots-for-entity-registry-renames) |
110| template: sensor/binary sensor in YAML | Template Helper via the config flow | A flow helper reloads in place and stays UI-editable; a template: entry needs a config reload and does not. Exceptions are real — trigger-based templates and attributes: have no flow field | [helper-selection #template-helpers](references/helper-selection.md#template-helpers) |
111| 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 | — |
112| 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 | [yaml-only-integrations](references/yaml-only-integrations.md) |
113| 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 | [automation-patterns](references/automation-patterns.md), [examples.yaml](references/examples.yaml) |
114| 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 | — |
115| 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" | — |
116| 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 | [device-control #vacuum-control](references/device-control.md#vacuum-control) |
117| Using color_temp (mireds) in light actions | Use color_temp_kelvin | The color_temp parameter was removed in 2026.3; only Kelvin is supported | [device-control #lights](references/device-control.md#lights) |
118| 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 | [automation-patterns #presence-and-person-triggers-and-conditions-removed-in-20265](references/automation-patterns.md#presence-and-person-triggers-and-conditions-removed-in-20265) |
119| Entity list in a trigger where an area/floor/label target fits | Purpose-specific trigger with target: {area_id: ...} | Automation follows area membership as devices change — no stale entity lists | [automation-patterns #purpose-specific-triggers--conditions-default-since-20267](references/automation-patterns.md#purpose-specific-triggers--conditions-default-since-20267) |
120| Old purpose-specific keys (battery.low, vacuum.docked, timer.time_remaining, ...) or trigger behavior: any/last | Renamed 2026.7 keys (battery.became_low, ...) and behavior: each/all | Old keys no longer load; old behavior values raise a repair issue and face removal | [automation-patterns #purpose-specific-triggers--conditions-default-since-20267](references/automation-patterns.md#purpose-specific-triggers--conditions-default-since-20267) |
121| AppDaemon: callbacks in __init__, uncancelled run_in timers, state in instance variables, hardcoded entity IDs | Register in initialize(), cancel before rescheduling, persist via input_* helpers, pass IDs through self.args | Each fails silently, resets on reload, or blocks reuse | [appdaemon #appdaemon-specific-anti-patterns](references/appdaemon.md#appdaemon-specific-anti-patterns) |
122| Blueprints: hardcoded entities, free text where a selector belongs, !input inside a template, missing source_url | Typed !input selectors; bind an input to variables: before templating it; always set source_url | Hardcoding defeats reuse, text lets typos through, and !input is a YAML tag rather than a template value | [blueprint-guide #common-pitfalls](references/blueprint-guide.md#common-pitfalls) |
123| Backups: full restore to undo one object edit, no backup before an irreversible operation (registry deletion, integration removal, Core/OS upgrade), calling an action "reversible" without naming its inverse | Roll the single object back; take the backup *before*; name the exact inverse or treat it as irreversible | A full restore reverts every unrelated change since and restarts HA; a backup taken afterward captures the damage | [backups #when-a-full-backup-earns-its-cost](references/backups.md#when-a-full-backup-earns-its-cost) |
124| Restoring a backup, deleting a backup, or upgrading Core or the OS without explicit user confirmation | Ask, name the concrete effect, and wait for an answer — every time, backup or not | A full restore discards everything since the archive for all restored parts and restarts HA; a Supervisor partial restore overwrites only the selected archive parts; deletion destroys a recovery point; a Core/OS upgrade is high-impact and its recovery path IS the pre-upgrade backup | [backups](references/backups.md) |
125| The same non-trivial Jinja expression repeated across templates | Once a native trigger/condition and a built-in helper are ruled out, define it once as a macro in config/custom_templates/*.jinja and import it | One definition to fix when the rule changes, instead of copies that drift apart | [template-guidelines #reusable-macros](references/template-guidelines.md#reusable-macros) |
126| trigger, this, value_json, or a {% set %} variable used inside an imported macro | Pass it to the macro as an argument | An import does not carry the caller's context — the variable is undefined inside the macro, so it renders empty and any attribute access on it errors (HA's own functions like states are globals and do work) | [template-guidelines #imports-do-not-carry-the-callers-context](references/template-guidelines.md#imports-do-not-carry-the-callers-context) |
127
128---
129
130## Reference Files
131
132Read these when you need detailed information:
133
134| File | When to read |
135|------|--------------|
136| [safe-refactoring](references/safe-refactoring.md) | Renaming entities, replacing helpers, restructuring automations, or any modification to existing config |
137| [automation-patterns](references/automation-patterns.md) | Writing triggers, conditions, waits, variables, or choosing automation modes; capturing action responses; documenting/annotating steps; disabling automations; continue_on_error, stopping a sequence, repeat, if/then vs choose, parallel, trigger IDs |
138| [helper-selection](references/helper-selection.md) | Deciding whether to use a built-in helper vs template sensor — aggregation, rate of change, thresholds, time-in-state, counting/timing, scheduling, grouping, probabilistic inference, smoothing, climate, domain conversion, decision matrix |
139| [template-guidelines](references/template-guidelines.md) | Confirming templates ARE appropriate for a use case; sharing Jinja logic between templates with custom_templates macros |
140| [yaml-only-integrations](references/yaml-only-integrations.md) | Creating or editing YAML-only integrations that have no config flow (e.g. command_line, platform-based mqtt, rest) |
141| [device-control](references/device-control.md) | Writing actions, button/remote automations, or using target: |
142| [scenes](references/scenes.md) | Authoring or activating scenes; snapshot/restore patterns; snapshot-vs-script distinction |
143| [dashboard-guide](references/dashboard-guide.md) | Designing or modifying Lovelace dashboards — layout, view types, strategies, sections, cards, badges, CSS styling, HACS |
144| [dashboard-cards](references/dashboard-cards.md) | Looking up available card types or fetching card-specific documentation |
145| [domain-docs](references/domain-docs.md) | Looking up integration/domain documentation, or the dedicated doc page for a specific trigger, condition, or action |
146| [examples.yaml](references/examples.yaml) | Need compound examples combining multiple best practices |
147| [appdaemon](references/appdaemon.md) | AppDaemon apps: when to use vs. native HA, app structure, actions, scheduling, error handling, safe refactoring impact |
148| [blueprint-guide](references/blueprint-guide.md) | Authoring reusable blueprints: metadata & source_url, inputs & selectors, target vs entity, defaults, input sections, !input templating, versioning |
149| [backups](references/backups.md) | Deciding whether an operation needs a backup first; choosing between a full restore, a partial restore, and rolling one object back; what an archive actually contains; encryption keys and the emergency kit; restore verification; what HA does and does not protect when deleting a backup |
150
In the file
SKILL.md2,055 words
Files15
LicenceMIT
Why you can read it

Nothing in a skill executes. The client loads the text and the model follows it, so a skill can be audited the way a runbook is — by reading it.

What it costs in context

Skills are not billed by the call. They are paid for in context: every token the instructions occupy is a token your code, your diff and your conversation cannot use. Here is what this one takes and when it takes it.

≈280
always loaded
The name and description, so the model knows the skill exists and when to reach for it.
64,595
on trigger
The instruction body and 14 supporting files, read only when the skill fires.
32.4%
of a 200k window
Ten skills this size would take about 324% of the window before you open a file.
050k100k150k200k context window

64.9k tokens, estimated from the bundle at four bytes to the token, held for the rest of the session once it triggers. Heavy. Teams tend to install this one per project rather than globally, and load it only when the job comes up.

Servers bill, skills cost

A server charges by the month. A skill charges once per session, in context, and then keeps charging it for as long as the session lives.

Before and after

The same question, put to the same model twice: once as it comes, and once with these instructions loaded.

No worked example has been published for this skill yet.

Adoption
Installsnone yet
Ratingno reviews yet

The procedure it runs

The procedure has not been published here. It is in the skill’s own SKILL.md, which its author has not sent to the marketplace yet.

Prose, not code

These steps are written for a model to follow, not executed by a runtime. It can still be told to skip one, and it will say so when it does.

Servers it uses

None. This skill calls no MCP servers at all.

Everything it needs is in the instructions, so it works in a project with nothing connected — the model reads the file and changes how it works with what it can already reach.

It writes no files and reaches no network. All it changes is how the model reasons and writes.

What it asks for
Writes filesno
Network accessno

Read from the allowed-tools line of this skill’s own SKILL.md. A skill grants no permissions of its own — it can only ask for tools your client already has.

What it will not do

Every skill is narrow, and the useful ones say where they stop. These are the jobs this one is the wrong tool for.

What this skill is not for has not been published here. Nothing is implied by that: it is a section the author has not filled in.

What is in the bundle

15 files, 259.5 kB on disk. A bundle is text throughout: the instructions the model reads, plus the templates it fills in.

  • SKILL.md17.2 kB
  • references/appdaemon.md18.4 kB
  • references/automation-patterns.md42.0 kB
  • references/backups.md12.2 kB
  • references/blueprint-guide.md14.7 kB
  • references/dashboard-cards.md2.0 kB
  • references/dashboard-guide.md26.4 kB
  • references/device-control.md14.3 kB
  • references/domain-docs.md1.7 kB
  • references/examples.yaml11.6 kB
  • references/helper-selection.md48.3 kB
  • references/safe-refactoring.md15.5 kB
  • references/scenes.md3.6 kB
  • references/template-guidelines.md28.0 kB
  • references/yaml-only-integrations.md3.6 kB
What is not in it

No dependencies and nothing executable: a skill is text the agent reads, so the bundle is 15 files you can review in full before installing. The MIT licence covers the templates and examples as well as the instructions.

Install

Installing copies the bundle into your project. Nothing runs at install time — the files sit on disk until the model reads them.

$49 once
Home Assistant Best Practices · MIT · homeassistant-ai
one-time
Price$49 once
LicenceMIT — the author’s, unchanged by this purchase
Paid throughStripe, once, on the card you add at the checkout
Keeps workingfor good — the files are yours once they are on disk
Updatesevery release of 25.x through this account

You can read the whole bundle before paying — the SKILL.md above is the product, not a preview of it. What the money buys is the delivery: the folder packaged and handed to your machine by key, every update its author ships, and our support if it does not do what this listing says. The terms of use are MIT, set by the author and unchanged by buying it here.

Payment runs through Stripe, on a page like this one rather than a redirect. Once there is an account it joins the same mcprush invoice as everything else you run, so there is never a second card to enter.

Which clients pick it up on their own

A skill is a folder of text. A client with a skills folder reads it without being told; everywhere else the same text works, it is just handed to the model rather than found.

Claude Code.claude/skills/
Claude Desktop
ChatGPT
Cursor.cursor/skills/
VS Code.github/skills/
Codex CLI.agents/skills/
Gemini CLI.gemini/skills/
Grok.grok/skills/
Zed.agents/skills/
Windsurf.windsurf/skills/
Agent SDK.claude/skills/
HTTP / API
This release
Version25
Publishedno release date on file
Price$49
Referencehomeassistant-ai/home-assistant-best-practices

Versions

v25 is what is on the shelf; no release here carries a date. Instructions change more often than APIs do — a skill can be rewritten entirely without anything it depends on moving.

v25
  • No earlier releases have been published to the marketplace.
Pinning

Put homeassistant-ai/home-assistant-best-practices@25 in the install command to hold this exact version. Without the suffix you get whatever is current the day you install, and nothing moves under you afterwards.

Reviews

no reviews yet · no installs yet

Nobody has reviewed this skill yet. The rating is the mean of the reviews written here, so there is none until somebody writes the first.

Who can post

Only accounts that have had the skill installed for fourteen days, so a review is written after living with it rather than after reading it. Publishers may reply once.

Who wrote it

HO
homeassistant-ai

Publishes on mcprush.

0 servers listed1 skill listednot claimed
Profile
Publisher
Servers0