Bug #1382
是由 陳國瑋 於 13 天 前更新
## 問題描述
Jimmy 大樓的 Fortune 充電樁 `CBDAX50A-24L-XX-B351` 已長時間未連線,但其 connector `CBDAX50A-24L-XX-B351-001` 在 ems_branch 仍顯示 `AVAILABLE / NOERROR`,導致後台/HQ/住戶端可能誤判該槍可用。
## 現場證據(2026-07-21 查 Jimmy)
- DB 現在時間:約 `2026-07-21 11:06:00`
- `e_charge_points.id = CBDAX50A-24L-XX-B351`
- `last_heartbeat = 2026-07-06 14:11:02`
- `last_boot_notification = 2026-07-06 13:20:51`
- `status = FAULTED`
- `e_connectors.id = CBDAX50A-24L-XX-B351-001`
- `status = AVAILABLE`
- `error_code = NOERROR`
- `last_status_change = 2026-07-06 14:04:50`
- `e_ocpp_message_log` 最後一筆 `Heartbeat` 在 `2026-07-06 14:11:02`
- `e_ocpp_message_log` 最後一筆 `StatusNotification` 在 `2026-07-06 14:09:38`,payload 為 `status: Available`
## 初步原因
目前 ems_branch 對 OCPP WebSocket close 與 heartbeat stale 沒有可靠地同步 connector 狀態:
- `OcppWebSocketHandler.afterConnectionClosed()` 只 unregister session,沒有更新 DB 狀態。
- `HeartbeatHandler` 只更新 charge point heartbeat。
- `ChargePointService.updateHeartbeat()` 只更新 `lastHeartbeat`。
- 前端/HQ connector DTO 直接讀 `e_connectors.status`,因此最後一次 `AVAILABLE` 會被長期保留。
## 需求確認紀錄
- 2026-07-21 Ken 確認:heartbeat stale timeout 預設使用 `5 分鐘`。
- 2026-07-21 Ken 確認:charge point 離線時,有 ACTIVE transaction 或 `currentTransactionId` 的 connector 不改 connector 狀態,只把 charge point 標為 `UNAVAILABLE` 並記錄 log;沒有 ACTIVE transaction / 沒有 `currentTransactionId` 的 connector 才改成 `UNAVAILABLE / NO_ERROR` 並發布 connector update event。
- 2026-07-21 Ken 確認:離線 charge point 重新連線時,BootNotification 或第一個 Heartbeat 可將 charge point 本體標回 `AVAILABLE`;connector 不整批自動恢復 `AVAILABLE`,必須等待實際 StatusNotification 回報後再恢復。
## 建議解法
採用 BE 修正 `1 + 2`:
1. 新增 heartbeat watchdog 排程:定期掃描 enabled 且 `last_heartbeat` 超過 timeout 的 charge point,將 charge point 標為 `UNAVAILABLE`,並將其底下非 active charging/transaction 的 connectors 標為 `UNAVAILABLE`,同時發布 connector update event。
2. 在 OCPP WebSocket close 時即時 mark offline:`afterConnectionClosed()` 觸發 service,將該 charge point/connectors 標為 offline。此機制作為即時修正,但仍需 watchdog 處理 TCP 半斷、process crash、server restart 等情境。
## FE 協作提醒
BE 完成並部署後,需要請 FE 協助確認:
- Branch Admin / HQ / LIFF 看到的 connector 狀態是否會由 `AVAILABLE` 更新為 `UNAVAILABLE`。
- 若現有 UI 只依 `connector.status` 顯示,確認收到 connector update event 後畫面會刷新。
- 若 UI 需要額外呈現「設備離線」與「槍本身 OCPP 最後狀態」的差異,再由 FE/API 討論是否另開欄位或 ticket。
## 驗收條件
- 當 charge point heartbeat 超過 timeout 或 WebSocket close 後,該 charge point 不應繼續讓 connector 顯示為 `AVAILABLE`。
- 不應覆蓋仍在有效交易中的狀態,需避免誤中斷 ACTIVE transaction。
- connector 狀態更新後需發布既有 connector update event,讓 HQ/前端可同步。
- Jimmy `CBDAX50A-24L-XX-B351-001` 這類長時間無 heartbeat 的案例,修正後應可被標為不可用。
返回