第 20 章

MQTT、預裝節點矩陣、Palette 管理與 FlowFuse Dashboard 2 選裝且非內建擴充

MQTT 不是「把 topic 填上就完成」:broker、協定版本、TLS、credentials(認證資料)、authentication(身分驗證)、authorization(授權)、QoS、retain 與 session 各有獨立語意。Add-on 又預裝 25 個直接 dependencies,可用 inventory(清冊)辨認角色,另可在啟動時安裝套件。本章只做離線檢查,不連線、不部署。

你需要讀哪一段?

需求閱讀路徑可以略過
只需要 MQTT核心觀念、步驟 1–4、MQTT、故障排除完整套件矩陣、Palette、Dashboard
稽核預裝節點預裝節點矩陣MQTT 與 Dashboard 細節
準備安裝套件預裝節點矩陣、Palette 管理Dashboard 遷移細節
採用或遷移 DashboardPalette 管理、Dashboard 邊界MQTT 細節

先區分核心協定、預裝套件與選裝套件

Add-on 22.0.1 內嵌 Node-RED 5.0.2 與 HA WebSocket nodes 0.80.3。MQTT In、MQTT Out、mqtt-broker 是 Node-RED core;package matrix 是 Add-on image 的直接 dependency 清單;Palette Manager 與 npm_packages 會再增加第三方 server code;FlowFuse Dashboard 2 1.30.2 則是選裝且非內建。這四層不能混稱。

層級本章基線安全問題
MQTT core nodesNode-RED 5.0.2 的 mqtt in、mqtt out、mqtt-brokerbroker ACL、topic、QoS、retain、session、TLS、credentials、訊息大小
Add-on bundled direct dependenciesnode-red/package.json 精確 25 項不是每一項都會出現在 Palette;其中有 runtime、theme 與 wrapper support libraries
自訂 packagesPalette Manager 或 Add-on npm_packages/system_packages供應鏈、native code、版本漂移、啟動失敗、備份後重建
FlowFuse Dashboard 2@flowfuse/[email protected],選裝且非內建新增 HTTP route、Socket.IO、browser input 與 widgets;認證邊界另管

Add-on 有 host_network: true 與 uart: true grants,並以 media:rw、share:rw 掛載資料。這些只表示可能可達或可讀寫,不表示 MQTT、serial、File、File In、Watch 已被使用。任何外連或檔案節點仍要逐一固定目的地、topic、裝置與路徑。備份與秘密處理見第 21 章。

MQTT 的每一層都要獨立選擇

Broker 連線設定決定 transport、協定版本與 session;MQTT In 決定 subscription filter、訂閱 QoS 與輸出資料型別;MQTT Out 決定 publish topic、QoS、retain 與 MQTT 5 properties。設定一個 TLS checkbox 不會自動建立 topic ACL,選 QoS 2 也不會讓下游業務「恰好執行一次」。

項目精確語意常見誤解
Topicsubscription 可使用 +/# filter;publish topic 不可含 wildcard訂閱整棵 # 不代表資料都可公開或處理
QoS 0最多一次傳遞,可能遺失低成本不等於可忽略錯誤與斷線
QoS 1至少一次,可能重複broker acknowledgement 不等於業務副作用只執行一次
QoS 2協定層的 exactly-once delivery handshake不保證 Flow、外部 API 或裝置端到端 exactly once
Retainbroker 保留該 topic 的最後 retained message,供後來訂閱者取得不是歷史資料庫;錯誤 retained command 會持續影響新 client
Sessionclean session/clean start、client ID、session expiry 與 broker state 共同決定不是 Node-RED Context,也不等於永遠不遺失
TLS/credentialsTLS 保護傳輸與 server identity;username/password 供 broker authentication兩者都不取代每個 client 的 publish/subscribe ACL

MQTT 5 增加 properties 與訂閱 flags;選 MQTT 3.1 或 3.1.1 時不能依賴 MQTT 5 的 response topic、correlation data、content type、message expiry、user properties、no local、retain as published、retain handling 或 session expiry。先固定 broker 支援版本,再設定 nodes,不要靠 client 自動猜測。

高頻 MQTT 與大型 payload 的測試方法可沿用第 18 章:只 Debug 白名單欄位,限制案例數。Message shape 與型別基礎見第 5 章。

