关于 home-assistant-best-practices
home-assistant-best-practices 是指导 Agent 创建和修改 Home Assistant 配置的技能。它优先采用原生构件,并强调按版本选择功能、查阅对应参考资料,以及安全处理现有配置。
主要功能
- 01优先使用原生触发器、条件和辅助工具
- 02按 Home Assistant 版本选择功能
- 03查阅与任务对应的参考文件
- 04按安全流程修改配置
- 05规避常见自动化与 YAML 陷阱
适用场景
- 01设计新的 Home Assistant 自动化
- 02为传感器计算选择辅助工具
- 03检查影响后重构实体 ID
- 04无法使用 API 时编辑配置
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ homeassistant-ai/ skills --skill home-assistant-best-practices安装后在 Claude Code 中输入/home-assistant-best-practices确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/appdaemon.mdautomation-actions.mdbackups.mdblueprint-guide.mddashboard-cards.mddashboard-guide.mddevice-control.mddomain-docs.mdexamples.yamlhelper-selection.mdsafe-refactoring.mdscenes.mdtemplate-guidelines.mdtriggers-and-conditions.mdyaml-only-integrations.md详细介绍
Home Assistant 最佳实践
核心原则: 尽可能使用 Home Assistant 原生构造。模板会绕过验证、在运行时静默失败,并使调试变得不透明。
没有工具能访问 HA API? 不要停下来请求访问权限。如果你能通过浏览器操作 HA 网页界面,就在那里进行更改,但先向用户展示确切的更改,并等用户同意后再保存:批准点击并不能让他们看到写入的内容。否则,提供用户可在界面中创建的完整配置(对于自动化,提供编辑器 Edit in YAML 模式所需的 YAML;对于辅助项,提供表单字段),并说明你假定的实体 ID。只能通过 YAML 写入的配置,应使用 File editor 应用编辑(Container 安装则在配置文件夹中编辑):先备份文件,再检查配置,并在 Tools 的 YAML 选项卡中执行相应的重新加载(2026.8 之前名为 Developer Tools;如果列表中没有该选项,则重启)。
标注了版本的功能(2026.5+)取决于实例的版本。 选择功能前先读取版本:通过 GET /api/config 中的 version,或在界面中查看 Settings → About。如果实例运行该版本或更新版本,请使用此功能,不要将旧方法作为同等选项提供。如果无法读取版本,则假定实例使用当前版本,并注明旧版备选方法所需的版本。
回答前阅读相应的参考资料。 本页仅概述了 Reference Files 中的文件;确切的键、字段和可用示例都在这些文件中。只阅读与任务匹配的文件,不要预先加载所有参考文件。
决策工作流
创建任何自动化时,请按以下顺序操作:
0. 前置检查:是否要修改现有配置?
如果更改会影响实体 ID、显示名称或跨组件引用——例如重命名实体或设备、用辅助项替换模板传感器、转换设备触发器或重构自动化——请先阅读 safe-refactoring。该参考资料涵盖影响分析、同设备关联项的发现、显示名称覆盖以及更改后的验证。继续操作前,请完成其中的工作流。
以下步骤 1–5 适用于新配置或模式评估。
1. 先检查特定用途的原生触发器/条件,再检查通用原生触发器/条件
自 2026.7 起,默认构建块是特定用途的触发器/条件——使用 <domain>.<name> 键(检测到移动、低电量、门打开),并支持区域/楼层/标签目标。先检查是否有符合意图的选项,然后检查通用原生触发器/条件,最后才考虑模板。编写触发器前,请阅读 triggers-and-conditions #purpose-specific-triggers--conditions-default-since-20267。
特定用途的触发器也可以在 target: 中使用 entity_id,因此,即使只知道一个传感器,也不构成退回使用 trigger: state 的理由。请使用特定用途的触发器编写自动化,不要只将其作为可选升级方案。
常见替换方式:
- 对移动、占用或门的
binary_sensor使用trigger: state→ 使用motion.detected/motion.cleared、occupancy.detected/occupancy.cleared或door.opened/door.closed,并设置target: {entity_id: ...};如果已知区域,则使用area_id - 触发器中列出多个独立传感器实体 → 使用一个带区域/楼层/标签
target:的特定用途触发器 - 为实现“任何位置 N 分钟内都没有移动”,在
motion.detected后使用delay→ 使用motion.cleared和options: {behavior: all, for: ...},当所有目标传感器都持续无移动这么久时触发一次(unavailable和unknown传感器不计入) {{ states('x') | float > 25 }}→ 使用带above: 25的numeric_state条件{{ is_state('x', 'on') and is_state('y', 'on') }}→ 使用包含状态条件的condition: and{{ now().hour >= 9 }}→ 使用after: "09:00:00"的condition: time
2. 检查是否有内置辅助工具或模板辅助工具
创建模板传感器之前,请阅读 helper-selection。
常见替代方案:
- 对多个传感器求和/求平均 →
min_max集成 - 二元任一开启/全部开启逻辑 →
group辅助工具 - 变化率 →
derivative集成 - 跨阈值检测 →
threshold集成 - 用量跟踪 →
utility_meter辅助工具
如果没有合适的内置辅助工具,请使用模板辅助工具,而不是 YAML。
通过 HA 配置流程创建(以编程方式或在 UI 中操作:
Settings → Devices & Services → Helpers → Create Helper → Template)。通过流程创建的辅助工具可在 UI 中编辑;template: YAML 条目则需要执行 template.reload,且无法在 UI 中编辑。
用户提出要求、两种方式都不可用,或配置需要流程中没有对应字段的键时,请编写 template: YAML——常见情况包括基于触发器的模板和 attributes:。然后使用受管理的 YAML 编辑方式(yaml-only-integrations),而不是手动编辑。
3. 选择正确的自动化模式
默认的 single 模式通常不合适。请参阅 automation-actions #automation-modes。
| 场景 | 模式 |
|---|---|
| 带超时的运动感应灯 | restart |
| 顺序处理(门锁) | queued |
| 对每个实体独立执行操作 | parallel |
| 一次性通知 | single |
4. 优先使用 entity_id,而不是 device_id
重新添加设备后,device_id 会失效。请参阅 device-control。
例外: Zigbee2MQTT 自动发现的设备触发器可以使用。
5. 对于按钮和遥控器
- 任何会公开
event.*实体的集成: 使用以该实体为目标的event.received(参见下方的反模式行) - ZHA: 没有事件实体——使用包含
device_ieee的event触发器(持久) - Z2M: 事件实体处于实验阶段,且默认关闭——使用
device触发器(自动发现)或mqtt触发器
编写触发器之前,请阅读 device-control #buttonremote-patterns。
关键反模式
| 反模式 | 改用 | 原因 | 参考 |
|---|---|---|---|
使用 condition: template 和 float > 25 | condition: numeric_state | 加载时会检查键和阈值;状态为 unavailable 或 unknown 时结果为 false,而不带默认值的 float 会引发错误 | triggers-and-conditions #native-conditions |
对可能已经满足的条件,使用带状态触发器的 wait_for_trigger | wait_template | 状态触发器只会在状态转换时触发,因此等待会持续到实体离开该状态并重新进入,或者在没有 timeout 的情况下永远等待(参见 safe-refactoring #trigger-restructuring) | automation-actions #wait-actions |
在触发器中使用 device_id | entity_id(ZHA 则使用 device_ieee) | 重新添加设备后,device_id 会失效 | device-control #entity-id-vs-device-id |
对于具有 event.* 实体的按钮,使用集成总线事件(例如 hue_event)的 event 触发器 | 使用 event.received 针对该实体,并从其 event_types 属性读取值 | 如果集成保留稳定的唯一 ID,该实体可以重命名并在重新添加后继续使用;总线事件数据因集成而异 | device-control #buttonremote-patterns |
未加保护的 numeric_state 触发器驱动高开销操作 | 添加条件,在 trigger.from_state 中排除 unavailable/unknown | 重启或短暂故障会重新布防触发器,因此数值未变也会触发(此保护也会丢弃真实的越界触发) | triggers-and-conditions #unavailable-arms-a-numeric-state-trigger |
动态灯光使用 mode: single | mode: restart | 重新触发时必须重置计时器 | automation-actions #automation-modes |
在 automations.yaml 中将 enabled: false 设为顶层键 | 使用 automation.turn_off(临时停用)或在实体注册表中停用(永久停用) | 这不是有效的顶层键,会在架构验证期间被拒绝;自动化会加载为 unavailable | automation-actions #disabling-automations |
| 用模板传感器计算总和/平均值 | min_max 辅助工具 | 声明式配置,可处理不可用状态 | helper-selection #numeric-aggregation |
| 使用带阈值的模板二进制传感器 | threshold 辅助工具 | 内置迟滞支持 | helper-selection #threshold |
| 未进行影响分析就重命名实体 ID | 按照 safe-refactoring 工作流操作 | 重命名会悄无声息地破坏仪表盘、脚本、场景、Config Entry 数据和存储中的仪表盘 | safe-refactoring #entity-renames |
| 重命名基于 Config Entry 的群组(UI 群组)成员,却不更新成员列表 | 在注册表中重命名后,通过 Options Flow 更新群组成员列表 | 实体注册表中的重命名不会更新 Config Entry 中的 options.entities,群组会悄无声息地失效 | safe-refactoring #config-entry-groups |
| 重命名 Min/Max 辅助工具或自定义 Config Entry 集成(例如 Better Thermostat)使用的实体,却不检查其 Config Entry 数据 | 扫描配置条目的 data+options;在 Min/Max Options Flow 中重新选择重命名后的实体。若集成将其保存在 data 中(Better Thermostat),则没有 API 修复方式:告知用户,并在重命名前进行完整备份 | 它们会在 Config Entry 中存储 entity_id,而注册表中的重命名不会更新这些值;Threshold(自 2025.6 起)和 Generic Thermostat 等单一来源辅助工具会自行更新 | safe-refactoring #config-entry-data--blind-spots-for-entity-registry-renames |
在 YAML 中使用 template: 传感器/二进制传感器 | 通过配置流程创建 Template Helper | 流程辅助工具可原位重新加载,并且可在 UI 中编辑;template: 条目则需要重新加载配置,且不能在 UI 中编辑。确实存在例外:基于触发器的模板和 attributes: 没有对应的流程字段 | helper-selection #template-helpers |
直接编辑 .storage/ 文件或其他 HA 内部状态 | 使用 HA REST/WebSocket API 管理状态和配置条目 | .storage/ 文件是 HA 的内部状态数据库;直接编辑会绕过验证、有损坏风险,且 HA 可能会悄无声息地覆盖修改 | — |
在 .storage/ 中查找自动化配置 | 通过 HA 配置 API 读取和写入自动化。通过 UI 创建的自动化会保存到 automations.yaml | 在任何配置模式下,都没有 .storage/ 文件保存自动化配置。.storage/ 只保存自动化的实体注册表条目 | — |
为仅支持 YAML 的集成手动将原始 YAML 写入 configuration.yaml | 使用带备份和验证的托管 YAML 配置编辑 | 未托管的写入有语法错误风险、没有备份,还会跳过 check_config;托管编辑可提供这三项保障 | yaml-only-integrations |
| 为自动化/脚本/场景生成 YAML 片段 | 使用 HA 配置 API 以编程方式创建自动化/脚本;如果无法访问 API,则提供供 UI 编辑器使用的配置 | API 调用会验证配置,避免语法错误,而且无需手动编辑文件或重启 | triggers-and-conditions,automation-actions,examples.yaml |
告诉用户通过编辑 configuration.yaml 配置集成 | 引导用户前往 HA UI 中的“设置”>“设备与服务” | 大多数集成都通过 UI 配置;YAML 集成配置很少见,而且因集成而异 | — |
| 将 HA 的“add-ons”称为插件 | 使用“Apps”这一术语 | HA 在 2026.2 中将 add-ons 更名为 Apps——“Apps 是与 Home Assistant 同时运行的独立应用程序” | — |
使用带厂商房间 ID 的 vacuum.send_command | 使用 vacuum.clean_area,并在 cleaning_area_id 中填写 HA 区域 ID(如果已映射区段) | 使用 HA 原生区域,可跨集成工作,但必须先在实体设置中映射区段和区域 | device-control #vacuum-control |
在灯光操作中使用 color_temp(mired) | 使用 color_temp_kelvin,并转换数值:开尔文 = 1,000,000 ÷ mired(500 mired = 2000 K) | color_temp 参数已于 2026.3 移除;现在只支持开尔文。HA 会接受该参数的任何正数,因此直接复制 mired 数值会被当作开尔文读取(500 mired 会变成 500 K) | device-control #lights |
在 variables: 中保存状态或属性,或硬编码数值,以便在临时更改后恢复设备 | 更改前使用 scene.create 和 snapshot_entities 创建快照,然后对该场景调用 scene.turn_on | 一次调用即可保存每个实体各自的状态,包括原本关闭的灯;变量需要为每个属性编写模板,并为每个实体添加恢复步骤 | scenes #snapshot--restore-scenecreate |
使用 Person/Device Tracker 的 entered_home/left_home 设备触发器或 is_home/is_not_home 条件 | 使用 to: home / to: not_home 的 state 触发器,或 state 条件 | 这些功能已于 2026.5 移除;应改用状态触发器和条件 | triggers-and-conditions #presence-and-person-triggers-and-conditions-removed-in-20265 |
| 在触发器中使用实体列表,而区域/楼层/标签目标更合适 | 使用带 target: {area_id: ...} 的专用触发器 | 设备变更时,自动化会随区域成员关系更新,无需维护过时的实体列表 | triggers-and-conditions #purpose-specific-triggers--conditions-default-since-20267 |
使用旧的专用键(battery.low、vacuum.docked、timer.time_remaining 等),或触发器的 behavior: any/last | 使用 2026.7 重命名后的键(battery.became_low 等)和 behavior: each/all(于 2026.6 重命名) | 旧键不再加载;旧行为值会引发修复问题,并将被移除 | triggers-and-conditions #purpose-specific-triggers--conditions-default-since-20267 |
AppDaemon:在 __init__ 中注册回调、不取消 run_in 计时器、将状态保存在实例变量中、硬编码实体 ID | 在 initialize() 中注册,重新安排前先取消,通过 input_* 辅助工具持久化,并通过 self.args 传递 ID | 这些做法都会导致故障悄无声息地发生、重新加载时重置,或阻碍复用 | appdaemon #appdaemon-specific-anti-patterns |
Blueprints:硬编码实体、应使用选择器的地方使用自由文本、在模板中使用 !input、遗漏 source_url | 使用带类型的 !input 选择器;在模板化输入前,将其绑定到 variables:;始终设置 source_url | 硬编码会破坏复用性,自由文本允许拼写错误,而 !input 是 YAML 标签,不是模板值 | blueprint-guide #common-pitfalls |
| 备份:为撤销单个对象的编辑而执行完整恢复;在不可逆操作(删除注册表条目、移除集成、升级 Core/OS)前不做备份;称某个操作“可逆”却不说明其逆操作 | 仅回滚该对象;在操作前进行备份;说明确切的逆操作,否则将其视为不可逆 | 完整恢复会撤销此后所有无关更改并重启 HA;事后进行的备份会把损坏状态也保存进去 | backups #when-a-full-backup-earns-its-cost |
| 未经用户明确确认就恢复备份、删除备份或升级 Core/OS | 每次都先询问,说明具体影响,并等待答复,无论是否已有备份 | 完整恢复会丢弃归档后对所有已恢复部分所做的一切更改,并重启 HA;Supervisor 部分恢复只会覆盖所选的归档部分;删除操作会销毁一个恢复点;Core/OS 升级影响重大,且其恢复途径就是升级前的备份 | backups |
| 在多个模板中重复使用同一段复杂 Jinja 表达式 | 排除原生触发器/条件和内置辅助工具后,将其作为宏在 config/custom_templates/*.jinja 中定义一次并导入 | 规则变更时只需修复一处,避免多个副本逐渐不一致 | template-guidelines #reusable-macros |
在导入的宏中使用 trigger、this、value_json 或 {% set %} 变量 | 将其作为参数传给宏 | 导入不会携带调用方的上下文——因此变量在宏内未定义,会渲染为空,对其进行任何属性访问都会报错(HA 自带的 states 等函数属于全局变量,可以正常使用) | template-guidelines #imports-do-not-carry-the-callers-context |
参考文件
回答前,请阅读任务匹配的每个文件:
| 文件 | 何时阅读 |
|---|---|
| safe-refactoring | 重命名实体或其显示名称、替换辅助工具、重构自动化,或修改现有配置时 |
| triggers-and-conditions | 编写自动化的触发器或条件时:特定用途和原生触发器/条件、for: 时长、触发器 ID |
| automation-actions | 编写自动化或脚本的操作,或选择其模式时:等待、变量、捕获操作响应、continue_on_error、脚本中的仅限管理员操作(Unauthorized)、停止序列、重复、if/then 与 choose、并行;记录/注释步骤;禁用自动化;通过 last_triggered 测量自动化之间的经过时间;Mobile App notify 操作与实体——将实体 ID 用作操作时出现 action not found;跟踪记录保留——频繁触发会将运行记录推入调试区,导致 5 条已存跟踪记录中有一条被挤出 |
| helper-selection | 决定使用内置辅助工具还是模板传感器时——聚合、变化率、阈值、状态持续时间、计数/计时、调度、分组、概率推断、平滑、气候、域转换、决策矩阵 |
| template-guidelines | 确认模板是否适用于某个用例;通过 custom_templates 宏在模板之间共享 Jinja 逻辑 |
| yaml-only-integrations | 创建或编辑没有配置流程的纯 YAML 集成时(例如 command_line、基于平台的 mqtt、rest) |
| device-control | 编写操作、按钮/遥控器自动化,或使用 target: 时 |
| scenes | 创建或启用场景;快照/恢复模式,包括在临时更改后将设备恢复原状;快照与脚本的区别 |
| dashboard-guide | 设计或修改 Lovelace 仪表盘时——布局、视图类型、策略、分区、卡片、徽章、CSS 样式、HACS |
| dashboard-cards | 查找内置卡片类型(核心、能源、旧版),或了解卡片字段的文档位置;实体卡片的属性行——带有 attribute: 但没有 type: attribute 的行显示的是实体状态,而不是属性 |
| domain-docs | 查找集成/域文档,或特定触发器、条件或操作的专属文档页面时 |
| examples.yaml | 需要结合多项最佳实践的复合示例时 |
| appdaemon | AppDaemon 应用:何时选择它而非原生 HA、应用结构、操作、调度、错误处理、安全重构影响 |
| blueprint-guide | 编写可复用蓝图:元数据与 source_url、输入与选择器、target 与 entity、默认值、输入分区、!input 模板、版本控制 |
| backups | 判断操作是否需要先备份;在完整恢复、部分恢复和回滚单个对象之间进行选择;了解归档文件的实际内容;加密密钥和应急工具包;验证恢复;删除备份时 HA 会保护和不会保护的内容;git 配置仓库是否能替代完整备份 |