包(Packages)
当你拥有许多 ESPHome 设备(或在大规模生产和分发它们)时,一个常见的需求往往会出现: 配置模块化。你可能想把配置拆分成通用(组)元素,构建 成可重用的部分,随后可以被许多/所有设备使用。只有你的配置中独特的片段 才会保留在任何给定设备的 YAML 配置文件中。
这可以通过 ESPHome 的 packages 功能实现。
来自包的所有定义将以非破坏性方式与你的设备的主配置合并。这 允许覆盖包中所包含的配置(的部分)。你主配置中的替换 (substitutions)将覆盖包中同名的替换。
字典按键逐个合并。组件列表按组件 ID 合并(如果指定)。其他列表按 连接方式合并。所有其他配置值都被后面的值替换。
ESPHome 使用 !include 从其他文件”引入”包;此功能在 !include 中有描述。
packages: 键的值可以是:
- 一个有效的包引用列表
- 一个将键映射到包引用的映射。使用映射时,键仅作参考,本身没有意义。
下面显示了所有格式的示例。
考虑以下示例,作者将公共配置片段(如 Wi-Fi 和 API)放入基础文件, 然后在主配置中用一些设备特定配置进行扩展。
注意 device_base.yaml 中描述 api 组件的配置片段是如何与主配置文件中的操作
定义合并的。
# 在 config.yaml 中packages: # 作为列表 - !include common/wifi.yaml - !include common/device_base.yaml
api: actions: - action: start_laundry then: - switch.turn_on: relay
# 任何其他配置...# 在 wifi.yaml 中wifi: ssid: !secret wifi_ssid password: !secret wifi_password# 在 device_base.yaml 中esphome: name: ${node_name}
esp32: board: wemos_d1_mini32
logger:
api: encryption: key: !secret api_encryption_key远程/Git 包
Section titled “远程/Git 包”也可以利用正确的配置语法从 Git 仓库加载包。 替换(Substitutions) 可以在远程包内部使用,这允许用户 用他们自己的替换值在本地覆盖它们。
NOTE
远程包中不能有 secret 查找。它们应改为在打包的 YAML 中使用带
可选默认值的替换,本地设备 YAML 可以使用来自本地密钥的值来设置。
# Git 仓库示例,作为映射packages: # 简写形式 github://username/repository/[folder/]file-path.yml[@branch-or-tag] remote_package_shorthand: github://esphome/non-existant-repo/file1.yml@main
remote_package_files: url: https://github.com/esphome/non-existant-repo files: [file1.yml, file2.yml] # 可选;如果未指定,将包含所有文件 ref: main # 可选 refresh: 1d # 可选
remote_package_files2: url: https://github.com/esphome/non-existant-repo files: - path: file1.yml vars: a: 1 b: 2 - path: file1.yml # 同一个文件可以用不同的 vars 多次指定。 vars: a: 3 b: 4 - file2.yml ref: main # 可选 refresh: 1d # 可选使用简写形式 URL 时,支持以下公共代码托管网站:
对于每个包:
-
url (必选, string): 仓库的 URL。
-
path (可选, string): 包含文件的公共基础路径。
-
username (可选, string): 如果需要身份验证,用于身份验证的用户名。
-
password (可选, string): 如果需要身份验证,用于身份验证的密码。
-
files (可选): 要包含的文件列表。可以是以下之一:
- 文件路径列表
- 包含
path和vars的对象列表
-
ref (可选, string): 从仓库拉取内容时使用的 Git 引用。
-
refresh (可选, Time): 从仓库刷新内容的间隔。
由于包是通过 !include 系统合并的,因此可以向它们提供变量。这意味着
包可以用作模板,允许将复杂或重复的配置存储在包文件中,
然后多次并入配置。
包还可以包含一个 defaults 块,为 !include 块未提供的变量提供替换。
例如,如果配置需要支持三扇使用 gpio 开关平台和
time_based 窗帘平台的车库门,可以像这样构建:
# 在 config.yaml 中packages: left_garage_door: !include file: garage-door.yaml vars: door_name: Left middle_garage_door: !include file: garage-door.yaml vars: door_name: Middle right_garage_door: !include file: garage-door.yaml vars: door_name: Right# 在 garage-door.yaml 中switch: - name: ${door_name} Garage Door Switch platform: gpio # ...按条件包含包
Section titled “按条件包含包”你可以根据条件包含一个包,或者通过将你的包用 !include 加载
到一个替换变量中(而不是放在 packages 下)来动态选择一个包:
# 在 config.yaml 中substitutions: left_garage_door: !include file: garage-door.yaml vars: door_name: Left
enable_extra_door: true
packages: extra_door: ${ left_garage_door if enable_extra_door else {} }上面利用了 Jinja 表达式 来确定
left_garage_door 包是否真正被包含。enable_extra_door 也可以从
命令行 设置。
使用动态文件名包含包
Section titled “使用动态文件名包含包”替换可以直接用在 !include 的文件名中,允许你根据
替换值动态选择加载哪个文件:
substitutions: platform: esp32
packages: hardware: !include device-${platform}.yaml
light: - platform: status_led name: "Board Status" pin: $LED_GPIOsubstitutions: LED_GPIO: GPIO2esp32: board: esp32devESPHome 会在加载文件之前展开 ${platform},因此在上面的示例中,device-${platform}.yaml
解析为 device-esp32.yaml。ESPHome 中任何有效的替换表达式——包括
Jinja 表达式——都可以用在文件名中。
NOTE
使用 YAML 合并键(<<: !include filename.yaml)时不支持文件名替换。
要对包含的配置进行更改或添加额外配置,可以使用 !extend config_id,其中
config_id 是要修改配置的 ID。
例如,为配置之间共享的公共 uptime 传感器设置特定的更新间隔:
# 在 common.yaml 中captive_portal:
sensor: - platform: uptime id: uptime_sensor update_interval: 5minpackages: - !include common.yaml
sensor: - id: !extend uptime_sensor update_interval: 10s也支持 LVGL 风格的配置层级:
# 在 interface.yaml 中lvgl: pages: - id: main_page widgets: - label: id: title_label text: "Main Page"packages: - !include interface.yamllvgl: pages: - id: !extend main_page widgets: - label: id: !extend title_label text: "New Title" text_color: red!extend 也适用于替换和 Jinja:
substitutions: switches: - left_switch - right_switch - center_switch
mains_switch: 1
switch: - platform: gpio id: left_switch pin: 1 - platform: gpio id: right_switch pin: 2 - platform: gpio id: center_switch pin: 3 - id: !extend ${ switches[mains_switch] } name: "Mains switch"要从包含的配置中移除现有条目,可以使用 !remove [config_id],其中 config_id 是
要修改条目的 ID。
例如,移除配置之间共享的公共 uptime 传感器:
packages: - !include common.yaml # 参见上文
sensor: - id: !remove uptime_sensor在 LVGL 风格的配置中移除一个项目:
packages: - !include interface.yaml # 参见上文lvgl: pages: - id: !extend main_page widgets: - label: id: !remove title_label移除特定设备的 captive portal:
packages: - !include common.yaml # 参见上文
captive_portal: !remove只为特定设备移除一个属性:
packages: common: !include common.yaml # 参见上文
sensor: - id: !extend uptime_sensor update_interval: !remove!remove 也适用于替换:
substitutions: disable_reboot: true
switch: - platform: restart id: restart_switch name: "Living Room Restart" - id: !remove ${disable_reboot and "restart_switch"}