MES I/O Gateway / 開發者 / 整合
04開發者 / 整合

出廠測試規範

#1.1.13 候選:遠端 DI → MQTT Converter 驗收(WI-266)

以下為必測項,尚非 PASS 紀錄;必須用最終候選 firmware 與配套網頁資產完成。記錄 UID、Build ID、boot、Master/Slave ID、接線及 MQTT topic。

項目 操作 通過條件
DC.1 Master 新增/辨識 OPTA DI Slave,在 MQTT Converter 開啟可用變數參考 以 Slave ID 列出 DI1~DI8;僅列有效已接擴充 DI;Finder 原有欄位保留;無截字、無頁面錯誤
DC.2 點擊複製 ${rs485.41.DI2:0} 放入 JSON 範本,按預覽 剪貼簿內容正確;合法 JSON;0=OFF、1=ON,與 Slave 本體 DI2 和 Master 總覽一致
DC.3 設定獨立測試 topic、儲存、關閉後重新開啟並重新整理頁面 範本、topic、啟用與「數值變動才送」設定保留;實際訂閱收到同一 payload,不以預覽代簽
DC.4 人工切換已接 DI2 OFF→ON→OFF,逐次等候有效輪詢 每次 Slave 本體、Master 顯示及 MQTT 值一致;時間戳為合法 UTC;記錄操作、收件及缺口時間
DC.5 「數值變動才送」分別開啟與關閉 開啟時固定 DI 不因量測時間更新而重送;關閉時依週期送;DI 改變後正常送出
DC.6 停用來源或暫停輪詢,並測不存在擴充引用 預覽與 MQTT 對應欄位為 null,其餘有效欄位照送;定時模式全部無效仍發送,變動才送模式只在有效/null 切換時發送;不得發布假 OFF 或舊值
DC.7 排定一次重開,重開後核對頁面及 MQTT 設備、範本與設定保存;有效新樣本恢復後正確傳送;恢復測試前設定並記錄清理結果

範例(41 須替換成現場站號):

json
{"di2":${rs485.41.DI2:0},"measuredAt":${rs485.41.DI2.timestamp}}

這是 Converter 範本,不是尚未填值即可解析的 JSON。量測時間為 Master 成功收到 FC02 的時間;未對時為 null。不可把無效來源當成 OFF。

2026-10-27/1.1.12 發布狀態:功能整合版已上雲端;Master/Slave、Finder 通訊及 HTTP 穩定性尚未完成驗收。發布與驗收分開記錄,以下測項仍須以目標設備實測,不以主機測試或短輪成功代替。

2026-10-27 增補:Master/Slave 交付另須完成下方 RN.1~RN.6;其後 6.0.134/135 結果為歷史記錄,不代表 1.1.8 已通過。

#2026-10-27:1.1.9 總覽角色驗收補充(待實機驗證)

  • Slave 模式總覽不顯示外接 RS485 設備卡,顯示本機 Slave ID 與 DI;角色未確認時不沿用舊 Master 卡。
  • 切回 Master 後恢復原設備卡,設備設定與 enable 值不變。
  • MQTT telemetry 啟用時仍更新角色;接收 DI 資料超過 10 秒後,下一次刷新須顯示未知/過期,新 IO 資料才可恢復 ON/OFF。角色回覆不能延長 IO 有效期。
  • 角色回覆逾時(含 body 未結束)須能自動恢復查詢。主機測試不替代安裝後的畫面核對。

#RS485 角色與網路並行驗收(1.1.8 新增)

適用於提供 Master/Slave 功能的韌體。8310/Ethernet 與 8320/Wi-Fi 分別測試;測到其中一台或只在 Master 操作不算通過。記錄 UID、版本、Build ID、bootCount、角色與起始完整設定備份。以下是測試要求,並非已完成結果。

項目 操作 通過條件與證據
RN.1 Master 下開啟總覽、設備、設定頁,讀取 /api/rs485/role 三頁與 API 可用;記錄載入時間及實際角色
RN.2 停止外部 Master,在設備頁切換為 Slave,設定本站唯一 Slave ID 收到 applied,重新讀取為 Slave;原 Master 設備設定仍保留
RN.3 Slave 下持續載入三頁、查角色與 /api/diag,並收 MQTT 狀態至少 10 分鐘 頁面完整、無連線失敗,bootCount 不增;MQTT 連線可用,逐次送 query 並核對回覆的最新 boot 與 role(query 回覆 requestId 為 0,不作命令 ACK)。不得只看 link=UP 或 connected 圖示
RN.4 外部 Master 經實體 A/B 持續 FC02 讀取,同時操作網頁與 MQTT DI ON/OFF 與實體輸入一致,連線沒有因輪詢或網頁載入失效;未接治具記 NOT RUN,不能以 USB 日誌/PTY 代簽
RN.5 保存 Slave,排定重開;再次開啟網頁並讀取角色及 DI 只有一次預期重開、Slave ID/通訊參數保存,網頁/MQTT/FC02 恢復;物理斷電另依既有步驟驗證
RN.6 先停止外部 Master,切回 Master,再切 Slave,至少三輪 每輪 fresh boot/revision/requestId 與 ACK 匹配;角色與網路均可用,最終恢復本站要求的角色及 Master 設定

USB rs485 <JSON> 僅存在於實驗室 network-diag 映像,不是交付介面。正式使用設備頁或既有 MQTT/HTTP 角色協定。診斷版的通過不可取代最終 production 映像測試;本輪實際結果見 1.1.8 驗證紀錄。

135手動測試增補(v2):135另跑OC.4/OC.5/OC.7,不能沿用134的實測PASS。確認sample在±0.02kg波動及20秒人工等待內固定、reading繼續增加;全區段最大最小差>0.1kg、失穩/讀取缺口後舊憑證不復活,重新穩定至少5秒。設定可由begin的toleranceKg調整,預設0.1kg,與精度允收分開。手動完整三段、工廠震動、保活/長時仍須本輪記錄。

2026-10-06 134 現場結果:.46 已安裝 6.0.134,Build ID 35B4EEB5DA9C49EC9B363566A7EFE4B7;實秤三段總量 5→25→45 kg 與 finish 均有匹配 applied/complete。降載 25/5/0 kg,面板與系統為 25.01/5.01/0.01 kg。原 checkbox/Converter 設定保存,收尾後已觀察到恢復數值變動才送。完整 MESB 含8資產,BIN 778128 bytes,餘裕1872。雲端通道 beta,僅此台此輪證據,其他設備仍須自行驗收。

仍未完成:業主允許誤差尚未定義,以上讀值不是精度簽核;五段實秤、校正後物理斷電保存、業主 Edge、長時與例外故障仍待驗。134 只讀觀察仍有 read_frame/MQTT 重連及最大27.772秒接收缺口;133保活逾時FAIL保留。OC.12與1.0均未放行。內部原始證據:docs/qa/qa-wi252-field134-2026-10-06.md。

版本:3.17 | 日期:2026-10-06 | 韌體版本:6.0.134(beta,1.0 未放行) 來源 PRD:docs/prd/prd-factory-test.md(內部文件,未公開) v1.2(結構基線)+ 本文件 v2.1 增量(依 6.0.8 源碼/實機核校) 操作手冊:guide-user-operation-manual.md

WI-252 新增範圍:交付線上多段校正時必做 Phase 5C。134已通過本輪容量、安裝及三段實秤協定核對;SC 舊流程與主機模擬均不能替代 OC 的實機結果。

#工站人員先看這一頁

這份文件要確認「設備出貨前,該做的檢查都有做」。自動程式跑完,只代表它負責的部分完成;磅秤、接線、斷電與現場交接還要逐項確認。

順序 要做什麼 完成後留下什麼
1 確認設備型號、版本、接線與測試工具 設備識別資料、起始設定備份
2 依下方指令跑自動檢查 原始結果;失敗與重跑分開記錄
3 依 Phase 0~5 做適用的網頁、接線與功能檢查 每項結果與實際觀察
4 依 Phase 5B 完整做新版驗收 磅秤 SC、量測時間 TS、網路恢復 NR 的逐項結果
5 做升級、維運與出貨清理(Phase 6~7) 清理後設定,以及最終備份
6 彙整、簽名與交接(Phase 8) 哪些通過、哪些沒做、誰要接著做

每個指令只做一次對應動作;看完預期結果,再往下一步。Mac 與 Windows 選自己的指令版本。有錯誤就記下來,不要直接跳到「出貨通過」。 沒有實體磅秤時,可以完成模擬和通訊檢查,但實際準確度要交接到現場。

新版校正與時間檢查的詳細命令集中在 現場驗收流程,不要另外抄出一套不同的指令。下表的編號是對照用,並不代表程式已經幫你全部做過。

#⚡ 先跑自動化閘門(v2.2 起,任何改動後都必須執行)

任何韌體或網頁改動之後,先跑這一道再談其他。 此套件含暫時寫入與還原設定的 ST 測項,必須在允許變更的測試設備執行。只讀頁面核對使用 test:factory:pages。

bash
cd web
DUT_URL=http://<設備IP> EXPECT_FW=<版本> npm run test:gate

目前包含 35 個 Playwright 測試:頁面渲染(2A–2F)、v6 能力契約、穩定性與持久化(ST.*)。 全數通過才算通過 —— 任何一項紅燈都代表出貨品質有缺口。

其他交機前自動化套件如下,均須確認治具可操作並保留起始完整備份:

bash
npm run test:converter  # ★ MQTT Converter 鏈路(產品主幹),素材自建自清,約 3 分鐘
npm run test:enable     # 啟用/停用機制(⚠ 見下方說明,目前不作為出貨門檻)
npm run test:backup     # ★ 雲端備份/還原閉環(會讓設備重開一次),約 2 分鐘
npm run test:persist    # 真的重開設備,驗設定與統計跨重開存活(約 1 分鐘)
npm run test:factory    # 完整功能測(含 MQTT 佈建,會寫入設定)

#驗收走查回歸(npm run test:regression,RG.1–RG.9)— 納入出貨門檻,須在當輪候選執行

2026-08-25/26 照著驗收單實機走了一遍,挖到五個缺陷。既有出廠閘門一個都沒攔到, 而且不是「剛好沒測到」,是測試的形狀不對 —— 既有測項驗的是「東西在不在、頁面開不開」, 五個缺陷全部落在「內容對不對、值有沒有真的寫進去」。

最直接的證據:把 WI-202 的壞值注回設備(整份 TCP IO 設定在網頁上消失、 顯示「尚無 TCP IO 通道」),factory-pages 依然 6/6 全綠。閘門對它完全無感。

bash
cd web
DUT_URL=http://<設備IP> npm run test:regression
測項 對應卡 驗什麼 預設
RG.1 WI-202 字串欄位含 " \ 時,各 GET 端點仍須回合法 JSON,且值讀回不得被截斷 執行
RG.2 WI-199 網頁上連續快速新增兩條規則,兩條都要在(必須走瀏覽器 —— 缺陷在前端算 index 的邏輯,直接打 API 碰不到) 執行
RG.3 WI-170/WI-201 網頁上連續改多個通道名稱,全部都要寫入(守 WI-170 的寫入佇列還在) 執行
RG.4 WI-200 POST /api/io/do 要能驅動擴充板輸出 執行
RG.5 WI-203 存 Converter 模板後立刻重開,長度須與模板一致 略過(需 RG_ALLOW_REBOOT=1)
RG.6 WI-205 被拒絕(400)的規則 POST 不得毀掉既有規則,也不得留下啟用中的死規則 執行
RG.7 WI-206 Parser「值類型」下拉的 option value 必須對得上韌體列舉(選「數值」不能拿到布林)—— 斷言 UI 的 option value,不是 API 回值 執行(需 MQTT 憑證)
RG.8 WI-208 / WI-208b 主迴圈不得被授權處理凍結 —— 兩條斷言:① 安定後 300 秒內 [WI-208] gate 重驗 須為 0 次;② 同一窗內 net 段不得有任何超過 1 秒的卡頓。窗長 300 秒是為了蓋過雲端心跳的 127 秒週期(至少 2 次),否則 WI-208b 那條路徑抓不到 執行(約 5 分)
RG.9 WI-212 / WI-215 跨網段連線必須通,不能只有區網通 —— 判準用 /api/net/diag 的分階結果:dnsErr 須為 0、connCloudIP443_ms 與 connCloudHost443_ms 須為正。會先靜置 8 秒再量、最多重試 4 次 —— 該端點在 inbound handler 裡再開 outbound,設備只有 4 個 socket,套件連跑時借不到會回 -1(WI-215)。只驗設備當下所在的介面;failover 之後的狀態要人拔線,屬人工驗收 ⑥ 執行(約 30 秒~2 分)

只有 RG.5 預設略過(它會重開設備,要跑帶 RG_ALLOW_REBOOT=1;已實測通過)。

⚠️ 2026-08-27:RG.7 在此之前從來沒有真的執行過。 package.json 的 test:regression 是唯一沒帶 MQTT 環境變數的腳本 (旁邊四個都有),RG.7 因此每次都靜默 skip —— 報表顯示「6 passed」, 看起來很健康。已補齊環境變數,現在會真的跑。

教訓:skipped 不是中性的。一個永遠跳過的測項,和沒有這個測項是一樣的, 但它在報表上長得像有在守。看回歸結果時要同時看 skipped 的數量與原因。

⚠️ 2026-08-28:RG.7 在整套連跑時偶發假紅燈,已修測試方法。 單獨跑綠、RG.5+RG.6+RG.7 最小組合也綠,只有整套跑會紅 —— 而整套跑到 RG.7 時 設備剛經歷 RG.5 的重開加一輪負載。原本的寫法是「建通道 → 固定等 2.5 秒 → 發一次 → 固定等 5 秒 → 讀一次」。MQTT 對「訂閱之前就發出的訊息」沒有補送 —— 設備若還沒訂好新通道的 topic,那則訊息就永遠消失,測試必紅。

