配置流(Config Flow)入门

说实话,我刚接触 Home Assistant 插件开发时,最头疼的就是配置流。那时候我写了个简单的传感器插件,每次配置都要手动改 configuration.yaml,用户反馈说「这也太不友好了」。嗯,确实如此。配置流就是来解决这个问题的。

配置流的概念

配置流是什么?说白了,它是一个让用户通过 UI 界面完成插件配置的机制。你想想看,如果每次装个插件都要去改 YAML 文件,重启 HA,那体验也太差了。配置流让用户可以在「设置 → 设备与服务 → 添加集成」的界面里,一步步完成配置。

我个人习惯把配置流理解成一个「向导」。它引导用户输入必要的信息,比如 API Key、IP 地址、用户名密码等。配置流会验证这些信息是否正确,然后把它们安全地存储起来。

核心要点:配置流是用户与你的插件交互的第一个界面。第一印象很重要,所以配置流的体验一定要做好。

配置流的生命周期

配置流不是一次性跑完就完事了。它有完整的生命周期。我在项目中遇到过不少新手,以为配置流只是「填表单 → 保存」这么简单,结果踩了不少坑。

配置流的生命周期包含以下几个阶段:

  1. 初始化阶段:用户点击「添加集成」,HA 调用你的配置流入口
  2. 用户输入阶段:你定义的表单一步步展示给用户
  3. 验证阶段:用户提交数据后,你进行校验(比如测试连接)
  4. 创建阶段:验证通过后,创建配置条目并存储
  5. 重配置阶段:用户后续可以修改配置
  6. 删除阶段:用户移除集成时触发

为什么会这样设计?因为配置流需要处理各种边界情况。比如用户输错了密码怎么办?网络超时怎么办?这些都需要在生命周期里妥善处理。

配置流生命周期 用户点击添加集成 初始化配置流 用户输入表单 验证输入数据 验证失败 → 返回表单 验证成功 → 创建条目 配置条目存储 错误 成功

创建第一个配置流

好,理论说完了,咱们动手写一个。我会创建一个最简单的配置流,让用户输入一个 API Key。

首先,你需要在插件目录下创建 config_flow.py 文件。这是配置流的入口文件。

# config_flow.py
from homeassistant import config_entries
from homeassistant.core import callback
import voluptuous as vol

class MyCustomConfigFlow(config_entries.ConfigFlow, domain="my_custom"):
    """我的第一个配置流"""

    VERSION = 1

    async def async_step_user(self, user_input=None):
        """用户手动添加时的第一步"""
        errors = {}
        
        if user_input is not None:
            # 验证用户输入
            api_key = user_input.get("api_key")
            if not api_key or len(api_key) < 10:
                errors["api_key"] = "API Key 长度至少为10个字符"
            else:
                # 验证通过,创建配置条目
                return self.async_create_entry(
                    title="我的自定义集成",
                    data=user_input
                )
        
        # 显示表单
        return self.async_show_form(
            step_id="user",
            data_schema=vol.Schema({
                vol.Required("api_key"): str,
                vol.Optional("name", default="我的设备"): str,
            }),
            errors=errors,
        )

这段代码看起来不多,但包含了配置流的核心逻辑。我来拆解一下:

  • async_step_user 是配置流的默认入口。用户点击添加集成时,HA 会调用这个方法
  • user_input 参数接收用户提交的表单数据。第一次调用时是 None
  • voluptuous 库用来定义表单结构。我习惯用它,因为语法简洁
  • async_create_entry 是创建配置条目的关键方法。调用它后,配置数据就存到 HA 的配置存储里了

小技巧:配置流的 VERSION 字段很重要。如果你后续修改了配置结构,记得升级版本号。我曾经因为忘了改版本号,导致用户升级后配置丢失,被吐槽了好久。

注册配置流

光有 config_flow.py 还不够,你得告诉 HA 你的插件支持配置流。在 __init__.py 里加上配置流的引用:

# __init__.py
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant

DOMAIN = "my_custom"

async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
    """通过配置流设置插件"""
    hass.data.setdefault(DOMAIN, {})
    hass.data[DOMAIN][entry.entry_id] = entry.data
    
    # 这里可以加载你的平台(传感器、开关等)
    await hass.config_entries.async_forward_entry_setups(entry, ["sensor"])
    return True

