第 12 章

Home Assistant Event、Device、Time 與排程觸發

同一個「觸發」可能來自事件匯流排、實體狀態、裝置自動化或本機計時器;它們的資料、重連行為與副作用並不相同。本章依 HA WebSocket 0.80.3 的固定原始碼逐一劃清邊界,並以只接 Debug、所有 HA 節點保持停用的方式規劃安全驗證。

為何需要本章

如果只看節點名稱,很容易把 Events: all、Device、Time 都理解為「收到某件事就送出訊息」。實際上,Events: all 訂閱 Home Assistant 事件或 WebSocket 用戶端生命週期;Device 可處於 Trigger 或 Action 模式;Time 依指定實體的狀態或屬性建立排程;Calendar 會輪詢行事曆並安排計時器。選錯入口會造成事件量暴增、重連後重複執行,或把原本只讀的流程變成對裝置有副作用的流程。

本章所有設定都是非執行規格。任何 Events、Device、Calendar、Tag、Webhook、Zone、Sentence、Time、Time entity 與 Fire Event 節點均須保持停用;輸出只接 Debug,Debug 也只顯示經遮罩的必要欄位。不要填入真實 webhook ID、裝置 ID、標籤 ID、人物位置、語句或行事曆內容。

若需求只是「某個實體由 off 變成 on」,優先回到第 9 章 Events: state;若需求是觸發後查一次現在狀態,使用第 10 章 Current State。本章的節點不是為了取代狀態節點,而是處理狀態模型以外的事件與排程來源。

先分清兩層整合:Events: all、Events: calendar、Tag、Time、Zone 與 Fire Event 等一般節點使用套件的 Home Assistant Server WebSocket/API 連線;0.80.3 的 Sentence、Webhook、Time entity 與 Device automation 還要求在 Home Assistant 另行安裝並載入 hass-node-red custom integration。只安裝 Node-RED palette 套件並不足夠,也不要自行假設 custom integration 版本。整體分類與 Server 連線先回看第 8 章。

四種觸發模型不可混用

模型觀察來源適合問題主要邊界
事件匯流排Home Assistant event type 與 event data不是單一實體狀態的離散事件空白事件類型可能接收大量事件;event data 可能含識別資訊
實體狀態state_changed 的 old_state、new_state門窗、燈、感測值等狀態轉換屬性更新也可能形成事件;unknown、unavailable 必須分流
裝置自動化特定整合所提供的 device trigger/action按鍵手勢或整合明確提供的裝置能力能力由整合與裝置決定,不保證每個裝置都有同樣選項
時間排程實體中的時間值、行事曆項目或 Node-RED 計時器在未來時刻產生訊息時區、日光節約時間、重啟、過期時間與資料更新都會改變結果

事件名稱不是實體 ID。例如事件類型用來選擇匯流排訊息,實體 ID 用來取得狀態,device ID 用於裝置登錄,tag ID 與 webhook ID 又是不同識別空間。不要因為字串看似相近就互換,也不要把 UI 顯示名稱當成穩定 ID。

接收與發送也不是同一風險。Events: all、Tag 與 Zone 是輸入型節點;Fire Event 會向 Home Assistant 發送事件;Device 的 Action 模式會送出裝置動作;Sentence 的 response 模式,以及 trigger 模式設定的固定回應或逾時 fallback,都會對語音助理回應;Time entity 的 set 模式會更新實體值。所有發送或回應設定在測試流程中一律停用且不接入口。

以觀察代替執行的六步驗證

  1. 寫出單一觸發契約。

    先記錄「來源、最小篩選、允許的欄位、斷線時怎麼辦、重複時怎麼辦」。用 PLACEHOLDER_EVENT_TYPE、PLACEHOLDER_ENTITY_ID、PLACEHOLDER_DEVICE_ID 等整值佔位符,不放真實環境資料。

  2. 選擇最窄的節點。

    狀態轉換選 Events: state;既有裝置自動化能力才選 Device Trigger;固定於實體時間選 Time;行事曆項目選 Calendar。不要以 Events: all 的空白事件類型作為萬用入口。

  3. 建立隔離副本並停用 HA 節點。

    只在測試工作區畫出「停用的觸發節點 → 欄位允許清單(allowlist)→ Debug」。所有發送型節點不接線,尤其 Device Action、Fire Event、Sentence response、帶固定/fallback 回應的 Sentence trigger、Time entity set 與任何後續 Action。

  4. 用人工建立的假訊息驗證分支。

    在純核心 Inject/Change 節點中建立不含真實 ID 的資料,檢查正常、重複、缺欄位、unknown、unavailable 與過期時間分支。這是資料路由測試,不會模擬 Home Assistant 對每個事件的完整語意。

  5. 逐一審查重連與時間。

    記錄部署、Node-RED 重啟、Home Assistant 重啟、WebSocket 斷線、跨午夜與 DST 切換時預期行為。任何不確定情況都走「不動作」分支,不能以重送真實動作驗證。

  6. 先觀察、後另行核准。

    若組織准許連到測試用 Home Assistant,仍一次只啟用一個唯讀觸發節點,保留下游 Action 停用;確認遮罩後的事件計數與時間戳。正式動作必須另走變更審查,本章不授權啟用。

