表达式引擎
表达式引擎是 Edge-EMS Builder “计算”能力的核心,聚合点位的取值、触发方案的判断条件、MQTT 报文的组装,本质上都是表达式引擎执行一段脚本的结果。脚本语法为 Lua。
一、变量引用规则
Section titled “一、变量引用规则”表达式脚本执行前,Edge-EMS Builder 会先把脚本中形如 ${...} 的占位符替换为实际数据值,再执行脚本主体。占位符支持以下写法,可以组合使用:
| 写法 | 说明 | 示例 |
|---|---|---|
${dataKey} |
引用某点位的当前值 | ${PCS1_有功功率} |
${dataKey[-NTimeUnit]} |
引用 N 个时间单位之前的历史值 | ${PCS1_有功功率[-5s]} 表示 5 秒前的值 |
${dataKey[#N]} |
引用倒数第 N 条历史采样值 | ${PCS1_有功功率[#3]} 表示倒数第 3 条值 |
${dataKey[raw]} |
原样输入,不做自动类型转换。数值 1000 与二进制 1000 等难以区分的场景,用 raw 强制原样注入;只能且必须放在最后 |
${设备状态[raw]} |
${[deviceCode]dataKey} |
引用共享设备(Share)点位的最新值 | ${[DeviceA]PCS1_有功功率} |
| 混合使用 | 上述规则可自由组合 | ${[DeviceA]PCS1_有功功率[-1s][#3]} |
缺失值:目标点位暂时无值时,引擎注入字符串
__Null__。可显式比较或使用isNull/isNotNull;数值计算先用tonumber,不要依靠or 0判断该字符串。
时间偏移支持的单位:
| 单位 | 可用简写 |
|---|---|
| 毫秒 | ms / millisecond |
| 秒 | s / sec / second / seconds |
| 分钟 | m / min / minute / minutes |
| 小时 | h / hour / hours |
| 天 | d / day / days |
| 周 | w / week / weeks |
| 月 | M / month |
二、脚本主体:标准 Lua 语法
Section titled “二、脚本主体:标准 Lua 语法”占位符替换完成后,剩余的脚本主体按标准 Lua 5.1 语法执行,最后通过 return 返回计算结果。这意味着你可以使用 Lua 原生的变量、条件、循环、函数等能力:
-- 计算总视在功率(简化示例)local ua, ub, uc = tonumber(${Meter1_Ua}), tonumber(${Meter1_Ub}), tonumber(${Meter1_Uc})local ia, ib, ic = tonumber(${Meter1_Ia}), tonumber(${Meter1_Ib}), tonumber(${Meter1_Ic})if not (ua and ub and uc and ia and ib and ic) then return "__Null__" end
local s = ua * ia + ub * ib + uc * icreturn s三、内置函数与模块
Section titled “三、内置函数与模块”除标准 Lua 语法(含原生 string/table/math 库)外,Edge-EMS Builder 在脚本环境中预置了一批全局函数与可 require 的模块,覆盖数据读取、写入构造、字符串/时间/正则处理等常见需求,无需编写底层代码即可完成复杂逻辑:
| 分类 | 说明 | 示例 |
|---|---|---|
| 数据读取(全局函数) | getLatestDataValue、getHistoryData、getDeviceShareValue,以及按前缀/后缀/模糊批量查询的函数族 |
动态扫描一批命名规则相同的点位(见 触发方案 中的动态设备发现示例) |
| 写入构造(全局函数) | buildCommonWriteMap、buildCustomizationWriteMap、buildDailyRepeatWriteMap、buildCommonAlarmMap、buildMqttAlarmMap、buildAlarmObservationMap、buildSlaveWriteMap |
构造要写入的目标数据结构,供触发动作/MQTT 动作统一执行 |
| 时间转换 | cp56Time2aToOffsetDateTime、offsetDateTimeToCP56Time2a,支持 AB/BA |
对接 IEC 时间寄存器 |
| 时间模块 | require("OffsetDateTime")、require("LocalTime") |
获取当前时间戳(限频判断)、比较时间区间 |
| 通用工具模块 | require("Logger")、require("JSON")、require("Regex")、require("String")、require("Math")、require("TableUtils") |
日志输出、JSON 深度操作、正则、字符串/数值/表处理 |
| JSON 转换(全局函数) | jsonToMap、jsonToList、toJsonString |
与外部系统交换结构化数据(常用于 MQTT 报文) |
| HTTP | require("http") |
脚本内直接发起 HTTP 请求,对接第三方接口,需自行控制频率与超时 |
完整的函数签名、模块方法清单可参考 Lua 脚本完整参考;变量引用的详细规则可参考 数据变量解析规则。
聚合点位表达式的返回值约定:
return单个值(数字/字符串等),作为该聚合点位的最新值;不要在这里返回buildCommonWriteMap这类写入描述数组——那是触发动作、MQTT 动作等场景的返回值格式,详见 Lua 脚本完整参考 · 返回值约定。
四、配置示例:剩余可用容量计算
Section titled “四、配置示例:剩余可用容量计算”以负载均衡类场景中常见的“剩余可用功率”为例:
-- 额定电流 × 电压 = 额定功率上限(kW)local rated_kw = tonumber(${Grid_current} or 0) * tonumber(${Grid_voltage} or 0) * 0.001
-- 已用功率(电网侧实测总功率,kW)local used_kw = tonumber(${Grid_total_power} or 0)
-- 预留 10% 安全裕量local avail_kw = (rated_kw - used_kw) * 0.9
return avail_kw把这段脚本配置为聚合点位 avail_kw 的表达式后,任何触发方案或其他聚合点位都可以直接通过 ${avail_kw} 引用这个计算结果,无需重复计算逻辑——这正是“逻辑复用”的体现。
五、试算功能
Section titled “五、试算功能”新增或修改聚合点位表达式后,可以在保存前使用试算功能验证表达式语法与计算结果是否符合预期,避免上线后才发现脚本错误。
- 查阅完整的内置函数签名、模块清单与更多示例:Lua 脚本完整参考
- 学习如何用触发方案把表达式的计算结果转化为实际动作:触发方案