找回密碼
 立即註冊
惟家LINE群QRCODE
    查看: 0|回覆: 0

    HA 模板實戰:最常用的寫法與五個會咬人的陷阱

    [複製鏈接]

    !lvup!   100%

    363

    主題

    27

    回帖

    2200萬

    積分

    管理員

    積分
    22005752
    發表於 3 天前 | 顯示全部樓層 |閱讀模式
    模板(template)是 HA 最強也最容易出錯的地方。

    這篇整理實際會用到的,還有那些「看起來對但會壞」的。



    先講最重要的工具

    開發者工具 → 模板


    • 左邊寫,右邊即時顯示結果
    • 所有模板都該先在這裡測過再貼進設定檔
    • 錯誤訊息在這裡看得到,寫進 YAML 之後就只剩「自動化沒反應」


    這個習慣可以省下八成的除錯時間。

    基本的取值
    1. {{ states('sensor.客廳溫度') }}
    2.   → 取狀態,回傳字串
    3. {{ states.sensor.客廳溫度.state }}
    4.   → 一樣的東西,但實體不存在時會報錯(上面那個回傳 'unknown')
    5. {{ state_attr('light.客廳', 'brightness') }}
    6.   → 取屬性
    7. {{ is_state('light.客廳', 'on') }}
    8.   → 回傳 true / false,比 states(...) == 'on' 好讀
    9. {{ is_state_attr('climate.客廳', 'hvac_action', 'cooling') }}
    10.   → 屬性的比對
    複製代碼



    陷阱一:狀態全部是字串

    這是第一名的坑。
    1. {{ states('sensor.溫度') > 25 }}
    2.   → 錯!字串跟數字不能比,會報錯或給錯的答案
    3. {{ states('sensor.溫度') | float(0) > 25 }}
    4.   → 對。float(0) 的 0 是「轉不出來就當 0」
    複製代碼

    一定要加預設值


    • float(0) —— 轉小數,失敗給 0
    • int(0) —— 轉整數
    • 沒加預設值的話,感測器變 unavailable 就整個模板爆掉


    字串比較的災難
    1. '30' > '9'   →  false   (因為 '3' < '9')
    複製代碼

    所以溫度 30 度會被判定為「小於 9 度」。

    陷阱二:unavailable 和 unknown

    感測器不是只有「有值」和「沒值」


    • unavailable —— 裝置離線、整合出錯
    • unknown —— 還沒有值(剛重啟)
    • none —— 實體不存在


    保險的寫法
    1. {% set t = states('sensor.溫度') %}
    2. {% if t not in ['unknown', 'unavailable', 'none'] %}
    3.   {{ t | float(0) }}
    4. {% else %}
    5.   0
    6. {% endif %}
    複製代碼

    或者用 has_value(HA 2023.9 之後有)
    1. {{ has_value('sensor.溫度') }}
    複製代碼

    在自動化的條件裡也可以直接用
    1.     conditions:
    2.       - condition: template
    3.         value_template: "{{ has_value('sensor.溫度') }}"
    複製代碼

    陷阱三:空白和換行

    YAML 的多行模板會留下換行
    1.         message: >
    2.           {{ states('sensor.溫度') }}
    3.   → 結果是 "26.5\n"(後面有換行)
    複製代碼

    解法
    1.         message: >-
    2.           {{ states('sensor.溫度') }}
    3.   → >- 會把結尾的換行拿掉
    複製代碼

    或者在模板裡用 trim
    1. {{ states('sensor.溫度') | trim }}
    複製代碼

    控制 Jinja 的空白
    1. {%- if ... -%}    左右兩邊的空白都吃掉
    2. {%- if ... %}      只吃左邊
    3. {% if ... -%}      只吃右邊
    複製代碼

    寫長模板的時候這個很重要,不然輸出會亂七八糟。

    陷阱四:now() 不會觸發更新

    這個很陰險。
    1. template:
    2.   - sensor:
    3.       - name: 現在幾點
    4.         state: "{{ now().hour }}"
    複製代碼

    這個感測器不會自己更新 ——
    HA 不知道「時間」是什麼東西,不會監聽它。

    解法一:加 trigger
    1. template:
    2.   - triggers:
    3.       - trigger: time_pattern
    4.         minutes: "/1"
    5.     sensor:
    6.       - name: 現在幾點
    7.         state: "{{ now().hour }}"
    複製代碼

    解法二:讓它依賴一個會變的實體
    1.         state: >
    2.           {% set _ = states('sensor.time') %}
    3.           {{ now().hour }}
    複製代碼

    sensor.time 來自「時間與日期」整合,每分鐘更新

    同樣的問題會出現在


    • now()utcnow()
    • today_at()
    • as_timestamp(now())




    陷阱五:模板自己觸發自己
    1. template:
    2.   - sensor:
    3.       - name: 總用電
    4.         state: >
    5.           {{ states('sensor.總用電') | float(0) + 1 }}
    複製代碼

    這會無限迴圈。

    模板感測器會監聽「模板裡出現的所有實體」
    包含它自己。

    要累加的話用 utility_meter 或 statistics,不要自己算。

    實用的寫法集

    一、找出所有開著的燈
    1. {{ states.light
    2.    | selectattr('state', 'eq', 'on')
    3.    | map(attribute='name')
    4.    | list | join('、') }}
    複製代碼

    二、算數量
    1. {{ states.light | selectattr('state', 'eq', 'on') | list | count }}
    複製代碼

    三、找出某個區域的實體
    1. {{ area_entities('客廳') }}
    2. {{ area_entities('客廳') | select('match', 'light\\.') | list }}
    複製代碼

    四、找出開了很久的燈
    1. {{ states.light
    2.    | selectattr('state', 'eq', 'on')
    3.    | selectattr('last_changed', 'lt', now() - timedelta(hours=2))
    4.    | map(attribute='name') | list }}
    複製代碼

    五、取多個感測器的平均
    1. {% set ids = ['sensor.客廳溫度', 'sensor.臥室溫度', 'sensor.書房溫度'] %}
    2. {{ (ids | map('states') | map('float', 0) | sum / ids | count) | round(1) }}
    複製代碼

    六、取最大 / 最小
    1. {{ [states('sensor.a') | float(0),
    2.     states('sensor.b') | float(0)] | max }}
    複製代碼

    七、標籤(label)篩選(HA 2024.4 之後)
    1. {{ label_entities('夜間照明') }}
    複製代碼

    標籤比區域彈性 —— 一個實體可以有很多標籤。

    八、時間判斷
    1. {{ now().hour >= 22 or now().hour < 7 }}        深夜
    2. {{ now().weekday() >= 5 }}                       週末(0=週一)
    3. {{ now().strftime('%Y-%m-%d %H:%M') }}           格式化
    4. {{ (now() - states.light.客廳.last_changed).total_seconds() / 60 }}
    5.                                                  開了幾分鐘
    複製代碼

    九、條件式的值
    1. {{ '開著' if is_state('light.客廳', 'on') else '關著' }}
    複製代碼

    十、四捨五入與格式
    1. {{ 26.567 | round(1) }}              26.6
    2. {{ 1234567 | round(0) }}             1234567
    3. {{ "%.1f" | format(26.567) }}        26.6
    4. {{ 0.856 * 100 | round(0) }}         86
    複製代碼

    十一、判斷實體存不存在
    1. {{ states('sensor.可能不存在') not in ['unknown', 'unavailable'] }}
    2. {{ 'sensor.某某' in states.sensor | map(attribute='entity_id') | list }}
    複製代碼

    十二、取觸發的資訊(在自動化裡)
    1. {{ trigger.entity_id }}
    2. {{ trigger.to_state.state }}
    3. {{ trigger.from_state.state }}
    4. {{ trigger.to_state.attributes.friendly_name }}
    5. {{ trigger.id }}
    複製代碼

    十三、裝置與區域的對應
    1. {{ area_name(trigger.entity_id) }}       這個實體在哪個區域
    2. {{ device_id(trigger.entity_id) }}       實體屬於哪個裝置
    3. {{ device_entities(device_id) }}         那個裝置有哪些實體
    複製代碼

    這組很好用:一個自動化服務全家的人體感應器,
    area_name(trigger.entity_id) 就知道要開哪個房間的燈。

    除錯的技巧

    一、拆開來測

    長模板出錯的時候,一段一段貼到模板工具裡測。

    二、用 | list 看中間結果
    1. {{ states.light | selectattr('state', 'eq', 'on') | list }}
    複製代碼

    先看篩選出什麼,再接後面的處理。

    三、在自動化裡插通知
    1.       - action: persistent_notification.create
    2.         data:
    3.           message: "現在的值是 {{ 你的模板 }}"
    複製代碼

    四、看日誌

    設定 → 系統 → 日誌,模板錯誤會寫在裡面。

    ---

    下一篇:HA 的藍圖(Blueprint) ——
    把你的自動化包裝成可以重複使用、可以分享的模板。
    您需要登入後纔可以回帖 登入 | 立即註冊

    本版積分規則

    Archiver|手機版|惟家的智能論壇

    GMT+8, 2026-9-24 10:30 , Processed in 0.079089 second(s), 26 queries .

    快速回覆 返回頂部 返回列表