返回部落格
教學10 分鐘閱讀

OCPP 智慧充電:SetChargingProfile 實戰

充電設定檔是 OCPP 1.6 裡被誤解最深的一塊。堆疊層級、用途、排程時段和複合排程——每一個到底在做什麼,附帶封包。

I
Infinite Service Team

智慧充電(Smart Charging)功能檔是 OCPP 1.6 不再是一個簡單請求/回應協定的地方。SetChargingProfile 有嵌套結構、三種不同用途、一套堆疊模型,以及一組很容易在細處弄錯的設定檔合併規則。

它也是大多數實作可以一直不管、混過去的那部分規範——直到某個電網營運商要求他們削減負載,這件事才突然變得緊急。

一份充電設定檔長什麼樣

一份充電設定檔回答的是一個問題:*這台充電樁被允許輸出多大電流或功率,以及在什麼時候?* 結構裡的每一樣東西都在為這件事服務。

[2, "msg-01", "SetChargingProfile", {
  "connectorId": 1,
  "csChargingProfiles": {
    "chargingProfileId": 100,
    "stackLevel": 0,
    "chargingProfilePurpose": "TxDefaultProfile",
    "chargingProfileKind": "Absolute",
    "chargingSchedule": {
      "chargingRateUnit": "A",
      "chargingSchedulePeriod": [
        { "startPeriod": 0,     "limit": 32.0 },
        { "startPeriod": 21600, "limit": 16.0 },
        { "startPeriod": 64800, "limit": 32.0 }
      ]
    }
  }
}]

這份設定檔說的是:一開始 32 A,六小時後降到 16 A,十八小時後回到 32 A。startPeriod 是相對於排程開始時刻的秒數,既不是鐘錶時間,也不是時長。

三種用途互不可換

chargingProfilePurpose 決定這份設定檔作用在什麼東西上,大部分混亂都從這裡開始。

ChargePointMaxProfile 是整台充電樁的實體上限。它設在 connectorId: 0 上,因為它描述的是站點而不是某個插座。任何東西都不能超過它——那是硬體以及它背後供電能力的極限。

TxDefaultProfile 是交易的預設設定檔。可以設在某個具體接口上,也可以設在 connectorId: 0 上,讓所有接口共用同一個預設值。它作用於那些自身沒有設定檔的交易,包括將來的交易。

TxProfile 作用於一筆具體的、正在進行的交易。它需要 transactionId,並且在那筆交易結束時被丟棄。要削減一次正在進行的工作階段,用的就是它。

實際後果是:給一筆已經停止的交易發 TxProfile,不會產生你會注意到的錯誤——充電樁收下它,然後扔掉。

堆疊不是相加

stackLevel 是一個整數,數值大的勝出。這是人們最常讀錯的一條規則。

處於不同堆疊層級的設定檔不會相加、取平均或混合。在同一種用途之內,層級最高的那個有效設定檔會完整取代它下面的所有設定檔。stackLevel 2 的設定檔不是在 stackLevel 1 之上再加一道約束,而是取代它。

跨用途之間的疊加是另一回事,那一層確實表現為上限:實際生效的限值,是適用的 ChargePointMaxProfile、勝出的 TxDefaultProfile 和勝出的 TxProfile 三者中最低的那個。所以用途之間互相設上限,而同一用途內的堆疊層級之間互相覆蓋。

一個常見的部署套路:

  • stackLevel 0 —— TxDefaultProfile,日常運行限值
  • stackLevel 1 —— TxDefaultProfile,由電價驅動的夜間排程
  • stackLevel 2 —— TxProfile,營運方針對某一次工作階段的削減

把層級 2 的設定檔移除,層級 1 的排程就恢復。沒有任何東西需要把它取代掉的內容再重述一遍。

Absolute、Recurring、Relative

chargingProfileKind 決定 startPeriod: 0 是什麼意思。

Absolute 把排程錨定在 startSchedule 這個明確的時間戳上。用於一次性的視窗:今晚 18:00 到 20:00 之間削減。

Recurring 按天或按週重複,由 recurrencyKind 控制。startSchedule 設定相位——也就是週期從每天的哪個時刻開始。用於電價情境。

Relative 把 startPeriod: 0 錨定在交易開始的那一刻,並且完全忽略 startSchedule。用於取決於工作階段已進行多久、而不是取決於一天中時刻的行為:第一個小時滿電流,之後降下來。

一個常犯的錯誤是發 Absolute 卻不帶 startSchedule。規範要求 Absolute 和 Recurring 都必須帶它,而各家充電樁的做法不一:有的拒掉這份設定檔,有的悄悄把它當成 Relative。

安培還是瓦特,以及為什麼這要緊

chargingRateUnit 取 A 或 W,而充電樁並不被要求同時支援兩者。對 ChargingScheduleAllowedChargingRateUnit 做一次 GetConfiguration,就能知道哪些可用。

交流充電下,換算取決於相數,而設定檔本身並不攜帶相數。單相 230 V 上的 32 A 大約是 7.4 kW;同樣的 32 A 在三相上大約是 22 kW。如果你的後端按瓦特思考而充電樁按安培工作,那麼關於相數的假設就藏在你程式碼的某個地方,而它必須是明確的。

排程時段裡的 numberPhases 在省略時預設為 3。在單相安裝上這個預設值是錯的,由它算出來的限值會高出三倍。

核實充電樁實際做了什麼

SetChargingProfile 會回 Accepted、Rejected 或 NotSupported。Accepted 的意思是充電樁把這份設定檔存下來了——不代表它目前生效,也不代表它產生了你想要的限值。

要看所有設定檔合併之後的結果,用 GetCompositeSchedule:

[2, "msg-02", "GetCompositeSchedule", {
  "connectorId": 1,
  "duration": 86400,
  "chargingRateUnit": "A"
}]

充電樁會回傳它實際會遵循的那份扁平化排程,所有設定檔都已經解算完畢。這是檢驗你堆疊邏輯唯一可靠的辦法,也是當一次削減看起來沒生效時第一個該伸手去拿的工具。

如果複合排程和你預期的不一樣,常見原因有三個:堆疊層級低於某個已經裝上去的設定檔;TxProfile 的 transactionId 和正在進行的交易對不上;或者有一個 ChargePointMaxProfile 在上面壓著你。

清除設定檔

ClearChargingProfile 是按過濾條件刪除,不是只按 ID 刪除。每個欄位都是選用的,而全部省略就會清掉所有東西:

[2, "msg-03", "ClearChargingProfile", {
  "connectorId": 1,
  "chargingProfilePurpose": "TxProfile"
}]

這會清掉 1 號接口上的 TxProfile,而預設設定檔保持不動。發一個 {} 會清掉這台充電樁上的每一份設定檔——偶爾這正是你想要的,更多時候它是一次故障。

怎麼測

智慧充電很難拿真實硬體來測,因為有意思的情況都跟時間有關——一個在跨日邊界上出問題的週期性設定檔、一次在工作階段中途抵達的削減、一份只有在三個設定檔疊起來之後才算錯的複合排程。

這正是值得放到模擬裡去跑的那類邏輯。SimPilot 可以把一個工作階段一直掛著,讓你對著它安裝、堆疊和清除設定檔;而 TestPilot 則按規範檢查一台充電樁自身對智慧充電功能檔的處理。完整的訊息集記錄在我們的 OCPP 1.6 參考文件裡。

相關文章