🔑 關鍵洞察
✦ AI·GEN作者想用語音控制 Home Assistant 裡的燈,選了不走雲端的路:用 home-assistant-matter-hub 把 HA 實體包成 Matter 橋接器,由客廳的 Google TV Streamer 4K 當中樞。配對時 Google Home 兩次顯示「找不到裝置」,原因卻完全不同:第一次是橋接器使用 Matter 測試廠商碼 0xFFF1,必須先在 Google Home Developer Console 建立 VID/PID 一致的 integration;第二次是伺服器的 ufw 只有 IPv4 的區網規則,ICMPv6 被預設放行所以 ping6 正常,真正走 IPv6 的 UDP 5540 卻被丟掉,而且配對後的連線走 link-local,fe80::/10 也必須放行。文中附上每一關的確認方法與修正指令,並記錄配對後的實際使用狀況:燈要改成「燈」類型並指定房間,而且語音必須講出房間;冷氣的溫度死區設定讓整個橋接器崩潰,換到 RiDDiX 維護的 fork 後解決;冷氣只能指定絕對溫度。
上一篇把房間那盞自發電開關的燈接進了 Home Assistant,手機可以控制之後,接下來想做的就是躺在床上用語音開關燈。
做法是用 home-assistant-matter-hub 把 HA 的實體包成一個 Matter 橋接器,由客廳的 Google TV 當中樞,整條路都在區網裡,不經過雲端。架設本身不難,花時間的是配對:Google Home 一直顯示「找不到裝置」,查到最後發現是兩個問題疊在一起,一個是 Google 對開發中裝置的限制,另一個是我自己伺服器的防火牆。
下面照順序整理:為什麼選 Matter、matter-hub 的設定、配對要經過哪幾關,以及每一關卡住時我怎麼確認、怎麼修。最後記錄配對完之後,語音控制實際用起來的幾個問題。
為什麼選 Matter#
HA 接 Google Home 大概有三種做法:
| Nabu Casa Cloud | 手動 google_assistant 整合 | Matter 橋接 | |
|---|---|---|---|
| 費用 | 月費訂閱 | 免費 | 免費 |
| 控制路徑 | 手機 → Google 雲 → Nabu Casa → HA | 手機 → Google 雲 → 你家對外的 HA | 區網直連 |
| 要對外開放 | 不用 | 要把 /api/google_assistant 給 Google 打 | 不用 |
| 斷網能用 | 不行 | 不行 | 可以 |
| 前提 | 付費 | Google Cloud 專案、OAuth、服務帳號 | 家裡要有 Matter 中樞 |
Matter 橋接需要一台 Matter 中樞。我原本以為家裡的 SwitchBot Hub 3 可以,查了官方說明才知道它只是橋接器,還需要另一台第三方平台的家庭閘道:
所以一度準備走第二條路。後來想到客廳的 Google TV Streamer 4K 本身就支援 Matter 中樞,就改回第三條:不用雲、不用對外開任何端點,我的 CrowdSec 也不用擔心誤擋 Google 的伺服器。
架 matter-hub#
原本的專案(t0bst4r)在 2026 年 1 月停止維護並封存,最後一版是 v3.0.4,現在由 RiDDiX 的 fork 接手。我一開始用的是原專案,後來因為一個崩潰的 bug 換到 fork(後面會講),新架的話建議直接用 fork 的 image。
services:
matter-hub:
image: ghcr.io/riddix/home-assistant-matter-hub:latest
container_name: matter-hub
restart: unless-stopped
network_mode: host # 必要,Matter 靠 mDNS 和 IPv6 做探索
environment:
- HAMH_HOME_ASSISTANT_URL=http://<你的HA位址>:8123/
- HAMH_HOME_ASSISTANT_ACCESS_TOKEN=${HA_TOKEN}
- HAMH_HTTP_PORT=8482 # 管理網頁
- HAMH_MDNS_NETWORK_INTERFACE=enp6s0 # 主機有多張網卡時,鎖定真正的區網介面
- TZ=Asia/Taipei
volumes:
- ./data:/data幾個設定上的細節:
network_mode: host不能省,Matter 的探索走 mDNS(UDP 5353)和 IPv6,bridge 模式收不到。- 會用到 5353(mDNS)、5540/5541(Matter)、8482(管理網頁)這幾個埠,文件有寫要開。
- 權杖用 HA 的長期存取權杖:左下角頭像 → 安全性 → 最下面「長期存取權杖」。我放在
.env,權限 600。 - 我的主機除了區網還有 WireGuard、Incus 的網段、NanoKVM 的 USB 網卡和一堆 docker bridge,不限定介面的話 log 會一直出現
wg0: send Unknown system error -126。HAMH_MDNS_NETWORK_INTERFACE設成區網那張網卡之後就沒了。這只影響 log,跟後面的配對問題無關。
起來之後到 :8482 的管理網頁建立 bridge。我只想放兩盞燈進去,原本想用 entity_id 篩選,但下拉選單裡沒有這個選項:
用 pattern 填完整的 entity ID 就是精確比對。domain 選 switch 會把所有開關都送出去,platform 選 esphome 會連 WiFi 訊號、IP 這些診斷感測器一起帶過去,這兩個要小心。
存檔後會產生配對碼和 QR code,Google Home App 的路徑是 + → 設定裝置 → 已有裝置嗎? → Matter 裝置。
配對要過的幾關#
先把配對的流程拆開,後面比較好對照是哪一關出問題:
麻煩的是,第二關和第三關失敗時,Google Home 顯示的都是同一個畫面:
而且兩種情況下 matter-hub 的 log 都是空的,看不出手機有沒有找到它。我兩關都卡了。
第一關:mDNS 探索#
我一開始懷疑的是網路分段:手機和 Google TV 都在 5G,server 是有線。不過配對階段要通的是手機和 server 之間,Google TV 是配對完成後才接手當中樞的,所以電視在哪個頻段不影響配對。
要確認手機到底有沒有找到橋接器,最直接的方式是聽區網上的 mDNS。我是在 server 上寫了個小程式加入群播組、聽 5353,結果是這樣:
手機 查詢 _matterc._udp ×30
server 回應 ×30
matter-hub 收到的連線 0手機查了 30 次,server 也回了 30 次,但手機一次都沒有連過來。代表第一關是過的,問題出在後面。
TIP
有裝 avahi 的話,用 avahi-browse -rt _matterc._udp 也能看到橋接器廣播的內容,包括下一節會用到的 TXT 欄位。
第二關:Google 的 VID/PID 檢查#
把 server 的回應拆開來看,TXT 紀錄裡有一個 VP=65521+32768,換成十六進位就是 Vendor ID 0xFFF1、Product ID 0x8000。0xFFF1 是 Matter 保留給測試用的廠商碼,matter-hub 這種沒有經過 CSA 認證的專案都用它。
照 Google 的開發者文件,要讓 Google Home 配對開發中的 Matter 裝置,得先在 Google Home Developer Console 建一個 Matter integration,VID 和 PID 要跟裝置一致。測試用的 VID 可以選聯盟配給的 0xFFF1 到 0xFFF4:
matter-hub 廣播的是 0xFFF1 / 0x8000,而我的帳號底下根本沒有任何 integration。
NOTE
matter.js 的文件寫說 Google 遇到未認證裝置會跳出「允許配對未認證裝置」的確認框,但那是舊版的行為。我實際遇到的是直接顯示「找不到裝置」,沒有任何確認框。
登記的步驟:
到 Google Home Developer Console,用跟 Google Home App 同一個帳號登入,建立一個專案。
點 Add Matter integration,第一次會先出現說明頁,按 Next: Develop、Next: Setup。
Product name 自己取,Device type 選 Outlet(On-Off Plug-in Unit)。
Vendor ID 選 Test VID 的 0xFFF1,Product ID 填 0x8000,要跟橋接器廣播的值一致。
存好之後回 App 再掃一次,畫面變成了「偵測到這部裝置在附近」,這關就過了:
第三關:IPv6 連線#
按下繼續之後,又是「找不到裝置」:
這次 matter-hub 的 log 一樣是空的。我先排除了一個方向:手機一直重複查詢,我懷疑無線 AP 把有線端的群播丟掉,所以寫了個小程式把 server 的回應直接單播給手機,送了 122 次,還是沒有連線。所以手機確實拿到了紀錄。
剩下沒驗證的是連線本身。廣播裡只有 IPv6 位址(Matter 規範規定走 IPv6),手機要用這個位址連 UDP 5540。我之前從同網段的 NanoKVM 用 ping6 測過這幾個位址,都有回應,就沒再往這裡查。
後來換成測 TCP。用 HA 的 8123 當目標,同一台機器、同一個位址,分別用 ping、IPv4 和 IPv6 連:
ping -6 -c 3 <server的IPv6位址>
curl -4 -m 5 -s -o /dev/null -w '%{http_code}\n' 'http://<server的IPv4位址>:8123/'
curl -6 -m 5 -s -o /dev/null -w '%{http_code}\n' 'http://[<server的IPv6位址>]:8123/'結果:
ping6 → 通(0.6ms)
IPv4 8123 → 200
IPv6 8123 → Connection timed outIPv6 的 ping 會通,TCP 卻 timeout。timeout 和 connection refused 不一樣,refused 是對方回絕,timeout 是封包被丟掉沒有任何回應,通常是防火牆。
原因:ufw 的區網規則只有 IPv4#
這台 server 用 ,預設擋掉所有進來的連線。一週前我在桌機連不到 HA 網頁的時候,加過這種規則:
sudo ufw allow from 192.168.50.0/24 to any port 8123 proto tcp comment 'HA UI from LAN'來源指定的是 IPv4 網段,所以 ufw 只會建立 IPv4 的規則。用 sudo ufw status verbose 看就很清楚(節錄):
22/tcp ALLOW IN Anywhere
8123/tcp ALLOW IN 192.168.50.0/24 # HA UI from LAN
22/tcp (v6) ALLOW IN Anywhere (v6)沒指定來源的 Anywhere 規則都有對應的 (v6),而所有限定區網來源的規則都沒有。換句話說,這台機器在 IPv4 對區網開了需要的埠,在 IPv6 對區網一個埠都沒開。
ping6 會通,是因為 ufw 的預設規則放行 ICMPv6(IPv6 的鄰居探索需要它),mDNS 也有預設規則放行。所以探索、ping 都正常,只有真正建立連線的 TCP 和 UDP 被擋掉,而 Google Home 把這種情況也顯示成「找不到裝置」。
修法#
我加了兩條規則,讓區網的 IPv6 跟 IPv4 一樣可以進來:
sudo ufw allow from fc00::/7 comment 'LAN IPv6 (ULA)'
sudo ufw allow from fe80::/10 comment 'LAN IPv6 (link-local)'fc00::/7 是 私有位址,fe80::/10 是 ,兩者都無法從網際網路路由進來。加完之後用 IPv6 連 8123 從 timeout 變成 200,再配對一次就成功了。
fe80::/10 不能省。配對成功後的 log 裡,手機和 Google TV 跟 matter-hub 建立的兩條連線,來源都是 fe80:: 開頭的 link-local 位址,只開 ULA 的話配對完一樣會連不上。
WARNING
這兩行等於讓區網內所有 IPv6 裝置可以連這台機器的所有埠,比我 IPv4 逐埠開放的範圍還寬。我家的區網都是自己的裝置,所以這樣設。如果你的區網有不信任的裝置,可以只對這兩個範圍開放 Matter 用的 5540/5541,但 fe80::/10 要包含在內。
配對之後#
配對成功後我又加了幾個裝置:落地燈、門鈴探照燈、冷氣、除濕機、空氣清淨機、貓台座的電源,最後是 8 個。HA 的 script、automation、input_boolean 沒有放進去,它們在 Google Home 會變成一堆插座。監視器的開關也沒放,怕語音誤觸。
接著遇到三個問題。
語音一定要講房間#
第一次對 Google 說「關燈」,它關掉的是落地燈和門鈴探照燈,房間的燈沒有動:
房間那兩盞燈在 HA 裡是 switch,matter-hub 會把它們當成插座(OnOffPlugInUnit)送出去,而 Google 的「開燈」「關燈」只作用在裝置類型是燈的項目。在 Google Home App 長按裝置 → 設定 → 裝置類型改成「燈」,再幫每個裝置指定房間。
改完之後換成另一個問題:現在它們都是燈了,只說「開燈」的話,Google 會把落地燈、媽媽房間的燈一起打開。所以實際上我每次都是說「Hey Google,開我房間的燈」,講到房間才只會動到那一盞。
冷氣讓整個橋接器崩潰#
加入冷氣之後,整個 bridge 掛掉並不斷重啟,其他裝置也跟著離線:
climate_leng_qi.thermostat
minHeatSetpointLimit (1600) must be ≤ minCoolSetpointLimit (1600) − minSetpointDeadBand (200)
Failed to update bridge due to error: [constraint]Matter 的恆溫器規範要求製熱下限比製冷下限低至少 2°C,我的冷氣兩個下限都是 16°C。設定已經寫進 data/,每次啟動都會撞到,管理網頁也進不去,只能先停掉容器,用一次性的容器改 bridge 設定檔,把冷氣拿掉再啟動。
原專案已經封存,不會再修。RiDDiX 的 fork 在 8 月改了恆溫器溫度死區的處理(#435),之後也有人回報跟我一樣的狀況(#454「Thermostat with equal min_temp for heat/cool crashes entire bridge process」)。遷移只要把 image 換成 fork 的,data/ 不用動,fabric 和 node 的 ID 都沒變,Google Home 不需要重新配對。換完之後冷氣被辨識成 RoomAirConditioner,可以正常加入。
冷氣只能指定絕對溫度#
「冷氣調高一度」沒有反應,log 是:
Invoke « thermostat.setpointRaiseLower
Validation-Error 0x80: Missing mandatory field mode in field mode這個指令規格上要帶模式和調整量,看起來 Google 送來的封包少了模式欄位。「冷氣設成 26 度」走的是寫入目標溫度,可以正常運作,開關冷氣也沒問題,目前就先這樣用。
排查順序#
整理成一張表,遇到「找不到裝置」可以照順序檢查:
| 檢查項目 | 怎麼確認 | 我的結果 |
|---|---|---|
| 手機有沒有收到 mDNS 回應 | 聽 5353,或 avahi-browse -rt _matterc._udp | 有,30 問 30 答 |
| 橋接器用的 VID | TXT 的 VP 欄位,65521 就是 0xFFF1 | 測試 VID |
| Developer Console 有沒有登記 | 同一個 Google 帳號,VID/PID 一致 | 沒有,登記後出現「偵測到附近」 |
| IPv6 的 TCP/UDP 通不通 | 用 curl -6 連一個 TCP 服務,不能只看 ping | ping 通、TCP timeout |
| 防火牆有沒有 IPv6 區網規則 | sudo ufw status verbose 看有沒有 (v6) | 沒有 |
| link-local 有沒有放行 | fe80::/10 | 補上後配對成功 |
現在躺在床上說一句「Hey Google,關我房間的燈」就能關燈。跟上一篇的 RF 開關接起來,整條路算是走完了,只是房間兩個字不能省。
- home-assistant-matter-hub:RiDDiX 維護中的 forkGitHub
- Google Home Developers:建立 Matter integrationdevelopers.home.google.com
- Google Home Developer Consoleconsole.home.google.com
還沒有留言
✨ 成為第一個留言的人吧