專案

一般

配置概況

Bug #1295

是由 陳國瑋23 天 前更新

## 問題描述 

 當充電樁連接器在資料庫中設定 `enable_off_peak = 0`(未啟用離峰充電),但在 `e_connector_priority` 表有 `charge_status = 'eligible'` 記錄時,系統會在離峰時段錯誤地將該連接器納入輪充 dispatch,導致車主在「未啟用離峰充電」的情況下被排程離峰充電。 

 **受影響實例:** 寶台A17(ct1-ssh.cloudlinkems.com),CP003-001(enable_off_peak=0,B3 群組) 

 --- 

 ## 觸發條件 

 1. `e_connectors.enable_off_peak = 0`(FALSE,非 NULL) 
 2. `e_connector_priority.charge_status = 'eligible'` 
 3. 離峰時段到來,`ChargingOrchestrator.rotationDispatchTick` 觸發 

 --- 

 ## 證據(寶台A17,2026-05-12 00:00) 

 ### 資料庫狀態 
 ``` 
 connector_id    = Test bug ticket for CP003-001 
 charge_point_id= CP003 
 enable_off_peak= \0 (0x00, FALSE,非 NULL) 
 charge_group    = B3 
 charge_status = eligible 
 status_reason = NULL 
 priority        = 15 
 ``` 

 ### API Log(ems_branch api-2026-05-12-1.log.gz) 
 ``` 
 00:00:00.018    離峰起點時重新亂數排序完成 - chargeGroupId=B3, connectorIds=[CP003-005, CP003-001, CP003-004] 
 00:00:00.045    rotationDispatchTick 輪充調度,佔用 slot 完成 - connectorId=CP003-001, userId=U2510220002, priority=2 
 00:00:00.046    不經過輪充檢查的RemoteStart - connectorId=CP003-001, userId=U2510220002, chargePointId=CP003 
 00:00:00.047    收到遠端啟動充電請求 - connectorId=CP003-001, chargePointId=CP003, userId=U2510220002 
 ... 
 00:02:14.230    開始交易,交易ID: 239, 連接器ID: CP003-001, 住戶ID: TAG20251022000000002 
 ``` 

 ### cp_transactions 記錄 
 ``` 
 transaction_id     = 239 
 connector_id       = CP003-001 
 start_time         = 2026-05-12 00:02:14 
 end_time           = 2026-05-12 03:09:42 
 energy_consumed    = 22870 Wh 
 is_offline         = 0 
 reason             = EVDisconnected 
 ``` 

 --- 

 ## 根本原因(Root Cause) 

 ### 問題程式碼位置 
 `ChargingOrchestrator.rotationDispatchTick` → `dispatchEligibleConnectors` → `loadEligiblePriorities` 

 ### 原因說明 

 **1. `OffPeakEnqueuePolicy.enqueueForOffPeak` 有正確的 `enable_off_peak` 檢查:** 
 ```java 
 if (enabledOffPeak == null || enabledOffPeak.equals(Boolean.FALSE)) { 
     log.warn("enqueueForOffPeak skipped - connectorId={}, reason={}, enableOffPeak={}, msg=off-peak not enabled"); 
     return OffPeakEnqueueResult.SKIPPED; 
 } 
 ``` 
 當 `enable_off_peak=0` 時,`enqueueForOffPeak` 正確 Skip,不更新 DB 記錄。 

 **2. `dispatchEligibleConnectors`(或 `loadEligiblePriorities`)缺少 `enable_off_peak` 過濾:** 
 從 `e_connector_priority` 表篩選 `charge_status = ELIGIBLE` 時,沒有 JOIN `e_connectors` 確認 `enable_off_peak` 是否為 true。 
 因此 `enable_off_peak=0` 的 CP003-001(當時 charge_status=eligible)仍然通過 filter。 

 **3. 排程繞過了 `OffPeakEnqueuePolicy` 的檢查**:`dispatchEligibleConnectors` 直接 dispatch,沒有再次確認 `enable_off_peak`。 

 ### 修復方向 

 在 `dispatchEligibleConnectors` 或 `loadEligiblePriorities` 的查詢邏輯中,加入 `e_connectors.enable_off_peak = TRUE` 的過濾條件。 

 - **選項A(推薦):** 在 `loadEligiblePriorities` 的 SQL JOIN `e_connectors` 表時加 `WHERE c.enable_off_peak = TRUE` 
 - **選項B:** 在 `dispatchEligibleConnectors` 的 Predicate filter 中加 `connector.getEnableOffPeak() == Boolean.TRUE` 

 --- 

 ## 受影響範圍 

 所有 `enable_off_peak=0` 但 `e_connector_priority` 有 `charge_status=eligible` 記錄的連接器,在離峰時段都有被錯誤 dispatch 的風險。 

 --- 

 ## 查閱的 Log 檔案 

 | 檔案路徑 | 內容 | 
 |----------|------| 
 | `/opt/ems/ems_branch/api/logs/api-2026-05-12-1.log.gz` | 寶台A17 ems_branch API 全日行為(含 ChargingOrchestrator) | 
 | `/opt/ems/ems_branch/api/logs/scheduler-2026-05-12-1.log.gz` | ems_branch scheduler 排程 Log | 
 | `/opt/ems/ems_cp3/api/logs/ocpp-modbus-2026-05-12-1.log.gz` | CP003 充電樁 Modbus/OCPP Log | 

 ## 查閱的 Database Table 

 | Table | 用途 | 
 |-------|------| 
 | `e_connectors` | 連接器設定(enable_off_peak, charge_group) | 
 | `e_connector_priority` | 排程優先順序(charge_status=eligible, priority) | 
 | `cp_transactions` | 充電交易記錄(is_offline, energy_consumed) | 
 | `cp_connectors` | 連接器狀態 | 
 | `e_charge_group` | 充電群組設定 | 
 | `s_user` | 車主帳號 | 

 ## 相關程式碼(反編譯自 api.jar) 

 - `ChargingOrchestrator.rotationDispatchTick`(行 2157, 2724, 341, 374) 
 - `ChargingOrchestrator.dispatchEligibleConnectors` 
 - `OffPeakEnqueuePolicy.enqueueForOffPeak`(有正確檢查但未被 dispatchEligibleConnectors 呼叫) 
 - `ConnectorPriorityRepository.findByChargeGroupAndChargeStatusOrderByPriorityAsc`

返回