六步離線檢查,不建立 broker 連線

  1. 建立 topic 契約表。

    為每個資料方向寫出 placeholder topic、publisher、subscriber、payload schema、最大 bytes、允許頻率、QoS、retain 與重複處理方式。不要填真實 broker、client ID 或 credentials。

  2. 選定協定與 session。

    明確記錄 MQTT 3.1、3.1.1 或 5;再決定 clean session/clean start、client ID、auto unsubscribe 與 MQTT 5 session expiry。協定不支援的欄位保持空白。

  3. 離線讀範例 JSON。

    開啟 14-mqtt-in-out.json,確認 MQTT In 與 MQTT Out 都是 d:true;broker config 為 autoConnect:false,host/client ID/topic 全為完整 placeholder,沒有 credentials。

  4. 檢查 TLS 與 ACL。

    在文字規格中指定受控 TLS config、server certificate 驗證、獨立 client credentials,以及最小 publish/subscribe topic ACL。不得把 secret 寫入 broker URL、Function、flow export 或 Debug。

  5. 條件式:盤點 package 來源。

    只有要稽核預裝節點或評估安裝時,才對照本章 25 項 bundled matrix,並記錄精確 npm package、固定版本、維護狀態、授權、transitive dependencies、權限與移除方式。本章不執行安裝;只讀 MQTT 的讀者可略過。

  6. 條件式:記錄套件或 Dashboard 失敗與回復。

    只有涉及套件或 Dashboard 時,才列出套件啟動失敗、route/Socket.IO 問題與回復方式;MQTT 的 broker 不可達、憑證錯誤、ACL 拒絕、duplicate、stale retained message 與 session 恢復則在 topic 契約中記錄。相關節點保持停用,且不執行 I/O。

離線 MQTT 契約(不是連線設定)
broker: PLACEHOLDER_MQTT_BROKER_HOST
client id: PLACEHOLDER_MQTT_CLIENT_ID
subscribe: PLACEHOLDER_MQTT_INPUT_TOPIC
publish: PLACEHOLDER_MQTT_OUTPUT_TOPIC
protocol: PLACEHOLDER_MQTT_VERSION
max payload: PLACEHOLDER_LIMIT
credentials: 只存受控 credentials store
network action: 禁止執行

章末離線驗收

產物預期內容失敗即停止
Topic 契約placeholder topic、publisher/subscriber、payload shape/bytes/頻率、QoS、retain、ACL 與重複處理出現真實 broker/client/topic/秘密,或 payload 與 ACL 邊界未定
Protocol/session 決策固定 MQTT 版本、clean start/session、client ID 規則、expiry、TLS server 驗證與 credentials 儲存位置依賴 broker 自動猜測、共用 client ID、關閉憑證驗證,或協定不支援的欄位仍被採用
停用狀態檢查MQTT In/Out 為 d:true、broker autoConnect:false,沒有安裝、連線、Dashboard、檔案或 serial 動作任何 executable node 已啟用、會在啟動時連線,或必須接觸 broker 才能完成驗收

Node-RED 5.0.2 MQTT In、Out 與 broker 欄位

MQTT In:訂閱與輸出資料型別

欄位5.0.2 選項安全界線
Broker必要的 mqtt-broker config reference只選經核准 config;不要接受外部 broker 覆寫
Action/TopicStatic topic 時無 input;Dynamic topic 時節點有一個 input優先固定 subscription filter;dynamic action 只接受受控內部訊息
QoS0、1、2是要求的訂閱 QoS 上限;仍須處理重複與 broker 降級
MQTT 5 flagsnl no local、rap retain as published、rh retain handling 0/1/2只在 MQTT 5 broker 顯示與生效;逐項定義,不照抄預設
Outputauto-detect、legacy auto、buffer、UTF-8 string、parsed JSON、Base64自動偵測仍要驗證型別;明確 schema 優先選固定 output

MQTT In 輸出至少包含 msg.topic、msg.payload、msg.qos、msg.retain。MQTT 5 packet 可能再投影 responseTopic、correlationData、contentType、messageExpiryInterval、payloadFormatIndicator、reasonString 與 userProperties。這些都是不可信 broker/message metadata,不能直接用來選 HA Action、檔案路徑或 HTTP URL。

MQTT Out:publish 欄位與 message overrides

