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 會輪詢行事曆並安排計時器。選錯入口會造成事件量暴增、重連後重複執行,或把原本只讀的流程變成對裝置有副作用的流程。
若需求只是「某個實體由 off 變成 on」,優先回到第 9 章 Events: state;若需求是觸發後查一次現在狀態,使用第 10 章 Current State。本章的節點不是為了取代狀態節點,而是處理狀態模型以外的事件與排程來源。
四種觸發模型不可混用
| 模型 | 觀察來源 | 適合問題 | 主要邊界 |
|---|---|---|---|
| 事件匯流排 | 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 模式會更新實體值。所有發送或回應設定在測試流程中一律停用且不接入口。
以觀察代替執行的六步驗證
- 寫出單一觸發契約。
先記錄「來源、最小篩選、允許的欄位、斷線時怎麼辦、重複時怎麼辦」。用
PLACEHOLDER_EVENT_TYPE、PLACEHOLDER_ENTITY_ID、PLACEHOLDER_DEVICE_ID等整值佔位符,不放真實環境資料。 - 選擇最窄的節點。
狀態轉換選 Events: state;既有裝置自動化能力才選 Device Trigger;固定於實體時間選 Time;行事曆項目選 Calendar。不要以 Events: all 的空白事件類型作為萬用入口。
- 建立隔離副本並停用 HA 節點。
只在測試工作區畫出「停用的觸發節點 → 欄位允許清單(allowlist)→ Debug」。所有發送型節點不接線,尤其 Device Action、Fire Event、Sentence response、帶固定/fallback 回應的 Sentence trigger、Time entity set 與任何後續 Action。
- 用人工建立的假訊息驗證分支。
在純核心 Inject/Change 節點中建立不含真實 ID 的資料,檢查正常、重複、缺欄位、unknown、unavailable 與過期時間分支。這是資料路由測試,不會模擬 Home Assistant 對每個事件的完整語意。
- 逐一審查重連與時間。
記錄部署、Node-RED 重啟、Home Assistant 重啟、WebSocket 斷線、跨午夜與 DST 切換時預期行為。任何不確定情況都走「不動作」分支,不能以重送真實動作驗證。
- 先觀察、後另行核准。
若組織准許連到測試用 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;應以版本實際輸出的生命週期事件更新流程健康狀態,再重查必要狀態,不能直接補送動作。
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 精確提交為版本邊界;官方節點文件用於操作語意補充,若後續文件已更新,以固定提交原始碼判斷本章基線。
- HA WebSocket 0.80.3 固定提交 2cbbb69
- 官方 Events: all 文件、0.80.3 Device automation 文件、Calendar 文件
- 官方 Time 文件、0.80.3 Time entity 文件、0.80.3 Webhook 文件
- 0.80.3 Sentence 文件與hass-node-red custom integration(不假設其版本)
本章涵蓋 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。