Events: all、Sentence 與 Fire Event

Events: all:只在事件類型明確時使用

0.80.3 的 Events: all 可填 Event Type,也可留空接收所有事件;編輯器與官方文件都明確警告,留空可能壓迫 WebSocket 訊息佇列。Event data 必須是 JSON 物件,執行時以子集合比對事件內容。這種比對適合再縮小已知事件,不應取代輸入驗證。

特別的事件類型 home_assistant_client 用來接收用戶端生命週期,但這些訊息只表示資料載入或 client 階段,不代表某個裝置狀態已符合業務條件。不要建立等待 connected 的 gate;應以版本實際輸出的生命週期事件更新流程健康狀態,再重查必要狀態,不能直接補送動作。

0.80.3 版本細節:controller 內另有 connecting、connected、disconnected、error handler,但實際事件註冊只接上 states_loaded、services_loaded、running 與 ready;未接線的 connected 不是此節點輸出契約。設定「只在 Home Assistant running 後輸出」會抑制一般事件,但 client events 另行輸出,因此重連分支必須另外處理。
重連閘門:以實際接線的 running/ready 作健康訊號後,仍須用 Current State 查詢必要實體、檢查資料時間與去重鍵;若狀態缺失就停止。生命週期事件只可更新流程健康狀態,不能直接補送動作。

Sentence:觸發語句與回應是兩個方向

Sentence 節點支援 trigger 與 response 模式,並要求另裝的 hass-node-red custom integration。trigger 模式由 Home Assistant 整合送入句子、比對結果、裝置 ID 與 response ID;輸出訊息會帶內部 _sentence_response_id。response 模式讀取這個 ID 並把動態回應送回整合。語句可能透露家庭活動與裝置位置,Debug 應只留下分類結果,不記錄原句或裝置 ID。

Trigger 不必等 response 節點才有外部輸出:固定 response 會直接回覆,dynamic 模式若逾時也可送 fallback response。觀察用途必須把固定 response 與 fallback 留白/設為不回應,且不連 response 模式節點;不能只因 mode=trigger 就稱為純輸入。逾時或遺失 response ID 應結束該次處理,不得拿舊 ID 重試。

Fire Event:它是輸出,不是測試按鈕

Fire Event 收到訊息後會透過 WebSocket 發送 fire_event,event type 可來自設定或訊息,data 可經模板或 JSONata 求值。Home Assistant 中其他自動化可能監聽該事件,因此即使「只是自訂事件」仍可能觸發警報、通知或控制。範例只寫 PLACEHOLDER_EVENT_TYPE 與空白資料,節點停用、不接 Inject、不得部署後試按。

Device、Tag、Webhook 與 Zone 的識別邊界

Device:先確認 custom integration 與裝置能力

Device 節點可選 Trigger 或 Action,這條 device automation 路徑要求 Home Assistant 端的 hass-node-red custom integration 已載入。Trigger 模式透過整合註冊並在裝置觸發時輸出;Action 模式則在收到 Node-RED 訊息後,把設定的動作與 capabilities 送給 Home Assistant。可選的 trigger、action 與 capabilities 來自該裝置所屬整合,不是 0.80.3 為所有裝置提供的共同清單。因此不能宣稱每個感測器都有「按一下」、每盞燈都有同一亮度欄位,或不同品牌會產生相同資料。

若 UI 查不到裝置能力,先回 Home Assistant 確認裝置登錄與整合支援;不要手寫猜測的物件。測試只保留 Device Trigger 且停用,Device Action 不接線。真正要控制服務時,通常應依第 11 章 Action 節點檢查 action、target 與 data。

Tag:標籤與掃描器都是敏感 ID