MQTT Out 有 Broker、Topic、QoS、Retain;Topic 留空時可取 msg.topic,QoS/Retain 留空時可取 message 值。節點中固定的 topic、QoS、retain 會優先套用。這種彈性也意味著不可信 message 可能改變 publish 行為;對外部輸入先移除或驗證 msg.topic、msg.qos、msg.retain。

MQTT 5 時另有 User Properties、Response Topic、Correlation Data、Content Type、Message Expiry。Response Topic 是協定 metadata,不會自動建立安全 RPC;reply topic ACL、correlation 唯一性、timeout、duplicate 與 late reply 都要另外設計。Publish topic 不可含 + 或 #。

mqtt-broker:連線、安全、session 與訊息

頁籤/群組5.0.2 欄位設定原則
ConnectionName、Broker、Port、Auto-connect、Use TLS/TLS config、Protocol Version 3/4/5、Client ID、KeepaliveBroker 欄填 host 或受控 scheme;固定 port,TLS 驗證 server cert;每個持久 session 使用唯一 client ID
SessionClean session(v3/v4)或 Clean start(v5)、Auto unsubscribe;v5 再有 Session Expiry 與 User Properties非 clean session 必須有 client ID;離線佇列與舊 subscription 要有上限與清理策略
SecurityUsername、Password credentialsNode-RED credentials store,不放在 broker URL 或 flow JSON;broker ACL 限制雙向 topics
MessagesBirth、Close、Will 各有 Topic、Payload、QoS、Retain只有明確生命週期需求才設定;避免 retained command,payload 必須固定且無秘密
MQTT 5 message propertiesContent Type、User Properties、Response Topic、Correlation Data、Expiry;Will 另有 Delay只在 v5 使用;限制 bytes、型別與 expiry,不讓外部輸入決定控制 topic

匯入舊 broker config 時還要檢查 persisted verifyservercert。5.0.2 編輯器定義的 legacy 預設為 false;若 TLS config 沒有提供 rejectUnauthorized,runtime 就以這個值作 fallback。舊設定必須改用核准的 TLS config,並確認最後得到 rejectUnauthorized=true;只打開 TLS toggle 只能表示使用加密 transport,不能證明已驗證 broker identity。

Protocol value 3 對應 MQTT 3.1 compatibility,4 是 MQTT 3.1.1,5 是 MQTT 5。若停用 auto-connect,5.0.2 允許由受控 action message 連線或斷線;這不是本章操作入口,不要把 MQTT In 或 HTTP In 的外部 payload 直接接去控制 broker。Add-on host_network:true 讓更多本機服務可能可達,因此 broker allowlist 與 ACL 特別重要。

範例邊界:14-mqtt-in-out.json 的 In/Out executable nodes 都固定 d:true;config node 不含 d 欄位,但以 autoConnect:false 防止建立連線。MQTT In/Out 的 broker 欄只引用同檔 config ID,真正 host、client ID、input topic、output topic 全是 placeholder。

Add-on 22.0.1 的直接 dependencies 角色摘要

固定 node-red/package.json 共 25 項直接依賴:19 項提供 Palette/config nodes,1 項是 Node-RED runtime,1 項是 editor theme,4 項是 wrapper/runtime support libraries。這不是完整 transitive tree;預裝只代表可用,不代表任何 flow 已執行它。只需 MQTT 的讀者可跳過下方參照清冊。