已改為週期重發 + 輪詢讀回(45 秒內每三輪重發一次)。這個教訓 acceptance_run.py 早就記過(「通道剛建好時設備可能還沒訂閱」),RG.7 沒套用。

誠實記一筆:那次的錯誤訊息因為輸出被 grep 過濾而遺失,根因是從程式碼推斷、 不是從錯誤訊息實證。修正本身站得住(移除的是本檔已咬過兩次的同一類問題), 但若日後 RG.7 再紅,不要假設就是這個原因。

教訓:跑長時間測試套件時,不要用 grep 過濾輸出 —— 失敗細節只有一次機會保留。

⚠️ 2026-09-01 追加 RG.9(WI-212)。 這一項補的是既有閘門的一個結構性盲點: 43 項測試全都在區網內對設備發請求,所以「設備連不到網際網路」一項都不會紅。

WI-212 的設備看起來完全健康 —— 網頁開得了、區網連得到、IP/閘道/遮罩查起來全對 —— 但跨網段的封包一個都出不去(真兇是多建的一張 netif 搶走預設介面)。

鑑別力是實測的:故障狀態(v6.0.86)量到 dnsErr=-3009、connCloudIP443_ms=0, 兩條斷言當時都會紅。

教訓:閘門測「設備回應我們」,不等於測「設備到得了外面」。 這兩件事在一台工控閘道上同樣重要,而後者過去完全沒有守。

⚠️ RG.2 / RG.3 必須走瀏覽器,不能用 API 並發代替。 這兩個缺陷都在前端 (saveRule 算 index 的邏輯、saveIoName 走 WI-170 的寫入佇列),直接打 API 測到的是我們自己的測試碼,不是產品。初版就是這樣寫的:RG.2 一次就綠(bug 還在)、 RG.3 則「測出」一個其實不存在的缺陷(WI-201 因此大幅更正)。

2026-08-27 追加 RG.8(WI-208)。 業主人工驗收時回報「藍色呼吸燈會卡住, 卡住的時候按鈕就延遲、甚至沒反應」—— 量出主迴圈有 6.8% 的時間完全凍結, 真兇是授權門控每 30 秒重驗一次簽章(663ms)。改為到期驅動後降到約 0.8%。

這一項有實測的鑑別力,不是推論:修正的第一版(v6.0.76)把 expiresAt==0 誤當成「1970 年就過期」,快取完全沒生效 —— 同樣的 200 秒觀測窗裡 gate 重驗 出現 8 次。RG.8 的判準當時會紅。

2026-08-27 更新:七項全綠(RG.5 另以 RG_ALLOW_REBOOT=1 單獨驗過)。 這一輪另外修掉兩個測試自身的問題,兩個都會產生假紅燈: ① RG.2/RG.3 用固定 4 秒等 window.nav 備妥 —— 單獨跑夠,整套跑時設備有負載就不夠 (實測單獨 2 秒即備妥、整套跑時逾時)。已改為輪詢至函式真的存在。 ② RG.3 用譯文 /儲存中|Saving/ 判斷寫入佇列是否忙碌,但徽章實際顯示「💾 bH 1」 —— io.saving 這個 i18n 鍵三個語系檔全缺(WI-207),t() 查不到時回傳鍵本身, 讓 || "儲存中" 變成死碼。判斷失效 → 提早讀取 → 假紅燈。已改為比對不會被翻譯的 💾。

2026-08-26 更新:六張卡全部修好,這一組已全綠。 每一項都經過「先紅後綠」—— 修正前該測項紅、修正後綠,同一台設備、同一支測試。 韌體 v6.0.72 經 LAN .mesb OTA 上機驗證,test:gate 35/35、test:regression 6/6。 已納入 test:gate:full,現在它真的有在守。


test:converter 是最該跑的一支。 業主買的就是「MQTT 進來能驅動輸出、 量測值能定時送出去」—— 頁面全部正常但這條鏈斷掉,設備等於沒有用。 它會自建 CV-* 前綴的素材、測完自己刪光,並以「素材必須清乾淨」作為最後一項斷言。

#閘門守著的「已知會壞的那幾類」(逐項對應真實事故)

測項 守的是什麼 來源事故
ST.0 / ST.9 測試期間設備不得重開 功能全對但設備會重開,對業主而言就是壞的
ST.1 連續請求不得連兩次失敗 併發過頭會把閘道器打重開(WI-176)
ST.2 / ST.3 規則不得存成永遠不觸發 下拉未載入就存 → signalId=0(WI-174)
ST.4 設定寫入後讀回一致 「回成功但沒進去」的靜默失敗
ST.5 統計/開機計數有落盤 重開後統計歸零(WI-164)
ST.6 index.html / app.js / 語系檔三者同版 短碼位移 → 全站標籤指到錯字串(WI-172/185b)
ST.7 WiFi 帳密不得為空 無聲清空 → 重開後失聯(WI-169)
ST.8 救援頁可用、主畫面沒退回救援頁 index.html 移到 QSPI 後的發佈陷阱(WI-178)
ST.10 欄位名打錯要回 400 靜默照收 → 整合商拿著 success 找三天(WI-179)
ST.11 TCP 來源的不可能條件要被拒 設了「>50」永遠不成立且無提示(WI-184)
ST.12 改 token 名稱/權限不必連帶換密碼 畫面寫「留空=不變」但兩端都沒實作(WI-188)
2F 畫面不得殘留 {UID} 這類佔位符 該告訴使用者的資訊變成一串符號(WI-185)
ST.13 I/O 名稱改了要能存進去 名稱是現場辨識訊號的唯一依據,存不進去整頁沒用
ST.14 現場硬體與環境設定檔相符 換了設備卻沒更新設定檔 → 這裡先紅,不必等功能測莫名失敗才回頭猜
ST.15 雲端有效身份可讀取本設備歷史(含 license fallback) 實際讀取歷史須成功;不能只以 cloudToken 是否空白判斷
ST.16 重開機後設定逐項完整(不是只驗「寫入後讀回」) 對應 D3/D4:保存設定、重開、逐項比對名稱、來源與動作引用、模板、閾值及計件參數。另建 A/B/C,規則指 B,刪 A 後重開仍須指 B;WI-156 未修前此項不得通過。既有 D3 清單及 test:persist 只覆蓋部分欄位。

#MQTT Converter 鏈路(npm run test:converter,5 項 + 收尾清理)

測項 守的是什麼
CV.0 佈建入向通道 / 輸入群組 / 規則 / 輸出群組(素材自建,不碰現場設定)
CV.1 入向 Parser:MQTT JSON 的數值要進到通道
CV.2 端對端:MQTT → 輸入群組 → 規則 → 輸出群組 → 實體 DO
CV.3 出向 Converter:閘門關不發、開了照間隔發
CV.4 onChange:值不變只發一次;閘門關再開要補發(v5.9.266 —— 否則使用者重新觸發卻沒反應)
CV.5 訊號內容決定回報頻率:送 15 就每 15 秒發一次,送 0 停 —— 業主用來調整回報間隔的功能,先前出廠沒有任何一項在守(WI-143,對應驗收單 B5)
CV.7 Legacy 入向指定訊息觸發,留空代表任意 payload;與驗收 M.1/M.2 同時驗命中與不命中(驗收執行器,尚非 Playwright 套件)
CV.6 並排對照:兩個通道除了「變更時才發」以外設定完全相同,同一時間跑 —— 先後比較答不出「會不會只是那一分鐘剛好沒變」(對應驗收單 B3b)
(afterAll) 收尾:本檔建立的素材必須全部清乾淨(留下殘骸就是污染現場設定)

這幾項固化的是 2026-08-18 夜間的完整手動驗證。當時結論只存在於對話裡, 下次改動不會有人幫忙擋 —— 這正是「測試樣本要全面覆蓋」的意思。

#啟用/停用機制(npm run test:enable,7 項)

畫面上到處是啟用/停用的開關,先前一個都沒測。這類機制壞掉的方式特別惡劣: 「畫面顯示停用、實際還在動」(業主以為關掉了,機器卻自己跑), 或「停用之後再啟用回不來」(現場只能重開機碰運氣)。兩種都不會有錯誤訊息。

測項 守的是什麼
EN.0 佈建 + 基線:鏈路本身要先是通的(否則「停用後不動」毫無意義)
EN.1 停用規則 → 觸發後輸出不動;重新啟用要回得來
EN.2 停用輸入群組 → 規則不觸發(signalSlotUsable 的 fail-safe)
EN.3 停用輸出群組 → 規則觸發但輸出不動
EN.4 停用TCP 通道 → 不再接收 MQTT(值凍結);重新啟用要收得到
EN.8 停用Config Server 總開關 → 不得再對外推送(業主關掉雲端同步就必須真的停)
EN.6 停用token → 該憑證不得再通過認證(以為撤銷了、其實還能用 = 安全問題)

⚠ test:enable 目前不列入出貨門檻。 它已經達成目的 —— 2026-08-20 完整跑過 7/7,證實六種停用機制的語意都正確 (停用真的停、重新啟用都回得來)。但這支測試本身還不夠穩: 測項之間有順序耦合(前一項的雲端等待會影響後一項的量測)、 依賴 MQTT 環境變數(用 npx playwright -g 單獨跑會因前綴/密碼未設而失敗)。 結論可信,工具待磨。修穩之前不要拿它當出貨紅綠燈,否則會訓練人忽略紅燈。 | 收尾 | 用 afterAll 清素材(不能寫成最後一個 test,見下方) |

每一項都同時驗兩個方向:停用要真的停、重新啟用要回得來。 只驗前者的話,「停用之後就再也回不來」這種更難救的缺陷會漏掉。

收尾一定要用 afterAll,不能寫成最後一個 test。 序列模式下只要前面任何一項失敗, 後續 test 就不會執行 → 素材殘留 → 下一輪再建一份同名的 → 名稱查找抓到第一份 → 鏈路指向錯的通道 → 之後每一輪都失敗。2026-08-20 實際踩到:一次失敗滾成兩份素材, 手動清掉才恢復。 一律走「真的送 MQTT、真的看實體 DO」,不看欄位存不存得進去(那是 ST.4 的事)。

#雲端備份 / 還原閉環(npm run test:backup,4 項)

備份/還原是所有其他測試的安全網 —— 出廠測試會寫入設定、現場調參數也會出錯, 能不能救回來全靠它。它壞掉時最危險的地方是平常看不出來:設備→雲端的推送 有自己的授權路徑、照樣 HTTP 200,只有真的要「讀回來」時才發現 401。

測項 守的是什麼
BK.0 設備有效身份可讀取自己的歷史(含 license fallback)
BK.1 改設定 → 推送 → 雲端真的出現新快照(不是只回 200)
BK.2 還原前一份 → 改動要被還原回去(閉環的關鍵一步)
BK.3 還原後雲端連線不得斷掉(否則還原一次就不能再還原 = 自斷後路)

寫這幾項時踩了兩個判準錯誤,值得記下來:

  1. 不能用「快照數量增加」當判準 —— 雲端會裁切舊快照,數量可能不變;要比對最新那份有沒有換人。
  2. 設定沒變更時推送不會產生新快照,那是正確行為(內容相同不重複存,實測連推 80 秒都不會多)。 所以測試要先真的改一個欄位再推,否則會把正確行為誤判成「回成功但沒發生」。

維護原則:每修一個缺陷,就在這裡加一列。 出廠測試的價值來自「它涵蓋了已知會壞的東西」,不是「它有很多項」。

#本批韌性修正:閘門測不到的那些(v6.0.41 → 6.0.65)

上面的表格是「有自動化守著」的部分。但這批交付還改了一些自動化測不到、卻直接影響 現場可靠度的行為。列在這裡不是為了完整,是因為下一個人改到這些地方時要知道當初為什麼這樣寫 —— 沒有測試會替他擋。

項目 改了什麼 為什麼會壞 怎麼驗的
WI-175 QSPI 長時間寫入期間持續餵狗(loopKeepAlive) OTA 撞上背景雲端 TLS → 主迴圈被佔住 → 看門狗砍掉升級 實機:雲端握手後 0.6s 觸發 OTA,守衛等 3765ms 後成功
WI-180/180b 設定存檔原子化:寫暫存 → 驗證 → 確認主檔有效才降級為備份 → rename 舊流程會在主檔還沒驗證前就覆蓋備份,一次斷電兩份全毀 單元級:刻意寫入半截 JSON,重開後仍載入得到有效設定
WI-181/181b WiFi 帳密改用 RAM 暫存再落盤 beginWiFi() 期間 QSPI 未掛載,在那裡讀寫會永久卡死、只能 DFU 實機:此路徑曾兩次把 .46 變磚,修正後重開 5 次帳密皆存活
WI-182 設定下載先試地端、再試雲端 地端 config server 不在時整個還原路徑斷掉 實機:拔掉地端來源仍能從雲端取回
WI-183/183b 對外連線硬性總時限 + 雲端卡死自我復原 connect() 對黑洞位址可阻塞 5 分鐘以上,期間整台設備沒有回應 黑洞位址實測:確認阻塞>5min,並在對抗性輪詢下觸發自我復原
WI-189 分頁切到背景時停掉輪詢與 telemetry 背景分頁持續要資料,排擠掉真正重要的控制迴圈 見 控制延遲特性 的前後對照

這張表的維護方式和上面那張不同。 上面那張是「每修一個缺陷加一列測試」; 這張是「改到這塊之前先讀這一列」。如果哪天有辦法替其中一項寫出自動化測試, 就把它搬到上面那張表去 —— 那才是真正被守住了。

#🔧 換設備 / 換現場時要改哪裡

測試分成兩類,換環境時只有第二類需要動:

類別 內容 換設備要改嗎
環境無關 契約與穩定性(ST.1–ST.13、2A–2F、V6-*)。這些測項自己建立所需的素材、測完自己清掉 ❌ 不用
環境相關 現場實際接了什麼:RS485 型號與 slave、擴充模組數量、MQTT broker ✅ 改 web/tests/factory-env.js

