Bug #1343
是由 陳國瑋 於 約 2 個月 前更新
## 問題描述
ct1 (寶台 A17) 案場的華城充電樁 (CBDAX50A-25L-A6-A072-001) 在「先插充電槍、再執行開始充電」的流程中,connector status 會卡在 FINISHING 狀態,導致後續完全無法充電。問題持續超過 10 分鐘無人值守恢復,必須手動 SQL 干預。
## 復現時序 (2026-06-18 14:28~14:38, ct1 log)
| 時間 | 方向 | 事件 | 說明 |
|------|------|------|------|
| 14:21:51 | ←樁 | StatusNotification: Preparing | 前次充電開始 (tx #507) |
| 14:21:56 | ←樁 | StartTransaction (tx #507, meter=3362) | |
| 14:26:52 | ←樁 | StatusNotification: SuspendedEV (vendorErrorCode=1000) | |
| 14:26:54 | 樁→ | DataTransfer | `車端要求暫停充電,220 斷開,停止發送電錶值,交易尚未結束,車端隨時會再要求充電` |
| 14:26:54 | ←樁 | StatusNotification: Finishing | |
| 14:26:57 | ←樁 | StopTransaction (tx #507, reason=EVDisconnected, meterStop=3938) | |
| 14:27:19 | ←樁 | StatusNotification: **Available** | EV 拔槍後正常 ✓ |
| **14:28:15** | ←樁 | StatusNotification: **Preparing** | **用戶插槍** |
| 14:28:17 | EMS→ | RemoteStartTransaction | 用戶點開始充電 |
| 14:28:18 | ←樁 | RemoteStartTransaction Response: Accepted | |
| 14:28:20 | 樁→ | DataTransfer | `transactionId=0, errorCode=1000` ← 根本沒開新 transaction |
| 14:28:21 | ←樁 | StatusNotification: **SuspendedEV + Finishing** | 1 秒內連送兩個 |
| 14:28:21 ~ 14:44:09 | | 完全沒有 StatusNotification,只有 Heartbeat | 充電樁送完 Finishing 後就斷了 |
| 14:38:16 | EMS | GET /api/cp/hq/user/connectors | 用戶查 connector (Ken 給的 log 起點) |
| 14:38:17 | EMS | GET /api/cp/hq/connector/info | status 仍為 FINISHING |
## 根本原因
### Bug 1(主因):華城 (FE-EVI) 充電樁在「先插槍再開機」流程下的 OCPP 行為異常
從 vendorErrorCode=1000 + DataTransfer 的中文訊息看,**充電樁判定 EV 端要求暫停充電**:
1. 收到用戶「插槍」→ 送 Preparing
2. EMS 送 RemoteStart → 充電樁回 Accepted
3. **但充電樁 1 秒後立刻送 SuspendedEV → Finishing**,且 DataTransfer 帶 `transactionId=0` 表示根本沒開始交易
4. 送完 Finishing 之後**再也沒有送 StatusNotification(Available)**,EMS 不知道它已經「準備好」
OCPP 1.6 規範下 StatusNotification 是單向通知,**充電樁不送 EMS 也沒轍**。這是華城充電樁 firmware 的問題。
### Bug 2:EMS 對 FINISHING 狀態沒有 timeout fallback
`RemoteChargingSupport.isConnectorAvailableForCharging` (line 145-156) 只接受 AVAILABLE 或 PREPARING:
```java
boolean available = status == ConnectorStatus.AVAILABLE
|| status == ConnectorStatus.PREPARING;
```
所以 FINISHING 的 connector 永久被擋。即使 EMS 再收到 RemoteStart,POST 進來會被擋掉回 400。
而且就算用戶重插槍觸發新的 Preparing StatusNotification,由於 connector 還卡在 FINISHING,新事件進來後雖然 StatusNotification handler 會 update status=Preparing,但中間可能會有 race condition / 排程 race。
## 影響範圍
- **影響案場**:ct1 (寶台 A17),所有華城 (FORTUNE, FE-EVI) 充電樁
- **影響場景**:
- 先插槍再點開始充電 (主要)
- 任何 EV 拔槍後充電樁不送 StatusNotification(Available) 的情境
- **使用者體驗**:車主完全無法充電,必須人工介入
- **錯誤代碼**:`isConnectorAvailableForCharging=false` → 400 Bad Request
## 修法方向(待 Ken 確認)
### 方案 A(推薦):EMS 加 FINISHING 狀態 timeout fallback
- 監測 FINISHING 狀態超過 N 分鐘(例如 5 分鐘)自動 reset AVAILABLE
- 並釋放對應 slot
- 觸發 `ConnectorForHqDto` 重新 query
- 同時 log 警告 + 觸發事件供後續追蹤
### 方案 B:被動等待 + 加重試
- 當用戶點開始充電時,若 connector 是 FINISHING 狀態超過 1 分鐘,強制 reset AVAILABLE
- 適用於「使用者已經想用」的情境
### 方案 C:華城充電樁 firmware 修
- 聯絡華城 (FORTUNE) 修正 firmware,確保 EV 拔槍後一定送 StatusNotification(Available)
- 中長期建議
## 建議採用:A + B 並行 + 開案追 C
## 暫時補救(已記錄於此 ticket)
```sql
-- 手動把卡在 FINISHING 的 connector 救回 AVAILABLE
UPDATE e_connectors
SET status='AVAILABLE', last_status_change=NOW(), update_time=NOW()
WHERE id='CBDAX50A-25L-A6-A072-001';
```
## 參考資訊
- 受影響 connector:CBDAX50A-25L-A6-A072-001 (FORTUNE 華城,B1 群組,private)
- 案場:ct1
- Charge Point:CBDAX50A-25L-A6-A072 (FE-EVI, FEEVC-3-32A-CNS)
- 案場 log 檔名:a17_0618_3---48ce5901-8336-4d6b-a7de-016b61287a66.txt
- 相關 ticket:#1342 (華城 TYPE_B/D stop 完全沒作用,FINISHING 後卡 PREPARING)
- Branch:private
---
## 2026-06-18 20:35 重新整理 Bug 1(5 小時觀察 + 程式碼分析) 補充觀察資料(Ken 要求)
### 重大發現:Bug 1 真正本質不是「卡 Finishing」,而是「先插槍 EMS 自動送電」 觀察 1:異常流程(先插槍再開機)— 14:21 ~ 15:07
從 5 小時的 6 次充電觀察(tx #507~#512),卡 Finishing 只發生 1 次(#507,28 分鐘),其他 5 次都是 8~24 秒正常補送。所以「卡 Finishing」是衍生症狀(低機率),不是核心 bug。
**真正 100% 重現的主症狀**:Fortune / Tesla / Unknown 充電樁在「先插槍、未按開始充電」時,EMS 會自動送電。
### 程式碼根本原因
**`FortuneConnectorTypeRotationStrategy.onPreparingWithoutRotation()` (line 25-27) 永遠回傳 `SEND_REMOTE_START`**:
```java | 時間 | 事件 |
@Override |------|------|
public ConnectorTypeActionResult onPreparingWithoutRotation(ConnectorTypeActionContext ctx) {
return ConnectorTypeActionResult.of(ConnectorTypeAction.SEND_REMOTE_START); // ← 自動送電 | 14:21:56 | StartTransaction (tx #507, meterStart=3362) |
} | 14:26:52 | StatusNotification: SuspendedEV (vendorErrorCode=1000) |
```
**對照組 `CloudLinkConnectorTypeRotationStrategy.onPreparingWithoutRotation()` (line 25-27) 回傳 `noAction()`** — 不自動送電。
**觸發鏈**:
- 樁送 `StatusNotification: PREPARING`
- → `ChargingOrchestrator.onStatusNotification()` (line 598)
- → `handleStatusNotificationForRotation()` (line 776)
- → `strategy.onPreparingWithoutRotation(ctx)` (line 851)
- → Fortune 回傳 `SEND_REMOTE_START`
- → 自動送 `RemoteStartTransaction` → 樁充電
**影響範圍**:
- `OtherConnectorTypeRotationStrategy extends FortuneConnectorTypeRotationStrategy` (line 6) — DEFAULT/TESLA/UNKNOWN 都受影響
- `ChargingOrchestrator.buildConnectorTypeRotationStrategies()` (line 252-254) 註冊:DEFAULT/TESLA/UNKNOWN → OtherConnectorTypeRotationStrategy
### 觀察資料(5 小時內,6 次充電完整記錄)
| tx 14:26:54 | 觸發模式 DataTransfer `車端要求暫停充電,220 斷開,交易尚未結束` | Finishing → Available
| reason 14:26:54 | 備註 StatusNotification: Finishing |
|----|---------|----------------------|--------|------|
| #507 14:26:57 | (前次,先插再開) StopTransaction (tx #507, reason=EVDisconnected, meterStop=3938) | **28 分鐘**才補送
| EVDisconnected 14:27:19 | 14:28 異常,DataTransfer `txId=0, errorCode=1000` StatusNotification: **Available** ✓ |
| #509 14:28:15 | (前次,正常) StatusNotification: **Preparing** ← 用戶再插槍 | 24 秒
| EVDisconnected 14:28:17 | 用戶手動按 Start → 插槍 → 充 → Stop → 拔槍 RemoteStartTransaction (EMS→樁) |
| #510 14:28:18 | **先插槍 EMS 自動送電** Accepted | 14 秒
| Remote 14:28:20 | 15:23 測試 DataTransfer `transactionId=0, errorCode=1000` ← **EV 沒拉到電** |
| #511 14:28:21 | **先插槍 EMS 自動送電** SuspendedEV + Finishing | 8 秒
| Remote 14:28:21 ~ 14:56:04(**28 分鐘**) | 15:33 測試 完全沒有 StatusNotification,只有 Heartbeat |
| #512 14:56:04 | **先插槍 EMS 自動送電** BootNotification(**樁自己重開機**)firmware V_0.09.43.00 | 9 秒
| Remote 14:56:13 | 15:55 測試 StatusNotification: Finishing(重開機後又送一次) |
**正常 Finishing 持續時間:8~24 秒**(平均 ~14 秒)
### 「卡 Finishing」只發生在 txId=0 的特殊情境
從 5 小時觀察:
- 6 次充電中只有 #507 那次卡 Finishing 28 分鐘
- 原因:DataTransfer `transactionId=0, errorCode=1000`(EV 不配合充電)
- 其他 | 15:01:44 ~ 15:04:38 | EMS 連送 5 次都是 8~24 秒正常補送 Available 次 RemoteStartTransaction(4 Rejected + 1 Accepted→Rejected) |
- 重現條件:EV 端要求暫停充電(華城 vendor-specific)
### 樁重開機行為
華城樁在以下時間點都自己重開機(BootNotification):
- 14:56:04(卡 | **15:04:26** | StatusNotification: **Available** ← 距第二次 Finishing 28 分鐘後)
- 15:25:03(充電中)
- 15:31:47(充電中)
- 15:49:08, 15:53:48, 16:03:02(空檔重連) **8 分鐘** |
**這是 vendor-specific 行為**,EMS 端目前沒對應處理(但目前沒造成壞處)。
### Bug 1 重新分層(取代原本 ticket 描述)
```
#1343 Bug 1
├── 主症狀 (重現率 100%)
│ └── Fortune / Tesla / Unknown 充電樁「先插槍、未按開始充電」時 EMS 自動送電
│ ├── 觸發:StatusNotification: PREPARING 觀察 2:正常流程(先按 Start → onPreparingWithoutRotation 插槍 → SEND_REMOTE_START
│ ├── 對照組:CloudLink 是 noAction()(行為不一致)
│ └── 影響:用戶未授權就被充電(體驗差 + 安全疑慮)
│
├── 衍生症狀 (低機率,特定條件才觸發)
│ └── Finishing 狀態卡住不送 Available
│ ├── 觸發:txId=0(華城樁 EV 不配合充電 充 → vendorErrorCode=1000) 按 Stop → 拔槍)— 15:12 ~ 15:14
| 時間 | 事件 |
│ ├── 正常 Finishing:8~24 秒補送 Available |------|------|
│ └── 異常 Finishing:8~28+ 分鐘才補送(甚至完全不送,要靠樁 BootNotification 觸發) | 15:12:24 | RemoteStartTransaction (EMS→樁) ← 用戶按「開始充電」 |
│ | 15:12:25 | Accepted |
└── 旁支發現 (與 Bug 1 共因)
└── StopTransaction 帶 transactionId=0 → EMS 拋 ERROR
└── TransactionService.stopTransaction() 沒容錯 txId=0 | 15:12:28 | Rejected + StatusNotification: **Preparing** ← 用戶此時插槍 |
```
### 修法方向(已大幅簡化)
**原本 ticket 列的 A (timeout fallback) 跟 B (user-triggered reset) 主要處理「卡 Finishing」這個衍生症狀。但從 5 小時觀察,「卡 Finishing」重現率極低(1/6),且 8 分鐘以上 timeout 仍會自動恢復。**
**真正要修的是「自動送電」這個主症狀**:
| 方案 15:12:28 | 改動 Rejected (第 2 次) | 影響範圍
| 適用情境 15:12:40 | RemoteStartTransaction (EMS retry) |
|------|------|---------|---------| | 15:12:41 | Accepted |
| **方案 X(推薦)**:把 Fortune 的 `onPreparingWithoutRotation` 改成 `noAction()` 15:12:44 | 1 個 class,3 行 StatusNotification: **Charging** | 改變 Fortune/Tesla/Unknown 行為,跟 CloudLink 一致
| 如果用戶體驗(不該自動送電)是首選 15:12:48 | StartTransaction (tx #509, meterStart=3940) |
| 方案 Y:加 flag `enableAutoStartOnPlugin`,default false 15:13:15 | 多個 class(config SuspendedEV + strategy + ChargingOrchestrator) DataTransfer `txId=509, errorCode=1000`(vendor-specific 訊息,這次 txId 有效) | 較複雜但保留彈性
| 如果部分場景需要自動送電(例如離峰自動充電) 15:13:35 | Finishing |
| 方案 Z:保留自動送電,但加「需要 user 授權」檢查 15:13:37 | 多個 class **用戶按結束充電 + 拔槍** → StopTransaction (tx #509, meterStop=3973, reason=EVDisconnected) | 最複雜
| 如果要兼顧自動 + 授權 **15:14:01** | StatusNotification: **Available** ← 距 Finishing **24 秒** ✓ |
**對於衍生症狀(卡 Finishing)**:
- 觀察顯示實際上 8~24 秒就恢復,影響很小
- 如果仍要做 fallback,建議 timeout 設 **2 分鐘**(遠大於正常 8~24 秒)
- 觸發條件:`status=FINISHING AND current_transaction_id IS NULL AND last_status_change < NOW() - 2min` `e_transactions` 確認:tx #509, energy_consumed=33 Wh(充了約 52 秒),status=COMPLETED
### 影響範圍重新評估 對照表
| 案場 / 樁類型 情境 | 主症狀(自動送電) Finishing → Available 間隔 | 衍生症狀(卡 Finishing) EV 是否拉電 | 修法方案 X 影響 |
|--------------|------------------|--------------------|---------------| |------|---------------------------|------------|
| ct1 華城 (FORTUNE) 華城樁 — 正常流程 | ✅ 100% 重現 **24 秒** | ✅ 1/6 機率 ✓ 是(tx #509, energy=33 Wh) | 改 noAction(),行為跟 CloudLink 一致
| 華城樁 — 先插槍再開機 | **8 ~ 28+ 分鐘**(重開機後)| ✗ 否(DataTransfer `transactionId=0, errorCode=1000`) |
| CloudLink(昨日 a17 華城 (FORTUNE) log) | ✅ 100% 重現 1~3 秒 | ✅ 1/6 機率 — | 同上
### 推論更新
#### 1. 異常觸發條件更明確
從兩次觀察比對:
- **正常流程**下,EV 真的有充電(有效 txId + energy > 0)→ Finishing 後 24 秒正常送 Available
- **異常流程**下,EV 沒真的拉到電(DataTransfer `transactionId=0, errorCode=1000`)→ Finishing 後卡住不送
**推測**:華城樁在「沒真的開始交易(transactionId=0)」時,Finishing 狀態會卡住不送 Available。**真正有效的判斷標準**可能是「transactionId != 0 的 FINISHING」才需要 EMS 主動監測。
#### 2. EMS retry 機制對 FINISHING 不觸發
從 #1342 ticket 描述的 `onStatusNotification` 觸發第二次 remoteStart 機制(用於「先按 Start → 插槍」情境),對「FINISHING 狀態」**不會**自動重試 RemoteStart,因為 status=FINISHING 不算 Preparing/Charging。
**重點**:Bug 不是 RemoteStart 沒送,而是「FINISHING 後沒送 Available」讓 connector 永遠被擋,方案 A 的「timeout 自動 reset」是必要的。
#### 3. 方案 A 的 timeout 重新建議
| 設定 | 原建議 | 觀察後更新 |
|------|--------|----------|
| a17 CloudLink (CLOUDLINK) 華城正常 Finishing | ❌ 已是 noAction() 預估 1~3 秒 | ⚠️ 見 #1342 實測 **24 秒** | 不受影響 |
| 任何 TESLA / UNKNOWN 華城異常 Finishing | ✅ 100% 重現(extends Fortune)| 機率同華城 預估永遠不送 | 同 Fortune 修法 實測 **8 ~ 28+ 分鐘** |
| 其他公版 (DEFAULT) A 建議 timeout | ✅ 100% 重現 5 分鐘 | 機率同華城 **2 分鐘**(24s 正常 << 2min A << 8min 異常) | 同 Fortune 修法 |
#### 4. 方案 B 維持 1 分鐘
- 24 秒遠小於 1 分鐘,正常流程不會被 B 誤觸發
### 待釐清問題(重新評估) 實作進度
- ✅ 2026-06-18 14:55 建立 Feature Branch `feature/redmine-1343-finishing-timeout-fallback`
- 2026-06-18 15:21 Ken 指示 **暫停實作,進入純觀察模式**
- 待釐清問題(待觀察方向):
- Q1: 華城樁 txId=0 的 Finishing 是不是 100% 重現?→ **否**,5 小時觀察只 1/6 機率
是不是**重現率 100%**?
- ⚠️ Q2: EMS retry 機制對「FINISHING 狀態」會不會自動重試?→ 從程式碼看不會
狀態」會不會自動重試?目前看是不會(需驗證)
- ✅ Q3: 「txId=0 → Finishing 卡住」是不是華城所有樁都這樣?→ 從 卡住」是不是華城**所有樁**都這樣?還是只有 ct1 + a17 log 都有類似行為,但重現率低
這台?
- ✅ Q4: 華城樁 24 秒 Finishing 是否所有情境都 是否**所有情境都 24 秒?→ **8~24 秒範圍**
秒**?還是會更長?
- ❌ Q5: EV 不同狀態會不會影響 不同狀態(充到 80% / 剛開始)會不會影響 Finishing 持續時間?→ 還沒測過
持續時間?
- ⚠️ Q6: StopTransaction 帶 txId=0 的 ERROR 會不會影響 connector 狀態?→ 從 #1342 ticket 看會 狀態?
### 實作進度更新 旁支發現(相關但獨立 bug)
- 2026-06-18 14:55 建立 Feature Branch `feature/redmine-1343-finishing-timeout-fallback`
- 2026-06-18 15:21 Ken 指示 **暫停實作,進入純觀察模式**
- 2026-06-18 20:35 Ken 要求 **重新整理 Bug 1**
- 重大發現:Bug 1 真正本質是「自動送電」不是「卡 Finishing」
### 旁支發現詳細記錄
- **2026-06-18 15:05:20、15:06:57**:兩次 `StopTransaction` 帶 `transactionId=0` → EMS 拋 ERROR
- 推測:EM 對 transactionId=0 的 StopTransaction 沒容錯
- 與 #1343 共因(華城樁 EV 不配合充電導致 txId=0)
- **建議併案處理**(同個 onStatusNotification / StatusNotification 流程)
- **華城樁反覆重開機**:14:56, 15:25, 15:31, 15:49, 15:53, 16:03
- vendor-specific 行為
- 目前無實質影響,但建議追蹤
### 觀察 log 時間區間
- 觀察 log 來源:`ems_branch.e_ocpp_message_log` table, charge_point_id=`CBDAX50A-25L-A6-A072`
- 觀察時間:2026-06-18 14:21 ~ 20:25(將近 6 小時)
- 觀察 connector:CBDAX50A-25L-A6-A072-001(華城 FORTUNE, B1 群組, private) 暫不併案處理,待觀察後決定
返回