展開完整 25 項直接依賴矩陣
Package/固定版本角色用途與主要風險
[email protected]Wrapper support library,非 Palette node為 HTTP Basic Auth 密碼建立 hash;不得輸出明文、hash input 或誤稱可用節點
[email protected]Wrapper/runtime support library,非 Palette node解析 YAML;不可信 YAML 仍須限制 bytes、結構與型別
[email protected]Runtime 基線,非額外 Palette node提供 editor、runtime 與 core nodes;版本不可與 Add-on 22.0.1 混稱
[email protected]Palette nodes排程可能因時區、DST、重啟而重複或錯時觸發 downstream action
[email protected]Palette/config nodes連線並控制 Cast 裝置;固定裝置、媒體 URL 與網路範圍
[email protected]Palette node驗證增減/reset 輸入與重啟狀態,避免錯誤門檻觸發
[email protected]Palette/config nodes可讀 HA 並執行 action;保護 token 與環境 ID,逐節點限制副作用
[email protected]Palette/config nodes查詢/寫入資料庫;固定 query/write shape、credentials 與 retention
[email protected]Palette node處理亂序、缺失、duplicate 與 deploy 後狀態,避免錯誤時長
[email protected]Palette/config nodes可讀寫 OT/實體裝置;固定 host、unit、address、function,所有 write 保持停用
[email protected]Palette node固定時區、locale 與輸入格式,避免解析歧義或 DST 錯誤
[email protected]Palette node持久 state 與 transition 必須驗證;恢復後先確認狀態再允許 action
[email protected]Palette node位置/時區可能敏感;重啟、DST、極區日期可能漏發或重複
[email protected]Palette node明確處理時區、DST 與跨午夜,不讓訊息進錯副作用分支
[email protected]Palette nodeBase64 是 encoding 不是 encryption;輸出仍可能是 secrets
[email protected]Palette/config nodes收信/外寄會造成網路與資料外洩;固定收件者、附件與 credentials
[email protected]Palette node取得外部 feed;固定 HTTPS URL、response limit、timeout,內容視為不可信
[email protected]Palette node可透過 host network 探測;固定 host 與頻率,不收動態目的地
[email protected]Palette node不是 cryptographic random;不得生成 token、password、nonce 或授權決策
[email protected]Palette/config nodes配合 UART grant 可讀寫實體裝置;固定 device path、baud、command,write 停用
[email protected]Palette node驗證 numeric type 並限制 sample window,避免無界 state 或錯誤平滑
[email protected]Palette node座標是敏感位置;處理時區、DST 與無有效日出日落日期
@node-red-contrib-themes/[email protected]Editor theme,非 runtime Palette node只改外觀,不是安全控制或 flow 功能
[email protected]Wrapper/runtime support library,非 Palette node逐行處理資料;大型/不可信檔案仍要限制大小與錯誤
[email protected]Stack support library,非 Palette node清單存在不證明已註冊;stack/log 仍可能洩漏路徑與敏感資料

其中 Cast、InfluxDB、Modbus、email、feedparser、ping、serialport 等具有網路、資料庫或實體 I/O;BigTimer、SunEvents、suncalc 相關節點可能依時間自主產生訊息。Counter、moment、smooth 等看似純轉換,也可能把錯誤結果送往後續 action。依第 17 章把運算與副作用分層,不因「bundled」而省略驗證。

Palette、npm_packages 與啟動持久性

Palette Manager 安裝 node module,module 的 server-side JavaScript 以 Node-RED process 權限執行;這不是只有 editor icon 的 UI 變更。Add-on 的 npm_packages 則在每次啟動時切到 /opt,執行 npm install --omit=dev --omit=optional。system_packages 先用 Alpine package manager 安裝,再處理 npm packages,最後才逐行 eval init_commands;任一失敗會中止初始化。

方式持久/啟動行為控制重點
Image bundled pins隨 Add-on image 提供,25 個直接版本固定升級 Add-on 時比較 package matrix 與節點行為
Palette Manager依 Node-RED user directory 管理額外 nodes;Add-on 固定 nodesDir=/config/nodes安裝前固定版本與來源;備份/恢復後確認 dependency 可重建
npm_packagesSupervisor option declaration 持續存在,但 package 安裝每次 Add-on 啟動重跑使用完整 package 加 exact version;registry 不可達或 install error 會阻止啟動
system_packages每次啟動先 update index 再逐項安裝原生執行面、architecture、repository availability 與啟動時間
init_commands安裝後逐行 shell eval不是 package manager;不可放 secrets,不可拿來繞過 pinning,本章不執行

不要只寫 package name 或寬鬆 semver。變更紀錄至少保留 exact version、官方 registry identity、來源 repo、license、維護者、發佈日期、known advisories、Node/Node-RED compatibility、transitive tree 摘要與 rollback(回復)version。鎖定 direct version 不等於所有 transitive dependencies 都永久不變;在隔離環境產生可重建 lock/清冊,再依正式程序更新。

Add-on backup 明確排除 node_modules,所以恢復不是逐 byte 還原安裝樹;自訂 declarations、package metadata 與可用 registry 必須能重新建立相同依賴。啟動時 install 也會增加 availability 依賴。不要同時以 Palette 與 npm_packages 管同一 package,以免 ownership 與版本不清。

