Home Assistant 中文文档 下载 App

Jinja2 模板语言在 Home Assistant 中的应用

模板在 Home Assistant 里是什么

Home Assistant 内置了 Jinja2 模板引擎。模板让你可以在配置里动态计算值,而不是把所有东西写死。模板用 {{ }}(输出)和 {% %}(逻辑块)包裹。

模板几乎可以用在 Home Assistant 的所有配置里:

模板里的全局上下文

在模板里你可以访问 Home Assistant 的运行时数据:

对象含义示例
states所有实体的当前状态states('sensor.temperature')
state_attr实体的属性state_attr('sensor.weather', 'humidity')
now()当前时间now().strftime('%Y-%m-%d %H:%M')
utcnow()UTC 时间类似 now(),UTC 时区
as_timestamp把字符串转时间戳as_timestamp('2024-01-01')
distance()两点距离distance('zone.home', 'zone.work')
is_state判断实体是否某状态is_state('light.kitchen', 'on')
has_value实体是否有有效值has_value('sensor.battery')
expand获取组内所有实体expand('group.all_lights')

基础语法

输出值

{{ states('sensor.living_room_temperature') }}
# → 24.5

{{ state_attr('sensor.sun', 'next_rising') }}
# → 2025-01-15 06:45:00

过滤器(管道符)

Jinja2 的过滤器用 | 管道符链式调用:

{{ states('sensor.temperature') | float + 2 | int }}
# 把温度转浮点 +2 度,再转整数

{{ states('sensor.battery') | int }}%
# 电量转整数

{{ states('sensor.power') | round(1) }}
# 保留一位小数

{{ state_attr('sensor.sun', 'next_rising') | as_local | strftime('%H:%M') }}
# 把 UTC 时间转本地时间,格式化为 HH:MM

条件(if)

{% if is_state('person.me', 'home') %}
  主人在家
{% else %}
  主人不在家
{% endif %}

循环(for)

{% for light in states.light %}
  {% if light.state == 'on' %}
    {{ light.name }}({{ light.entity_id }})
  {% endif %}
{% endfor %}

实战场景

场景一:通知里动态填充数据

alias: 温度过高推送
trigger:
  - platform: numeric_state
    entity_id: sensor.kitchen_temperature
    above: 30
action:
  - service: notify.mobile_app_me
    data:
      title: "厨房高温预警!"
      message: >
        厨房当前温度已达 {{ states('sensor.kitchen_temperature') }}°C!
        湿度 {{ states('sensor.kitchen_humidity') }}%
        请检查是否有设备过热。
      data:
        ttl: 0
        priority: high

场景二:Lovelace Markdown 卡片

type: markdown
content: |
  ## 家里概况

  👤 **{{ states('sensor.person_count') }}** 人在家
  ☀️ **{{ states('sensor.sun_elevation') | round(1) }}**° 太阳高度
  🌡️ 客厅 **{{ states('sensor.temperature_living_room') }}°C**
  💡 **{% if is_state('light.living_room', 'on') %}开{% else %}关{% endif %}**
  🔋 电池 **{{ states('sensor.battery_state') }}%**
  ⚡ 太阳能 **{{ states('sensor.solar_production') }}W**

场景三:Template Sensor(自定义传感器)

Template Sensor 是用模板创建的自定义实体——基于其他实体的状态计算出新的值:

template:
  - sensor:
      # 客厅平均温度(多传感器平均)
      - name: 客厅平均温度
        state: >
          {{ ((states('sensor.temp_a') | float) + (states('sensor.temp_b') | float)) / 2 | round(1) }}
        unit_of_measurement: "°C"

      # 家里总能耗(所有打开的灯的功率之和)
      - name: 家里总光功率
        state: >
          {% set ns = namespace(total = 0) %}
          {% for light in expand('group.all_lights') %}
            {% if light.state == 'on' and state_attr(light.entity_id, 'brightness') %}
              {% set ns.total = ns.total + (state_attr(light.entity_id, 'brightness') | int) %}
            {% endif %}
          {% endfor %}
          {{ ns.total }}
        unit_of_measurement: "lm"

      # 上班通勤时间估算
      - name: 预计通勤时间
        state: "{{ distance('zone.home', 'zone.work', 'km') | round(1) * 4 }}"
        unit_of_measurement: "分钟"

场景四:条件开关的动态状态

switch:
  - platform: template
    switches:
      auto_mode:
        friendly_name: "自动模式"
        value_template: >
          {{ is_state('input_boolean.auto_mode', 'on') }}
        turn_on:
          service: input_boolean.turn_on
          target:
            entity_id: input_boolean.auto_mode
        turn_off:
          service: input_boolean.turn_off
          target:
            entity_id: input_boolean.auto_mode

场景五:自动化里的动态目标

action:
  - service: light.turn_on
    target:
      entity_id: >
        {% if is_state('person.me', 'home') %}
          {{ states('sensor.preferred_lights') }}
        {% else %}
          light.entrance
        {% endif %}

模板调试技巧

Developer Tools → Template 编辑器

Home Assistant 内置了一个模板调试器:Settings → System → Developer Tools → Template

在左侧输入模板,右侧实时显示渲染结果。也可以选一个 Trigger(比如 state trigger)来模拟自动化触发时的上下文。

错误排查

模板报错时 Home Assistant 会在日志里写 Jinja2 错误信息。常见错误:

错误原因修复
UndefinedError: 'xxx' is undefined引用了不存在的实体或对象检查实体 ID 拼写
TypeError: unsupported operand types对字符串做了数值运算用 `float 或 int` 先转类型
Filter 'xxx' is not defined用了不存在的过滤器查 Jinja2 文档看正确名称
渲染为空实体可能是 unknown 或 unavailable先检查实体是否有有效值

高级技巧

ns namespace(在 for 循环里累积变量)

{% set ns = namespace(total = 0) %}
{% for entity in states.sensor %}
  {% if state_attr(entity.entity_id, 'device_class') == 'power' and entity.state != 'unknown' %}
    {% set ns.total = ns.total + (entity.state | float) %}
  {% endif %}
{% endfor %}
{{ ns.total | round(0) }}

避免 Division by Zero

{% set production = states('sensor.solar') | float %}
{% set consumption = states('sensor.grid') | float %}
{% if consumption != 0 %}
  自给率:{{ ((production / consumption) * 100) | round(1) }}%
{% else %}
  自给率:100%(无电网消耗)
{% endif %}