跳转到内容
返回官网

案例:充电桩集群负载均衡

本案例演示如何仅用 Edge-EMS Builder 的通用能力——动态数据扫描、表达式计算、触发方案、限频控制——搭建出一套具备“设备数量可变、无需改脚本”能力的负载均衡策略。文中设备品牌、命名前缀均为示意,请替换为你项目中的实际命名。

配电箱同时接入若干台充电桩(协议不限,可为 OCPP 或厂商私有协议)与其他必要负载(如照明、空调)。配电箱的电网侧进线容量固定,当所有充电桩同时全功率充电时,总用电量可能超过进线额定容量,导致跳闸或超容罚款。

目标:在保证必要负载优先获得供电的前提下,让所有在线充电桩共享剩余可用容量,动态调整每台桩的充电电流,任何一台桩上下线都能在数秒内完成再平衡,且新增充电桩不需要修改任何策略脚本。

系统中有两个关键测量点:

  • Grid_total_power:电网侧实时输入总功率(含配电箱内所有负载:必要负载 + 充电桩 + 其他);
  • 必要负载已经体现在这个实测值里,因此只需要控制充电桩的总消耗,就能保证配电箱总输入不超过额定功率,必要负载自然被优先满足。
-- 可分配余量(kW)= (额定功率 - 实测电网总功率) × 安全系数
-- 10% 安全裕量防止功率超调,实测值已含必要负载,无需单独扣除
local avail_kw = (rated_kw - grid_kw) * 0.9
local 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
end
end

只要新充电桩的采集点位按约定的命名规则接入(见下方“命名规则”),下一次触发时就会被自动纳入均分计算,不需要修改脚本、不需要重启服务。这正是 数据模型 与 Lua引擎 组合出来的能力,而非某个专属功能。

四、触发模型:数据刷新 + 脚本内限频

Section titled “四、触发模型:数据刷新 + 脚本内限频”

如果单纯用固定周期轮询,会造成“数据没变也执行一次”的冗余写入;如果把限频条件也放进触发器,又会让条件配置变复杂。这里采用更简洁的模式:

数据刷新触发 + 脚本内时间戳限频:触发器只负责感知数据刷新,实际的指令下发频率由脚本自主控制。

数据刷新 → 满足条件 → 触发脚本 → 读取聚合点位 last_ctrl_ms(上次执行时间戳)
→ 距今 < 5000ms:直接返回,不下发指令
→ 距今 ≥ 5000ms:执行控制 → 写入指令 → 刷新时间戳

部署前置步骤:需要先手动创建一个聚合点位,作为脚本的“记忆”:

{
"dataKey": "last_ctrl_ms",
"dataName": "充电控制上次执行时间戳",
"expression": "return 0",
"collectionCycle": -1
}

每次触发后,脚本按顺序执行:读取电网参数 → 限频检查 → 扫描在线充电桩 → 计算可用电流 → 逐桩决策 → 刷新时间戳 → 返回指令列表。逐桩决策规则:

条件 充电桩状态 执行动作
超载 或 均分电流 < 最小电流 充电中 停止充电(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.001
local 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
end
end
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……即可自动被纳入均分逻辑。

场景 是否需要改脚本 操作
新增同品牌充电桩 否 按命名规则新增采集点位即可
调整额定容量上限 否 修改聚合点位 Grid_current 的值
调整最小充电功率 否 修改聚合点位 min_charge_power 的值
充电桩临时下线 否 断开后 _status 变空,自动从在线列表排除
新增充电桩品牌 是 扫描列表新增一个前缀,如 {"VENDORA", "VENDORB", "VENDORC"}
安全裕量系数可配置化 是(一次性) 新增聚合点位承载该系数,脚本改为读取该点位

这张表本身也说明了 设计理念 里强调的一点:大部分业务变化只是改配置,只有少数结构性变化才需要改脚本,而且改动范围是可预期、可控的。

  • 若充电桩集群分布在多个子配电箱,可通过 设备协作 把各子配电箱的电网实测功率共享到主控设备,在主控上统一做全局均分。
  • 若充电桩品牌型号会随项目不断增加,且不同项目的桩群结构相似,可通过 设备单元动态扩展 把“品牌前缀 + 命名规则 + 关联点位”沉淀为模板,缩短新项目的搭建时间。
  • 若需要云端下发限流阈值、查看整体负载均衡状态,通过 云边协同 定期上报电网余量、各桩下发指令记录。
充电桩负载均衡的采集、计算、分配与执行流程

本图根据本页配置逻辑绘制,展示数据与控制流程。具体操作字段请参照文中的配置与脚本。