File/File In/Watch 與 mounted storage

Node-RED core 另有 File、File In、Watch。Add-on 的 media:rw、share:rw grants 讓容器具備讀寫可能性;不是自動授權 Flow 使用任意 path。File name 若來自 MQTT、Dashboard 或 HTTP input,可能形成 traversal、覆寫與資料外洩。固定 base directory 與 filename allowlist,限制 bytes/頻率,所有 write 保持停用。Serial nodes 同理:uart:true 是 grant,不是任意裝置命令的核准。

FlowFuse Dashboard 2 1.30.2:選裝且非內建

Add-on 22.0.1 的 25 項清單沒有 @flowfuse/node-red-dashboard。固定 package 1.30.2 宣告 Node >=14、Node-RED >=3.0.0;Node-RED 5.0.2 位於宣告範圍,但仍要在目標 Add-on 測試。Package 註冊 5 個 config nodes 與 22 個 ui-* widgets,共 27 registrations,會新增 server code、browser code、HTTP route 與 Socket.IO 通訊。

邊界1.30.2 行為必須確認
Package identity@flowfuse/[email protected]scoped package 與 exact version;不要誤選 unscoped legacy package
Routeui-base path 預設 /dashboard,並掛在 Node-RED httpNodeRoot 下Add-on 根為 /endpoint,實際外部 path、proxy rewrite 與衝突需在隔離環境確認
PWA manifest/dashboard/manifest.webmanifest 是 hard-coded route;自訂 ui-base.path 不會改它,且它位於 custom path 的 route-local Dashboard middleware 之外使用自訂 path 時,明確測試這條固定路由的外部 path、authentication、authorization 與預期回應
HTTP authDashboard 有自己的 optional HTTP middleware;Add-on editor/Ingress/direct endpoint 是不同層初始 HTML、setup、assets、page routes 都必須受同一 authentication/authorization policy
Socket.IOsocket path 組合 httpNodeRoot、dashboard path、socket.io;可另設 ioMiddlewarehandshake、same-origin、session auth、message size、proxy upgrade/stream 與 reconnect 都要測
Browser inputbutton、form、template 等 widgets 可送資料回 Flow全部視為不可信;schema、authorization、rate limit 與 downstream 副作用隔離

Add-on direct NGINX 的 /endpoint/ 不走 editor 的 Supervisor auth_request;Ingress 只允許 Supervisor ingress source,但不能外推成每個 Dashboard user 都有 widget authorization。http_node Basic Auth 是否符合你的 route 與 Socket.IO session 要以實際 proxy 路徑驗證。使用 custom Dashboard path 時,必須把 custom route 與 hard-coded /dashboard/manifest.webmanifest 分開測試 path 與 auth;切勿因 editor 有登入,就假設 dashboard page、manifest、assets 與即時 channel 自動安全。

只說明選項,不執行安裝:固定 README 的正確 package 是 scoped @flowfuse/node-red-dashboard;本章不提供 Palette 點擊安裝或 npm_packages 可直接套用值。任何選裝都要先完成上一節的 pinning、供應鏈、路由與回復計畫。

Legacy migration,不是 drop-in replacement

舊的 unscoped node-red-dashboard 以 Angular v1 為基礎,屬 legacy;本章不教 fresh install。先前 scoped 名稱 @flowforge/node-red-dashboard 已 deprecated 且不再更新。FlowFuse Dashboard 2 是重寫產品,不可宣稱既有 ui_* nodes、theme、layout、custom template、browser script、URL、authentication 或 client state 能自動、原樣遷移。

既有 legacy flow 應先清冊化 pages/groups/widgets、template code、routes、身分驗證、CSS、browser dependencies 與 message contracts,再在隔離副本逐頁重建和比對。Legacy 與新 Dashboard 並行時還要防止 route、Socket.IO、credentials 與雙重副作用衝突。不要先移除舊套件,也不要把新 widget 接到 production action。

