MQTT 整合
狀態:✅ IMPLEMENTED(v5.9.197,2026-06-02 實機驗證) | 草擬:2026-06-02
⚠️ 實作與本草案的差異:因設備 MQTT buffer 限 512B,通道清單改「分頁」——
info只回摘要(身分/net/counts),每個通道另發{prefix}/info/io/<id>(見 §3 實際格式)。 草案 §3 的「單一 info 內含 channels[]/commands[]」未採用。commands[](cmd/signal 角色標註)v1 未做, 夥伴端可由info/io/<id>的 in 通道 topic 推得:規則引擎以cmd/signal/<N>數值訊號為來源,訊號可為 latched(持續閘控)或 pulse(上升緣觸發),再對應到 TCP IO 通道。 對象:現場管理端整合方(第三方軟體團隊)+ 本控制器韌體開發本合約定義第三方現場管理軟體如何只透過 MQTT(不需逐台 IP、不需走雲端): ①探索現場有哪些設備 ②取得設備管理資訊 ③知道能對哪些 topic 做遠端控制。
已實作的底層語意:
cmd/signal/<N>為規則引擎的數值訊號來源,可作 latched(持續閘控)或 pulse(上升緣觸發),並對應到 TCP IO 邏輯通道。
#0. 完整系統 MQTT Topic 清單(權威)
<P> = mes/gateway/<UID>(24 字 UID 前綴,強制、綁設備)。以下為韌體實際 sub/pub 的系統 topic(v5.9.250 核對 src/MesMQTT.h / main.cpp)。
#探索 / 身分 / 狀態
| Topic | 方向 | Retained | 說明 |
|---|---|---|---|
mes/gateway/whoami |
管理端 → 全設備(免前綴廣播) | – | 探索全廠;各設備回 <P>/info |
<P>/cmd/info |
管理端 → 設備 | – | 指定查詢單台 → 回 <P>/info |
<P>/info |
設備 → 管理端 | – | 身分摘要(uid/name/fw/ip/online/uptime/counts) |
<P>/info/io/<id> |
設備 → 管理端 | – | 每通道控制/資料介面(分頁,避 512B 上限) |
<P>/status |
設備 → broker | ✅ | 在線狀態 birth/LWT(online) |
#命令(管理端 → 設備,<P>/cmd/#)
| Topic | Retained | 說明 |
|---|---|---|
<P>/cmd/signal/<N> |
❌ 切勿 retain | MQTT 訊號值(規則引擎來源;觸發/閘控;payload 數值) |
<P>/cmd/do/<N> |
– | 數位輸出 DO<N> 控制 |
<P>/cmd/scale/active |
– | 磅秤發重量門控(1 開 / 0 停) |
<P>/cmd/scale/calibrate |
– | 磅秤校正命令 |
<P>/cmd/telemetry |
– | 啟動聚合遙測 + keepalive(payload=間隔秒數,0 停;超時自停) |
<P>/cmd/_ping |
– | 內部 self-ping:設備每 45s 發給自己訂的此 topic,確認 MQTT subscribe 仍活著 |
#回報 / 輸出(設備 → 外)
| Topic | Retained | 說明 |
|---|---|---|
<P>/telemetry |
– | 聚合遙測(cmd/telemetry keepalive 門控才發) |
<P>/cmd/scale/calibrate/ack |
– | 磅秤校正命令 ack |
<P>/<自訂> |
– | CONVERTER 通道輸出,topic 由設定決定。慣例:<P>/scale/weight(磅秤)、<P>/power(用電量)、<P>/count(SF965 計米);見 ../guides/guide-triggered-periodic-report.md |
#授權(雲端 → 設備)
| Topic | Retained | 說明 |
|---|---|---|
<P>/license/state |
✅ | 簽章 token 下發(base64;WI-145;唯一 publisher = 雲端;retained 重連即重投最新 token) |
#雲端中繼(cloud-bridge)
- 雲端
cloud-bridge訂mes/gateway/#(全收)做 telemetry fan-out(→wss://opta.smms.com.tw/ws/telemetry);遙測拆解子主題如<P>/rs485/<idx>/<field>、<P>/power/<idx>/<field>。
小結:固定系統 topic 約 14 條(探索 5 + 命令 6 + 回報 2 + 授權 1),外加數量不定的 CONVERTER 自訂輸出 topic。 ⚠️
cmd/signal/*與所有cmd/*:MQTT 無 per-message 授權,控制權 = broker 連線權(見 §6 安全)。cmd/*一律別 retain(retained 重連會反覆灌回誤觸發)。
#1. 為什麼需要這份合約
- 雲端 config server 有自己的設備管理;但現場管理端是另一個團隊的獨立軟體,不走雲端、不便逐台用 HTTP(要先知道每台 IP)。
- 控制器與現場管理端共用現場 MQTT broker。最自然的整合面就是 MQTT:pub/sub、免逐台 IP、可廣播。
- 前綴
mes/gateway/<UID>是強制的、綁設備 UID(韌體以設備 24 字 UID 組 topicPrefix,確保每台 topic 命名空間唯一、不撞台)。 → 管理端「要先知道 UID 才能跟設備對話」,因此需要不需先知 UID 的探索機制。
#2. 介面總覽(三個能力)
| 能力 | 方向 | Topic | 機制 |
|---|---|---|---|
| 探索(whoami) | 管理端→全設備 | mes/gateway/whoami(免前綴廣播) |
廣播請求 |
| 資訊回報(info) | 設備→管理端 | <P>/info(<P>=mes/gateway/<UID>) |
回應 / 也可指定查 <P>/cmd/info |
| 在線狀態(status) | 設備→管理端 | <P>/status(retained) |
既有,birth/LWT |
探索流程:管理端訂
mes/gateway/+/info(萬用)→ 發一筆mes/gateway/whoami(payload 空或1) → 每台設備各自回<P>/info(含自己的 UID)→ 管理端即取得全廠清單與每台的控制合約。 指定查詢:已知 UID 時發<P>/cmd/info(payload 空)→ 該台回<P>/info。
#3-IMPL. 實際回應格式(v5.9.197,分頁)★以此為準
收到 whoami / cmd/info 後,設備發多筆訊息(QoS0、非 retained):
① 摘要 → <P>/info(單筆,小):
{"schema":1,"uid":"003100443033511034323932","name":"OPTA-KC","fw":"5.9.197",
"ip":"192.168.72.77","online":true,"uptimeSec":46,
"counts":{"signals":7,"rules":7,"actions":6,"tcpio":5}}② 每個啟用通道 → <P>/info/io/<channelId>(控制/資料介面,分頁):
{"id":5,"name":"啟動磅秤","dir":0,"mode":0,"proto":0,"topic":"mes/gateway/<UID>/cmd/signal/7"}
{"id":22,"name":"發出重量","dir":1,"mode":2,"proto":0,"topic":"mes/gateway/<UID>/scale/weight"}dir:0=IN(管理端可發此 topic 控制)/1=OUT(設備發、管理端訂閱取資料)mode:0=Legacy/1=Parser/2=Converterproto:0=MQTT/1=Modbus TCP- 管理端流程:訂
mes/gateway/+/info+mes/gateway/+/info/io/+→ 發mes/gateway/whoami→ 收齊全廠摘要+各通道。
以下 §3 為原始草案(單一大 JSON),保留作設計脈絡;實際以上方 §3-IMPL 為準。
#3. info 回應 payload(JSON)★合約核心〔草案,未採用〕
重點:
channels與commands就是遠端控制合約 —— 管理端據此知道「能對哪些 topic 發什麼、設備從哪些 topic 出資料」。
{
"schema": 1, // 合約版本,破壞性變更才 +1
"uid": "003100443033511034323932",
"name": "OPTA-KC-A1", // 設備名稱(設定頁可改)
"model": "MES-Gateway-Opta",
"fw": "5.9.196",
"net": { "ip": "192.168.72.77", "mac": "AA:BB:..", "online": true, "uptimeSec": 12345 },
"rs485": [ // 掛載的 Modbus 設備
{ "name": "TDA08B-1", "slave": 3, "baud": 9600, "online": true }
],
"counts": { "signals": 7, "rules": 7, "actions": 6, "tcpio": 5 },
// ★ 遠端控制 / 資料介面(TCP IO 通道)— 管理端最需要的
"channels": [
{ "name": "發出重量", "dir": "out", "proto": "mqtt",
"topic": "mes/gateway/<UID>/scale/weight", "desc": "每2秒,門控開時。payload {weight,stable,ms}" },
{ "name": "啟動磅秤", "dir": "in", "proto": "mqtt",
"topic": "mes/gateway/<UID>/cmd/signal/7", "desc": "發重量開關" }
],
// ★ 內建命令暫存器對照(cmd/signal/N,遠端控制用)
"commands": [
{ "topic": "mes/gateway/<UID>/cmd/signal/5", "role": "啟動", "kind": "pulse" },
{ "topic": "mes/gateway/<UID>/cmd/signal/6", "role": "校正參數", "kind": "latched", "note": "0=免校正/砝碼克數×100" },
{ "topic": "mes/gateway/<UID>/cmd/signal/7", "role": "發重量開關", "kind": "latched", "note": "1=開/0=關" }
]
}#欄位語意
kind:pulse=要送1再0(邊緣觸發);latched=送一次保留(狀態);level=持續電平門控。 管理端據此知道怎麼驅動每個控制 topic(pulse 須送1再送0才不會卡在觸發態,latched/level 則送一次即保留,故只要遵守 kind 語意就不會前後競態)。dir:in=管理端可發佈來控制;out=設備發佈、管理端訂閱取資料。topic:合約回完整 topic(已含前綴),管理端直接用,不必自己拼。
大小考量:
channels多時 payload 會變大。若超過單筆 MQTT/RAM 上限,v1 可: ①info只回身分+net+counts,②另設<P>/cmd/io→<P>/io專回完整 channels 清單(分頁)。實作時定。
#4. 安全性(實作前必須拍板)
- MQTT 沒有 per-message 授權 —— 任何能連上 broker 的人都能發 whoami / cmd/signal。
info是唯讀管理資訊 → 一般可接受(不含密碼/token)。- 但
cmd/signal/*(遠端控制)同樣無授權 → 控制權=broker 連線權。現場 broker 的帳密/網段隔離就是安全邊界。 - ⚠️ 若管理資訊含敏感欄位(MAC、內網拓樸)或要限制控制,需在 broker ACL(依 topic/帳號授權)層處理,韌體不做 per-client 授權。
- 廣播 whoami 要評估多設備同時回報的訊量(N 台 → N 筆 info);可加隨機抖動避免同時湧出。
#5. 與現有介面的關係
| 現有 | 提供什麼 | 為何仍需本合約 |
|---|---|---|
| 雲端 config server | 雲端設備清單/部署 | 現場第三方不走雲端 |
HTTP /api/system、/api/poll、/api/config、/api/tcpio |
同等資訊(含 deviceUid、IP、通道) | 要先知道每台 IP;MQTT 免逐台 IP |
<P>/status(retained online) |
在線與否 | 只有 online 字串、無設備資訊、無 UID 以外內容 |
本合約等於把 HTTP 的
/api/system+/api/tcpio精華,用 MQTT 廣播探索 + 回應 包成第三方好整合的形狀。
#6. 實作備註(韌體,WI-131 待排)
- 新增 handler:訂
mes/gateway/whoami(免前綴,需在既有cmd/#之外多訂一條)+<P>/cmd/info。 - 組
infoJSON:重用既有/api/system、/api/tcpio的序列化邏輯(ArduinoJson)。 - Flash 預算:目前 91.8%(餘 ~64KB)。新 handler + JSON 組裝要量 size;channels 清單可能要分頁/精簡。
- birth 是否一併豐富化(
status改 JSON,於上線時即帶身分摘要)→ 可選。 - 合約版本
schema欄位:破壞性變更才 +1,讓管理端能相容多版設備。
#7. 待夥伴團隊確認
-
info要哪些欄位(本草案:身分/net/rs485/counts/channels/commands)是否齊全? - channels 是否需要更細(每通道的 payload schema、QoS、retain 慣例)?
- 探索:廣播 whoami 足夠,還是也要定期主動 publish(管理端被動清點)?
- 安全邊界:broker ACL 由誰管?是否需要限制
cmd/*控制權?
#8. 相關文件
- 通用引擎 / API:
spec-mqtt-chain-workflow.md - HTTP API:
../api/api-firmware.md