#只改一個檔:web/tests/factory-env.js

js
const HARDWARE = {
  // RS485 上預期存在的設備。空陣列 = 該站沒有 RS485,相關測項自動略過
  rs485: [ { slaveId: 1, model: 'finder6m', name: '電流計' } ],
  // 預期的擴充模組「實際連線」數量。0 = 沒有擴充槽
  expansionModules: 1,
  hostDoWiring: '4 個 DO 接三色燈(DO1=紅 DO2=綠 DO3=藍 DO4=蜂鳴器)',
};

改完之後 ST.14 會替你把關:設定檔宣告的硬體與設備實際回報不符就直接紅燈, 不必等某個功能測莫名其妙失敗才回頭猜哪裡不一樣。

#常見情境

情境 怎麼改
換一台設備(IP 不同) DUT_URL=http://新IP npm run test:gate,不必改檔
對外 MQTT topic 前綴 不必改 —— 留空時測試會向設備問它自己的 UID 自動組出來
RS485 換型號或 slave 改 HARDWARE.rs485(model 用 /api/config 的 modbusDevices[].type 值)
該站沒有 RS485 EXPECT_RS485='' npm run test:gate,或改檔案的 rs485: []
一份設定檔要服務多台不同配置 用環境變數逐台覆寫,不必改檔:
EXPECT_RS485='1:finder6m:電流計' EXPECT_EXPANSIONS=1(8320)
EXPECT_RS485='' EXPECT_EXPANSIONS=0(8310)
沒有擴充模組 EXPECT_EXPANSIONS=0 → 自動略過
韌體出新版 EXPECT_FW=6.0.xx npm run test:gate,或改 factory-env.js 的預設值

原則:測試碼一行都不該為了換環境而改。要改就改設定檔 —— 改測試碼會讓「這一站為什麼要特別處理」的知識散落各處,下一個人接手就看不懂。

#文件用途

本文件是正式工站操作規範,供產線測試人員逐步執行。所有步驟可由一位測試員在單一工站完成。

自動化實作(v5.9.130+,跑真實 DUT):

🚀 一鍵測試(自動偵測 UID + 前置檢查 + 跑功能+頁面):

bash
./scripts/run-factory-test.sh [DUT_IP] [ADMIN_TOKEN]
# 預設 192.168.72.77 / smmsadmin;輸出 12 tests PASS/FAIL
套件 涵蓋 執行
web/tests/factory-functional.spec.js 決定性韌體能力(beforeAll 自佈建 fixtures,不依賴設備現狀/RS485):連線、MQTT 輸入、2-source AND 順序強制、signal→rule→CH_TCP publish→broker loopback(6 tests) npm run test:factory:func
web/tests/factory-pages.spec.js Phase 2 五頁面渲染(Overview/Config/Rules/Devices/Settings,5 tests) npm run test:factory:pages
web/tests/factory-v6.spec.js v6.0.x 能力回歸(純 HTTP 唯讀契約,不改 config):Phase 0 機型身分(hasWifi/boardModel/version/mac)、Phase 6B 遠端診斷(/api/log + /api/diag + auth 401)、Phase 2E.6a MQTT 測試契約(202+輪詢)、Phase 2E.6b namespace 欄位 + TLS 出廠預設(13 tests) npm run test:factory:v6
web/tests/factory-cleanup.spec.js Phase 7 出貨清理(FR-H,部分 test.skip 待韌體 endpoint) —

一次跑功能+頁面+v6 回歸:npm run test:factory(於 web/,共 41 tests,含 stability)或 ./scripts/run-factory-test.sh(repo root,自動偵測 UID)。EXPECT_FW 環境變數鎖定出廠版號基線(預設讀取 src/config.h)。

決定性原則(出廠品質基準):functional 測試在 beforeAll 自己 idempotent 佈建 fixtures(wdprobe + ft_* 引擎元件)+ 清 retained,不依賴設備現有 config、不依賴 RS485 硬體。因此同韌體 → 同結果;唯有韌體能力改變才會讓結果變。對出廠空機也成立。fixtures 由 Phase 7 一併清除。 物理治具步驟(砝碼/SG-002/DI 開關/拔網路線)無法自動化,仍由本文件手動 ☐ 執行。 ⚠️ 跑前 watchdog 須暫停(會 reboot 干擾)。

#工站前置條件

#治具接線

連接點 接線對象 API/UI 位置 用途
Host DI 1 Toggle Button /api/io di[0] 數位輸入驗證
Host AI 2 FNIRSI-SG-002 信號產生器(0–10V) /api/io ai[1] 類比輸入驗證
Host DO 1~4 三色燈 + 蜂鳴器(紅/綠/藍/蜂鳴) /api/io do[0..3] 數位輸出驗證
Expansion 0 DO 3~6 第二組三色燈 + 蜂鳴器 expansions[0].doNames[2..5] 擴充模組驗證
RS485 Bus 0 Finder 6M.TB(Slave ID=1, Baud 9600, machineId=48) /api/config modbusDevices[0] 電力表讀取
RS485 Bus 0 YX523R 光警器(Slave ID=4, machineId=24325) /api/config modbusDevices[1] RS485 寫入
Ethernet 工站電腦區網 — Web UI + Playwright
MQTT Broker (新增) 工站本地 Mosquitto(明文 1883) factory/<topicPrefix>/... FR-G E2E 雙向訊息

#平台容量基準(硬體衍生,6.0.8 沿用)

項目 容量 用途
Host DI / DO / AI 8 / 4 / 3 主機 I/O
Expansion 槽位 5(Exp0~Exp4,目前 fixture 只用 Exp0) 擴充模組
Modbus 設備 / Register 12 / 32 RS485
RS485 Bus 韌體 2 條,UI 只外露 Bus 0(Bus 1 由 FR-H1-03 確保不誤露) —

#變體識別(機型 × 網路,二維)

工站開始前必須讀 /api/system 判定 兩個維度,並寫入結果摘要 metadata:

維度 1 — 機型(來源 = OTP boardInfo().wifi,不可靠 WiFi.status()):

  • hasWifi=false / boardModel="8310" → 8310 機型(無 WiFi 模組):強制乙太網路;設定頁隱藏 WiFi 欄位;心跳燈 = 琥珀色(紅+綠同亮);H6 Failover Skip;AP 模式進不了。
  • hasWifi=true / boardModel="8320" → 8320 機型(有 WiFi):可 WiFi;心跳燈 = 藍燈(LEDB);H6 Failover 依網路變體決定。

維度 2 — 網路變體(讀 network.netType 與 /api/config interfaceMode):

  • netType="Ethernet" 且 interfaceMode=0/1 → ethernet 變體(H6 Failover Skip)
  • netType="WiFi" 或 interfaceMode=2 → wifi 變體(H6 Failover 必測,僅 8320 可能)

⚠️ 8310 恆為 ethernet 變體(無 WiFi 硬體)。wifi 變體必為 8320。

工站 profile 需於啟動時設 model: 8310|8320 + variant: ethernet|wifi,寫入結果摘要 metadata。