故障排除

  • MQTT node 一直 disconnected:保持 In/Out 停用,依序檢查 placeholder、DNS、port、協定版本、TLS chain、server hostname、client ID、credentials 與 broker ACL。不要先關閉 certificate validation,也不要改成匿名連線。
  • 收到重複訊息:QoS 1、reconnect 或 subscriber restart 都可能重送。以穩定 message ID/業務 key 做有界 deduplication,記錄期限;不要假設 QoS 2 能讓 HA、email 或資料庫副作用端到端 exactly once。
  • 新訂閱立刻收到舊命令:檢查 packet 的 retain flag 與 broker retained state。不要由本章範例發佈清除訊息;先由 broker 管理程序確認 topic、權限與影響範圍。
  • 非 clean session 後 subscription 異常:確認 client ID 唯一且固定、session expiry、auto unsubscribe、broker 佇列上限與舊 client 是否仍在線。不要讓多個執行個體共用 client ID。
  • JSON output 報解析錯誤:確認 content type、encoding 與 publisher schema;不要把無法解析的 bytes 直接改成 auto-detect 後當可信 object。限制 payload bytes 並把錯誤路徑接有限 Catch。
  • Add-on 在自訂 package 後無法啟動:檢查 exact package、architecture、registry availability、system_packages → npm_packages → init_commands 的 fail-fast 順序。使用已記錄的回復版本,不能用未 pin 版本反覆試裝。
  • Palette 有 package,但找不到預期 node:先看 package role;bcryptjs、js-yaml、line-by-line、source-map-support、node-red runtime 與 theme collection 都不是一般 runtime Palette node。再檢查 package 的實際 registrations 與啟動 log。
  • Dashboard page 可開啟但即時資料不更新:分開檢查外部 route rewrite、Socket.IO path、HTTP 與 io middleware、proxy streaming/upgrade、same-origin 與 session。不要為排錯公開 direct endpoint 或移除 authentication。
  • Legacy Dashboard flow 匯入後版面/template 不同:Dashboard 2 不是 drop-in。逐頁重建 config nodes、widgets、layout、CSS、template 與 message contract,不要 fresh install legacy package,也不要把兩套 nodes 名稱直接互換。

固定版本來源與官方文件

本章用 exact commits 確認 MQTT fields、25 項直接依賴、啟動安裝順序與 Dashboard 2 邊界。外部 broker 與組織 ACL 屬環境政策,不由這些原始碼自動提供。

常見問題

QoS 2 是否保證 Home Assistant Action 只執行一次?
不保證。QoS 2 處理 MQTT client 與 broker 間的協定傳遞,不涵蓋 Flow restart、節點重試、HA API 或實體裝置。副作用仍需要 idempotency key、有界 deduplication、確認訊號與重試上限。
Broker ACL 尚未核准,可以先用共用管理者帳號完成測試嗎?
不可以。管理者 credentials 會掩蓋 publish/subscribe 權限錯誤,也擴大誤送 retained command 的影響。先停止連線設計,完成每個 client 的最小 topic ACL 與獨立 credentials;本章的離線契約不需要 broker 帳號。
範例的 mqtt-broker config 沒有 d:true,是否會自動連線?
Config node 本來就沒有 executable node 的 d 欄位。範例把 autoConnect 固定為 false,而且 MQTT In/Out 都是 d:true;host 與 client ID 也是 placeholder,所以不得替換、啟用或 Deploy。
Add-on 預裝 25 個 packages,是否表示 Palette 會多 25 組 nodes?
不是。25 是 direct dependencies:19 項是 palette/config node packages,另有 Node-RED runtime、theme,以及 bcryptjs、js-yaml、line-by-line、source-map-support 等支援 libraries。Transitive dependencies 也不在這個 25 項計數內。
可以只在 npm_packages 寫 package name,自動追最新版本嗎?
不應如此。每次啟動都會重跑安裝,未固定版本會造成不可預期漂移與 availability 風險。先記錄 exact version、來源、compatibility、transitive tree 與回復版本;本章不執行安裝。
FlowFuse Dashboard 2 是否已隨 Add-on 安裝?
沒有。@flowfuse/[email protected] 是選裝且非內建,不在 25 項 bundled direct dependencies 中。加入它會新增 route、Socket.IO 與 browser input,需要獨立的供應鏈、認證與 proxy 設計。
舊 node-red-dashboard 可以在新 Flow fresh install 嗎?
本教學不這樣做。Unscoped node-red-dashboard 是 Angular v1 legacy;新的 scoped package 是重寫,不是 drop-in。既有系統只做清冊與分階段 migration,不教新的 legacy 部署。