模板

这是 Home Assistant 的一个高级功能。您需要具备以下基本知识:

模板是一种强大的功能,允许您控制进入和离开系统的信息。它用于:

创建模板

Home Assistant 中的模板由 Jinja2 模板引擎供给。这意味着我们使用他们的语法,并在渲染期间向模板提供一些自定义 Home Assistant 变量。Jinja2 支持多种操作:

我们不会讨论语法的基础知识,因为 Jinja2 在他们的 模板文档 中对此做得很好。

前端有一个 模板编辑器工具 来帮助开发和调试模板。导航至 开发者工具 > 模板,在 模板编辑器 中创建模板,并在右侧检查结果。

模板可以迅速变得庞大。为了保持清晰的概述,请考虑使用 YAML 多行字符串来定义模板:

script:
  msg_who_is_home:
    sequence:
      - action: notify.notify
        data:
          message: >
            {% if is_state('device_tracker.paulus', 'home') %}
              哈,Paulus 回家了!
            {% else %}
              Paulus 在 {{ states('device_tracker.paulus') }}。
            {% endif %}

重要的模板规则

在向 YAML 添加模板时,有几个非常重要的规则需要记住:

  1. 必须 用双引号 (") 或单引号 (') 包围单行模板。
  2. 建议使用 if ... is not nonedefault 过滤器 进行未定义变量的准备,或者两者都使用。
  3. 建议在比较数字时,通过使用相应的 过滤器 将数字转换为 floatint
  4. 虽然 floatint 过滤器允许在转换失败时使用默认回退值,但它们不提供捕获未定义变量的能力。

记住这些简单规则会帮助您避免在使用自动化模板时的各种头疼问题和无尽的挫折。

已启用的 Jinja 扩展

Jinja 支持一组语言扩展,为语言添加新功能。为了改善编写 Jinja 模板的体验,我们启用了以下扩展:

重用模板

您可以通过将其添加到配置目录下的 custom_templates 文件夹中来编写可重用的 Jinja 模板。所有模板文件必须具有 .jinja 扩展名,并且大小必须小于 5MiB。该文件夹中的模板将在启动时加载。要在不重启 Home Assistant 的情况下重新加载模板,请调用 homeassistant.reload_custom_templates 操作。

加载模板后,Jinja 包含导入 将以 config/custom_templates 作为基本目录。

例如,您可以在 config/custom_templates/formatter.jinja 中定义一个宏:

{% macro format_entity(entity_id) %}
{{ state_attr(entity_id, 'friendly_name') }} - {{ states(entity_id) }}
{% endmacro %}

然后在您的自动化中通过导入来重用此宏:

{% from 'formatter.jinja' import format_entity %}
{{ format_entity('sensor.temperature') }}

Home Assistant 模板扩展

扩展允许模板访问所有 Home Assistant 特有的状态,并添加其他便利函数和过滤器。

限制模板

某些 触发器 以及 trigger_variables 的模板仅支持一部分 Home Assistant 模板扩展。这部分称为 “限制模板”。

this

基于状态和触发器的模板实体在其模板和操作中有可用的特殊模板变量 this。更多细节和示例请见 模板集成文档

状态

限制模板 中不支持。

  • 迭代 states 将产出每个状态对象。
  • 迭代 states.domain 将产出该域的每个状态对象。
  • states.sensor.temperature 返回 sensor.temperature 的状态对象(尽量避免使用,见下文说明)。
  • states 也可以用作一个函数,states(entity_id, rounded=False, with_unit=False),它返回给定实体的状态字符串(而不是状态对象),如果不存在则返回 unknown,如果对象存在但不可用则返回 unavailable
    • 可选参数 roundedwith_unit 控制传感器状态字符串的格式,详见下面的 示例
  • states.sensor.temperature.state_with_unit 以与调用 states('sensor.temperature', rounded=True, with_unit=True) 相同的方式格式化状态字符串。
  • is_state 将实体的状态与指定状态或状态列表进行比较,并返回 TrueFalseis_state('device_tracker.paulus', 'home') 将测试给定实体是否为指定状态。is_state('device_tracker.paulus', ['home', 'work']) 将测试给定实体是否为列表中的任意状态。
  • state_attr('device_tracker.paulus', 'battery') 将返回属性的值,如果不存在则返回 None。
  • is_state_attr('device_tracker.paulus', 'battery', 40) 将测试给定实体属性是否为指定状态(在此情况下为数值)。请注意,当属性为 None 时,如果您想检查它是否为 None,您需要使用 state_attr('sensor.my_sensor', 'attr') is nonestate_attr('sensor.my_sensor', 'attr') == None(注意两种写法中 none 的大写差异)。
  • has_value('sensor.my_sensor') 将测试给定实体是否不为未知或不可用。可以作为过滤器或测试使用。

Warning

避免使用 states.sensor.temperature.state,而应使用 states('sensor.temperature')。强烈建议尽可能使用 states()is_state()state_attr()is_state_attr(),以避免在实体尚未准备好时(例如,在 Home Assistant 启动期间)出现错误和错误消息。

状态示例

下面的两个语句在状态存在时结果相同。如果状态不存在,第二个语句将导致错误。

{{ states('device_tracker.paulus') }}
{{ states.device_tracker.paulus.state }}

打印出所有传感器状态的列表:

{% for state in states.sensor %}
  {{ state.entity_id }}={{ state.state }},
{% endfor %}

打印出按 entity_id 排序的所有传感器状态列表:

{% for state in states.sensor | sort(attribute='entity_id') %}
  {{ state.entity_id }}={{ state.state }},
{% endfor %}

开启的实体:

{{ ['light.kitchen', 'light.dining_room'] | select('is_state', 'on') | list }}

其他状态示例:

{% if is_state('device_tracker.paulus', 'home') %}
  哈,Paulus 回家了!
{% else %}
  Paulus 在 {{ states('device_tracker.paulus') }}。
{% endif %}

#检查传感器 train_departure_time 状态
{% if states('sensor.train_departure_time') in ("unavailable", "unknown") %}
  {{ ... }}

{% if has_value('sensor.train_departure_time') %}
  {{ ... }}


{% set state = states('sensor.temperature') %}{{ state | float + 1 if is_number(state) else "无效温度" }}

{% set state = states('sensor.temperature') %}{{ (state | float * 10) | round(2) if is_number(state)}}

{% set state = states('sensor.temperature') %}
{% if is_number(state) and state | float > 20 %}
  太热了!
{% endif %}

{{ as_timestamp(states.binary_sensor.garage_door.last_changed) }}

{{ as_local(states.binary_sensor.garage_door.last_changed) }}

{{ as_timestamp(now()) - as_timestamp(states.binary_sensor.garage_door.last_changed) }}

{{ as_local(states.sensor.time.last_changed) }}

{{ states('sensor.expires') | as_datetime }}

# 制作状态列表
{{ ['light.kitchen', 'light.dining_room'] | map('states') | list }}

格式化传感器状态

以下示例显示了状态为 20.001 的温度传感器的输出,单位为 °C,用户配置的展示四舍五入设置为 1 位小数。

以下示例结果是数字 20.001

{{ states('sensor.temperature') }}

以下示例结果是字符串 "20.0 °C"

{{ states('sensor.temperature', with_unit=True) }}

以下示例结果是字符串 "20.001 °C"

{{ states('sensor.temperature', with_unit=True, rounded=False) }}

以下示例结果是数字 20.0

{{ states('sensor.temperature', rounded=True) }}

以下示例结果是数字 20.001

{{ states.sensor.temperature.state }}

以下示例结果是字符串 "20.0 °C"

{{ states.sensor.temperature.state_with_unit }}

属性

限制模板 中不支持。

如果状态定义了,可以使用 state_attr 打印属性。

属性示例

{% if states.device_tracker.paulus %}
  {{ state_attr('device_tracker.paulus', 'battery') }}
{% else %}
  ??
{% endif %}

使用字符串:

{% set tracker_name = "paulus"%}

{% if states("device_tracker." + tracker_name) != "unknown" %}
  {{ state_attr("device_tracker." + tracker_name, "battery")}}
{% else %}
  ??
{% endif %}

友好名称列表:

{{ ['binary_sensor.garage_door', 'binary_sensor.front_door'] | map('state_attr', 'friendly_name') | list }}

亮度为 255 的开启灯光列表:

{{ ['light.kitchen', 'light.dining_room'] | select('is_state', 'on') | select('is_state_attr', 'brightness', 255) | list }}

状态翻译

限制模板 中不支持。

state_translated 函数使用当前在 常规设置 中配置的语言返回实体的翻译状态。

状态翻译示例

{{ states("sun.sun") }}             # below_horizon
{{ state_translated("sun.sun") }}   # Below horizon
{{ "sun.sun" | state_translated }}  # Below horizon
{{ states("binary_sensor.movement_backyard") }}             # on
{{ state_translated("binary_sensor.movement_backyard") }}   # Detected
{{ "binary_sensor.movement_backyard" | state_translated }}  # Detected

处理分组

限制模板 中不支持。

expand 函数和过滤器可用于排序实体并展开组。它输出一个无重复的排序实体数组。

展开示例

{% for tracker in expand('device_tracker.paulus', 'group.child_trackers') %}
  {{ state_attr(tracker.entity_id, 'battery') }}
  {%- if not loop.last %}, {% endif -%}
{% endfor %}

同样的事情也可以用过滤器表示:

{{ expand(['device_tracker.paulus', 'group.child_trackers'])
  | selectattr("attributes.battery", 'defined')
  | join(', ', attribute="attributes.battery") }}
{% for energy in expand('group.energy_sensors') if is_number(energy.state) %}
  {{ energy.state }}
  {%- if not loop.last %}, {% endif -%}
{% endfor %}

同样的事情也可以以测试的形式表示:

{{ expand('group.energy_sensors')
  | selectattr("state", 'is_number') | join(', ') }}

实体

  • is_hidden_entity(entity_id) 返回一个实体是否被隐藏。也可用作测试。

实体示例

{{ area_entities('kitchen') | reject('is_hidden_entity') }} # 获取厨房区域的可见实体列表

设备

  • device_entities(device_id) 返回与给定设备 ID 相关联的实体列表。也可用作过滤器。
  • device_attr(device_or_entity_id, attr_name) 返回给定设备或实体 ID 的 attr_name 值。也可用作过滤器。在 限制模板 中不支持。
  • is_device_attr(device_or_entity_id, attr_name, attr_value) 返回给定设备或实体 ID 的 attr_name 值是否与 attr_value 匹配。也可用作测试。在 限制模板 中不支持。
  • device_id(entity_id) 返回给定实体 ID 或设备名称的设备 ID。也可用作过滤器。

设备示例

{{ device_attr('deadbeefdeadbeefdeadbeefdeadbeef', 'manufacturer') }}  # Sony
{{ is_device_attr('deadbeefdeadbeefdeadbeefdeadbeef', 'manufacturer', 'Sony') }}  # true
{{ device_id('sensor.sony') }}  # deadbeefdeadbeefdeadbeefdeadbeef

配置条目

  • config_entry_id(entity_id) 返回给定实体 ID 的配置条目 ID。也可用作过滤器。
  • config_entry_attr(config_entry_id, attr) 返回给定实体 ID 的配置条目的 attr 值。也可用作过滤器。允许以下属性:domaintitlestatesourcedisabled_by。在 限制模板 中不支持。

配置条目示例

{{ config_entry_id('sensor.sony') }}  # deadbeefdeadbeefdeadbeefdeadbeef
{{ config_entry_attr(config_entry_id('sensor.sony'), 'title') }}  # Sony Bravia TV

楼层

  • floors() 返回完整的楼层 ID 列表。
  • floor_id(lookup_value) 返回给定设备 ID、实体 ID、区域 ID 或区域名称的楼层 ID。也可用作过滤器。
  • floor_name(lookup_value) 返回给定设备 ID、实体 ID、区域 ID 或楼层 ID 的楼层名称。也可用作过滤器。
  • floor_areas(floor_name_or_id) 返回与给定楼层 ID 或名称关联的区域 ID 列表。也可用作过滤器。

楼层示例

{{ floors() }}  # ['floor_id']
{{ floor_id('第一层') }}  # 'first_floor'
{{ floor_id('my_device_id') }}  # '第二层'
{{ floor_id('sensor.sony') }}  # '第一层'
{{ floor_name('first_floor') }}  # '第一层'
{{ floor_name('my_device_id') }}  # '第二层'
{{ floor_name('sensor.sony') }}  # '第一层'
{{ floor_areas('first_floor') }}  # ['客厅', '厨房']

区域

  • areas() 返回完整的区域 ID 列表。
  • area_id(lookup_value) 返回给定设备 ID、实体 ID 或区域名称的区域 ID。也可用作过滤器。
  • area_name(lookup_value) 返回给定设备 ID、实体 ID 或区域 ID 的区域名称。也可用作过滤器。
  • area_entities(area_name_or_id) 返回与给定区域 ID 或名称关联的实体 ID 列表。也可用作过滤器。
  • area_devices(area_name_or_id) 返回与给定区域 ID 或名称关联的设备 ID 列表。也可用作过滤器。

区域示例

{{ areas() }}  # ['area_id']
{{ area_id('客厅') }}  # 'deadbeefdeadbeefdeadbeefdeadbeef'
{{ area_id('my_device_id') }}  # 'deadbeefdeadbeefdeadbeefdeadbeef'
{{ area_id('sensor.sony') }}  # 'deadbeefdeadbeefdeadbeefdeadbeef'
{{ area_name('deadbeefdeadbeefdeadbeefdeadbeef') }}  # '客厅'
{{ area_name('my_device_id') }}  # '客厅'
{{ area_name('sensor.sony') }}  # '客厅'
{{ area_entities('deadbeefdeadbeefdeadbeefdeadbeef') }}  # ['sensor.sony']
{{ area_devices('客厅') }}  # ['my_device_id']

集成的实体

  • integration_entities(integration) 返回与给定集成(如 huezwave_js)相关联的实体列表。
  • integration_entities(config_entry_title) 如果您为集成设置了多个条目,则可以使用您为集成设置的标题,以便仅针对特定条目。

如果有多个条目具有相同的标题,将返回所有匹配条目的实体,即使这些条目属于不同的集成。无法搜索未命名集成的实体。

集成示例

{{ integration_entities('hue') }}  # ['light.hue_light_upstairs', 'light.hue_light_downstairs']
{{ integration_entities('楼下的 Hue 桥') }}  # ['light.hue_light_downstairs']

标签

  • labels() 返回完整的标签 ID 列表,或返回给定区域 ID、设备 ID 或实体 ID 的标签。
  • label_id(lookup_value) 返回给定标签名称的标签 ID。
  • label_name(lookup_value) 返回给定标签 ID 的标签名称。
  • label_areas(label_name_or_id) 返回与给定标签 ID 或名称关联的区域 ID 列表。也可用作过滤器。
  • label_devices(label_name_or_id) 返回与给定标签 ID 或名称关联的设备 ID 列表。也可用作过滤器。
  • label_entities(label_name_or_id) 返回与给定标签 ID 或名称关联的实体 ID 列表。

每个标签模板函数也可以用作过滤器。

标签示例

{{ labels() }}  # ['christmas_decorations', 'energy_saver', 'security']
{{ labels("living_room") }}  # ['christmas_decorations', 'energy_saver']
{{ labels("my_device_id") }}  # ['security']
{{ labels("light.christmas_tree") }}  # ['christmas_decorations']
{{ label_id('节能灯') }}  # 'energy_saver'
{{ label_name('energy_saver') }}  # '节能灯'
{{ label_areas('security') }}  # ['车道', '花园', '门廊']
{{ label_devices('energy_saver') }}  # ['deadbeefdeadbeefdeadbeefdeadbeef']
{{ label_entities('security') }}  # ['camera.driveway', 'binary_sensor.motion_garden', 'camera.porch']

问题

  • issues() 返回所有开放问题,映射为 (domain, issue_id) 元组到问题对象。
  • issue(domain, issue_id) 返回提供的域和 issue_id 的特定问题。

问题示例

{{ issues() }}  # { ("homeassistant", "deprecated_yaml_ping"): {...}, ("cloud", "legacy_subscription"): {...} }
{{ issue('homeassistant', 'python_version') }}  # {"breaks_in_ha_version": "2024.4", "domain": "homeassistant", "issue_id": "python_version", "is_persistent": False, ...}

立即 if (iif)

一个常见的情况是根据另一个值条件性地返回一个值。例如,当灯亮或灭时返回 “是” 或 “否”。

这可以写为:

{% if is_state('light.kitchen', 'on') %}
  是
{% else %}
  否
{% endif %}

或使用更简短的语法:

{{ '是' if is_state('light.kitchen', 'on') else '否' }}

此外,您可以使用 iif 函数/过滤器,它是一个立即 if。

语法:iif(condition, if_true, if_false, if_none)

iif 会返回 if_true 的值(如果条件为真),if_false 的值(如果条件为假)和 if_none 的值(如果条件为 None)。 一个空字符串、一个空映射或一个空列表,都是假值,参见 Python 文档 以获取详细说明。

if_true 是可选的,如果省略则返回条件为真时的值 Trueif_false 是可选的,如果省略则返回条件为假时的值 Falseif_none 是可选的,如果省略则返回条件为 None 时的 if_false 的值。

使用 iif 的示例:

{{ iif(is_state('light.kitchen', 'on'), '是', '否') }}

{{ is_state('light.kitchen', 'on') | iif('是', '否') }}

{{ (states('light.kitchen') == 'on') | iif('是', '否') }}

Warning

立即 if 过滤器不会像您期望的那样短路,像典型的条件语句。if_trueif_falseif_none 表达式都会被评估,并且过滤器只会返回其中一个结果值。这意味着您不能使用此过滤器来阻止执行可能导致错误的表达式。

例如,如果您想根据平台选择自动化中的 trigger 字段,您可能会编写此模板:trigger.platform == 'event' | iif(trigger.event.data.message, trigger.to_state.state)。这将不起作用,因为两个表达式都会被评估,并且一个会失败,因为该字段不存在。相反,您必须这样做:trigger.event.data.message if trigger.platform == 'event' else trigger.to_state.state。这个形式的表达式将短路,因此如果平台是 event,表达式 trigger.to_state.state 将永远不会被评估并且不会导致错误。

时间

now()time_since()time_until()today_at()utcnow()限制模板 中不支持。

  • now() 返回一个表示您时区当前时间的 datetime 对象。

    • 您还可以使用:now().secondnow().minutenow().hournow().daynow().monthnow().yearnow().weekday()now().isoweekday() 以及其他 datetime 属性和函数。
    • 使用 now() 会使模板在每分钟开始时刷新。
  • utcnow() 返回一个表示 UTC 时区当前时间的 datetime 对象。

    • 对于特定值:utcnow().secondutcnow().minuteutcnow().hourutcnow().dayutcnow().monthutcnow().yearutcnow().weekday()utcnow().isoweekday()
    • 使用 utcnow() 会使模板在每分钟开始时刷新。
  • today_at(value) 将包含军用时间格式的字符串转换为具有当前日期的 datetime 对象。默认为午夜(00:00)。

    • 使用 today_at() 会使模板在每分钟开始时刷新。
    # 当前时间是否过了 10:15?
    {{ now() > today_at("10:15") }}
    
  • as_datetime(value, default) 将包含时间戳的字符串或有效的 UNIX 时间戳转换为 datetime 对象。如果失败,则返回 default 值,或如果省略则引发错误。当输入已是 datetime 对象时,将按原样返回。如果输入是 datetime.date 对象,则会添加午夜作为时间。此函数还可以用作过滤器。

  • as_timestamp(value, default) 将 datetime 对象或字符串转换为 UNIX 时间戳。如果失败,则返回 default 值,或如果省略则引发错误。此函数还可以用作过滤器。

  • as_local() 将 datetime 对象转换为本地时间。此函数还可以用作过滤器。

  • strptime(string, format, default) 根据 format 解析字符串并返回 datetime 对象。如果失败,则返回 default 值,或如果省略则引发错误。

  • time_since(datetime, precision) 将 datetime 对象转换为可读的时间字符串。时间字符串可以以秒、分钟、小时、天、月和年为单位。precision 采用整数(整数)并指示返回的单位数量。最后一个单位是四舍五入的。例如:precision = 1 可能返回 “2 years”,而 precision = 2 可以返回 “1 year 11 months”。此函数还可以用作过滤器。 如果 datetime 在未来,则返回 0 秒。 精度为 0 返回所有可用单位,默认为 1。

  • time_until(datetime, precision) 将 datetime 对象转换为可读的时间字符串。时间字符串可以以秒、分钟、小时、天、月和年为单位。precision 采用整数(整数)并指示返回的单位数量。最后一个单位是四舍五入的。例如:precision = 1 可能返回 “2 years”,而 precision = 2 可以返回 “1 year 11 months”。此函数还可以用作过滤器。 如果 datetime 在过去,则返回 0 秒。 精度为 0 返回所有可用单位,默认为 1。

  • timedelta 返回一个 timedelta 对象,表示持续时间(两个 datetime 之间的时间量)。它接受与 Python datetime.timedelta 函数相同的参数 – 天数、秒数、微秒数、毫秒数、分钟、小时、周。

    # 当前时间之前的 77 分钟。
    {{ now() - timedelta(hours=1, minutes=17) }}
    
  • as_timedelta(string) 将字符串转换为 timedelta 对象,该对象表示持续时间(两个 datetime 之间的时间量)。期望格式为 DD HH:MM:SS.uuuuuuDD HH:MM:SS,uuuuuu,或按 ISO 8601 规定(例如 P4DT1H15M20S 等价于 4 1:15:20)或 PostgreSQL 的日-时间间隔格式(例如 3 days 04:05:06)。此函数还可以用作过滤器。

    # 渲染为 "00:10:00"
    {{ as_timedelta("PT10M") }}
    
  • 过滤器 timestamp_local(default) 将 UNIX 时间戳转换为 ISO 格式字符串表示的本地时区日期/时间。如果失败,则返回 default 值,或如果省略则引发错误。如果在字符串中需要自定义字符串格式,请使用 timestamp_custom

  • 过滤器 timestamp_utc(default) 将 UNIX 时间戳转换为 ISO 格式字符串表示的 UTC 时区日期/时间。如果失败,则返回 default 值,或如果省略则引发错误。如果在字符串中需要自定义字符串格式,请使用 timestamp_custom

  • 过滤器 timestamp_custom(format_string, local=True, default) 将 UNIX 时间戳转换为基于自定义格式的字符串表示,使用本地时区是默认值。如果失败,则返回 default 值,或如果省略则引发错误。支持标准 Python 时间格式选项

Tip

UNIX 时间戳 是自 1970 年 1 月 1 日 00:00:00 UTC 起经过的秒数。因此,如果用作函数的参数,可以用数字值(intfloat)替代。

Important

如果您的模板返回的时间戳应在前端显示(例如,作为具有 device_class: timestamp 的传感器实体),则必须确保它为 ISO 8601 格式(这意味着它在日期和时间部分之间包含 “T” 分隔符)。否则,在 macOS 和 iOS 设备上的前端渲染将显示错误。以下值模板将导致此类错误:

{{ states.sun.sun.last_changed }} => 2023-07-30 20:03:49.253717+00:00(缺少 “T” 分隔符)

要修复它,通过 isoformat() 强制 ISO 转换:

{{ states.sun.sun.last_changed.isoformat() }} => 2023-07-30T20:03:49.253717+00:00(包含 “T” 分隔符)

{{ 120 | timestamp_local }}

To/From JSON

to_json 过滤器将对象序列化为 JSON 字符串。在某些情况下,可能需要格式化 JSON 字符串以与 Webhook、命令行工具或其他多个应用程序一起使用。在模板中处理特殊字符转义时,这可能会变得复杂。使用 to_json 过滤器时,这将自动处理。

to_json 还接受布尔值参数 pretty_print,这将以 2 个空格缩进对 JSON 进行漂亮打印,使其更加可读,以及 sort_keys,这将对 JSON 对象的键进行排序,确保相同输入的结果字符串是一致的。

如果您需要生成 JSON,该 JSON 将由不支持 Unicode 字符的解析器使用,您可以添加 ensure_ascii=True 以让 to_json 在字符串中生成 Unicode 转义序列。

from_json 过滤器操作方式类似,但方向相反,将 JSON 字符串反序列化回对象。

To/From JSON 示例

模板

{% set temp = {'temperature': 25, 'unit': '°C'} %}
字符串化对象: {{ temp }}
对象|to_json: {{ temp|to_json(sort_keys=True) }}

输出

字符串化对象: {'temperature': 25, 'unit': '°C'}
对象|to_json: {"temperature": 25, "unit": "°C"}

相反,from_json 可用于将 JSON 字符串反序列化回对象,以便轻松提取可用数据。

模板

{% set temp = '{"temperature": 25, "unit": "°C"}'|from_json %}
温度是 {{ temp.temperature }}{{ temp.unit }}

输出

温度是 25°C

是否定义

有时,模板应仅在值或对象已定义时返回,否则应返回提供的默认值。这对于验证 JSON 有效负载会很有用。is_defined 过滤器允许在值或对象未定义时抛出错误。

使用 is_defined 解析 JSON 有效负载的示例:

{{ value_json.val | is_defined }}

如果 JSON 有效负载没有 val 属性,则会抛出错误 UndefinedError: 'value_json' is undefined

版本

  • version() 返回给定括号内值的 AwesomeVersion 对象
    • 这也可以作为过滤器使用(| version)。

示例:

  • {{ version("2099.9.9") > "2000.0.0" }} 将返回 True
  • {{ version("2099.9.9") < "2099.10" }} 将返回 True
  • {{ "2099.9.9" | version < "2099.10" }} 将返回 True
  • {{ (version("2099.9.9") - "2100.9.10").major }} 将返回 True
  • {{ (version("2099.9.9") - "2099.10.9").minor }} 将返回 True
  • {{ (version("2099.9.9") - "2099.9.10").patch }} 将返回 True

距离

限制模板 中不支持。

  • distance() 测量从家、实体或坐标的距离。测量的单位(公里或英里)取决于系统的配置设置。
  • closest() 将查找最近的实体。

距离示例

如果仅传入一个位置,Home Assistant 将测量与家之间的距离。


使用经纬度坐标: {{ distance(123.45, 123.45) }}

使用状态: {{ distance(states.device_tracker.paulus) }}

这些也可以以任何组合组合:
{{ distance(123.45, 123.45, 'device_tracker.paulus') }}
{{ distance('device_tracker.anne_therese', 'device_tracker.paulus') }}

最近示例

最接近的函数和过滤器将找到离 Home Assistant 位置最近的实体:

查询所有实体: {{ closest(states) }}
查询特定域的所有实体: {{ closest(states.device_tracker) }}
查询 group.children 中的所有实体: {{ closest('group.children') }}
查询 group.children 中的所有实体: {{ closest(states.group.children) }}

查找离坐标或另一个实体最近的实体。所有先前的参数仍适用于第二个参数。

离坐标最近: {{ closest(23.456, 23.456, 'group.children') }}
离实体最近: {{ closest('zone.school', 'group.children') }}
离实体最近: {{ closest(states.zone.school, 'group.children') }}

由于 closest 返回一个状态,我们也可以将其与距离相结合。

{{ closest(states).name }} 距离 {{ distance(closest(states)) }} 公里。

closest 函数的最后一个参数具有隐式 expand,并且可以接受任何可迭代状态或实体 ID 的序列,并将展开组:

在给定实体中的最近:
    {{ closest(['group.children', states.device_tracker]) }}
离坐标最近:
    {{ closest(23.456, 23.456, ['group.children', states.device_tracker]) }}
离某些实体最近:
    {{ closest(states.zone.school, ['group.children', states.device_tracker]) }}

它也将作为过滤器在可迭代的实体或组上工作:

在给定实体中的最近:
    {{ ['group.children', states.device_tracker] | closest }}
离坐标最近:
    {{ ['group.children', states.device_tracker] | closest(23.456, 23.456) }}
离某些实体最近:
    {{ ['group.children', states.device_tracker] | closest(states.zone.school) }}

包含

Jinja 默认提供了一个 in 操作符,当一个元素在提供的列表中时返回 Truecontains 测试和过滤器允许您执行完全相反的测试,检查一个列表是否包含一个元素。这在 selectselectattr 过滤器中非常有用,还可以检查设备是否具有特定属性、supported_color_modes、特定灯光效果。

一些示例:

  • {{ state_attr('light.dining_room', 'effect_list') | contains('rainbow') }} 如果灯光具有 rainbow 效果将返回 true
  • {{ expand('light.office') | selectattr("attributes.supported_color_modes", 'contains', 'color_temp') | list }} 将返回所有在办公室组中支持 color_temp 的灯光。
  •   {% set current_month = now().month %}
      {% set extra_ambiance = [
        {'name':'Halloween', 'month': [10,11]},
        {'name':'Noel', 'month': [1,11,12]}
      ]%}
      {% set to_add = extra_ambiance | selectattr('month', 'contains', current_month ) | map(attribute='name') | list  %}
      {% set to_remove = extra_ambiance | map(attribute='name') | reject('in', to_add) | list %}
      {{ (state_attr('input_select.light_theme', 'options') + to_add ) | unique | reject('in', to_remove) | list }}
    
    这个稍微复杂的示例使用 contains 过滤器将当前月份与列表匹配。在此情况下,它用于生成要提供给 Input select: Set options 操作的灯光主题列表。

数字函数和过滤器

这些函数中的一些也可以在 过滤器 中使用。这意味着它们可以像这样作为普通函数使用 sqrt(2),或者作为过滤器的一部分使用 2|sqrt

Note

数字函数和过滤器在输入不是有效数字时会引发错误,默认值可以选择性地指定,如果输入无效则返回该默认值。可以使用 is_number 函数和过滤器检查值是否为有效数字。错误可以通过 default 过滤器捕获。

  • {{ float("not_a_number") }} - 模板将无法渲染

  • {{ "not_a_number" | sin }} - 模板将无法渲染

  • {{ float("not_a_number", default="无效数字!") }} - 渲染为 "无效数字!"

  • {{ "not_a_number" | sin(default="无效数字!") }} - 渲染为 "无效数字!"

  • float(value, default) 函数将尝试将输入转换为 float。如果失败,则返回 default 值,或如果省略则引发错误。

  • float(default) 过滤器将尝试将输入转换为 float。如果失败,则返回 default 值,或如果省略则引发错误。

  • is_number 如果输入可以被 Python 的 float 函数解析并且解析后的输入不是 infnan,则返回 True,在所有其他情况下返回 False。值得注意的是,Python 的 bool 将返回 True,但字符串 "True""False" 都将返回 False。也可以作为过滤器使用。

  • int(value, default) 函数类似于 float,但转化为 int。与 float 一样,它具有过滤器形式,如果省略 default 值会引发错误。小数部分被丢弃:int("1.5")1

  • bool(value, default) 函数将值转换为 truefalse。 被认为是 true 的值包括:布尔值 true、非零的 intfloat,以及字符串 "true""yes""on""enable""1"(不区分大小写)。相反值:布尔值 false、整数或浮点数 0,以及字符串 "false""no""off""disable""0"(同样不区分大小写)。 如果值未在此列表中,函数将返回 default 值,或如果省略则引发错误。 此函数尤其适用于 二进制传感器开关 或类似实体的状态,因此其行为与 Python 的内置 bool 转换不同,例如:"on""off""unknown" 都将被视为 true,但 "" 将被视为 false;如果需要,使用 not not value 或类似结构。 像 floatint 一样,bool 也具有过滤器形式。使用 none 作为默认值在使用 立即 if 过滤器 时特别有用:它可以在一行中处理所有三种可能的情况。

  • log(value, base, default) 将计算输入的对数。当省略基数时,默认为 e - 自然对数。如果 valuebase 不能转换为 float,则返回 default 值,或如果省略则引发错误。也可以用作过滤器。

  • sin(value, default) 将返回输入的正弦值。如果 value 不能转换为 float,则返回 default 值,或如果省略则引发错误。可以用作过滤器。

  • cos(value, default) 将返回输入的余弦值。如果 value 不能转换为 float,则返回 default 值,或如果省略则引发错误。可以用作过滤器。

  • tan(value, default) 将返回输入的正切值。如果 value 不能转换为 float,则返回 default 值,或如果省略则引发错误。可以用作过滤器。

  • asin(value, default) 将返回输入的反正弦值。如果 value 不能转换为 float,则返回 default 值,或如果省略则引发错误。可以用作过滤器。

  • acos(value, default) 将返回输入的反余弦值。如果 value 不能转换为 float,则返回 default 值,或如果省略则引发错误。可以用作过滤器。

  • atan(value, default) 将返回输入的反正切值。如果 value 不能转换为 float,则返回 default 值,或如果省略则引发错误。可以用作过滤器。

  • atan2(y, x, default) 将返回 y / x 的四象限反正切。如果 yx 不能转换为 float,则返回 default 值,或如果省略则引发错误。可以用作过滤器。

  • sqrt(value, default) 将返回输入的平方根。如果 value 不能转换为 float,则返回 default 值,或如果省略则引发错误。可以用作过滤器。

  • max([x, y, ...]) 将获取序列中的最大项。使用与内置 max 过滤器相同的参数。

  • min([x, y, ...]) 将获取序列中的最小项。使用与内置 min 过滤器相同的参数。

  • average([x, y, ...], default) 将返回序列的平均值。如果列表为空或包含非数字值,则返回 default 值,或如果省略则引发错误。可以用作过滤器。

  • median([x, y, ...], default) 将返回序列的中位数。如果列表为空或包含非数字值,则返回 default 值,或如果省略则引发错误。可以用作过滤器。

  • statistical_mode([x, y, ...], default) 将返回序列的众数(最频繁出现的值)。如果列表为空,则返回 default 值,或如果省略则引发错误。可以用作过滤器。

  • e 数学常数,约等于 2.71828。

  • pi 数学常数,约等于 3.14159。

  • tau 数学常数,约等于 6.28318。

  • 过滤器 round(precision, method, default) 将输入转换为数字并四舍五入到 precision 位小数。四舍五入有四种模式,默认模式(未指定任何模式)将进行 even 取整。如果输入值无法转换为 float,则返回 default 值,或如果省略则引发错误。

    • round(precision, "floor", default) 将始终向下舍入到 precision 位小数
    • round(precision, "ceil", default) 将始终向上舍入到 precision 位小数
    • round(1, "half", default) 将始终四舍五入到最近的 .5 值。此模式的 precision 应为 1
  • 过滤器 value_one|bitwise_and(value_two) 对两个值执行按位与(&)操作。

  • 过滤器 value_one|bitwise_or(value_two) 对两个值执行按位或(|)操作。

  • 过滤器 value_one|bitwise_xor(value_two) 对两个值执行按位异或(^)操作。

  • 过滤器 ord 将返回长度为一的字符串的整数,表示字符的 Unicode 码点,当参数为 Unicode 对象时,或在参数为 8 位字符串时返回字节的值。

  • 过滤器 multiply(arg) 将输入转换为数字并乘以 arg。在与 map 的列表操作中非常有用。

  • 过滤器 add(arg) 将输入转换为数字并加上 arg。在与 map 的列表操作中非常有用。

复杂类型检查

除了字符串和数字,Python(和 Jinja)还支持列表、集合和字典。为帮助您测试这些类型,可以使用以下测试:

  • x is list 将返回 x 是否为 list(例如 [1, 2] is list 将返回 True)。
  • x is set 将返回 x 是否为 set(例如 {1, 2} is set 将返回 True)。
  • x is tuple 将返回 x 是否为 tuple(例如 (1, 2) is tuple 将返回 True)。
  • x is datetime 将返回 x 是否为 datetime(例如 datetime(2020, 1, 1, 0, 0, 0) is datetime 将返回 True)。
  • x is string_like 将返回 x 是否为字符串、字节或字节数组对象。

请注意,在 Home Assistant 中,Jinja 有内置测试器用于 boolean (True/False)、callable(任何函数)、float(带小数的数字)、integer(不带小数的数字)、iterable(可以迭代的值,如 listsetstring 或生成器)、mapping(主要为 dict ,但也支持其他类字典类型)、numberfloatint)、sequence(可迭代且可索引的值,如 liststring)以及 string