#啟動檢查清單

  • DUT 已上電,Status LED 閃爍中
  • DUT 已取得 IP,工站電腦可 ping 通
  • 瀏覽器可開啟 DUT Web UI(http://<DUT-IP>)
  • RS485 設備已上電(Finder + YX523R 兩台)
  • SG-002 信號產生器已上電
  • MQTT Broker 已啟動(明文 1883)
  • 機型 + 網路變體 已從 /api/system 讀取並寫入結果摘要
  • 首次燒錄後首開機:Web UI 完整渲染(非裸 HTML;app.js 走 QSPI 已載入)

#Phase 0:連線檢查(FR-F、FR-A1-07)

# 步驟 驗收條件 類型
0.1 開啟瀏覽器,連接 DUT Web UI Dashboard 頁面載入完成;無 JS error;非裸 HTML 自動
0.2 確認左下角韌體版本號 #sideVersion 顯示 v6.0.100(/api/system version;自動化 V6-ID.3 斷言,可 EXPECT_FW 覆寫) 自動
0.3 記錄 DUT UID #sysDeviceUid 24-hex 格式 自動
0.4 讀取 /api/config configCrc 寫入結果摘要(firmware.configCrcReference) 自動
0.5 讀取 network.netType 判定網路變體 profile 對齊;異常則 fail 自動
0.6 讀取 /api/system boardModel/hasWifi 判定機型 hasWifi=boolean;boardModel="Opta RS485 (8310)"(hasWifi=false)/ "Opta WiFi (8320)"(hasWifi=true);兩者一致;profile 對齊(自動化 V6-ID.1/2) 自動
0.7 讀取 /api/config mac 冒號大寫 MAC(如 A8:61:0A:50:8B:61);對外 topic 身分 = 去冒號轉小寫 12-hex;寫入結果摘要(自動化 V6-ID.4) 自動

測試記錄:

DUT UID:        ___________________
DUT MAC:        ___________________  (12-hex 對外身分)
FW Version:     6.0.100 (預期)
Board Model:    8310 | 8320
Variant:        ethernet | wifi
configCrc:      ___________________  (出廠 baseline)
測試日期:        ___________________
測試員:          ___________________

#Phase 0A:空機、網路與授權路徑(人工治具)

# 步驟 驗收條件 類型
0A.1 準備燒錄工具、核對 USB serialNumber 與目標 UID,核對拓荒包 manifest/SHA-256,再依現場驗收階段 1 燒錄 Port 與目標 UID 相符;確認實際為 pioneer,不能用舊 QSPI 畫面當作證據 人工/會改韌體
0A.2 8320 AP 設定後接回測試網路;8310/8320 驗 Ethernet DHCP;記錄 UID、IP 與介面 頁面與 API 可達,設定的介面與讀回一致;8310 AP 項標不適用 人工/會重開
0A.3 由 pioneer 上傳指定完整 .mesb,核對完整資產與 firmwareVariant 韌體版本與資產均為指定候選;上傳失敗不得算通過 人工/OTA
0A.4 依驗收 2D.1–2D.3 核對新機申請、管理者核准、設備取件 UID 相符且設備授權狀態正確,重新開機仍有效;與 Phase 7 的撤銷/重置分開記錄 人工/需管理端

#Phase 1:初始化(FR-C1)

# 步驟 驗收條件 類型
1.1 清空所有殘留規則(含未命名「Rule 2」) /api/rules ruleCount = 0 自動
1.2 關閉所有 DO 輸出 /api/io do[] 全為 false 自動
1.3 載入 baseline 設定檔(含 Finder + YX523R) 設定載入 Toast,configCrc 等於 baseline 預期值 自動
1.4 確認 eepromPendingReboot == false /api/system 欄位 自動

#Phase 2:UI 驗證

#2A. Dashboard 總覽頁(FR-A1)

# 測試項目 驗收條件 對應 PRD
2A.1 統計卡片 #diCnt / #doCnt / #ruleCnt 非空 FR-A1-01
2A.2 MQTT 卡片四態 #mqttSt 為「未設定/連線中/已連線/失敗」之一 FR-A1-02
2A.3 Modbus TCP 卡片 卡片靜態存在;⚠️ 已知 UI bug:硬編碼顯示「Port 502」(FR-A1-03 註腳,PRD 附錄 E E-01) FR-A1-03
2A.4 物理 / Expansion 切換 Tab 🏠 主機 8DI / 4DO ↔ Digital-SSR #0 16DI / 8DO 可切換 FR-A1-04
2A.5 RS485 卡片 — Finder 12 量測 12 格全顯示(電壓 V/電流 A/有功 W/無功 var/視在 VA/PF/頻率 Hz/諧波 %/總/正/反向 kWh),無 NaN FR-A1-05
2A.6 頂部控制列 Poll Rate Selector + IP + 連線狀態徽章 FR-A1-06 + A1-10
2A.7 側邊欄頁尾 系統時間跳動 + #sideVersion 顯示 v6.0.100 FR-A1-07
2A.8 I/O 卡片三態徽章 DI 顯示「待機/未啟用」;DO 顯示「關閉/開啟/未啟用」 FR-A1-08
2A.9 每張卡片 ↺ 清除統計 點按只重設該通道 FR-A1-09

#2B. Config 配置頁(FR-A2)

# 測試項目 驗收條件 對應 PRD
2B.1 Tab 切換 🏠 主機 / Digital-SSR #0 可切;物理通道 / 虛擬通道 / TCP 通道 三子分頁可切 FR-A2-01 / 02
2B.2 TCP 通道列表 進頁面後等 5 秒,#tcpChannelsList 渲染為清單或「尚無 TCP IO 通道」(不可保留「載入中...」) FR-A2-02b
2B.3 物理輸入「資料型態」下拉 I1~I8 每行有 數位/類比 dropdown FR-A2-02c
2B.4 DO 標籤 1-based 物理通道輸出列表顯示 DO1~`DO4;不可出現 DO0` FR-A2-02d / WI-102
2B.5 虛擬通道類型 計數器 / 計時器 / 類比邏輯三型可切換 FR-A2-03
2B.6 設備樣板 「PATLITE NE-M1ATB-M」+「Toggle Button」可點擊套用 FR-A2-06
2B.7 TCP IO Modal + 新增通道 → #tcpIoModal 開啟 + 欄位完整 FR-A2-08~15
2B.8 群組 Modal #groupModal 編輯成員清單 + Device Tag FR-A2-16
2B.9 儲存回饋 #toast 出現綠色成功訊息 FR-A2-04 / FR-A6-01

#2C. Rules 規則頁(FR-A3)

# 測試項目 驗收條件 對應 PRD
2C.1 規則列表 #rulesList 不停在「載入中」 FR-A3-01
2C.2 優先權提示 banner 顯示「越下方的規則擁有最終覆蓋優先權」 FR-A3-05
2C.3 規則卡片優先權徽章 每卡片標題前綴 🟢/🟡/🔴 之一(priority 0/1/2 對應) FR-A3-06b / WI-101
2C.4 新增規則 + 新增規則 → 右側 inline 編輯器 #ruleEditor 開啟 FR-A3-02
2C.5 三級優先權選擇器 #rulePriority 下拉含 🟢 一般 / 🟡 高 / 🔴 緊急 (互鎖) FR-A3-06
2C.6 互鎖實測 兩條互斥規則 + 一條設「緊急」→ DO 最終由互鎖決定 FR-A3-07
2C.7 啟停切換 toggle 後 /api/rules 與畫面同步 FR-A3-03

#2D. Devices 設備頁(FR-A4)

# 測試項目 驗收條件 對應 PRD
2D.1 5 槽 Expansion 卡片 #expSlots 顯示 5 槽,未連接者標「未連接」 FR-A4-01
2D.2 匯流排掃描 #btnScan → 進度條 + 結果列表(含 Finder slave 1, YX523R slave 4) FR-A4-02
2D.3 Modbus Probe #btnProbe 對 Slave 1, Reg 0, Count 4 → 成功且 raw hex 有資料 FR-A4-03
2D.4 EEPROM Modal 開啟 openEepromModal() → 顯示橘色警告「DIP OFF/OFF + 斷電上電」 FR-A4-04
2D.5 RS485 Modal 11 fieldMask 新增 RS485 設備 → 「總覽顯示」11 個 checkbox 全可勾選 FR-A4-05
2D.6 RS485 樣板 dropdown 含 Finder 6M / YX523R / 自訂三選項 FR-A4-06
2D.7 Bus Settings 不外露 Bus 1 #busSettingsModal 內僅 Port 1,無 Port 2 / bus1* FR-A4-08 + FR-H1-03

#2E. Settings 設定頁(FR-A5)

# 測試項目 驗收條件 對應 PRD
2E.1 裝置識別 #cfgName + #sysDeviceUid 可讀;UID 點擊複製 FR-A5-01
2E.2 系統時間 #sysCurrentTime.value 每秒跳動(用 .value 不是 .innerText) FR-A5-03
2E.3 授權卡片 #sysExpiresAt.value 顯示「永久授權」/具體日期/「未授權」 FR-A5-03
2E.4 License 啟用 #btnLicenseActivate → 輪詢 /api/license 直到 ACTIVE FR-A5-03
2E.5 License Renewal #renewalTokenInput + renewLicense() 路徑 FR-A5-11
2E.6 MQTT 設定 Broker / Port / Client / Auth 欄位儲存;TLS 已實作(#mqttTls 勾選 + #mqttTlsInsecure);出廠預設 tlsInsecure=true(不驗 CA,業主指定,勿改回) FR-A5-02
2E.6a MQTT 測試連線(v6.0.4) 點「測試連線」→ POST 回 202 → 前端輪詢 /api/mqtt/test 顯示「測試中 n/30」→ 結果成功/失敗;密碼欄留空 = 用已存密碼;對已連線同 broker 直接短路判定成功 FR-A5-02
2E.6b MQTT 命名空間(WI-155 / 6.0.0) #mqttProject+#mqttEnv 兩欄留空 = legacy mes/gateway/{uid};填值 = {proj}-{env}/gateway/{mac}(全小寫);儲存後心跳 topic 對齊 FR-A5-02
2E.7 Config Server 雙位址 + auto-disable banner #csUrl + #csCloudUrl 各自獨立;configServerAutoDisabled=true 時 banner 顯示 FR-A5-04 / 15
2E.8 網路模式三選一 #netModeSelect radio:自動 / 僅有線 / 僅 WiFi FR-A5-05
2E.9 DHCP/Static 切換 #ethDHCP ↔ #ethStatic 對應顯示 / 隱藏 IP 欄位 FR-A5-21
2E.10 WiFi AP 掃描流程(變體 = wifi) switchToApMode() → scanWifi() → 選 SSID → 儲存並重啟 FR-A5-06 / 20
2E.11 OTA 雙路徑 拖曳 #otaFileInput + 伺服器 #otaVersionSelect FR-A5-08 / 23
2E.12 破壞性維護防呆 重啟 / 恢復原廠 / 清除 三 Modal 各有遮罩 FR-A5-09
2E.13 MAC 軟體覆寫(進階,WI-155) 進階區可填軟體 MAC(不碰硬體 OTP)+ 即時驗證;設定後 90s 內無 IP 自動回退 防失聯;複製鈕給對外格式(無冒號小寫) FR-A5(WI-155)
2E.14 📟 設備日誌 按鈕(v6.0.1) 設定頁「儲存名稱」與「📟 設備日誌」同一列並排(v6.0.4 UI);點按開 /log.html 顯示即時 serial log FR-A5(WI-155-遠端診斷)

#🛑 Phase 2 的判準:畫面說成功,不算數

上面 2A–2F 驗的是「頁面元素在不在」。那擋得住整頁壞掉, 但擋不住這一族更常見的失敗:

畫面回成功、HTTP 回 200、清單上東西也在 —— 唯獨值沒寫進去,或寫到別的地方。

走查至今挖到的假 PASS 幾乎都是這個形狀(WI-199 index 撞號覆蓋、 WI-202 一個引號讓整頁設定蒸發、WI-206 下拉選項對錯韌體列舉)。

所以凡是在網頁上做的設定,存完要立刻打 API 對照,兩者相符才算過:

在畫面上做了什麼 立刻對照
幫 I/O 通道命名 GET /api/config 的 inputNames / doNames
建輸入群組 GET /api/signals —— sourceCount 不可以是 0
建輸出群組 GET /api/actions —— outputCount 不可以是 0
建規則 GET /api/rules + 交叉比對 signals/actions,抓懸空參照

懸空參照特別重要:群組被刪掉、規則還指著它,韌體是 fail-safe 當「關」, 不會報任何錯,畫面上也看不出來。

完整做法見驗收單〈情境 U:網頁設定流程〉—— 那一段就是為這件事寫的。


#Phase 3:跨頁與持久化驗證(FR-B)

# 步驟 驗收條件 對應 PRD
3.1 修改 Device Name + I/O 別名 出現成功 Toast FR-B1-01 / 03
3.2 F5 重新整理 設定保留 FR-B3-02
3.3 觸發系統重啟(rebootDevice() → #rebootOverlay 倒數) 90 秒內回上線 FR-B3-03 / FR-A5-22
3.4 重啟後驗證設定未掉 步驟 3.1 修改仍在 FR-B3-03
3.5 跨頁設定驅動呈現驗證 Config Alias 改 → Dashboard 卡片標題同步 FR-B1-01
3.6 TCP IO 持久化 新增 channel → 重啟後仍存在 FR-B1-07

#Phase 4:硬體煙霧測試(FR-C)

#H1. 初始化

# 步驟 驗收條件
H1.1 清空規則綁定 /api/rules ruleCount = 0
H1.2 關閉所有 DO 全部 OFF

#H2. Host / Expansion DO 跑馬燈(FR-C2)

測試員操作:觀察燈號與通道對應

# 動作 預期結果 Pass/Fail
H2.1 Host DO 1 ON (1秒) 🔴 紅燈亮 ☐
H2.2 Host DO 2 ON (1秒) 🟢 綠燈亮 ☐
H2.3 Host DO 3 ON (1秒) 🔵 藍燈亮 ☐
H2.4 Host DO 4 ON (1秒) 🔊 蜂鳴器響 ☐
H2.5 Expansion 0 DO 3 ON (1秒) 🔴 第二組紅燈亮 ☐
H2.6 Expansion 0 DO 4 ON (1秒) 🟢 第二組綠燈亮 ☐
H2.7 Expansion 0 DO 5 ON (1秒) 🔵 第二組藍燈亮 ☐
H2.8 Expansion 0 DO 6 ON (1秒) 🔊 第二組蜂鳴器響 ☐

#H3. RS485 驗證(FR-C3)

#H3-A. YX523R 光警器寫入(Slave ID=4)

透過 Dashboard setDO() 或 POST /api/modbus/manual_write(FR-I1-02)

# 命令 暫存器 寫入值 預期結果 Pass/Fail
H3.1 紅燈長亮 17 0x11 光警器顯示紅色 ☐
H3.2 綠燈長亮 17 0x13 光警器顯示綠色 ☐
H3.3 紅燈爆閃 17 0x31 紅燈爆閃 2 秒 ☐
H3.4 關閉 17 0x60 警報熄滅 ☐

人工確認點:測試員目視確認光警器燈色 / 爆閃模式(FR-C3-01)

#H3-B. Finder 6M.TB 讀取驗證(Slave ID=1)

# 步驟 驗收條件 Pass/Fail
H3.5 Dashboard RS485 卡片顯示 Finder 12 量測 12 格非 NaN,數值合理 ☐
H3.6 Modbus Probe Slave 1 / Reg 0 / Count 4 回應成功,rawHex 有資料 ☐

#H3-B2. 同型號多台 slaveId 持久化(v6.0.2,選做)

驗 6.0.2 修正:ModbusRegister.slaveId 存進 flash,重開機後不歸零、不退回陣列位置比對 → 同型號多台不串台。需兩台同型號設備(如兩台 SF965)。單台工站可跳過並標 H3-B2: SKIPPED (單台)。

# 步驟 驗收條件 Pass/Fail
H3.6a 兩台同型號各設不同 slaveId(≤32) 並儲存 兩張卡片各顯示自己 slaveId 的即時值,無交叉 ☐
H3.6b 重開機後回到 Dashboard 兩台仍以 slaveId 穩定綁定;值不互換、不串台 ☐

#H3-B3. 離線來源不發假 0(v6.0.7,選做)

驗 6.0.7:converter 模板引用到離線 RS485 來源時,整筆跳過發佈(不送 {"counter":0} 讓 MES 誤判計數歸零)。ConverterEngine::pushTemplate 依 _fillHadOfflineSource 跳過。需 broker 訂閱觀測。單台工站可跳過並標 H3-B3: SKIPPED。

# 步驟 驗收條件 Pass/Fail
H3.6c 建 converter 模板引用某 RS485 來源 → 閘控發佈,訂閱其 topic 來源在線時:每期收到含實值的 payload ☐
H3.6d 拔線 / 關機讓來源離線,續觀測 topic 完全靜默(不送 0);設備 log 出現 skip publish: RS485 source offline ☐
H3.6e 來源回線 自動恢復發佈實值 ☐

#H3-B4. SF965 計數器原生解碼(v6.0.8,選做,需 SF965 硬體)

驗 6.0.8 新 dataType VAR_SF965_PV(=8):SF965 PV@addr4 為特規 32-bit——高 3 byte=計數值、低 byte=小數點位數(dot)→ 值 = (raw>>8)/10^dot。選 SF965 型號套預設暫存器即用此型別(不再靠 ÷256 scale 湊)。

# 步驟 驗收條件 Pass/Fail
H3.6f RS485 新增設備選「SF965 計數器」樣板 → 套預設暫存器 PV 暫存器 dataType 顯示 SF965 PV(=8);儲存後讀回仍為 8 ☐
H3.6g Dashboard 顯示 SF965 計數即時值 dot=0 為乾淨整數、dot≠0 自動小數;與機台面板顯示一致(顯示 + 發佈一致) ☐

#H3-C. TDA-08B 稱重控制器情境驗證(Slave ID=1,v5.9.111 sensor-fusion 計件器情境)

對應源碼提交 9cea4cd(v5.9.111)TDA-08B + sensor-fusion 虛擬通道 + 計數器 peak-detection。 v5.9.112+ 已移除 TDA-08B 模板,本情境必須手動建立暫存器與虛擬通道。 完整逐欄位 / 標定流程 / 排錯:docs/hardware/setup-tda-08b.md(內部文件,未公開) 治具:TDA-08B 稱重控制器 1 台、5kg 標準砝碼、感測器(壓力 / 應變片)。

❗ curl 配置時 JSON 必須 compact(無空格):Python 用 json.dumps(obj, separators=(',', ':')),否則 firmware parser 靜默忽略。詳見 setup-tda-08b.md §2B。

#Step 1:手動建立 RS485 設備(Slave ID=1, 9600/8N1, ABCD Big-Endian)
# 步驟 驗收條件 Pass/Fail
H3.7 RS485 設定 → 新增「自訂設備」名為 TDA-08B 稱重控制器,Slave=1,輪詢 2000 ms 卡片顯示 🟢 在線 ☐
H3.8 加 5 筆讀取暫存器(FC03):實時值@11(INT32) / 穩定狀態@9(UINT16) / 線上狀態@10(UINT16) / 峰值@43(INT32) / 谷值@75(INT32) 5 行顯示 ✅ 啟用,倍率=1,偏移=0 ☐
H3.9 加 2 筆寫入暫存器(FC06):標定指令@113(UINT16) / 砝碼值@108(UINT16) 2 行顯示,模式=Write ☐
H3.10 儲存設備設定 設備卡片顯示 7 個暫存器即時值 ☐
#Step 2:建立 Scale 虛擬通道(sensor-fusion)
# 步驟 驗收條件 Pass/Fail
H3.11 Config → 邏輯類型「⚖️ 秤重計(重量→件數)」新增虛擬通道 Scale 通道卡片出現 ☐
H3.12 Scale 設定 — 來源=Modbus TDA-08B 實時值,tare=空秤值,unitWeight=單件重量(克),tolerance=±10% 公式預覽顯示 round((讀值 − tare) / uw) ☐
H3.13 空秤點「⚙️ 自動校準」→ 寫入 標定指令=4(清零) 實時值歸零 ±0.5g ☐
#Step 3:計數器 peak-detection 規則
# 步驟 驗收條件 Pass/Fail
H3.14 新增計數器虛擬通道 合格計件器,triggerSource=Scale.currentCount,threshold=1 通道卡片顯示 count=0 ☐
H3.15 規則:合格達標 (count ≥ 10) → MQTT 通知 mes/gateway/{uid}/scale/done 規則 🟢 Active ☐
H3.16 📢 提示:放上 1 顆 5g 標準砝碼於秤上 Scale.currentCount = 1,計數 +1 ☐
H3.17 重複 9 次(共 10 顆砝碼) 每次讀值穩定在 unitWeight ± tolerance 才 +1;雜訊或半顆不算 ☐
H3.18 達到 count=10 觸發 MQTT 通知 broker 收到 scale/done 訊息 ☐
#Step 4:標定指令往返驗證
# 步驟 驗收條件 Pass/Fail
H3.19 規則「MQTT→清零」: 外部 mes/gateway/{uid}/scale/calibrate → Modbus Write 標定指令=4 TDA-08B 實時值歸零 ☐
H3.20 規則「MQTT→零點」: 外部 ... /scale/zero → 標定指令=1 TDA-08B 重新標定零點 ☐
H3.21 (選做)寫 砝碼值=5000 + 標定指令=2 標定增益 5g 砝碼讀值 = 5000 ±5 ☐

人工確認點:H3.16 / H3.17 / H3.21 需測試員實際操作砝碼並目視確認讀值穩定(FR-C3-01 延伸)

#Step 5:校正引導精靈 chain 驗證(v5.9.130+,選做)

驗證 MQTT-Chain 工作流校正精靈(4 步驟 + 燈號)。需先佈建 wizard(見 guide-calibration-wizard.md §5)。無 wizard 佈建則跳過並標 H3 Step5: SKIPPED。

# 步驟 驗收條件 Pass/Fail
H3.22 重置:發 …/cmd/signal/3=1→0 …/cmd/signal/0(state)=0,燈號全滅 ☐
H3.23 推進標零:發 …/cmd/signal/1=1→0(瞬時) 收到 …/rules/{n}/trigger 校正標零;state→1;第一顆燈亮 ☐
H3.24 順序強制:state=0 時發 …/cmd/signal/2(標增益) 不該 fire(AND 條件 state==1 不成立) ☐
H3.25 推進標增益:state=1 時發 …/cmd/signal/2=1→0 state→2;第二顆燈亮;reg108/113 寫入 ☐
H3.26 (有砝碼)放 5kg 砝碼跑標零→標增益完整流程 weight 校到 5.00 ±0.01 ☐

人工確認點:H3.23/H3.25 目視燈號切換;H3.26 需實體砝碼。

#H4. 類比輸入 AI 驗證(FR-C4)

# 步驟 驗收條件 Pass/Fail
H4.1 📢 提示測試員:將 SG-002 調至 5.00V — —
H4.2 等待 3 秒後讀取 /api/io ai[1] 值在 5.00V ±5%(4.75 ~ 5.25V) ☐
H4.3 📢 提示測試員:將 SG-002 調至 0.00V — —
H4.4 等待 3 秒後讀取 /api/io ai[1] 值在 0 ~ 0.25V ☐

容差數值在 HW 拆工後由 web/tests/fixtures/factory-baseline.json 鎖定。

#H5. 數位輸入 DI 驗證(FR-C5)

# 步驟 驗收條件 Pass/Fail
H5.1 📢 提示測試員:按下 DI 1 開關 — —
H5.2 等待偵測 /api/io di[0] = true 10 秒內偵測到 ☐
H5.3 📢 提示測試員:放開 DI 1 開關 — —
H5.4 等待偵測 /api/io di[0] = false 10 秒內偵測到 ☐

#H6. 網路 Failover 驗證(變體 = wifi 限定,FR-C6)

Skip 條件:variant != wifi 時整個章節跳過,並在報告標 H6: SKIPPED (ethernet-only)

# 步驟 驗收條件 Pass/Fail
H6.1 📢 拔除 Ethernet 網路線 — —
H6.2 等 30 秒,DUT 自動切到 WiFi WiFi IP 可 ping,MQTT 重連 ☐
H6.3 📢 插回 Ethernet — —
H6.4 等 30 秒,DUT 切回 Ethernet 有線 IP 可 ping,MQTT 重連 ☐

#H7. 跨協議多對多路由(FR-C7)

# 步驟 驗收條件 Pass/Fail
H7.1 Fan-out: TCP Parser → Host DO 1 + Expansion DO 3 + MQTT Converter 一次外部 MQTT 觸發 → 兩燈同亮 + 收到 broker 推送 ☐
H7.2 防迴圈: Converter Topic = Parser Topic 10 秒內無 MCU 重啟 / 無 watchdog ☐

#H8. 機型感知 UI 過濾 + 心跳燈(WI-151 / WI-152,8310 / 8320)

來源 = OTP boardInfo().wifi。此章節依機型分流:8310 驗「無 WiFi + 琥珀燈」,8320 驗「有 WiFi + 藍燈」。

# 步驟 8310(hasWifi=false) 8320(hasWifi=true) Pass/Fail
H8.1 /api/system hasWifi/boardModel false / 8310 true / 8320 ☐
H8.2 設定頁網路區 WiFi 欄位 隱藏 SSID/密碼 + 介面模式選單(強制乙太網路) 露出 SSID/密碼 + 三選一模式 ☐
H8.3 📢 目視心跳燈 琥珀色(紅+綠同亮) 藍燈(LEDB) ☐
H8.4 AP 模式進入 進不了(無 WiFi,會 fallback) 可進 AP(switchToApMode()) ☐

#H9. 冷開機:設備比網路先起來(WI-236,每一台都要做)

斷電前先確認所有供電來源;同時接 USB 與獨立 DC 時,必須兩路都切斷並確認設備熄燈。延長線斷電但 USB 仍供電,不算冷開機。

為什麼要單獨測:H6 只是拔網路線,那時分享器是好的 —— 線一插回去馬上就有 IP。 但客戶端停電是整廠一起停,分享器也會關,而設備開機比分享器快很多:

大約多久可用
設備 20 幾秒
一般網路分享器 60~120 秒

所以設備開機時網路根本還沒好。這件事在 6.0.94 之前是壞的 —— 一台 8310 因此離線 18.4 小時而沒有人發現:它有電、燈在閃, 雲端後台也顯示「上線中」,只有真的去打開網頁才會發現進不去。

⚠️ 8310 沒有 Wi-Fi 備援,一定要測。 8320 就算有線慢了還有 Wi-Fi 頂著, 所以同樣的問題在 8320 上不容易看出來 —— 那正是它長期沒被發現的原因。

# 步驟 驗收條件 Pass/Fail
H9.1 📢 把 DUT 與網路分享器插在同一條延長線上,記下 DUT 的 IP — —
H9.2 📢 關掉延長線電源,等 10 秒,再打開。之後不要碰任何東西 — —
H9.3 等 5 分鐘後:curl -s -o /dev/null -w "%{http_code}" http://<DUT>/ 回 200 ☐
H9.4 /api/system 的 network.ip 不是 0.0.0.0 ☐
H9.5 /api/diag 的 bootCount 只比 H9.2 之前多 1~2 次(網路晚到會做一次回復重開,屬正常) ☐

兩種「沒過」的樣子,都不可出貨:

看到的 意思
網頁打不開,ping 也不通 設備沒拿到 IP,也沒有再試
雲端顯示上線中,但網頁打不開 最陰險的一種:底層網路好了、MQTT 也通,設備自己卻不知道 → 網頁伺服器沒啟動。從遠端看一切正常

⚠️ 第二種不會出現在任何監控指標上。唯一的檢查方式就是真的去打開那個網頁(H9.3)。

對應驗收單:7.4 設備和網路設備一起斷電


#H10. 單機斷電後完整復原(與驗收 7.1–7.3 對齊)

保留起始完整設定與模板,單獨切斷 DUT 所有供電(含 USB 與獨立 DC),確認熄燈並等待 30 秒後復電(網路設備保持供電)。核對網路、RS485 清單、規則引用、Converter 模板與 onChange,並以新鮮 MQTT 訊息及輸出雙向轉換驗證功能。逐欄比對 D4/ST.16;軟體 reboot 不代替此項。H9 另外驗設備與網路共同斷電。

#Phase 5:端到端業務流(FR-G)

必須在 Phase 4 全通過後才執行。

# 步驟 驗收條件 Pass/Fail
5.1 配置 1 個 DI / 1 個 TCP Parser / 1 個虛擬輸入 三者 Enabled ☐
5.2 配置 1 個 DO / 1 個 TCP Converter / 1 個虛擬輸出 三者 Enabled ☐
5.3 建立 IG_All_Inputs / OG_All_Outputs 各納 3 件 群組 Modal 儲存成功 ☐
5.4 建立 Rule_E2E:IG_All_Inputs → OG_All_Outputs(priority 0) 規則卡片含 🟢 徽章 ☐
5.5 觸發外部 MQTT → Parser 命中 實體 DO 點亮 + Broker 收到 Converter 推送 ☐
5.6 Dashboard 三類卡片同步 Active Input Group / Rule / Output Group 皆變色 ☐

#Phase 5B:磅秤、量測時間與復電都要驗(6.0.122)

出廠時也要做現場會做的驗收:必須逐列執行驗收 v3.51 的 SC.1~7、TS.1~7、NR.1,並完成其他適用的既有驗收及本文 Phase。以 現場驗收流程「新增驗收」節為操作與通過條件的唯一來源;下表指定出廠證據與責任邊界,不縮減步驟。

ID 測項 出廠執行與證據
SC.1 前置與隔離 依驗收的動作逐項做並保存結果;電腦模擬、測試設備與實際磅秤的結果分開填。
SC.2 標零與命令放開 依驗收的動作逐項做並保存結果;電腦模擬、測試設備與實際磅秤的結果分開填。
SC.3 3/4/5 段與收尾 依驗收的動作逐項做並保存結果;電腦模擬、測試設備與實際磅秤的結果分開填。
SC.4 重校與漏收尾 依驗收的動作逐項做並保存結果;電腦模擬、測試設備與實際磅秤的結果分開填。
SC.5 失敗不誤報完成 依驗收的動作逐項做並保存結果;電腦模擬、測試設備與實際磅秤的結果分開填。
SC.6 復電後 reset 依驗收的動作逐項做並保存結果;電腦模擬、測試設備與實際磅秤的結果分開填。
SC.7 實秤精度與最終清理 實體磅秤與核准砝碼必測;無資源時交接待現場,不得签完整磅秤放行。
TS.1 新範本與既有遷移 依驗收的動作逐項做並保存結果;電腦模擬、測試設備與實際磅秤的結果分開填。
TS.2 UTC 與原始樣本 依驗收的動作逐項做並保存結果;電腦模擬、測試設備與實際磅秤的結果分開填。
TS.3 未知時間與校時 依驗收的動作逐項做並保存結果;電腦模擬、測試設備與實際磅秤的結果分開填。
TS.4 延遲接收/補送 依驗收的動作逐項做並保存結果;電腦模擬、測試設備與實際磅秤的結果分開填。
TS.5 讀失敗與恢復 依驗收的動作逐項做並保存結果;電腦模擬、測試設備與實際磅秤的結果分開填。
TS.6 onChange 與格式邊界 依驗收的動作逐項做並保存結果;電腦模擬、測試設備與實際磅秤的結果分開填。
TS.7 接收端與清理 Gateway 清理必測;外部接收端無入口時明列待整合與負責人,不能捏造接收端 PASS。
NR.1 路由器延後啟動 合併 H9 流程取證,勿二次人工重開;仍不替代 H10 獨立 DUT 斷電。

#哪些程式會幫你做,哪些要另外做

  • scripts/tests/test_scale_multical.py:校正建構與模擬;scripts/tests/calibration_write_failures.py --out OUTPUT_DIR:production loop 寫入失敗停止及 3/4/5 段。需要專案開發環境,不能當實秤精度。
  • scripts/tests/calibration_no_scale_live.py --gw DEVICE_IP --out OUTPUT_DIR:無磅秤實機負例,會建立夾具及刻意重開;只在已備份的隔離台操作,結束核對完整清理。不能拿缺設備、沒收到命令的沉默當 PASS。
  • scripts/tests/wi250_timestamp_live.cjs:指定實驗室 .46 真 Finder 的 7 項 broker 路徑測試,須提供本輪 EXPECT_FW 與 EXPECT_BUILD_ID;不是任何現場 IP 可直接套用的通用命令。
  • Native/host clock 故障測試、實際 Chrome 範本測試、遷移測試與逐輪證據補足 TS 項;單一 timestamp 腳本不代表 TS.1~7 全部完成。
  • 現有 test:gate:full/acceptance_run.py 沒有自動串入以上全部新流程。執行者必須另附 SC/TS/NR 結果表;任一適用項缺結果、FAIL 或未清理,不可把出廠標成完整通過。
  • 磅秤精度、接點量測、接收端事件時間及完整 H9/H10 依實際資源分別取證。移交待現場項需有負責人與條件,不是放寬 PASS。

#Phase 5C:線上多段校正(WI-252,134 beta)

出廠完整承接 現場 OC.1~OC.12,該節是操作與判準的唯一來源,包含工程命令、治具前置及結果欄。先通過 OC.1,才可進行硬體寫入。不可為了工站先測而調高 OTA 上限或改用 USB 繞過候選門檻。

ID 測項 工站執行/證據
OC.1 候選容量與安裝識別 逐項依現場 OC.1 操作;工站填本台本輪證據與層級,缺治具/業主 Edge 時保留 NOT RUN 並交接,不得代簽。
OC.2 控制器設定與精確換算(含 TDA-08B 狀態位元勘誤;132無版本白名單) 逐項依現場 OC.2 操作;工站填本台本輪證據與層級,缺治具/業主 Edge 時保留 NOT RUN 並交接,不得代簽。
OC.3 三/五段累加與完整收尾 逐項依現場 OC.3 操作;工站填本台本輪證據與層級,缺治具/業主 Edge 時保留 NOT RUN 並交接,不得代簽。
OC.4 原重量 payload 夾帶狀態、固定重量持續上報與原設定 逐項依現場 OC.4 操作;工站填本台本輪證據與層級,缺治具/業主 Edge 時保留 NOT RUN 並交接,不得代簽。
OC.5 新鮮穩定樣本與收尾防呆 逐項依現場 OC.5 操作;工站填本台本輪證據與層級,缺治具/業主 Edge 時保留 NOT RUN 並交接,不得代簽。
OC.6 ACK、冪等與順序/重量負例 逐項依現場 OC.6 操作;工站填本台本輪證據與層級,缺治具/業主 Edge 時保留 NOT RUN 並交接,不得代簽。
OC.7 寫入/量測故障與未知結果:133 短暫唯讀失敗135須至少5秒穩定量測才可續段;達 10 秒量測缺口/設定或感測器故障仍停止;另驗持續讀值與保活下人工等待逾 5 分鐘 逐項依現場 OC.7 操作;工站填本台本輪證據與層級,缺治具/業主 Edge 時保留 NOT RUN 並交接,不得代簽。
OC.8 租期、Edge/OPTA 重開與取消 逐項依現場 OC.8 操作;工站填本台本輪證據與層級,缺治具/業主 Edge 時保留 NOT RUN 並交接,不得代簽。
OC.9 目標/廣播保留鎖與其他設備 逐項依現場 OC.9 操作;工站填本台本輪證據與層級,缺治具/業主 Edge 時保留 NOT RUN 並交接,不得代簽。
OC.10 Edge 單重量 topic/命令 ACK 與原始量測時間 逐項依現場 OC.10 操作;工站填本台本輪證據與層級,缺治具/業主 Edge 時保留 NOT RUN 並交接,不得代簽。
OC.11 實秤精度與真正斷電保存 逐項依現場 OC.11 操作;工站填本台本輪證據與層級,缺治具/業主 Edge 時保留 NOT RUN 並交接,不得代簽。
OC.12 長時串流、清理與最終簽核 逐項依現場 OC.12 操作;工站填本台本輪證據與層級,缺治具/業主 Edge 時保留 NOT RUN 並交接,不得代簽。

同一個 ID 可有主機、MQTT+UART替身、真實OPTA+RS485治具、實秤、業主Edge 多列結果。工站只能簽自己實際執行的層級;完整線上校正交付需補齊所有適用層級。控制器掉電保存不能用 OPTA config 備份替代;業主 Edge 生產統計分流不能用我們的模擬器替代。

test:gate:full、acceptance_run.py 尚未自動執行 OC 全套。Phase 8 摘要必須附 OC.1~12 逐項結果、原始證據與未完成責任人。缺任何適用結果、容量 FAIL、未恢復配置或未完成實秤/Edge 驗收,就不能簽完整出廠/交付 PASS。舊 123、其他 UID 或較舊 Build ID 的 PASS 不繼承。

#Phase 6:OTA + 升級迴歸(FR-D / FR-E)

# 步驟 驗收條件 Pass/Fail
6.1 上傳 OTA payload(拖曳或伺服器版本) #otaProgressBar 100% 完成 ☐
6.2 觸發重啟 RTC Backup Register swap flag 設為待 swap ☐
6.3 📢 重啟期間目視確認 無紅燈閃爍(紅燈 = swap fail) ☐
6.4 重啟後比對版本 /api/system version 已切到新版,無 rollback ☐
6.5 跨版本升級驗證(N-1 → N) 既有 Rule / Modbus / MQTT 設定無損;新欄位有預設值 ☐
6.6 模擬 OTA 中斷後復原 5 分鐘內以舊版可開機 ☐

#Phase 6B:遠端維運健檢(v6.0.1)

驗證 VPN-only / 現場無 USB 情境的遠端診斷能力。需 PERM_ADMIN(Bearer smmsadmin)。

# 步驟 驗收條件 Pass/Fail
6B.1 GET /api/log(帶 Bearer) 回純文字 ring buffer(text/plain;RS485 輪詢 / MQTT / 開機序列可見);無 Bearer → 401(自動化 V6-DIAG.1/2) ☐
6B.2 開 /log.html(走 QSPI) 頁面渲染即時 log;設定頁「📟 設備日誌」按鈕可達 ☐
6B.3 GET /api/diag(帶 Bearer) 回 resetReason/bootDetail/prevResetReason/bootCount/prevUptimeSec/uptimeSec/rawRsr/fwVersion;fwVersion 應等於 /api/system version;無 Bearer → 401(自動化 V6-DIAG.3/4/5) ☐
6B.4 主動重啟後查 resetReason 標記正確重開 → SOFTWARE(bootDetail 附細節);非當機不應標 UNEXPECTED ☐
6B.5 密碼遮罩不外洩 log 內 MQTT/AP/license 密碼皆遮罩(****/長度),無明文 ☐

⚠️ 勿以「打整頁 + 高頻並發」壓 /api/log(會觸 IWDG 重開);/ 是 gzip,curl 用 --compressed。


#Phase 7:出貨前清理(FR-H)

由 WI-103 自動化腳本執行。

# 步驟 驗收條件 Pass/Fail
7.0 授權撤銷門控(WI-145,選做) 撤銷狀態下:TCPIO / MQTT 對外功能被擋;DIO / 管理介面不擋(設備仍可設定/救援);撤銷 banner 於下次心跳(~127s)顯示 ☐
7.1 License Reset → /api/license status = UNLICENSED 重啟後維持 UNLICENSED ☐
7.2 清除測試殘留(Rules / Virtual / TCP IO / MQTT broker / Config Server / WiFi 密碼) 各端點回應全空 / 預設值 ☐
7.3 確認 #busSettingsModal 不外露 Bus 1 DOM 不含 bus1* element ☐
7.4 記錄出廠 baseline configCrc 寫入結果摘要 + DUT QR 標籤 ☐
7.5 重啟一次 → 30 秒內三 endpoint 200 /api/system /api/config /api/io ☐

註 — 校正精靈 / wdprobe / watchdog:H3-C Step5 佈建的 wizard signals/actions/rules、以及 watchdog 用的 wdprobe signal,屬部署時佈建、非出廠基線,會被步驟 7.2 一併清除。出廠不保留;現場部署時依 guide-first-deployment.md §6 重新佈建。


#Phase 8:結果輸出與彙整(FR-F)

#總結表

Phase 測試項目數 Pass Fail Skip
Phase 0 連線 7
Phase 1 初始化 4
Phase 2 UI(A~E) 45
Phase 3 跨頁/持久化 6
Phase 4 硬體(H1~H8) 32(H6 wifi/8320 限定 4;H3-B2 需兩台同型;H3-B3 需 broker 觀測;H3-B4 需 SF965;H8 依機型分流)
Phase 5 E2E 6
Phase 6 OTA + 升級 6
Phase 6B 遠端診斷 5
Phase 7 出貨清理 6
Phase 5B 新驗收 SC 7+TS 7+NR 1(NR 與 H9 共用證據,不重複計執行數)
本輪合計 按實際適用 ID 去重計數,舊 117 不含後增項,不得作新版總數

自動化入口範圍:test:factory = functional 6 + pages 6 + v6 13 + stability 16,共 41 個測試;test:gate 為其中 35 項。test:gate:full 另串 regression/converter/backup,enable 仍按既有政策列非阻擋結果;它不含 test:persist、驗收執行器與人工 Phase,因此名稱中的 full 不代表整份出廠完成。RG.5 須 RG_ALLOW_REBOOT=1 才執行;所有 SKIP 都須列明。完整出廠另需逐項完成本文 Phase 0–8、0A、H9/H10、CV.5/CV.6、ST.16 並簽核。

#結果摘要 metadata

DUT UID:          ___________________
DUT MAC:          ___________________ (12-hex 對外身分)
Board Model:      8310 | 8320
Variant:          ethernet | wifi
FW Version (前):  ___________________(本輪 6.0.134 beta,實際讀回並核對Build ID)
FW Version (後):  ___________________ (Phase 6 後)
configCrc (前):   ___________________
configCrc (後):   ___________________ (Phase 7 後)
Boot Reason:      ___________________ (Phase 6B /api/diag)
測試日期:          ___________________
測試員:            ___________________
工站位置:          ___________________
PRD v1.2 已知 bug 命中:  E-01 / E-04 / E-08 / E-09 (列舉)
擋出貨 bug:        無 | E-XX

#判定

  • ☐ PASS — 全部通過 + 0 個擋出貨 bug → 可出貨
  • ☐ CONDITIONAL — 全部通過 + 含 🟡 不擋 bug → 可出貨但記錄
  • ☐ FAIL — 任一擋出貨 bug 或 Phase 失敗 → 退回工程修復

#失敗項目記錄

Phase # 描述 對應 PRD FR / 附錄 D 編號 對應 sprint card 備註

#附錄 A:API 快速參考

用途 API Method 對應 PRD
韌體 + 系統摘要 /api/system GET FR-0
全配置 roundtrip /api/config GET / POST FR-A5-10
Config Server payload /api/config_server GET FR-A5-04
I/O 即時值 /api/io GET FR-C
直接驅動 DO /api/io/do POST FR-I1-01
規則 /api/rules GET / POST FR-A3
訊號群組(Signal) /api/signals GET / POST FR-A3
動作群組(Action) /api/actions GET / POST FR-A3
TCP IO /api/tcpio GET / POST FR-A2
Converter 模板 /api/converter/template GET / POST FR-A2
授權狀態 /api/license GET FR-A5-03
授權啟用 / 續約 /api/license/activate / /renew POST FR-A5-03 / 11
授權憑證遞送(救 outbound 壞設備) /api/license/token POST WI-147
網頁 Serial Log(v6.0.1) /api/log GET(PERM_ADMIN) Phase 6B
開機診斷(v6.0.1) /api/diag GET(PERM_ADMIN) Phase 6B
MQTT 測試連線(v6.0.4) /api/mqtt/test POST(202)/ GET(輪詢) Phase 2E.6a
OTA 上傳 / 伺服器 /api/ota/upload / /api/ota/server POST FR-D / FR-A5-08
Modbus 掃描 / Probe / 改 EEPROM / 手寫 /api/modbus/{scan, probe, eeprom_write, manual_write} POST FR-A4 / FR-I
重啟 / 恢復原廠 /api/reboot / /api/factory_reset POST FR-A5-09 / FR-H1-01

不存在的端點(404,腳本不可引用):/api/devices、/api/status、/api/health、/api/version、/api/expansion、/api/tcp_io、/api/templates。

#附錄 B:操作手冊章節對照

出廠測試 Phase 操作手冊章節
Phase 0 連線 §6 首次上線流程
Phase 2A Dashboard §8 總覽頁操作
Phase 2B Config §9 配置頁操作
Phase 2C Rules §10 規則頁操作
Phase 2D Devices §11 設備頁與 RS485 操作(含 EEPROM)
Phase 2E Settings §12 設定頁操作
Phase 3 持久化 §14 備份、還原與工廠重置
Phase 4 H2 DO §9.2 設定 DO1-DO4 輸出
Phase 4 H3 RS485 §11.2a 自訂 Modbus 設備 / §11.2b 手動寫入
Phase 4 H4 AI §9.3 類比邏輯處理
Phase 4 H5 DI §9.1 設定 I1-I8 輸入
Phase 4 H7 多對多 §10 規則引擎 + TCP IO
Phase 6 OTA §13 韌體更新

#附錄 C:PRD v1.2 已知 UI bug 對工站的影響

Bug ID 說明 影響 Phase 處理方式
E-01 Modbus TCP 卡片硬寫 Port 502 Phase 2A.3 腳本對 /api/config tcp.port=5000 斷言;UI 文字差異記為 known issue
E-03 Rules 卡片 priority 0 缺 🟢 徽章 Phase 2C.3 ✅ 已修(WI-101)
E-04 HTTP server 並發 reset Phase 2D 全段 腳本層序列化 fetch;FR-A5-24 韌體層長期解
E-06 Config DO 0-based Phase 2B.4 ✅ 已修(WI-102)
E-07 baseline 殘留未命名規則 Phase 1.1 / Phase 7 由 WI-103 cleanup 處理
E-08 Modbus Probe 預設 Slave 3 Phase 2D.3 UX 改善卡,不擋
E-09 UI「Port 1」 vs API busId=0 Phase 2D.7 / RS485 Modal 腳本斷言 API 數值,不對 UI 文字斷言

已關閉 (False Positive):E-02(TCP loading 慢顯示)、E-05(時間欄位 probe 用錯 selector)。


#文件修訂紀錄

日期 版本 韌體基線 變更
2026-09-09 3.8 6.0.94 新增 H9 冷開機(設備比網路先起來,WI-236) —— H6 只拔網路線、那時分享器是好的;但現場停電是整廠一起停,而設備 20 幾秒就開好、分享器要 60~120 秒。6.0.94 之前這是壞的:一台 8310 因此離線 18.4 小時而沒有人發現,雲端後台還顯示「上線中」。8310 沒有 Wi-Fi 備援必測。同時韌體基線 6.0.90 → 6.0.94。
2026-08-20 2.5 6.0.65 新增雲端備份/還原閉環(test:backup,4 項)與 ST.15 雲端設定完整性
2026-08-20 2.4 6.0.65 新增啟用/停用機制回歸(test:enable,6 項);factory-functional 的 CH_TCP 輸出改用 channelId、MQTT 輔助函式支援 TLS broker;ST.3 判準改為只看已啟用的規則
2026-08-19 2.3 6.0.65 新增 MQTT Converter 鏈路回歸(test:converter,6 項);新增環境設定檔 factory-env.js 與「換設備要改哪裡」章節;ST.14 環境符合性
2026-08-19 2.2 6.0.65 新增「先跑自動化閘門」章節與缺陷對應表;閘門擴充到 29 項(新增 ST.11 TCP 來源不可能條件、ST.12 token 免密碼更新、2F 佔位符殘留);基線自 6.0.8 更新
2026-07-16 2.1 6.0.8 /api/diag 欄位名對齊實際韌體
2026-09-02 3.7 韌體基線 → 6.0.90(WI-216/WI-217),兩者皆無功能變更:/api/net/diag 移除 netifIsDefault(mbed get_default_instance() 是 weak、回編譯期預設,量不到執行期 set_as_default(),該欄恆為 false,長得像 WI-212 復發)、app.js loadTcpIo() 刪除對著已改名容器組 HTML 的死碼。實機驗證 test:gate 35/35、factory-stability 16/16、RG.9 通過。另開 WI-218:OTA 後設備在 WiFi 上要 605 秒 MQTT 才接上,期間每次重連失敗卡住主迴圈 18.4 秒,ST.0/ST.1/RG.8 會連紅三項 —— 測試的「開機安定」判準(只等 uptime≥120s)在無線環境不成立,應改為輪詢 mqttConnected。
2026-09-01 3.6 首次在無線環境完整重跑三套。 抓出兩個只在較慢介面發作的假紅並修掉,韌體沒有回歸:WI-214(2B 固定等待 → 改輪詢到數量相符,斷言一字未改)、WI-215(RG.9 → 先靜置 8 秒再量、最多重試 4 次,timeout 120s→240s;重試在驗證時真的被用到,第一次量到 0、重試後才成功)。順帶開卡 WI-216(netifIsDefault 恆為誤導,已從 RG.9 訊息移除)、WI-217(loadTcpIo() 死碼)。

#2026-09-11 v3.9 同步紀錄

對齊驗收 v3.45/候選 6.0.100,新增 0A、H10、CV.7;ST.16 加入虛擬引用與參數持久化判準。測試基線改讀 src/config.h;保留 EXPECT_FW 覆寫。test:gate 含暫時寫入,不能稱唯讀。

#2026-09-12 v3.10 同步紀錄

驗收 v3.46/出廠 v3.10 同步補記正式雲端 2.5.8 的實測狀態與剩餘門檻;候選規範基線仍為 6.0.100,8320 的 6.0.103 為診斷版。測項 ID 與對應不變;補上 backup 整輪重開數守門,清理失敗與診斷缺樣都不放行。

#2026-09-12 v3.11 同步紀錄

驗收 v3.47/出廠 v3.11 同步明列各套件的版本與證據範圍,撤除未標版本的回歸全數通過標題;階段 7/H9/H10 補上切斷 USB 與獨立 DC 等所有供電。韌體規範基線仍為 6.0.100,未將診斷版 111 或單輪 41 項通過提升為整機放行;測項 ID 不變。

#2026-09-12 v3.12 同步紀錄

驗收v3.48/出廠v3.12同步WI-246的單次補發訂閱前置與失敗分類。出廠CV.4使用MQTT客戶端實際SUBACK,未放寬12秒/至少1則判準;驗收B6固定等待的證據限制明列。測項ID與6.0.100規範基線不變,111的實機結果另記。

#2026-10-01 v3.13 同步紀錄

承接驗收 v3.50 的全部 SC/TS/NR 項,區分模擬、實機與現場精度,明列既有自動化未自動串入新版完整流程。

#驗收既有項目的出廠交接補齊

ID 測項 工站操作/通過條件
0A.7 供電與接地 依驗收 0.1 檢查工站供電與接地,記錄數值/檢查者;客戶現場接地列入交接,工站 PASS 不等於現場 PASS。
2A.10 操作紀律 逐項依驗收 U.0 核對設備畫面、API 讀回及保存設定;不以按下保存或畫面 toast 當成功。
CT.1 計數事件 完整執行驗收 CT.1:隔離計數來源觸發一次,面板與網頁均加 1、MQTT 恰一筆;靜止 60 秒零筆。無計數器治具記待現場或不適用原因。
8.2 照片與證據 工站銘牌、接線、總覽與本輪結果歸檔;現場最終照片交接安裝人員補齊,不沿用工站照片。
8.3 簽核與交接 出廠負責人簽核結果與未完項;業主現場簽名由現場執行,不得提前代簽。完整交付須有雙方確認或書面未完項。

#附錄:版本演進與工程判定規則

以下保留先前的版本紀錄與工程規則,供查問題時使用。

#歷史:2026-10-01 出發前候選補充(6.0.122)

下方 2026-09 的版本與逐輪紀錄保留為歷史;本輪候選為 6.0.122,並非 1.0 正式放行。雙機全套最終 .46 72 PASS、.250 70 PASS/2 硬體 SKIP(含保留首輪失敗的明確補跑);acceptance .46 29 PASS/2 原接線 WARN,.250 18 PASS/5 硬體 SKIP。

本次重點為 磅秤零點+3~5 段 與 MQTT 原始量測時間。缺實體磅秤的精度/實際 RS485 校正仍需現場驗收;不能把邏輯故障模擬當成實秤 PASS。整組斷電且路由器延後啟動已驗雙機自動恢復與 186 秒穩定觀察;未做逐路接點/獨立 DUT 斷電,也未量精準全滅時間。本次整組斷電不能替代下方 H9/H10 全部條件。

新驗收應檢查量測時間屬於原樣本、未知時間為 null、寫入失敗不誤亮完成燈,以及復電後先 reset 再重新標零。原測項 ID 與歷史證據不改寫。

v3.7 修訂摘要(2026-09-02,韌體基線 → 6.0.90):

  • 韌體基線 6.0.89 → 6.0.90(WI-216 / WI-217)。兩者都無功能變更: /api/net/diag 拿掉恆為誤導的 netifIsDefault、app.js 刪掉一段死碼。 驗證結果:test:gate 35/35、factory-stability 16/16(ST.1 40/40、 ST.9 bootCount 全程未變)、test:regression 的 RG.9 通過。
  • ⚠️ 新開 WI-218:OTA 之後不要馬上跑閘門。 這次 OTA 後設備在 WiFi 上 花了 605 秒 MQTT 才接上,期間每次重連失敗把主迴圈卡住 18.4 秒 (設備單執行緒,那段時間 HTTP server 沒被輪到)。結果 ST.0 ECONNRESET、 ST.1 超時、RG.8 抓到一次 NTP 校時觸發的授權重驗 —— 三項紅在三個不同理由上, 但根都是「設備還在暖機」。等 /api/system 的 mqttConnected 翻成 true 再開跑,同樣的測試全綠。詳見 docs/sprints/cards/backlog/wi-218-*.md。

v3.6 修訂摘要(2026-09-01,首次在「無線」環境完整重跑三套):

  • 兩個假紅被抓出來並修掉,都在測試裡、韌體沒有回歸(WI-214 / WI-215)。 當晚網路線被移到 8310,8320 落到 WiFi 上 —— 這是這兩個缺陷第一次被看見, 因為它們只在較慢的無線環境發作,有線環境一路全綠。
  • RG.9 改為「先靜置再量、最多重試 4 次」,timeout 120s → 240s。 原因:/api/net/diag 是在 inbound handler 裡再開 outbound 連線,而設備共 4 個 socket(ADR-019)。套件連跑時借不到 socket,connect() 回 -1,長得像網路斷了。 靜置後連量三次全部健康(閘道 38ms、跨網段 9113ms、dnsErr=0)。
  • 2B(TCP 通道渲染數)改為輪詢到數量相符,斷言本身一字未改。 同一頁在 WiFi 上要 5~7 秒才畫完,而原本只等 4 秒。
  • ⚠️ 教訓:測試套件在單一環境全綠,不代表它在交付環境會綠。 出貨前至少要在「設備當下實際使用的介面」上跑過一次。

v2.9 修訂摘要(2026-08-26,完整重跑驗收流程後):

  • 新增 RG.7(WI-206:Parser「值類型」下拉的 option value 必須對得上韌體 ParserValueType)。該缺陷是走情境 M.3 時抓到的:選「數值」實際會得到布林, 任何非零數字變成 1.0。RG.7 必須斷言 UI 的 option value —— 只用 API 送 parserType:1 驗「韌體會給數值」是抓不到的(韌體本來就對,錯的是前端綁定)。
  • 韌體基線 6.0.72 → 6.0.74(WI-206 + WI-197)。
  • 全流程重跑結果:test:gate 35/35、test:regression 7/7。

v2.8 修訂摘要(2026-08-26,六張卡修完並實機驗證):

  • test:regression 全數通過,已納入 test:gate:full —— WI-199/200/202/203/205 五個缺陷 已修並經「先紅後綠」驗證(修正前紅、修正後綠,同一台設備同一支測試); WI-201 經查是誤判(WI-170 的寫入佇列早就處理了),已大幅更正該卡。
  • 韌體基線 6.0.69 → 6.0.72,經 LAN .mesb OTA 上機,test:gate 35/35。
  • 新增 RG.6(WI-205:被拒絕的規則 POST 不得毀掉既有規則)。
  • 順帶修好一個從沒被測到的舊 bug:modbusTcpWriteDO 的擴充分支對區域副本取址轉型, Modbus TCP 寫擴充輸出一直沒有作用;已與規則引擎統一用 getExpansionPtr。

v2.7 修訂摘要(2026-08-26,與驗收走查對齊):

  • 新增 npm run test:regression(RG.1–RG.5) —— 驗收走查挖到五個缺陷, 既有閘門一個都沒攔到。這五項是它們的回歸,目前預期紅燈,修好前不列入出貨門檻。
  • 修正一個實驗證明的閘門盲點:2B 原本只斷言「TCP 通道」標題可見, 注入 WI-202 的壞值(整份 TCP IO 設定在網頁上消失)後仍 6/6 全綠。 已改為比對「設備上有幾個通道」與「畫面上列出幾個」。
  • 環境預設值對齊:factory-env.js 的 DUT_URL 改 .77(有線)、EXPECT_FW 改 6.0.69; package.json 內的舊值一併更新。
  • ST.2 改為非破壞性:原本寫死 index: 7,設備規則數 ≥ 8 時會覆蓋現場既有規則 —— 2026-08-26 實際毀掉一條 A2-MQTT亮。已改用「附加位置」(ruleCount)。 該次紅燈同時揭露韌體缺陷 WI-205(回 400 卻仍寫入且不回滾),已補 RG.6 回歸。
  • 測試設定來源收斂:先前 6 支 spec 各自寫死 DUT_URL 預設(3 支 .46、3 支 .77), factory-v6 的 EXPECT_FW 還停在 6.0.8 —— 文件卻宣稱「換設備只改一個檔」。 已全部改為從 factory-env.js 取值,那句承諾現在才是真的。
  • 已知未處理:package.json 有 4 處明文 broker 密碼(見 WI-204,交付優先暫緩)。

v2.6 修訂摘要(2026-08-20,交付定案版):

  • 測項與腳本對齊(文件先前寫錯):test:converter 是 5 項 + afterAll 收尾(CV.9 是清理不是測項); test:enable 是 7 項,EN.5(停用 RS485 設備)已從腳本移除 —— 該卡片在畫面上只有「刪除」沒有停用開關, 測一個使用者碰不到的控制項沒有意義;新增 EN.8(停用 Config Server 總開關)。
  • 新增章節「本批韌性修正:閘門測不到的那些」:WI-175/180/181/182/183/189 六項, 列出各自「為什麼會壞」與「怎麼驗的」。這張表的用途是改到那塊之前先讀,不是測試清單。
  • 新增 npm run test:gate:full:唯讀閘門 + 三支會改動設備狀態的套件一次跑完(交機前用)。 test:gate 維持唯讀語意不變(OTA 後、現場都能安全跑)。
  • 本文件已發佈到雲端文件中心 /docs/factory-test.html。

v2.1 修訂摘要(2026-07-16,韌體 6.0.4 → 6.0.8 對齊 + 源碼核校修正):

  • 韌體基線 6.0.4 → 6.0.8:全文版號斷言改 v6.0.8;新增 v6.0.5~6.0.8 能力。
  • 新增自動化套件 web/tests/factory-v6.spec.js(13 tests,純 HTTP 唯讀契約):Phase 0 機型身分 + Phase 6B 遠端診斷 + Phase 2E.6a MQTT 測試契約 + Phase 2E.6b namespace 欄位;npm run test:factory:v6。已對實機 8320(6.0.8)全綠。
  • ⚠️ 源碼核校修正欄位名(舊文件錯,自動化已抓出):
    • /api/diag 實際欄位 = resetReason(非 bootReason)、bootDetail、prevResetReason、bootCount、prevUptimeSec(非 prevUptime)、uptimeSec、rawRsr、fwVersion。
    • /api/system boardModel 值 = 字串 "Opta RS485 (8310)" / "Opta WiFi (8320)"(非 "8310"/"8320");hasWifi 為 boolean;兩者一致。
    • mac 在 /api/config(非 /api/system),格式為冒號大寫(如 A8:61:0A:50:8B:61);對外 topic 12-hex 身分 = 去冒號轉小寫。
  • SF965 原生解碼(6.0.8):H3 新增 VAR_SF965_PV(dataType=8)手動驗證列(需 SF965 硬體;PV@addr4 高 3 byte=值、低 byte=小數點)。
  • 離線來源不發假 0(6.0.7):Phase 4 新增 H3-B3(converter 引用離線 RS485 來源 → 整筆跳過發佈,不送假 0 誤導 MES)。

v2.0 修訂摘要(2026-07-02,韌體 5.9.45 → 6.0.4 對齊):

  • 韌體基線 5.9.45 → 6.0.4:全文版號斷言改 v6.0.4;Phase 0 讀 boardModel/hasWifi/mac。
  • 機型維度(8310 / 8320)新增:變體識別從單一「網路變體」擴為 機型 × 網路 二維(8310 無 WiFi / 8320 有 WiFi),來源 = OTP boardInfo().wifi。新增 Phase 4 H8 機型感知 UI 過濾 + 心跳燈(8310 隱藏 WiFi 欄位 + 琥珀燈;8320 露 WiFi + 藍燈)。
  • WI-155 平台化(6.0.0):新增 Phase 2E MQTT 命名空間(projectName+env → {proj}-{env}/gateway/{mac},留空 = legacy)與 MAC 軟體覆寫 + 90s 試用回退 驗證。
  • 遠端診斷(6.0.1):新增 Phase 6B 遠端維運健檢——/api/log 網頁 Serial Log(/log.html)+ /api/diag 開機原因(BKPSRAM intent 標記)+ 密碼遮罩不外洩。
  • RS485 slaveId 持久化(6.0.2):H3 新增 同型號多台防串台 驗證(各設不同 slaveId ≤32,重開機後不退回陣列位置、不串台)。
  • MQTT 測試連線修正(6.0.4):Phase 2E MQTT 測試改 deferred(POST 202 → GET /api/mqtt/test 輪詢)+ 對已連線同 broker 短路判定;密碼留空 = 用已存密碼。
  • 授權撤銷門控(WI-145):Phase 7 補「撤銷後 TCPIO/MQTT 擋、DIO/管理不擋」的門控驗證。
  • MQTT TLS 出廠預設:tlsInsecure=true(業主指定,不驗 CA)——Phase 2E 斷言此為出廠預設,勿改回驗 CA。
  • Web 部署模型:index.html 編進韌體、app.js 等 6 資產走 QSPI 熱更——出廠燒錄後首開機須確認網頁完整(非裸 HTML)。
  • 附錄 A 補 /api/log、/api/diag、/api/mqtt/test、/api/license/token 端點。

v1.2 修訂摘要(2026-05-27):

v1.1 修訂摘要:

  • 韌體版本對齊:5.9.25 → 5.9.45
  • 治具校正:Expansion 1 → Expansion 0(array 從 0 起);YX523R Slave ID 2 → 4
  • 新增 MQTT broker fixture(FR-G E2E 必需)與變體識別(ethernet/wifi)
  • Phase 結構從 05 擴充為 08,補上 OTA、E2E 業務流、出貨前清理、結果輸出
  • 各步驟加上 PRD FR-* 對應 ID + DOM ID 速查表
  • 補上 EEPROM DIP+斷電 物理步驟(先前完全漏掉)
  • 附錄 C 列 PRD v1.2 已知 UI bug 對工站的影響

#1.0 候選的驗證與文件同步規則

驗收流程確認現場使用情境;出廠測試另涵蓋機型、硬體、授權、升級、故障恢復及出貨清理。出廠應包含驗收的產品行為;現場接地、照片與業主簽名保留現場執行。

  • 每輪記錄 commit、韌體與網頁資產版本、設備 UID/機型、實際網路介面、治具、起訖時間與 bootCount。文件版號表示規範修訂,不表示該版全部實測通過。
  • BK.0–BK.3 整輪另守重開數:還原排程前 bootCount 必須維持起始值;取得有效還原工作後,收尾必須恰好增加一次且為 SOFTWARE/api-reboot。缺少診斷、額外重開或非預期原因一律 FAIL;清理失敗時仍要檢查重開,兩種錯誤都保留。
  • BK.2 等待雲端 ACK 最多六分鐘(另受整項十二分鐘上限約束),期間只輪詢雲端。此測試預算考量主迴圈 127 秒心跳排程、工作執行緒 60 秒喚醒,以及靜默延後與連線時間;工作 ID 必須相同且狀態為 applied,逾時仍 FAIL。
  • PASS、FAIL、WARN、SKIP、未測、受阻分開記錄。缺治具的 SKIP 不能算硬體已通過;刻意略過重開不能算持久化已通過。讀不到 bootCount 時不得宣告整輪通過。
  • 各套件的 PASS 必須附當輪韌體、Build ID、設備與報告;舊版回歸結果不能沿用為新候選通過。test:factory 的 41 項不含獨立 regression/converter/backup/persist、完整驗收執行器或人工測項;長時觀察另記實際時長,不以短輪代替。
  • 單次補發先建立接收端訂閱,再觸發開閘;出廠 CV.4 等實際 SUBACK 成功後才觸發,保持原12秒觀察與至少1則判準。接收端拒訂、斷線或確認逾時列測試失敗,不能當作有效的0則窗口;驗收 B6 既有4秒等待只屬預備時間,若收不到訊息,須區分訂閱未就緒與產品漏發。
  • 未接 RS485 測試目標的工站,驗收執行器須明確加 --no-rs485;階段 5 記 SKIP,不能當成 RS485 已通過。出廠另以 EXPECT_RS485='' 指定無該治具。
  • 自動 6.2 選主機及每個已連線擴充中未被已啟用規則控制的 DO 各一路,記錄實際 index;測後即使發生錯誤也恢復原值。所有 DO 都被規則占用時須安排隔離治具,不能把規則持續覆寫當成輸出故障;全路實體接點仍須另驗。
  • 備份還原比對排除系統產生的版本、還原工作 ID、checksum、timestamp 與 license.lastCheckAt;身份本身、授權設定及模板內容仍須相符。
  • 日誌穩定性測項 RG.8 只計觀察基線後的新增紀錄,保持完整 300 秒;相同文字的新事件仍計入,不能把舊開機日誌重算,日誌銜接中斷或 bootCount 改變也不得通過。
  • HTTP 200/queued 只證明推送排程。4.3/8.1/BK.1 必須核對新送達狀態及雲端選定快照內容(含 Converter 模板);最終備份在 QA 素材清理與原設定核對之後執行。
  • 雲端身份以設備管理介面取得的有效身份為準,包含 license fallback。空 cloudToken 本身不是 FAIL;以本設備歷史讀取的實際 HTTP 結果判斷,不把 token 寫入公開紀錄。
  • 改測項時,同一筆變更更新驗收步驟、出廠對應及相關自動化;唯一 ID 對應來源為驗收單的「出廠測試對照」。執行 python3 scripts/test_coverage_matrix.py --write 後再以 --check 檢查。
  • 同步 docs/assets/acceptance_run.py 與文件站附件,重新建置文件站。靜態對照只證明編號與腳本關係;頁面測試只證明該套頁面斷言,均不能代替整份驗收或出廠簽核。

歷史限制(2026-09-09 候選):曾有 WI-156 虛擬通道引用錯位及計數器參數跨重開遺失的重現證據,該輪 D4/ST.16 不得簽 PASS。新候選應看相同 Build ID 的逐項重測,不能沿用舊版 PASS 或 FAIL;2026-10-01 本輪結果見本文開頭。

9/11 授權桌上驗收中,8320 在 6.0.100 發生 SOFTWARE/cs-wedge(392 → 393,未要求重開),WI-220 仍擋發布。正式雲端實讀為 2.5.5,8310 的 BK.2 因缺少候選 2.5.8 所要求的 restore.id 未過;不能把部分功能或名稱還原成功當成完整簽核。

9/12 正式 Config Server 已升到 2.5.8;8310/6.0.100 的 BK.0–BK.3 通過,驗收自動項為 18 PASS/0 FAIL/5 SKIP,另四組出廠自動項為 40 PASS/0 FAIL/1 SKIP。8320/Wi-Fi 曾在收到完整內容後拒絕套用;6.0.103 復測的備份/還原功能通過,但還原排定重開之外又多出一次 UNEXPECTED/webhdr,整輪穩定性不合格。WI-220 非預期重開、WI-156、實體斷電與長時門檻仍開啟;不得把部分自動項通過當作整機出廠通過。

#2026-10-01 v3.14:照表操作與白話說明

與驗收 v3.50 同步;操作順序移到前面,保留原測項、完整驗收對照與未執行項標示。

#畫面操作驗收補充(2026-10-02)

多段校正請先依畫面設定 A~E核對入口。6.0.122 尚缺全程網頁的多段安裝與參數操作;工程工具驗證與畫面驗收分欄記錄,不得因 SC 邏輯通過就把純網頁流程標成完成。

#2026-10-05 v3.15:承接線上校正驗收

新增 Phase 5C/OC.1~OC.12,與驗收 v3.51 一對一對照;適用項未測、容量受阻或尚缺業主 Edge/實秤不得簽完整出廠。既有 SC/TS/NR 與自動化套件範圍不改寫。

#6.0.128 毫秒時間驗收補充(WI-250)

沿用 TS.1~7,不以本補充取代原項目。TS.2 檢查 ${sys.timestamp} 訊息時間與 ${rs485.<站號>.<欄位>.timestamp} 量測時間:收到的 UTC 字串有三位小數(例如 .237Z);Edge 能完整解析並保存,不能固定只收 20 字元。保存至少三筆原始 MQTT payload,確認毫秒不是一律補 .000。未對時/無有效樣本仍為 null。

TS.4 的延遲/補送須逐位元組比對原 payload;TS.3/5/6 依原有時鐘修正、讀取失敗與 onChange 判準驗證,時間單獨改變不得觸發發送。跨秒、跨日、長時計數回繞與舊樣本不被重新對時改寫由時鐘/Converter/輪詢測試留證。毫秒解析度不代表 UTC 誤差小於 1 ms,不可在驗收表代簽該準確度。

#WI-253:32 個 MQTT 命令通道補充驗收(6.0.130 候選)

在隔離設備將測試群組綁定 cmd/signal/31,輸出使用測試 MQTT topic,不接實體 DO。等待接收端 SUBACK 後,分別發裸數字及 value JSON,核對規則/Converter 行為;另驗 0、7、8。32、負數與非數字尾碼不得改變既有命令值。

保存測試前設定及閘門值,設定 31 為非零,等待落地後正常重啟,核對映射與閘門恢復;真正斷电保存仍需獨立物理斷電測試。升級舊 8 筆保存檔時確認 0–7 保留、8–31 為零。測完回復群組/模板/閘門與原設定,確認無殘留。

主機測試不代替 MQTT 實機、重啟或物理斷電證據;本次不擴充輸入群組數。

#WI-259 靜態 IP 中斷復原補充驗收(1.1.6 候選)

此項需 USB 接在受測 OPTA,並先保存設定備份與連續 USB 日誌;一般 USB 可供救援指令,不是 RS485 轉接器。

  1. 記錄 UID、版本、Build ID、bootCount、原網路設定;每次測試只操作指定設備。
  2. 正確固定 IP:透過 net static <ip> <mask> <gateway> 套用,等首次重啟後從 Ethernet 開網頁確認;再次重啟仍保留設定。
  3. 錯誤閘道:使用隔離測試網段,不得占用其他設備 IP;持續 USB 錄影式日誌,測試期間不要對設備送 HTTP/API 或 net keep(這些會確認試用)。
  4. 連線未確認:連續 link-up 五分鐘後還原原設定;若試用途中另一次重啟,應在網路初始化前還原,不能每次重啟重算五分鐘而失聯。
  5. 核對日誌的實際重啟原因、檢查點及還原訊息,再讀回網路、MQTT、I/O、群組設定;不能只依 LED 或「沒有 fault record」宣稱正常。
  6. 正確 Ethernet 連線可確認;Wi-Fi 連線不應替未使用的 Ethernet 設定確認。儲存失敗不得宣稱已還原或刪除唯一備份。

結果需逐項附實機證據;主機測試或候選版建置成功不等於現場/出廠驗收完成。本補充不表示 1.1.6 已正式發布。

#WI-266 交易排程補充(2026-11-02)

  • DC.8:網頁輸入20、50、1000 ms並儲存重讀;拒絕19、1001、小數、空白;重開後仍保留。舊設定缺鍵回到50 ms。
  • DC.9:單次輪詢失敗後按原週期重試;連續第三次起退避;其他設備仍輪詢,MQTT繼續含null發送。
  • DC.10:容量提示區分設定週期、交易間隔、排程窗口及整輪估算;16台邏輯測試不代替16台實機。
  • DC.11:混合有效/失敗自訂暫存器,逐欄位null;資料年齡及失敗次數與原始API核對。

#MQTT 密碼邊界(WI-267/1.1.13)

  • 31 ASCII:測試/儲存可送出完整值;使用隔離 Broker或攔截請求,不覆寫現場正式憑證。
  • 32 ASCII、11個中文字、8個emoji:測試與儲存均提示超長,沒有POST。
  • 貼上40 ASCII:整次貼上拒絕並提示,不能先截成31後顯示成功;選取原值後貼上31 ASCII可完整替換。
  • 檢查三語提示皆清楚標示31 UTF-8 bytes;頁面無JavaScript錯誤。

#密碼眼睛與 Wi-Fi 長度(1.1.14)

  • 在Wi-Fi與MQTT輸入測試字串,實際點眼睛兩次,核對password→text→password、內容不變、aria-pressed與提示切換;不應送出任何設定。
  • Wi-Fi63ASCII、21中文符合上限;64ASCII、22中文、16emoji應拒絕。即時計數與aria-invalid一致。
  • Wi-Fi一般儲存、全部網路設定儲存、AP儲存並重啟都要在超長時零POST;測試需攔截有效請求,不可用假密碼改正式網路。
  • 重載後密碼輸入值為空且隱藏,已存密碼不由API取回;留空保留僅適用一般設定頁。

#1.1.14 出廠 Ethernet 直連驗收

  • 清空設定的新機與一般恢復原廠:無 DHCP 伺服器,電腦 192.168.50.10/24 直連,開啟 http://192.168.50.50。核對遮罩 /24、閘道 0.0.0.0,觀察至少 10 分鐘沒有閘道自救重啟。
  • 網頁改 DHCP/其他靜態 IP 後重啟,讀回儲存設定;再次升級不得恢復成出廠 IP。
  • USB net show、net dhcp、net static 192.168.50.50 255.255.255.0 0.0.0.0,核對試用確認與還原。
  • 2026-11-02:預設值、實際 JSON 儲存/載入程式、舊格式遷移及 USB 命令解析已做主機測試;因沒有可清空設定的備用設備,出廠直連、無閘道 10 分鐘與設定切換的實機驗收尚未執行,不得填 PASS。