YAML 配置文件中的 ESPHome

概述

ESPHome 配置文件使用 YAML,这是一种人类友好的数据序列化标准。本页面解释了标准 YAML 功能和 ESPHome 特有的扩展。

YAML 设计为易于阅读和编辑,但在处理缩进时也可能令人沮丧。YAML 是 JSON 的超集,因此 JSON 语法可以用于 YAML 文件。

ESPHome YAML 文件中的配置块的顺序通常不重要,因为整个内容将在任何验证或处理之前被读取。

标准YAML功能

  • 注释: 任何以 # 开头的文本都是注释。
  • 标量: 字符串、数字、布尔值。
  • 序列: 列表项,使用 -[ ... ]
  • 映射: 键值对,使用 key: value{ ... }
  • 锚点和别名: 使用 &anchor*alias 重用 YAML 块。
  • 多行字符串: 使用 |> 表示多行文本。

注释

YAML 注释是任何以 # 符号开头的文本,延伸到行尾。如果你需要在字符串中包含 # 字符,它必须出现在引号内。

示例:

# 这是一个注释
foo:
  bar: 3 # 这是另一个注释
  text: "# 可以包含在字符串中"

标量

YAML 标量是任何不包含冒号(:)的值。它可以是字符串、数字、布尔值或空值。