async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry):
    """卸载配置条目"""
    await hass.config_entries.async_forward_entry_unload(entry, ["sensor"])
    return True

然后在 manifest.json 里声明配置流支持:

{
  "domain": "my_custom",
  "name": "我的自定义集成",
  "version": "1.0.0",
  "config_flow": true,
  "requirements": [],
  "dependencies": [],
  "codeowners": ["@your_github"]
}

注意 "config_flow": true 这一行。少了它,HA 就不会在 UI 里显示你的集成。

配置流的进阶用法

基础的配置流写完了,但实际项目中往往需要更复杂的交互。我分享几个常用的模式:

多步骤配置流

有时候一个表单不够用。比如你要先让用户选择设备类型,再根据类型展示不同的配置项。这时候可以用多步骤:

class MyCustomConfigFlow(config_entries.ConfigFlow, domain="my_custom"):
    
    async def async_step_user(self, user_input=None):
        """第一步:选择设备类型"""
        if user_input is not None:
            self.device_type = user_input["device_type"]
            # 根据类型跳转到不同步骤
            if self.device_type == "sensor":
                return await self.async_step_sensor_config()
            else:
                return await self.async_step_switch_config()
        
        return self.async_show_form(
            step_id="user",
            data_schema=vol.Schema({
                vol.Required("device_type"): vol.In(["sensor", "switch"]),
            }),
        )

    async def async_step_sensor_config(self, user_input=None):
        """第二步:传感器配置"""
        if user_input is not None:
            return self.async_create_entry(
                title="传感器设备",
                data={**user_input, "device_type": "sensor"}
            )
        
        return self.async_show_form(
            step_id="sensor_config",
            data_schema=vol.Schema({
                vol.Required("sensor_type"): str,
                vol.Optional("unit", default="°C"): str,
            }),
        )

注意:多步骤配置流里,记得用 self 变量保存中间状态。我之前犯过错误,在步骤之间用局部变量传数据,结果异步调用时数据丢了。嗯,血的教训。

配置选项流

用户安装完集成后,可能想修改配置。这时候需要选项流(Options Flow)。它和配置流很像,但入口不同:

@staticmethod
@callback
def async_get_options_flow(config_entry):
    return OptionsFlowHandler(config_entry)

class OptionsFlowHandler(config_entries.OptionsFlow):
    """选项流处理"""

    async def async_step_init(self, user_input=None):
        """选项流入口"""
        if user_input is not None:
            return self.async_create_entry(title="", data=user_input)
        
        return self.async_show_form(
            step_id="init",
            data_schema=vol.Schema({
                vol.Optional(
                    "api_key",
                    default=self.config_entry.data.get("api_key")
                ): str,
            }),
        )

选项流让用户可以随时修改配置,不用重新安装集成。这个功能我建议每个插件都加上,用户体验会好很多。

配置流的调试技巧

写配置流时难免遇到问题。我分享几个调试方法:

问题 排查方法 常见原因
配置流不显示 检查 manifest.json 的 config_flow 字段 忘记设置 config_flow: true
表单提交后没反应 查看 HA 的日志(设置 → 系统 → 日志) 验证逻辑抛异常了
配置数据没保存 检查 async_create_entry 是否被调用 验证条件没满足,没走到创建步骤
多步骤跳转失败 确认 self 变量是否正确保存了状态 异步上下文导致变量丢失

调试小技巧:我习惯在配置流里加 _LOGGER.debug 日志。比如在 async_step_user 里打印 user_input 的内容。这样能清楚看到用户提交了什么数据,验证逻辑有没有走对。

总结

配置流是 Home Assistant 插件开发的核心技能。它让用户通过 UI 完成配置,大大提升了使用体验。从初始化到创建条目,再到选项流和删除,每个阶段都有它的意义。

我个人建议,刚开始写配置流时,先从一个简单的单步骤表单入手。跑通了再尝试多步骤和选项流。别一上来就想搞复杂的,容易把自己绕进去。

嗯,配置流的内容就讲到这里。记住,好的配置流能让用户对你的插件第一印象加分不少。花点心思在设计上,值得的。

可可精品资料库