类型转换

尽管 Jinja 原生支持将可迭代的值转换为 list,但不支持转换为 tupleset。为帮助您使用这些类型,可以使用以下函数:

  • set(x) 将任何可迭代 x 转换为 set(例如 set([1, 2]) == {1, 2}
  • tuple(x) 将任何可迭代 x 转换为 tuple(例如 tuple("abc") == ("a", "b", "c")

请注意,在 Home Assistant 中,将值转换为 liststringintfloat 时,Jinja 的内置函数名称与每种类型相对应。

迭代多个对象

zip() 函数可用于在一次操作中迭代多个集合。

{% set names = ['客厅', '餐厅'] %}
{% set entities = ['sensor.living_room_temperature', 'sensor.dining_room_temperature'] %}
{% for name, entity in zip(names, entities) %}
  {{ name }} 温度是 {{ states(entity) }}
{% endfor %}

zip() 还可以拆分列表。

{% set information = [
  ('客厅', 'sensor.living_room_temperature'),
  ('餐厅', 'sensor.dining_room_temperature')
] %}
{% set names, entities = zip(*information) %}
名称是 {{ names | join(', ') }}
实体是 {{ entities | join(', ') }}

处理原始数据的函数和过滤器

这些函数用于将原始值的 bytes 格式处理为 Python 本地类型值,或反之亦然。packunpack 函数也可以用作过滤器。它们使用 Python 3 的 struct 库。 参见 Python struct 库文档

  • 过滤器 value | pack(format_string) 将本地类型转换为 bytes 类型对象。这将调用函数 struct.pack(format_string, value)。如果发生错误或 format_string 无效,则返回 None
  • 函数 pack(value, format_string) 将本地类型转换为 bytes 类型对象。这将调用函数 struct.pack(format_string, value)。如果发生错误或 format_string 无效,则返回 None
  • 过滤器 value | unpack(format_string, offset=0) 将尝试将 bytes 对象转换为本地 Python 对象。参数 offset 定义输入的 bytes 基于缓冲区开头的偏移位置(以字节为单位)。这将调用函数 struct.unpack_from(format_string, value, offset=offset)。如果发生错误或 format_string 无效,则返回 None。注意过滤器 unpack 只会返回第一个 bytes 对象,尽管函数 struct.unpack_from 支持返回多个对象(例如,format_string">hh")。
  • 函数 unpack(value, format_string, offset=0) 将尝试将 bytes 对象转换为本地 Python 对象。参数 offset 定义输入的 bytes 基于缓冲区开头的偏移位置(以字节为单位)。这将调用函数 struct.unpack_from(format_string, value, offset=offset)。如果发生错误或 format_string 无效,则返回 None。注意函数 unpack 只会返回第一个 bytes 对象,尽管函数 struct.unpack_from 支持返回多个对象(例如,format_string">hh")。

Note

一些示例:

  • {{ 0xDEADBEEF | pack(">I") }} - 渲染为 b"\xde\xad\xbe\xef"

  • {{ pack(0xDEADBEEF, ">I") }} - 渲染为 b"\xde\xad\xbe\xef"

  • {{ "0x%X" % 0xDEADBEEF | pack(">I") | unpack(">I") }} - 渲染为 0xDEADBEEF

  • {{ "0x%X" % 0xDEADBEEF | pack(">I") | unpack(">H", offset=2) }} - 渲染为 0xBEEF

字符串过滤器

  • 过滤器 urlencode 将对象转换为百分比编码的 ASCII 文本字符串(例如,用于使用 application/x-www-form-urlencoded 的 HTTP 请求)。
  • 过滤器 slugify(separator="_") 将给定字符串转换为 “slug”。
  • 过滤器 ordinal 将整数转换为一个数字,表示系列中的位置(例如,1st2nd3rd4th 等)。
  • 过滤器 value | base64_decode 将 base 64 字符串解码为字符串,默认使用 utf-8 编码。
  • 过滤器 value | base64_decode("ascii") 将 base 64 字符串解码为字符串,使用 ascii 编码。
  • 过滤器 value | base64_decode(None) 将 base 64 字符串解码为原始字节。

一些示例:

  • {{ "aG9tZWFzc2lzdGFudA==" | base64_decode }} - 渲染为 homeassistant
  • {{ "aG9tZWFzc2lzdGFudA==" | base64_decode(None) }} - 渲染为 b'homeassistant'

正则表达式

有关正则表达式的更多信息,请参见 Python 正则表达式操作

  • 测试 string is match(find, ignorecase=False) 将在字符串开头使用正则表达式匹配查找表达式。
  • 测试 string is search(find, ignorecase=False) 将在字符串的任何位置使用正则表达式匹配查找表达式。
  • 过滤器 string|regex_replace(find='', replace='', ignorecase=False) 将使用正则表达式将查找表达式替换为替换字符串。访问 replace 中的匹配组可以使用 '\\1''\\2' 等。
  • 过滤器 value | regex_findall(find='', ignorecase=False) 将查找值中查找表达式的所有正则表达式匹配并返回匹配数组。
  • 过滤器 value | regex_findall_index(find='', index=0, ignorecase=False) 将执行与 regex_findall 相同的操作,并返回索引处的匹配项。

合并操作响应

使用操作响应,我们可以收集来自多个实体的信息。使用 merge_response 模板,我们可以将多个响应合并为一个列表。

变量 描述
value 传入值(必须是操作响应)。

entity_id 键将附加到模板输出列表中的每个字典中,以指示来源。如果输入字典已包含 entity_id 键,则模板将失败。

如果原始服务调用提供的是字典列表,value_key 键将附加到模板输出列表中的每个字典中作为来源的参考,例如,calendar.get_eventsweather.get_forecasts

这两个键的示例可以在 示例合并日历操作响应 模板输出中查看。

示例



{% set combined_forecast = merge_response(response) %}
{{ combined_forecast[0].precipitation | float(0) | round(1) }}


示例如何排序

可以直接使用 Jinja 的 sort 过滤器根据特定键对列表中的字典进行排序。



{{ merge_response(calendar_response) | sort(attribute='start') | ... }}


示例合并日历操作响应

{
  "calendar.sports": {
    "events": [
      {
        "start": "2024-02-27T17:00:00-06:00",
        "end": "2024-02-27T18:00:00-06:00",
        "summary": "篮球 vs. 火箭",
        "description": "",
      }
    ]
  },
  "calendar.local_furry_events": {"events": []},
  "calendar.yap_house_schedules": {
    "events": [
      {
        "start": "2024-02-26T08:00:00-06:00",
        "end": "2024-02-26T09:00:00-06:00",
        "summary": "医生预约",
        "description": "",
      },
      {
        "start": "2024-02-28T20:00:00-06:00",
        "end": "2024-02-28T21:00:00-06:00",
        "summary": "烤个蛋糕",
        "description": "好吃的东西",
      }
    ]
  },
}

{{ merge_response(response_variable) }}

[
  {
    "description": "",
    "end": "2024-02-27T18:00:00-06:00",
    "entity_id": "calendar.sports",
    "start": "2024-02-27T17:00:00-06:00",
    "summary": "篮球 vs. 火箭",
    "value_key": "events"
  },
  {
    "description": "",
    "end": "2024-02-26T09:00:00-06:00",
    "entity_id": "calendar.yap_house_schedules",
    "start": "2024-02-26T08:00:00-06:00",
    "summary": "医生预约",
    "value_key": "events"
  },
  {
    "description": "好吃的东西",
    "end": "2024-02-28T21:00:00-06:00",
    "entity_id": "calendar.yap_house_schedules",
    "start": "2024-02-28T20:00:00-06:00",
    "summary": "烤个蛋糕",
    "value_key": "events"
  }
]

示例非列表操作响应

{
  "vacuum.deebot_n8_plus_1": {
    "header": {
      "ver": "0.0.1",
    },
    "payloadType": "j",
    "resp": {
      "body": {
        "msg": "ok",
      },
    },
  },
  "vacuum.deebot_n8_plus_2": {
    "header": {
      "ver": "0.0.1",
    },
    "payloadType": "j",
    "resp": {
      "body": {
        "msg": "ok",
      },
    },
  },
}

{{ merge_response(response_variable) }}

[
  {
    "entity_id": "vacuum.deebot_n8_plus_1",
    "header": {
      "ver": "0.0.1",
    },
    "payloadType": "j",
    "resp": {
      "body": {
        "msg": "ok",
      },
    },
  },
  {
    "entity_id": "vacuum.deebot_n8_plus_2",
    "header": {
      "ver": "0.0.1",
    },
    "payloadType": "j",
    "resp": {
      "body": {
        "msg": "ok",
      },
    },
  },
]

处理传入数据

模板的另一个部分是处理传入数据。它允许您修改传入数据并提取您关心的数据。这将仅适用于在其文档中提到支持此功能的平台和集成。

这取决于集成或平台,但通常可以使用 value_template 配置关键字定义模板。当新值到达时,您的模板将被渲染,同时有权访问以下值,除了常规的 Home Assistant 扩展:

变量 描述
value 传入值。
value_json 解析为 JSON 的传入值。

这意味着如果传入值看起来像以下示例:

{
  "on": "true",
  "temp": 21
}

on 的模板将是:

"{{value_json.on}}"

响应中的嵌套 JSON 也被支持:

{
  "sensor": {
    "type": "air",
    "id": "12345"
  },
  "values": {
    "temp": 26.09,
    "hum": 56.73
  }
}

只需使用“方括号表示法”来获取值。

"{{ value_json['values']['temp'] }}"

以下概述包含几种获取所需值的选项:

# 传入值:
{"primes": [2, 3, 5, 7, 11, 13]}

# 提取第一个质数
{{ value_json.primes[0] }}

# 格式化输出
{{ "%+.1f" | value_json }}

# 数学
{{ value_json | float * 1024 if is_number(value_json) }}
{{ float(value_json) * (2**10) if is_number(value_json) }}
{{ value_json | log if is_number(value_json) }}
{{ log(1000, 10) }}
{{ sin(pi / 2) }}
{{ cos(tau) }}
{{ tan(pi) }}
{{ sqrt(e) }}

# 时间戳
{{ value_json.tst | timestamp_local }}
{{ value_json.tst | timestamp_utc }}
{{ value_json.tst | timestamp_custom('%Y', True) }}

要评估响应,请转到 开发者工具 > 模板,在“模板编辑器”中创建输出,并检查结果。

{% set value_json=
    {"name":"Outside",
     "device":"weather-ha",
     "data":
        {"temp":"24C",
         "hum":"35%"
         } }%}

{{value_json.data.hum[:-1]}}

使用模板与 MQTT 集成

MQTT 集成 在很大程度上依赖于模板。模板用于将传入有效负载(值模板)转换为状态更新,或传入操作(命令模板)转换为配置 MQTT 设备的有效负载。

使用值模板与 MQTT

值模板将接收到的 MQTT 有效负载转换为有效状态或属性。 接收到的 MQTT 可以在 value 模板变量中找到,如果接收到的 MQTT 有效负载是有效 JSON,则可以在 value_json 模板变量中找到。

此外,MQTT 实体值模板可用的模板变量还包括 entity_idnamethisthis 属性指的是 MQTT 项目的 实体状态

Note

值模板示例:

给定有效负载:

{ "state": "ON", "temperature": 21.902 }

模板 {{ value_json.temperature | round(1) }} 渲染为 21.9

使用命令模板与 MQTT

对于操作,命令模板被定义为格式化发出的 MQTT 有效负载,以便与远程设备支持的格式匹配。当执行某个操作时,模板变量 value 在大多数情况下包含操作数据,除非在文档中另行指定。

此外,MQTT 实体命令模板可用的模板变量还有 entity_idnamethisthis 属性指的是 MQTT 项目的 实体状态

Note

将 JSON 数据与命令模板结合的示例:

给定值 21.9,模板 {"temperature": {{ value }} } 渲染为:

{
  "temperature": 21.9
}

使用原始数据的命令模板示例:

当命令模板渲染为有效的 bytes 字面量时,MQTT 将以原始数据发布此数据。在其他情况下,将发布字符串表示。因此:

  • 模板 {{ "16" }} 渲染为有效负载编码字符串 "16"
  • 模板 {{ 16 }} 渲染为有效负载编码字符串 "16"
  • 模板 {{ pack(0x10, ">B") }} 渲染为原始 1 字节有效负载 0x10

其他需要记住的事项

以数字开头的 entity_id

如果您的模板使用以数字开头的 entity_id(示例:states.device_tracker.2008_gmc),则必须使用括号语法以避免因不当呈现 entity_id 而引起的错误。在给定示例中,设备跟踪器的正确语法应该是:states.device_tracker['2008_gmc']

操作符的优先级

默认的操作符优先级是过滤器(|)的优先级高于除括号外的所有操作。这意味着:

{{ states('sensor.temperature') | float / 10 | round(2) }}

将把 10 四舍五入为 2 位小数,然后将 states('sensor.temperature') 除以 10(四舍五入为 2 位小数,因此是 10.00)。这种行为可能不是预期的,但优先级规则意味着这样。