專案

一般

配置概況

Feature #1400

是由 鍾正剛3 天 前更新

h2. 背景 

 Branch Admin 「連接器 → 編輯 → 充電樁狀態」分頁(@react/branch/app/(dashboard)/connector/components/connector-status.tsx@)目前全靠 REST 輪詢取得狀態: 

 * @GET /api/connector/status/{connectorId}@ 在 @AVAILABLE@/@PREPARING@/@CHARGING@ 時每 *2 秒*輪詢一次。 
 * 另外為了判斷是否可遠端操作,再打 ChargePoint API 取 @ocppConnectionStatus@,離線時每 *10 秒*輪詢。 
 * 送出 start/stop 後靠 @setTimeout(3000)@ 硬等 3 秒才 refetch,用猜的等待後端狀態落地。 

 問題: 

 # 後端資料實際上只在 OCPP @StatusNotification@/@MeterValues@ 進來時才更新(@MeterValueService@、@TransactionService@、@ChargingOrchestrator@、@ChargePointOfflineService@ 都會發 connector event)。2 秒輪詢絕大多數拿到同一份資料,是純浪費,卻又不保證比推送快。 
 # 同一份 Connector 狀態,LIFF(#1399)已改為由 WebSocket 推送的 @ConnectorForHqDto@ 取得,後台仍是輪詢。同一個真實狀態有兩條取得路徑、兩種時序,出事時無法對齊時間軸。 
 # 一個畫面同時掛兩條不同節奏的輪詢,@status@ 與 @ocppConnectionStatus@ 可能短暫互相矛盾,已經需要在 FE 用 @prevOnlineRef@ 補償。 

 *注意:本案不是要後台照抄 LIFF 的顯示或操作方式。* LIFF 的 @driverState@/@actions[]@ 是車主語意(@OFF_PEAK_WAITING@、「取消排隊」),授權綁住戶關聯與 transaction owner,管理員不適用也不需要。本案只要求*資料取得管道與來源一致*:同一份 Connector 狀態、同一個推送時機,後台用自己的維運語意呈現與操作。 

 h2. 目標 

 * 提供後台專用的 Connector 狀態 WebSocket 推送,讓 FE 可移除輪詢與 3 秒硬等。 
 * 後台需要的維運欄位由同一份 payload 一次給齊,不再為了單一欄位另打一支 API。 
 * 後台充電操作維持現行 operator 授權模型,但補上可追蹤性與重送防護。 

 h2. A-1. 新增後台專用 Connector WebSocket endpoint(ems_branch) 

 * @ems_branch@ 目前只有 OCPP 用的 @/ws/ocpp/*@,沒有供 UI 使用的 WebSocket,需新增。 
 * *不可*沿用 HQ 的 @/ws/connector/{buildingId}/{connectorId}@:該 endpoint 的 @LineIdHandshakeInterceptor@ 以 @xLineId@ 查 @findByLineIdAndBuildingId@ 驗證,後台管理員沒有 LINE 身分也非該 building 住戶,握手必定被拒。 
 * 握手驗證改用 Branch 既有的 ss3a 身分(JWT),並套用該管理員對此 Connector/Building 的既有權限判斷。授權失敗時的 close code 與原因請明確定義,供 FE 分辨「無權限」與「連線失敗」。 
 * Branch 本身就是 connector event 的 publisher,*直接由 Branch 推送即可,不需要繞 RabbitMQ 再回來*。 
 * 推送時機請與現有 @ConnectorEventPublisher@ 的觸發點一致(狀態變更、MeterValues、交易起訖、離線偵測、remote operation lifecycle)。 
 * 連線建立時需給一份 *initial snapshot*,FE 不再另打 detail REST。 

 h2. A-2. Payload 欄位需求 

 Base 沿用 @ConnectorForHqDto@(@GET /api/connector/status/{connectorId}@ 現在回的就是它),後台已使用: 
 @id@/@status@/@statusLabel@/@startTime@/@currentPower@/@currentVoltage@/@currentCurrent@/@energyUsage@/@totalEnergy@/@remainTime@/@costPredict@/@currentTariff@ 

 需要補進同一份 payload 的維運欄位: 

 |_. 欄位 |_. 用途 |_. 目前如何取得 | 
 | @ocppConnectionStatus@(id + label)| 判斷是否可遠端操作、離線時停用按鈕 | *另打 ChargePoint API 並自行輪詢* | 
 | @chargePointId@ | 關聯導頁與 engineer tools | 由 FE 從 ConnectorDto 帶入 | 
 | @lastHeartbeatAt@ | 判斷離線多久,區分剛斷線與長期失聯 | 無 | 
 | @statusChangedAt@ | 狀態停滯多久(例如卡在 @PREPARING@)| 無 | 
 | @errorCode@/@vendorErrorCode@/@vendorId@ | @FAULTED@ 時的實際故障原因 | *無,後台目前只顯示「故障/請聯繫技術支援」* | 
 | @currentTransactionId@ | 對照充電記錄、engineer tools 追查 | 無 | 
 | @currentIdTag@/使用者識別 | 知道現在是誰在充電,公樁停止前確認 | 無 | 
 | @activeOperation@(#1398 已有)| 有未終結的 RemoteStart/RemoteStop 時,避免管理員重複送指令 | 無 | 

 @driverState@(車主語意)在後台不使用;payload 帶著無妨,但後台不得用它決定顯示或操作。 

 h2. A-3. 操作面 API 

 後台維持現行 @POST /api/tx/charge/start@/@POST /api/tx/charge/stop@(以 ss3a 管理員身分帶 @userId@),*不改用* @POST /api/connector/commands@ —— 後者的 @authorizeConnector()@ 檢查住戶關聯、公樁停止還要求是 transaction IdTag owner,管理員一律會被 @CONNECTOR_FORBIDDEN@ 擋掉。 

 但需要補齊: 

 # *回傳 @operationId@*,與 #1398 的 @e_remote_transaction_log.id@ 一致,讓後台操作能與 LIFF、Branch、OCPP log 串起同一條時間軸。目前後台送出的指令在稽核上是斷點。 
 # *明確的成功/失敗語意*。現行回應是 @isSuccess@ + @message@,FE 只能把訊息原樣丟給使用者。請提供穩定的 @errorCode@(如「充電樁離線」「已有未終結 operation」「狀態不允許」),讓 FE 能分流而不是比對字串。 
 # *operation 結果透過 A-1 的 WebSocket 推送*,取代 FE 目前的 @setTimeout(3000)@ 硬等。 
 # *已有未終結 operation 時明確拒絕*(@activeOperation@ 不為 null),不要讓管理員連送兩筆 RemoteStart/RemoteStop。#1398 §15.2 已規定同一 Connector 不得存在重疊的未完成 operation,後台入口也必須遵守。 

 h2. 不在本次範圍 

 * Connector 列表頁的狀態顯示(仍走既有查詢;本案先處理單一 Connector 詳細狀態)。 
 * Engineer tools(#1380)既有的 OCPP/Modbus 指令面板。 
 * LIFF 端行為(#1397/#1398/#1399)。 

 h2. 驗收重點 

 * 後台可透過新 WebSocket endpoint 以管理員身分連線並取得 initial snapshot;非授權身分(含 LIFF lineId)連線被拒且 close code 明確。 
 * Payload 一次帶齊 A-2 全部欄位,@status@ 與 @ocppConnectionStatus@ 來自同一份資料。 
 * 推送時機涵蓋狀態變更、MeterValues、交易起訖、離線偵測與 remote operation lifecycle。 
 * @FAULTED@ 時 payload 帶出實際 @errorCode@/@vendorErrorCode@。 
 * start/stop 回傳 @operationId@ 與穩定 @errorCode@;已有未終結 operation 時被拒絕。 
 * 後台送出的充電操作可用 @operationId@ 在 Branch log 追到對應的 RemoteStart/RemoteStop。 

 h2. 對應 FE ticket 

 FE 實作見 #1401。 {{FE_TICKET}}。 

返回