先寫資料契約 再選編碼
收到一包能解析的JSON,並不代表收到正確的量測。先問六件事:是哪個來源、哪個測點、何時量到、數值是多少、單位是什麼、品質能否使用。MQTT負責傳遞訊息,payload的欄位與工程意義由應用定義;換成二進位編碼也不會自動解決單位與版本問題。
| 本例欄位 | 約定 | 錯誤處理 |
|---|---|---|
| schemaVersion | 整數主版本 | 未支援版本隔離 |
| source / point | 來源與測點識別 | 未知來源不入正式報表 |
| timestamp | UTC來源量測時間 | 格式及時鐘可信度分開查 |
| value / unit | 累計電能及kWh | 型別或單位不合即拒收 |
| quality | v2必填自訂品質 | 未知品質保留原包待查 |
本文用虛構電表EM01的累計電能示範。數字1250.25的單位固定為kWh,量測時間採UTC字串,來源時間不能偷偷改成broker接收時間。累計值可因換表或歸零而下降,所以兩筆相減得到負值時先查換表事件,不直接當成負耗電。
這份契約適用於能自訂MQTT payload的應用與閘道器,不代表Q06UDVCPU或QJ71C24N原生支援這些格式。選定產品前查可用記憶體、編碼函式庫、授權與版本;若現有閘道只有固定JSON格式,應在受控轉換端適配,不能憑文章新增不存在的PLC指令。
三種格式如何比較
| 格式 | 主要特性 | 部署前確認 |
|---|---|---|
| JSON | 文字鍵值,容易人工檢查 | 數字精度、UTF-8、欄位契約 |
| CBOR | 二進位資料項目,可表達多種型別 | 標籤、映射鍵、解碼器支援 |
| Protobuf | 依訊息定義及欄位號碼編碼 | IDL版本、生成工具及未知欄位處理 |
先用同一百筆實際樣本比較編碼後位元組數,再量測解碼耗時及故障排查成本。不要拿有縮排JSON和只含必要欄位的二進位樣本宣稱格式差距;兩邊要攜帶相同時間、品質、單位與識別欄位。TLS、MQTT標頭及重送另列,payload縮小不等於整條鏈路成本同比下降。
CBOR不等於壓縮過的JSON。若使用整數鍵取代文字鍵,接收端需要共同字典;若使用日期標籤或其他擴充,必須確認函式庫是否保留語意。格式能表達某型別,不代表現有PLC閘道器或資料庫就能無損接收。
Protobuf演進要維持欄位號碼的意義,刪除欄位後保留其號碼與名稱,避免後續重用造成誤解。不能因二進位可解析就認定改型別相容;跨JSON轉換或逐欄複製還可能丟掉未知欄位。把新舊產生器及接收端版本一起列入測試矩陣。
JSON的number並沒有替你選好資料庫精度。累計量很大或需要固定小數位時,決定使用可精確處理的十進位型別、整數最小單位或受驗證字串契約。不要在同一欄位有時傳數字、有時傳文字;這會讓圖表看似成功,計算卻在不同路徑發生。
用v1與v2看懂相容性
v1範例欄位為schemaVersion=1、source=EM01、point=energy、timestamp=2026-09-17T02:00:00Z、value=1250.25、unit=kWh。v1沒有quality,不得把缺欄位解讀成已確認Good。本例舊消費者將它記為LegacyUnknown,只供帶品質提示的歷史顯示,不用於自動控制。
v2保留前述數值欄位,schemaVersion改2並增加必填quality,其允許值為Good、Uncertain、Bad。這些是本例應用字串,不是完整OPC UA StatusCode。若來源是OPC UA,完整原碼另存,轉成三分類時保留映射版本,避免丟失原始診斷。
| 收到的資料 | 舊v1消費者 | 支援v1及v2的新消費者 |
|---|---|---|
| v1合法樣本 | 接收並標LegacyUnknown | 走v1規則 |
| v2且quality=Good | 版本未支援,隔離 | 驗證後接收 |
| v2缺quality | 版本拒絕 | 必填欄位失敗 |
| v2的value為字串 | 版本拒絕 | 型別失敗 |
| v2多出note | 版本拒絕 | 本例允許額外欄位並保留 |
新增欄位不一定向後相容。若舊規則只允許schemaVersion等於1,版本變2就會拒絕;若舊規則禁止額外欄位,增加quality也會拒絕。先查真正的驗證規則,不能只因新增的是可選欄位就保證舊consumer能吃。
遷移時先部署能讀兩版的新消費者,維持原發布內容,確認v1處理一致後再切換來源至v2。若必須雙發,另設遷移識別避免同一筆能源資料入庫兩次。回復方案要包含來源版本和接收規則,不能只退回一端程式。
離線驗證怎麼做
建立兩份獨立JSON Schema,清楚指定使用的草案版本。各欄位在properties宣告型別,必要欄位另列required;只有properties並不表示欄位必須存在。對schemaVersion與unit使用固定值約束,對quality使用列舉。是否允許額外欄位要明寫,避免換驗證器時誤以為有相同政策。
本例v2要求六個原有欄位加quality,value為非負number,unit固定kWh,quality限三種字串。timestamp採date-time格式,但某些驗證器把format只當註記;因此明確啟用格式檢查,再加應用層的時區與來源時鐘判斷。格式合法並不保證來源時鐘準確。
| 測試輸入 | 預期結果 | 證據 |
|---|---|---|
| 完整v2且1250.25 | 通過結構驗證 | 版本、規則ID及欄位值 |
| 刪除quality | 拒收 | required失敗位置 |
| value改成文字1250.25 | 拒收 | 型別錯誤 |
| unit改Wh | 拒收 | 固定值不符 |
| quality改Maybe | 拒收 | 不在列舉 |
| 加note字串 | 依本例允許 | 保留原包及額外欄位 |
驗收輸出至少分成解析失敗、結構不符、工程規則不符與成功四類。前者可能是截斷或編碼,第二類是型別或缺欄位,第三類是時鐘、來源或單位契約。不要把所有錯誤寫成MQTT失敗,否則維護人員會一直重連卻無法修正payload。
保留原始位元組、接收時間、topic、內容摘要及驗證規則版本,隔離區限制存取與保存期限。修復規則後重處理時仍使用原事件身分,不為同一筆資料重新生成業務識別。這樣可以比較修復前後結果,又不把重處理算成新量測。
完成結果與常見問題
完成後應有版本欄位表、新舊consumer相容矩陣、六筆測試的逐項結果,以及拒收資料查詢方式。格式比較另附相同樣本的大小與耗時,尚未量測的欄位保留待測。
FAQ1:JSON看得到字就最好嗎?它便於人工排查,但仍須比較產品資源與精度。不要為了節省少量頻寬,讓現場失去可用的解碼工具。
FAQ2:新欄位可忽略就不用版本嗎?仍需記錄契約版本。忽略未知欄位只是一項相容政策,不能處理既有欄位改單位、改意義或改型別。
FAQ3:缺quality能補Good嗎?不能從缺失推論品質良好。本例v1明確標未知,v2缺失則拒收;兩條規則不能混用。
FAQ4:資料通過Schema就是正確嗎?它只證明已檢查的結構條件成立。來源身分、時鐘偏差、設備換表及工程合理性仍要另外判斷。
參考:JSON Schema官方文件:properties、required與additionalProperties。
參考:Protocol Buffers proto3官方指南:欄位演進與未知欄位。