跳转到内容

ESPHome 中的 YAML 配置

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

YAML 设计为人类可读且易于编辑,但有时使用起来可能令人沮丧,特别是在缩进方面。YAML 是 JSON 的超集,JSON 语法可以在 YAML 文件中使用。

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

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

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

示例:

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

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

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

布尔值为 true 或 false,不区分大小写。ESPHome 还将其他字符串映射为布尔值:

  • yes、on 和 enable 映射为 true。
  • no、off 和 disable 映射为 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: "温度 1"
pin: GPIO32
- platform: gpio
name: "温度 2"
pin: GPIO33

YAML 格式的序列有时可能相当令人困惑——考虑以下示例:

- platform: gpio
name: "温度 1"
- label:
text: "温度 1"

可能看起来很奇怪,第一种情况没有额外的缩进,而第二种情况有。区别在于,第一种情况下序列项本身是一个映射,键为 platform 和 name,而第二种情况下序列项是一个键 label,其值为一个映射,键为 text,值为 "温度 1"。将它们重写为 JSON 格式可以更清楚地说明问题:

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

一个有用的经验法则是,凡是序列项以冒号结尾的,其值必须是一个映射,而不是标量,因此后续行需要进一步缩进。以下示例是错误的,将抛出两个错误:

- label: # 将抛出错误 "expected a dictionary"
text: "温度 1" # 错误!应该缩进。将抛出错误 "text 是 ... 的无效选项"

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

示例:

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

在上面的示例中,“sensor” 是映射中的一个键,其值是另一个映射。第二个映射的键为 platform、pin、name、device_class、unit_of_measurement、accuracy_decimals 和 state_class。

当映射值是一个序列时,它应该在键之后缩进,但这是 YAML 对不正确的缩进较为宽容的少数地方之一,例如:

widgets:
- label:
text: 温度 1
- label:
text: 温度 2

请注意,序列标记 - 没有缩进在映射键 widgets 下方。这在技术上不正确,但 YAML 解析器会正确解释。建议你坚持使用正确的格式,但如果你在 YAML 文件中看到这种用法,要知道它确实有效——并且在复杂配置中限制缩进深度可能很有用。

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

sensor:
- &common_adc
pin: GPIO32
platform: adc
name: "温度 1"
device_class: temperature
unit_of_measurement: "°C"
accuracy_decimals: 1
state_class: measurement
- <<: *common_adc
pin: GPIO33
name: "温度 2"

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

YAML 支持几种不同形式的多行字符串。

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

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

一般来说,如下所述的块字符串比引号多行字符串更可取。

示例:

sensor: # 此传感器的名称将为 "Sensor Name"
- platform: template
name: "Sensor
Name"

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

  • 块样式指示符(| 或 >)(必需)
  • 块截断指示符(- 或 +)(可选)
  • 缩进值(数字,可选)

块样式控制如何处理嵌入的换行符——使用 |(字面)样式时,保留嵌入的换行符;使用 >(折叠)样式时,嵌入的换行符折叠为单个空格。

块截断指示符控制字符串末尾的处理方式:

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

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

在 ESPHome 中,你通常会使用 |- 样式,该样式保留内部换行符并删除尾随换行符。

示例:

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

ESPHome 在标准 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: 功能允许你定义可重用的值,这些值可以在整个配置中引用。有关完整详情,请参见替换。

  • 将另一个 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: 功能允许你定义可重用的、可能部分的配置,可以包含在主配置中。数据与主配置合并,主配置中的值优先于包数据中的值。

详情请参见包。

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

.number: &AnchorNumber # 定义一个锚点,但排除它
optimistic: true
min_value: 0
max_value: 600
step: 1
initial_value: 0
number:
- platform: template
<<: *AnchorNumber # 包含之前定义的锚点
id: "SwitchMainDelay"
name: "主开关延迟"

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

在 ESPHome 配置文件中,可以嵌入 lambda,这些是 C++ 代码块,在运行时求值,以提供动态值并实现 YAML 无法实现的逻辑。lambda 使用 !lambda 标签定义。请参见模板了解更多信息。