Tag 可選特定標籤或全部標籤,並可限制掃描裝置;未指定 devices 時,0.80.3 會接受任何掃描裝置。輸出可包含 tag name、tag ID、device ID 與 user ID。這些欄位足以推測人員與位置,應把篩選設到最窄,僅輸出匿名用途代碼;「全部標籤」不得用於正式流程。

Webhook:知道 ID 可能就能呼叫

Webhook 節點要求 Home Assistant 端另裝的 hass-node-red custom integration,並向該整合登錄 webhook ID 與允許的 POST、PUT、GET、HEAD 方法,接收 payload、headers 與 params。它不是 Node-RED HTTP In,也不代表具備使用者登入驗證。實際可達性由 Home Assistant 的網路與 webhook 機制決定;不要為了方便公開 Home Assistant,也不要把 webhook ID 放在教學、截圖、版本庫或 Debug。

本章不建立端點。PLACEHOLDER_WEBHOOK_ID 只是不可解析的標記;Webhook 節點保持停用,不填真值、不測 curl、不顯示外部網址。若未來確有需求,另做威脅模型、方法允許清單、來源驗證、速率限制與撤銷程序。

Zone:位置跨界不是即時在場保證

Zone 依人物或追蹤實體的舊、新座標與 zone 座標判斷 enter、leave 或兩者。沒有 old_state/new_state、位置資料或 zone 資料時不輸出。定位延遲、GPS 漂移與半徑邊界可造成抖動;位置資料也是高度敏感資訊。安全流程只輸出「匿名區域狀態已變」並加持續時間或冷卻,不保存座標。

Time 與 Time entity:排程和可寫時間實體

Time 節點讀取指定實體的 property,預設為 state。本章只保證先驗證過的日期字串(優先使用含 offset 的 ISO 8601)與 HH:MM[:SS];若上游是 epoch 數值,必須先明確轉成 ISO 字串再交給 Time,不能直接傳數字。節點會套用正負 offset,選配在 offset 範圍隨機化,並可依勾選星期每日重複。實體狀態或屬性變更時會重建計時器。值為 unavailable、型別不符、日期無效、offset 不是數字或未選任何重複星期,都應視為設定或資料錯誤而不輸出。

輸入情況安全解讀處置
一次性時間已過不應立即補執行記錄過期狀態;即使忽略警告也不把它當 catch-up
HH:MM 每日重複依執行環境本地時間建立排程跨 DST 前後人工驗證下一次執行時間
負 offset 加隨機可能被限制以避免落在現在以前不要用於必須精準或法規要求的時刻
實體更新或重連排程可能被重算下游以事件日期加用途建立去重鍵
unknown/unavailable不是合法時間走異常分支,不沿用先前值

DST 不是單純加減一小時。某些本地時間可能一天不存在或重複兩次。你應以 Home Assistant、Node-RED 主機及來源行事曆的實際時區做隔離測試,記錄春季跳時與秋季回撥的期望,且將下游動作設計成冪等。需要絕對時間時,保存含 offset 的 ISO 時間並在顯示層轉換,不要混合無時區字串。

Time entity 是另一個節點:它要求 Home Assistant 端另裝的 hass-node-red custom integration,並搭配 Entity config 把時間值暴露給 Home Assistant,模式為 listen、get 或 set。set 是寫入操作,0.80.3 驗證 24 小時制 HH:MM[:SS] 並補上秒數;listen/get 則處理現有值。這不是一般 WebSocket Time trigger 的替代品。測試中三種模式都保持停用,尤其 set 不接任何不受信任訊息。

Calendar 排程、重啟與去重

Events: calendar 選擇一個 calendar 實體,依 start 或 end,加上正負 offset 觸發;Filter 是對 summary 的包含比對。0.80.3 原始碼大約每 15 分鐘輪詢,查詢視窗帶 1 分鐘重疊,取得項目後在記憶體佇列安排精確計時器,並以已送出快取降低重複。全天事件先對齊午夜再套 offset。

這些機制改善一般排程,但不是「永不漏、永不重」。輪詢間最後一刻新增或修改可能來不及被發現;Node-RED 重啟會清掉記憶體計時器與快取,重新掃描後的結果取決於當時查詢視窗;網路錯誤會重試,但該輪最終失敗時沒有可用項目。故障恢復策略必須由你的業務規則決定,不能宣稱節點保證補發。

