Modbus 透傳 vs. JSON 動態配置
討論背景與現狀痛點
目前系統在藍牙傳輸上面臨資料點位(Data Map)發散與變動頻繁的問題。例如:
- 資料結構不一致:總電壓等核心欄位,在某些版本區分高低位元(Hi/Lo Byte)1,某些版本則無。
- 拓撲變動影響格式:BCU 或 Rack 層級常會夾帶 Pack 資料。當 Pack 數量不同時,整個數據排列格式會完全不同,導致軟體端維護極為困難2。
為解決此痛點,目前韌體端與軟體端分別提出以下兩種架構主張:
方案一:韌體端主張 —— 基於既有 Modbus 格式進行藍牙透傳 (UART Bridge)3
機制說明:藍牙晶片扮演「隱形序列訊號線(UART Line)」的角色。MCU 透過串口(UART)送出 Modbus 原始 binary 資料4,藍牙晶片原封不動透過無線電波發射,接收端(App/EMS)收到後再依 Modbus 協定解析。
優點
- 時程優勢:已有完整的既有 Spec(規格書),可立即啟動開發,不需為藍牙通訊重新制定每點位的傳輸協議。
- 概念簡單:採用「輸入 = 輸出」的直覺概念,資料不需在通訊層做二次轉換,維護與除錯(Debug)相對單純5。
- 精力聚焦:韌體人員可將核心精力專注在底層控制程式的優化與穩定度,減少通訊層的開發耗時。
缺點
- 格式無法相容:目前各專案的 Modbus 格式發散、缺乏共同點(如上述 Hi/Lo 差異、Pack 數量變動導致 Data Map 大幅位移)。
- 新舊版斷層:新舊版本的 Modbus 位址差異甚大,絕對不可能做到向下相容(Backward Compatibility),軟體端需針對不同版本寫死(Hard-code)不同的解析邏輯。
若採用此方案,後續需討論項目
- 統一重構 Modbus 規範:韌體端必須根據目前所有專案的痛點,徹底重新制定一套通用的新版 Modbus 格式規範6,避免各專案持續發散,嚴禁每個專案/版面使用特殊格式。
- 陣痛期評估:新舊格式差異極大,需評估既有客戶/設備升級時的陣痛與相容性策略。
方案二:軟體端主張 —— 導入 JSON 設定檔與通用數據介面 (Interface)7
機制說明:不論底層藍牙傳的是什麼格式,軟體端(App/平台)在程式碼中建立一套通用的數據結構介面(Interface)。透過導入外部的 JSON 設定檔8(定義欄位、Offset、倍率等),讓程式動態去解析並填入該介面。
優點
- 架構極具彈性:只要全面性的 Interface 討論定義得當,後續不論韌體規格怎麼變,軟體端只需要更新 JSON 規格設定檔即可完成動態對接,無需修改並重新編譯/發布 App 程式碼9。
- 一勞永逸:前期雖然需要較多討論,但完成後可大幅減少未來新專案或版本更新時的重複開發與測試時間。
缺點
- 前期溝通成本高:需要兩端非常縝密地討論出「各架構都能通用的 Interface(最大公約數)」,若思慮不周,未來一旦修改底層 Interface10,兩端都需同步大改。
- 讀寫機制驗證:主要的技術攻關點會落在「寫入(控制/設定參數)」與「讀出(狀態監控)」時,動態對照機制是否會產生時序(Timing)11 或型態轉換(Type Casting)12 的問題。
總結
這場討論本質上是在決定「痛在前面(軟韌體花時間做抽象化架構)」還是「痛在後面(韌體每次重排點位、軟體每次重寫解析)」。
- 若選擇方案一 (Modbus):焦點在於「韌體規格的強制作風」。公司必須下定決心規範出一套嚴格的 BMS Modbus Data Map 標準,往後所有專案只能增改、不能破壞基礎結構。
- 若選擇方案二 (JSON Interface):焦點在於「軟韌體邊界的定義」13。兩端需共同召開架構會議,定義出第一版通用的 JSON Schema14(例如:如何定義單體電壓陣列、如何定義高低位元),並拿現有最複雜的專案規格來做概念驗證(POC)15。
註解解說
Footnotes
-
高低位元 (Hi/Lo Byte):在工業通訊(如 Modbus 16-bit 暫存器)中,若要傳輸大於 65535 的大數值(如高精度的總電壓、總電流),韌體必須拆成高位(High Byte)與低位(Low Byte)存放在連續的兩個暫存器中。若各專案定義的擺放順序(大端序/小端序)不統一,軟體解析出來會變成完全無意義的亂數。 ↩
-
軟體端維護極為困難:此處指軟體端(App/平台)需要為每個不同專案的設備「硬編碼(Hard-code)」。只要硬體點位一變,App 程式碼就得人工修改並重新發布更新,無法做到用同一個 App 相容所有現場設備。 ↩
-
藍牙透傳 (UART Bridge):在此模式下,藍牙晶片不對資料做任何解析或拆包,僅在實體層扮演「無線序列訊號線」的角色,MCU 丟出什麼,手機端就收到完全相同的二進位串流。 ↩
-
Modbus 原始 binary 資料:通常指 Modbus RTU 格式,由設備位址、功能碼、數據內容及 2 位元組的 CRC(循環冗餘校驗)碼組成的緊湊二進位流。 ↩
-
維護與除錯相對單純:因為通訊協定完全等於實體線路(如 RS-485),韌體工程師可以直接用邏輯分析儀(Logic Analyzer)掛載在硬體腳位上抓取原始 Binary 訊號進行比對,不需要軟體端協助模擬。 ↩
-
通用的新版 Modbus 格式規範:例如「固定空間預留(Padding)」。不論專案實際上是 8 個還是 12 個 Pack,暫存器地圖一律固定預留 16 個 Pack 的空間(沒用到的填 0),確保後續的核心欄位不會因為 Pack 數量變動而發生偏移(Offset)。 ↩
-
通用數據介面 (Interface):軟體架構上的「抽象化(Abstraction)」。指軟體程式內部不再直接認硬體位址(如 0x4001),而是宣告一個標準的資料物件(如 BmsDataModel,內含總電壓、最高單體電壓等變數),上層 UI 只跟這個 Interface 拿資料。 ↩
-
JSON 設定檔:由軟體定義的結構化表格。例如:{“fieldName”: “total_v”, “address”: “0x4001”, “multiplier”: 0.1}。當新專案變更點位時,只需置換這張對照表,軟體解析引擎就會自動到新位址讀取資料並換算。 ↩
-
無需修改並重新編譯/發布 App 程式碼:未來若有新產品或韌體改版,軟體團隊只需將新的 JSON 設定檔上傳至伺服器,App 啟動時自動線上下載(類似 OTA 更新配置),即可立刻支援新硬體,不需重新提交到 App Store / Google Play 審核。 ↩
-
修改底層 Interface:此方案的最大風險。如果未來產品線出現全新架構(例如從「單一 Rack」變成「多櫃並聯」),原先定義的資料欄位(Interface)無法承載,軟軟兩端(前端 App 與後端平台)或韌體都必須面臨同步大改的風險。 ↩
-
時序問題 (Timing / Race Condition):當通訊層引入動態解析後,若 App 在同一個通訊週期內同時執行「讀取狀態」與「寫入控制參數」,需確保動態映射層不會因為非同步處理延遲,而導致寫入錯誤位址或通訊逾時(Timeout)。 ↩
-
型態轉換 (Type Casting):硬體暫存器存放的資料型態各有不同(如 int16、uint32、float)。動態解析時,軟體端必須根據 JSON 宣告進行精準的二進位強制轉換,否則極易因正負號(Signed/Unsigned) or 溢位(Overflow)導致數值異常。 ↩
-
軟硬體邊界的定義:此處特指釐清兩端在資料處理上的職責分工與對接協議。方案一側重於在硬體底層規範出高標準的固定排列,由韌體端確保傳輸資料的結構化;方案二則側重於在軟體端建構靈活的映射引擎,由軟體端來消化規格變動帶來的解析邏輯彈性。 ↩
-
JSON Schema:定義 JSON 設定檔語法規則的規範(例如:強制規定每個點位必須包含 address、data_type、unit 等欄位),確保軟軟、軟韌之間在撰寫配置檔時有統一的語法標準。 ↩
-
概念驗證 (POC - Proof of Concept):在全面投入開發前進行的實驗性測試。例如由韌體提供現有最複雜的暫存器清單,軟體端試著寫出對應的 JSON 檔並用主程式讀取,驗證是否真的能在「完全不改動 App 原始碼」的前提下,100% 正確解析出數據。 ↩