出廠測試規範
#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 須替換成現場站號):
{"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 ID35B4EEB5DA9C49EC9B363566A7EFE4B7;實秤三段總量 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.mdWI-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。
cd web
DUT_URL=http://<設備IP> EXPECT_FW=<版本> npm run test:gate目前包含 35 個 Playwright 測試:頁面渲染(2A–2F)、v6 能力契約、穩定性與持久化(ST.*)。 全數通過才算通過 —— 任何一項紅燈都代表出貨品質有缺口。
其他交機前自動化套件如下,均須確認治具可操作並保留起始完整備份:
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 全綠。閘門對它完全無感。
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
.mesbOTA 上機驗證,test:gate35/35、test:regression6/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 | 還原後雲端連線不得斷掉(否則還原一次就不能再還原 = 自斷後路) |
寫這幾項時踩了兩個判準錯誤,值得記下來:
- 不能用「快照數量增加」當判準 —— 雲端會裁切舊快照,數量可能不變;要比對最新那份有沒有換人。
- 設定沒變更時推送不會產生新快照,那是正確行為(內容相同不重複存,實測連推 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
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:funcweb/tests/factory-pages.spec.jsPhase 2 五頁面渲染(Overview/Config/Rules/Devices/Settings,5 tests) npm run test:factory:pagesweb/tests/factory-v6.spec.jsv6.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:v6web/tests/factory-cleanup.spec.jsPhase 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 型號套預設暫存器即用此型別(不再靠÷256scale 湊)。
| # | 步驟 | 驗收條件 | 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(Bearersmmsadmin)。
| # | 步驟 | 驗收條件 | 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 用的
wdprobesignal,屬部署時佈建、非出廠基線,會被步驟 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:gate35/35、factory-stability16/16(ST.1 40/40、 ST.9 bootCount 全程未變)、test:regression的 RG.9 通過。- ⚠️ 新開 WI-218:OTA 之後不要馬上跑閘門。 這次 OTA 後設備在 WiFi 上 花了 605 秒 MQTT 才接上,期間每次重連失敗把主迴圈卡住 18.4 秒 (設備單執行緒,那段時間 HTTP server 沒被輪到)。結果
ST.0ECONNRESET、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:gate35/35、test:regression7/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
.mesbOTA 上機,test:gate35/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/systemboardModel值 = 字串"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):
- H3-C 新增 Step 5 校正引導精靈 chain 驗證(4 步驟 + 燈號 + 順序強制,v5.9.130+)
- 附錄 A 補
/api/signals、/api/actions、/api/converter/template端點- Phase 7 註記 wizard / wdprobe / watchdog 屬部署佈建非出廠基線
- 相關:
spec-mqtt-chain-workflow.md、guide-calibration-wizard.md、guide-failover-resilience.mdv1.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 結構從 0
5 擴充為 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 轉接器。
- 記錄 UID、版本、Build ID、bootCount、原網路設定;每次測試只操作指定設備。
- 正確固定 IP:透過
net static <ip> <mask> <gateway>套用,等首次重啟後從 Ethernet 開網頁確認;再次重啟仍保留設定。 - 錯誤閘道:使用隔離測試網段,不得占用其他設備 IP;持續 USB 錄影式日誌,測試期間不要對設備送 HTTP/API 或
net keep(這些會確認試用)。 - 連線未確認:連續 link-up 五分鐘後還原原設定;若試用途中另一次重啟,應在網路初始化前還原,不能每次重啟重算五分鐘而失聯。
- 核對日誌的實際重啟原因、檢查點及還原訊息,再讀回網路、MQTT、I/O、群組設定;不能只依 LED 或「沒有 fault record」宣稱正常。
- 正確 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。