安全的「會議前提醒」規格

  • Calendar 節點保持停用,calendar 使用 PLACEHOLDER_CALENDAR_ENTITY;Filter 使用不含姓名與地點的分類詞。
  • 輸出只保留匿名 UID 雜湊、事件開始時間與分類,不記 description、location 或原 summary。
  • 以「匿名 UID+發生日期+提醒類型」建立去重鍵;鍵有合理期限,不永久保存行程。
  • 過期超過容忍窗、時間解析失敗、剛重連或資料缺失時,送到有限診斷 Debug,不接通知 Action。
  • 真正通知節點仍停用,待第 14 章通知與異常分支的速率限制驗證後另行核准。

如果排程只需等待某實體條件,而非到某個日曆時刻,請改用第 13 章 Wait Until 設計。兩者分別處理「何時」與「條件何時成立」,不要以長時間 Delay 猜測外部狀態。

故障排除:先停用,再看來源

  • Events: all 訊息暴增:立即停用節點,確認 Event Type 是否空白、event data JSON 是否真的縮小範圍。清空 Debug 後只用已知的 PLACEHOLDER_EVENT_TYPE 重新審查,不以全事件模式找答案。
  • Device 下拉沒有預期 trigger/action:這通常表示目前整合或裝置未暴露該能力。確認 Home Assistant 裝置登錄、整合狀態與 0.80.3 相容性;不要複製別種裝置的設定或手工猜 capability。
  • Time 顯示 invalid、unavailable 或 in the past:檢查 property 路徑、原始型別、時區、offset 與星期選擇。將錯誤資料分流,不用舊時間、不把 ignore past date 誤當成補執行。
  • Calendar 漏掉臨時變更:比對事件更新時間與約 15 分鐘輪詢邊界,確認 API 查詢是否曾重試失敗。若需求不能容忍輪詢延遲,停止自動化並重新選架構,而不是縮短未公開的內部常數。
  • 重連後看似重複:比較來源事件 ID、業務去重鍵、running 時間與部署時間。先阻擋所有 Action,再判斷是來源重送、狀態重新載入或流程重啟;不要直接刪除去重資料試跑。
  • Webhook、Tag、Zone 或 Sentence Debug 洩漏資料:停用並刪除該次 Debug 訊息,輪替已暴露的 webhook ID,遮罩 tag/device/user/座標/原句;依事件回報程序處理,不把原始輸出貼到公開 issue。

固定來源與相關節點

本章技術事實以 HA WebSocket 0.80.3 精確提交為版本邊界;官方節點文件用於操作語意補充,若後續文件已更新,以固定提交原始碼判斷本章基線。

本章涵蓋 10 個相關節點:Device、Events: all、Events: calendar、Fire Event、Sentence、Tag、Time、Webhook、Zone 與 Time entity。Fire Event、Device Action、Sentence response、帶固定/fallback 回應的 Sentence trigger 與 Time entity set 都有外部副作用,示例中一律停用;Device automation、Sentence、Webhook 與 Time entity 另需 custom integration。

常見問題

可以把 Events: all 的 Event Type 留空來探索事件嗎?
不建議。0.80.3 明確警告全事件可能壓迫 WebSocket 訊息佇列,而且事件資料可能含敏感內容。先從 Home Assistant 開發者文件或隔離環境找出精確事件類型,再以最小欄位允許清單觀察。
Device 節點為何沒有別人教學中的選項?
Device 能力由 Home Assistant 整合與實際裝置提供,不是每個整合都有同樣 trigger、action 或 capabilities。不要憑空手填;缺少能力時改用可驗證的實體狀態或核准 Action。
可以用 home_assistant_client 的 connected 建立重連 gate 嗎?
不可以。0.80.3 的 Events: all 實際只接上 states_loaded、services_loaded、running 與 ready,connected handler 並未接線。以 running/ready 作健康訊號後仍要重查必要狀態、驗證時間窗與去重鍵;沒有明確 catch-up 規則時不動作。
Time 的 Repeat Daily 能保證 DST 當天只執行一次嗎?
本章不做這種保證。排程依執行環境時間建立,DST 可能產生不存在或重複的本地時間。用隔離環境測試兩個切換方向,並讓下游以日期與用途去重。
Webhook ID 可以當作一般公開網址的一部分嗎?
不可以視為公開資訊。知道 ID 的呼叫者可能觸發流程;不要放進版本庫、畫面或 log。可達性、認證與反濫用必須另行評估,本章不建立或測試 webhook。
Calendar 節點重啟後會補發所有錯過項目嗎?
不能宣稱會。0.80.3 重新輪詢並安排仍在查詢視窗的項目,但記憶體佇列與已送快取會隨程序結束。你的流程必須明定過期容忍窗、去重與不補發條件。