字符串用双引号(")或单引号(')括起来。标准转义序列(如换行符 \n 和 Unicode 代码点)仅在双引号内被转换。字符串也可以是非引号的字符序列,它不是有效的数字或布尔值,例如 23times 即使未加引号也会被视为字符串。字符串也可以是多行的,使用 |>

布尔值是 truefalse,不区分大小写。ESPHome 还将其他字符串映射到布尔值:

  • yesonenable 映射为 true
  • nooffdisable 映射为 false

数值是整数或浮点数。在 ESPHome 中,在大多数需要数字的地方,它也可以写为包含整数或浮点数的字符串,这将自动转换。

示例:

esp8266:
  board: esp8285    # esp8285 是一个字符串
  restore_from_flash: true # 布尔值

web_server:
  port: 80 # 整数值

序列

YAML 序列是一个列表(或数组),使用 -[ ... ]。项可以是标量、序列或映射。每个序列项使用 - 标志,而 JSON 风格的 [ ... ] 可以在一行中,或跨多行。

示例:

# JSON 风格
data_pins: [48, 47, 39, 40]

# YAML 风格
data_pins:
  - 48
  - 47
  - 39
  - 40

sensors:
# 一系列传感器,每个都是映射
  - platform: gpio
    name: "Temperature 1"
    pin: GPIO32

  - platform: gpio
    name: "Temperature 2"
    pin: GPIO33

YAML 格式的序列有时会让人困惑 - 考虑以下示例:

- platform: gpio
  name: "Temperature 1"

- label:
    text: "Temperature 1"

看起来第一个例子中没有额外的缩进,而第二个例子中有。区别在于第一个例子中的序列项本身是一个映射,有 platformname 键,而第二个例子中的序列项是一个键 label,其值为一个映射,键为 text,值为 "Temperature 1"。将这些重写为 JSON 格式可以更清楚地理解:

- {
    "platform": "gpio",
    "name": "Temperature 1"
  }
- {
    "label": {
      "text": "Temperature 1"
    }
  }

一个有用的经验法则是,无论序列项以冒号结尾的地方,其值必须是映射,而不是标量,因此它需要进一步缩进来表示后续行,这个例子是错误的,并且会抛出两个错误:

- label: # 会抛出错误 "expected a dictionary"
  text: "Temperature 1"  # 错误!应该缩进。会抛出错误 "text is an invalid option for ..."

映射

YAML 映射是一系列键值对,使用 key: value{ ... }。键可以是任何有效的 YAML 标量(尽管它们通常会被限制为预定义集中的字符串),而值可以是任何有效的 YAML 标量、列表或映射。映射也可以称为字典、关联数组或哈希表。单个映射中使用的键必须是唯一的。

示例:

sensor:
  platform: gpio
  pin: GPIO32
  name: "Temperature 1"
  device_class: temperature
  unit_of_measurement: "°C"
  accuracy_decimals: 1
  state_class: measurement

在上面的示例中,“sensor”是一个映射中的键,其值是另一个映射。第二个映射有 platformpinnamedevice_classunit_of_measurementaccuracy_decimalsstate_class 键。

当映射值是一个序列时,它应该在键之后缩进,但 YAML 在缩进错误方面很宽容,例如:

widgets:
- label:
    text: Temperature 1
- label:
    text: Temperature 2

注意,序列标记 - 在映射键 widgets 缩进。这在技术上是不正确的,但 YAML 解析器会正确解释。建议你坚持正确的格式,但如果你在 YAML 文件中看到这种情况,要知道它确实有效 - 它在复杂的配置中限制缩进深度时非常有用。

锚点、别名和覆盖值

YAML 锚点(&anchor)和别名(*alias)允许你定义一个配置块并在其他地方重用它。这对于重复元数据字段特别有用。 你还可以在合并时覆盖特定值,使用 <<: *anchor

sensor:
  - &common_adc
      pin: GPIO32
      platform: adc
      name: "Temperature 1"
      device_class: temperature
      unit_of_measurement: "°C"
      accuracy_decimals: 1
      state_class: measurement

  - <<: *common_adc
    pin: GPIO33
    name: "Temperature 2"

在这个示例中,两个传感器共享 common_adc 的元数据,但第二个传感器覆盖了 pinname 值。

多行字符串

YAML 支持多种格式的多行字符串。

引用多行字符串

用双引号(")或单引号(')引用的字符串可以跨多行。注意:

  • 后续行的前导空白被忽略;
  • 可以通过留空行插入换行符;
  • 转义序列如 \n 仅在双引号内被转换;

通常来说,下面描述的块字符串比引用的多行字符串更可取。

示例:

sensor:  # 这个传感器的名称将是 "Sensor Name"
  - platform: template
    name: "Sensor
           Name"

块字符串

块字符串是以特殊字符序列引入的多行字符串,后续所有缩进大于引入字符串的键的行都被视为字符串的一部分。 块字符串标记有三部分:

  • 块风格指示器(|>)(必需)
  • 塞切指示器(-+)(可选)
  • 缩进值(一个数字,可选)

块风格控制嵌入换行符的处理方式 - 使用 |(字面)风格时,嵌入换行符被保留,而使用 >(折叠)风格时,嵌入换行符被折叠成一个空格。

塞切指示器控制字符串末尾的处理方式:

  • 无塞切指示器:以单个换行符结束字符串
  • -:删除所有尾随换行符;
  • +:保留所有尾随换行符。

缩进值指定每行开头要插入多少空格。它是可选的,默认缩进将根据文本的第一行猜测,因此通常不需要使用它。

在 ESPHome 中,你通常使用 |- 风格,它将保留内部换行符并删除尾随换行符。

示例:

multiline_string: |-
  这是一个跨多行分割的字符串。内部换行符将被保留,尾随换行符将被删除。  
some_other_key: # 这不是字符串的一部分

ESPHome YAML 扩展

ESPHome 在标准 YAML 中添加了几个非标准但非常有用的功能:

密码和 secrets.yaml 文件

!secret 标签允许你引用存储在单独的 secrets.yaml 文件中的敏感值(如密码或 API 密钥)。当你希望能够在分发配置文件时而不泄露你的秘密时,这特别有帮助。

ℹ️ Important

为了保护你的秘密,secrets.yaml 文件不应提交到 git 或任何其他版本控制系统。

示例:

wifi:
  ssid: "MyWiFi"
  password: !secret wifi_password

并在你的 secrets.yaml 中:

wifi_password: my_super_secret_password

秘密文件必须只包含键到标量值的平面映射。

替换

substitutions: 功能允许你定义可在整个配置中引用的可重用值。有关详细信息,请参阅 Substitutions

!include

  • 在此位置插入另一个 YAML 文件的内容。
  • 可以用于配置的任何级别,并在该级别进行替换。
  • 除非与 packages:(见下文)一起使用,否则插入是字面的。
  • 可以在包含文件中使用替换来引用传递给 !include 的值。此类值将覆盖任何全局替换,因此全局替换可用于提供默认值。

示例:

binary_sensor:
  - platform: gpio
    id: button1
    pin: GPIOXX
    on_multi_click: !include { file: on-multi-click.yaml, vars: { id: 1 } } # 内联语法
  - platform: gpio
    id: button2
    pin: GPIOXX
    on_multi_click: !include
      # 多行语法
      file: on-multi-click.yaml
      vars:
        id: 2

packages: 功能允许你定义可重用且可能是部分配置,可以包含在你的主配置中。数据与主配置合并,主配置中的值优先于包数据中的值。

有关更多详细信息,请参阅 Packages

隐藏项

任何以点(.)开头的顶级配置键都将被忽略,并且不会包含在最终配置中。这主要用于定义不是配置一部分的锚点。

.number: &AnchorNumber # 定义一个锚点,但排除它
    optimistic: true
    min_value: 0
    max_value: 600
    step: 1
    initial_value: 0

number:
  - platform: template
    <<: *AnchorNumber # 包含之前定义的锚点
    id: "SwitchMainDelay"
    name: "Main Switch Delay"

隐藏键的名称并不重要,实际上可以只是一个点,但建议使用更具描述性的名称。

Lambda

在 ESPHome 配置文件中,可以嵌入 lambda,它们是 C++ 代码块,在运行时被评估,以提供动态值并实现 YAML 中不可能实现的逻辑。lambda 使用 !lambda 标签定义。有关更多信息,请参阅 模板

参考文档