Skip to content
JelinaJelina DocumentationTechnical documentation
Back to website

Expression Engine

The expression engine is the core of Edge-EMS Builder’s computation capabilities. Aggregation point values, trigger conditions, and MQTT message construction are all results of scripts executed by this engine. Scripts use Lua syntax.

Before executing a script, Edge-EMS Builder replaces placeholders in the form ${...} with actual data values, then executes the script body. The following placeholder forms can be combined:

Syntax Description Example
${dataKey} Current value of a point ${PCS1_有功功率}
${dataKey[-NTimeUnit]} Historical value N time units ago ${PCS1_有功功率[-5s]} means the value 5 seconds ago
${dataKey[#N]} Nth most recent historical sample ${PCS1_有功功率[#3]} means the third most recent value
${dataKey[raw]} Injects the value unchanged, without automatic type conversion. Use raw where values such as numeric 1000 and binary 1000 are difficult to distinguish; it must appear last and nowhere else ${设备状态[raw]}
${[deviceCode]dataKey} Latest value of a shared device (Share) point ${[DeviceA]PCS1_有功功率}
Combined forms The rules above can be freely combined ${[DeviceA]PCS1_有功功率[-1s][#3]}

Missing values: when the target point has no value, the engine injects the string __Null__. Compare explicitly or use isNull / isNotNull. For numeric calculations, use tonumber first; do not rely on or 0 to detect this string.

Supported time-offset units:

Unit Accepted abbreviations
Milliseconds ms / millisecond
Seconds s / sec / second / seconds
Minutes m / min / minute / minutes
Hours h / hour / hours
Days d / day / days
Weeks w / week / weeks
Months M / month

After placeholder substitution, the remaining script body executes using standard Lua 5.1 syntax and returns its result with return. You can therefore use native Lua variables, conditions, loops, functions, and other features:

-- Calculate total apparent power (simplified example)
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 * ic
return s

In addition to standard Lua syntax, including the native string/table/math libraries, Edge-EMS Builder supplies global functions and modules accessible through require. These cover common needs such as data reads, constructing writes, and string, time, and regular-expression processing, enabling complex logic without low-level code:

Category Description Example
Data reads (global functions) getLatestDataValue, getHistoryData, getDeviceShareValue, and function families for batch queries by prefix, suffix, or fuzzy match Dynamically scan points sharing a naming convention; see the dynamic device discovery example in Trigger schemes
Write construction (global functions) buildCommonWriteMap, buildCustomizationWriteMap, buildDailyRepeatWriteMap, buildCommonAlarmMap, buildMqttAlarmMap, buildAlarmObservationMap, buildSlaveWriteMap Construct target data structures for unified execution by trigger/MQTT actions
Time conversion cp56Time2aToOffsetDateTime, offsetDateTimeToCP56Time2a, with AB/BA support Integrate IEC time registers
Time modules require("OffsetDateTime"), require("LocalTime") Get the current timestamp for rate limiting; compare time intervals
General utility modules require("Logger"), require("JSON"), require("Regex"), require("String"), require("Math"), require("TableUtils") Logging, deep JSON operations, regular expressions, and string/number/table processing
JSON conversion (global functions) jsonToMap, jsonToList, toJsonString Exchange structured data with external systems, often in MQTT messages
HTTP require("http") Send HTTP requests directly from scripts to third-party APIs; manage request rates and timeouts yourself

For complete function signatures and module methods, see the complete Lua script reference. For detailed variable reference rules, see Data variable parsing rules.

Aggregation point expressions must return a single value (a number, string, etc.) as the point’s latest value. Do not return arrays of write descriptors such as buildCommonWriteMap here; those formats belong to trigger actions, MQTT actions, and similar contexts. See the return-value conventions in the complete Lua script reference.

4. Configuration example: remaining available capacity

Section titled “4. Configuration example: remaining available capacity”

The following example calculates remaining available power, commonly used in load balancing:

-- Rated current × voltage = rated power limit (kW)
local rated_kw = tonumber(${Grid_current} or 0) * tonumber(${Grid_voltage} or 0) * 0.001
-- Used power: measured total grid-side power, kW
local used_kw = tonumber(${Grid_total_power} or 0)
-- Reserve a 10% safety margin
local avail_kw = (rated_kw - used_kw) * 0.9
return avail_kw

After configuring this script as the expression for aggregation point avail_kw, any trigger scheme or other aggregation point can reference the result through ${avail_kw} without duplicating the calculation logic. This is how logic reuse works.

After adding or editing an aggregation point expression, use Trial calculation before saving to verify syntax and expected results, avoiding script errors discovered only after deployment.