案例:充電樁叢集負載平衡
本案例演示如何僅用 Edge-EMS Builder 的通用能力——動態資料掃描、運算式計算、觸發方案、限頻控制——搭建出一套具備“裝置數量可變、無需改指令碼”能力的負載平衡策略。文中裝置品牌、命名前綴均為示意,請替換為你專案中的實際命名。
一、業務背景
Section titled “一、業務背景”配電箱同時接入若干臺充電樁(協定不限,可為 OCPP 或廠商私有協定)與其他必要負載(如照明、空調)。配電箱的電網側進線容量固定,當所有充電樁同時全功率充電時,總用電量可能超過進線額定容量,導致跳閘或超容罰款。
目標:在保證必要負載優先獲得供電的前提下,讓所有線上充電樁共享剩餘可用容量,動態調整每臺樁的充電電流,任何一臺樁上下線都能在數秒內完成再平衡,且新增充電樁不需要修改任何策略指令碼。
二、功率模型
Section titled “二、功率模型”系統中有兩個關鍵測量點:
Grid_total_power:電網側即時輸入總功率(含配電箱內所有負載:必要負載 + 充電樁 + 其他);- 必要負載已經體現在這個實測值裡,因此只需要控制充電樁的總消耗,就能保證配電箱總輸入不超過額定功率,必要負載自然被優先滿足。
-- 可分配餘量(kW)= (額定功率 - 實測電網總功率) × 安全係數-- 10% 安全裕量防止功率超調,實測值已含必要負載,無需單獨扣除local avail_kw = (rated_kw - grid_kw) * 0.9local per_A = (avail_kw / n) * 1000 / voltage_V -- 均分為電流(A)三、動態裝置發現:新增充電樁無需改指令碼
Section titled “三、動態裝置發現:新增充電樁無需改指令碼”策略不預設充電樁數量。每次執行時,透過按前綴+後綴批次掃描的方式,自動發現所有線上充電樁:
local online = {}
-- 逐個品牌前綴掃描,可按需增減for _, brandPrefix in ipairs({"VENDORA", "VENDORB"}) do local statusMap = getLatestDataValuesByPrefixAndSuffix("Collection", brandPrefix, "_status") if statusMap then -- 回傳值是以 dataKey 為鍵的 Table,用 pairs() 遍歷;判空比較哨兵字串 "__Null__" for dataKey, dto in pairs(statusMap) do if dto.DataValue ~= "__Null__" then table.insert(online, dto) end end endend只要新充電樁的擷取點位按約定的命名規則接入(見下方“命名規則”),下一次觸發時就會被自動納入均分計算,不需要修改指令碼、不需要重新啟動服務。這正是 資料模型 與 Lua引擎 組合出來的能力,而非某個專屬功能。
四、觸發模型:資料重新整理 + 指令碼內限頻
Section titled “四、觸發模型:資料重新整理 + 指令碼內限頻”如果單純用固定週期輪詢,會造成“資料沒變也執行一次”的冗餘寫入;如果把限頻條件也放進觸發器,又會讓條件設定變複雜。這裡採用更簡潔的模式:
資料重新整理觸發 + 指令碼內時間戳限頻:觸發器只負責感知資料重新整理,實際的指令下發頻率由指令碼自主控制。
資料重新整理 → 滿足條件 → 觸發指令碼 → 讀取聚合點位 last_ctrl_ms(上次執行時間戳) → 距今 < 5000ms:直接回傳,不下發指令 → 距今 ≥ 5000ms:執行控制 → 寫入指令 → 重新整理時間戳部署前置步驟:需要先手動建立一個聚合點位,作為指令碼的“記憶”:
{ "dataKey": "last_ctrl_ms", "dataName": "充电控制上次执行时间戳", "expression": "return 0", "collectionCycle": -1}五、逐樁決策表
Section titled “五、逐樁決策表”每次觸發後,指令碼按順序執行:讀取電網參數 → 限頻檢查 → 掃描線上充電樁 → 計算可用電流 → 逐樁決策 → 重新整理時間戳 → 回傳指令清單。逐樁決策規則:
| 條件 | 充電樁狀態 | 執行動作 |
|---|---|---|
| 超載 或 均分電流 < 最小電流 | 充電中 | 停止充電(stop_transaction) |
| 超載 或 均分電流 < 最小電流 | 其他 | 跳過 |
| 未超載 且 均分電流 ≥ 最小電流 | 充電中 | 下發新的限流值(set_charging_profile) |
| 未超載 且 均分電流 ≥ 最小電流 | 非充電中 | 啟動充電(start_transaction,需授權 Tag 有效) |
對應的核心指令碼片段(觸發動作,回傳寫入描述陣列):
local OffsetDateTime = require("OffsetDateTime")
local ratedKw = tonumber(${Grid_current} or 0) * tonumber(${Grid_voltage} or 0) * 0.001local gridKw = tonumber(${Grid_total_power} or 0)local overload = gridKw >= ratedKw
local voltage = tonumber(${Grid_voltage} or 1)local minChargePower = tonumber(${min_charge_power} or 4200)
local resultList = {}if #online > 0 then local availKw = (ratedKw - gridKw) * 0.9 local perA = math.floor((availKw / #online) * 1000 / voltage) local minA = math.floor(minChargePower / voltage)
for _, pile in ipairs(online) do local prefix = pile.DataKey:gsub("_status$", "") -- 從 dataKey 還原出充電樁前綴,如 VENDORA01 if overload or perA < minA then if pile.DataValue == "Charging" then table.insert(resultList, buildCommonWriteMap("Collection", prefix .. "_type", "stop_transaction", nil, nil, false)) end else if pile.DataValue == "Charging" then table.insert(resultList, buildCommonWriteMap("Collection", prefix .. "_periods", '[{"start":0,"limit":' .. perA .. '}]', nil, nil, false)) elseif ${id_tag} ~= "__Null__" then table.insert(resultList, buildCommonWriteMap("Collection", prefix .. "_type", "start_transaction", nil, nil, false)) end end endend
table.insert(resultList, buildCommonWriteMap("Aggregation", "last_ctrl_ms", OffsetDateTime.now():unixMilli(), nil, nil, false))return resultList六、命名規則:批次識別的前提
Section titled “六、命名規則:批次識別的前提”指令碼按 {品牌前缀}{两位编号}_{属性} 的格式批次掃描充電樁擷取點位,必須嚴格遵守:
| 部分 | 規則 | 示例 |
|---|---|---|
| 品牌前綴 | 全大寫、不含底線 | VENDORA、VENDORB(請替換為你實際使用的裝置品牌標識) |
| 編號 | 兩位零填充 | 01、02…10 |
| 屬性 | 見下表 | status、type |
每臺充電樁需要具備的擷取點位(部分示例):
| 屬性 | 完整 dataKey 示例 | 讀/寫 | 說明 |
|---|---|---|---|
_status |
VENDORA01_status |
讀 | 充電樁狀態,掃描依據,缺失則該樁不被發現 |
_transaction_id |
VENDORA01_transaction_id |
讀 | 目前交易 ID |
_type |
VENDORA01_type |
寫 | 指令型別:start/stop/set_charging_profile |
_periods |
VENDORA01_periods |
寫 | 限額週期 JSON,如 [{"start":0,"limit":16}] |
新增第 6 臺該品牌充電樁時,只需按上述命名接入其擷取點位——VENDORA06_status、VENDORA06_type……即可自動被納入均分邏輯。
七、如何應對未來變化
Section titled “七、如何應對未來變化”| 場景 | 是否需要改指令碼 | 操作 |
|---|---|---|
| 新增同品牌充電樁 | 否 | 按命名規則新增擷取點位即可 |
| 調整額定容量上限 | 否 | 修改聚合點位 Grid_current 的值 |
| 調整最小充電功率 | 否 | 修改聚合點位 min_charge_power 的值 |
| 充電樁臨時下線 | 否 | 斷開後 _status 變空,自動從線上清單排除 |
| 新增充電樁品牌 | 是 | 掃描清單新增一個前綴,如 {"VENDORA", "VENDORB", "VENDORC"} |
| 安全裕量係數可設定化 | 是(一次性) | 新增聚合點位承載該係數,指令碼改為讀取該點位 |
這張表本身也說明了 設計理念 裡強調的一點:大部分業務變化只是改設定,只有少數結構性變化才需要改指令碼,而且改動範圍是可預期、可控的。
八、與其他能力的組合
Section titled “八、與其他能力的組合”- 若充電樁叢集分佈在多個子配電箱,可透過 裝置協作 把各子配電箱的電網實測功率共享到主控裝置,在主控上統一做全域均分。
- 若充電樁品牌型號會隨專案不斷增加,且不同專案的樁群結構相似,可透過 裝置單元動態擴充 把“品牌前綴 + 命名規則 + 關聯點位”沉澱為範本,縮短新專案的搭建時間。
- 若需要雲端下發限流閾值、檢視整體負載平衡狀態,透過 雲端與邊緣協作 定期回報電網餘量、各樁下發指令記錄。
本圖根據本頁設定邏輯繪製,展示資料與控制流程。具體操作欄位請參照文中的設定與指令碼。