Lua 脚本完整参考
本页是 Edge-EMS Builder 表达式引擎(聚合表达式、触发条件/动作、后处理动作、MQTT 发布/订阅内容)所用脚本能力的完整参考手册。脚本语法为 Lua 5.x,由内置的 Lua 运行时解析执行。快速入门请先阅读 表达式引擎,本页补充完整的内置模块、全局函数签名与返回值约定。
⚠️ 如果你接触过 Edge-EMS Builder 早期 Java 版本(QLExpress4 引擎,类 Java 语法),请注意:变量引用写法
${...}基本保持不变,但脚本主体语法已从类 Java 语法改为标准 Lua 语法(如new ArrayList()→{}、.add(x)→table.insert(t, x)、new HashMap()→{}、.put(k, v)→t[k] = v)。内置函数名称大部分保留,可直接对照本页迁移。
- 脚本语言:Lua 5.x,函数名及占位符区分大小写。
- 数据占位符:
${dataKey}由引擎在脚本运行前替换为当前值;跨设备写${[deviceCode]dataKey}。 - 哨兵值:取不到数据时,占位符会被注入字符串
__Null__,可显式比较或使用isNull/isNotNull;数值计算先使用tonumber。 - 返回值因场景而异(详见下方「返回值约定」),写错返回值类型是最常见的配置错误来源。
- 模块函数需先
require("模块名")再调用;全局函数(如buildCommonWriteMap、jsonToMap)无需require,直接调用。 - 日志:
Logger模块默认输出级别为 WARN,仅Logger.warn()/Logger.error()会实际输出,调试时不要只用Logger.info()/Logger.debug()。
一、数据解析(变量引用)
Section titled “一、数据解析(变量引用)”| 写法 | 说明 |
|---|---|
${variable} |
返回当前值 |
${variable[-1s]} |
返回上一秒的值 |
${variable[-5s]} |
返回 5 秒前的值 |
${variable[raw]} |
原样输入不做自动类型转换(针对数值 1000 与二进制 1000 等难以区分的数据,用 raw 控制是否原样输入)。[raw] 只能且必须放在最后。 |
${[deviceA]variable} |
返回共享设备 deviceA 的值 |
${variable[@timestamp]} |
返回指定绝对时间点的值 |
${variable[#N]} |
返回倒数第 N 条历史值;不带此规则时默认返回最新值 |
${[deviceA]variable[-5s][#N]} |
返回共享设备 deviceA 在 5 秒前时刻的倒数第 N 个采样值 |
若目标点位取不到值,引擎统一注入哨兵字符串
__Null__,请在脚本中显式判断,例如:if ${some_key} == "__Null__" then ... end。
二、返回值约定(按场景)
Section titled “二、返回值约定(按场景)”不同脚本填写位置,对返回值的要求完全不同,这是最容易出错的地方:
| 场景 | 填写位置 | 返回值要求 |
|---|---|---|
| 触发条件 | 触发条件表达式 | 单个布尔值(true = 条件成立) |
| 触发动作(表达式类触发方案) | 动作内容(Expression) | 数组表(下标从 1 开始连续),元素为 buildCommonWriteMap(...) 等函数返回的 map;空表 {} 视为「无写入项」 |
| 触发动作(混合写入类触发方案) | 每个 dataKey 单独绑定的动作 |
单个值(字符串/数字/布尔),作为该 dataKey 的写入内容;不要返回 buildCommonWriteMap 数组 |
| 后处理动作 | 触发动作执行完成后的收尾脚本 | 与表达式类触发动作相同:写入描述数组表;可通过固定变量 ${trigger_result}(布尔)、${trigger_write_result}(JSON 字符串,需 jsonToMap 解析)判断主流程执行结果 |
| 聚合点位表达式 | 聚合数据计算表达式 | 单个值(数字/字符串等),作为该聚合点位的最新值 |
| MQTT 发布内容(publishContent) | MQTT 发布配置 | Lua 表,将被序列化为 JSON 作为发布载荷 |
| MQTT 订阅动作(actionContent) | MQTT 订阅配置 | 与表达式类触发动作相同:写入描述数组表 |
| MQTT 响应 Topic(responseTopic) | MQTT 订阅配置 | 单个字符串,作为响应发布的 Topic |
| MQTT 响应内容(response) | MQTT 订阅配置 | 字符串原样发送,其他值(如 Lua 表)序列化为 JSON |
单次脚本调用有执行超时限制(默认 10 秒,超时会导致本次执行失败),脚本应避免在循环中做无节制的历史数据查询或 HTTP 请求。
三、内置模块
Section titled “三、内置模块”以下模块需先 require("模块名") 才能使用:
OffsetDateTime 模块
Section titled “OffsetDateTime 模块”完整的日期时间处理模块,支持时区、格式化、计算等功能。
local OffsetDateTime = require("OffsetDateTime")| 方法 | 说明 | 返回值 |
|---|---|---|
new() |
创建当前时间 | OffsetDateTime |
new(sec, nsec?) |
从 Unix 时间戳创建 | OffsetDateTime |
now() |
获取当前时间 | OffsetDateTime |
parse(str) |
解析时间字符串 | OffsetDateTime | (nil, err) |
parseInLocation(str, location) |
在指定时区解析时间 | OffsetDateTime | (nil, err) |
unix(sec, nsec?) |
从 Unix 秒创建 | OffsetDateTime |
unixMilli(msec) |
从毫秒时间戳创建 | OffsetDateTime |
unixMicro(usec) |
从微秒时间戳创建 | OffsetDateTime |
实例方法 - 时间组件
Section titled “实例方法 - 时间组件”| 方法 | 说明 | 返回值 |
|---|---|---|
year() |
获取年份 | number |
month() |
获取月份 (1-12) | number |
day() |
获取日期 (1-31) | number |
hour() |
获取小时 (0-23) | number |
minute() |
获取分钟 (0-59) | number |
second() |
获取秒 (0-59) | number |
nanosecond() |
获取纳秒 | number |
yearDay() |
获取一年中的第几天 | number |
weekday() |
获取星期 (0=周日) | number |
isoWeek() |
获取 ISO 周信息 | {year, week} |
date() |
获取年月日 | {year, month, day} |
clock() |
获取时分秒 | {hour, minute, second} |
实例方法 - 时间计算
Section titled “实例方法 - 时间计算”| 方法 | 说明 | 返回值 |
|---|---|---|
add(durationStr) |
增加时间间隔 | OffsetDateTime | (nil, err) |
addDate(years, months, days) |
增加年月日 | OffsetDateTime |
sub(other) |
计算时间差(纳秒) | number |
addYears(n) |
增加年 | OffsetDateTime |
addMonths(n) |
增加月 | OffsetDateTime |
addDays(n) |
增加天 | OffsetDateTime |
addHours(n) |
增加小时 | OffsetDateTime |
addMinutes(n) |
增加分钟 | OffsetDateTime |
addSeconds(n) |
增加秒 | OffsetDateTime |
addMilliseconds(n) |
增加毫秒 | OffsetDateTime |
addMicroseconds(n) |
增加微秒 | OffsetDateTime |
addNanoseconds(n) |
增加纳秒 | OffsetDateTime |
实例方法 - 时间差计算
Section titled “实例方法 - 时间差计算”| 方法 | 说明 | 返回值 |
|---|---|---|
diffYears(other) |
计算年份差 | number |
diffMonths(other) |
计算月份差 | number |
diffDays(other) |
计算天数差 | number |
diffHours(other) |
计算小时差 | number |
diffMinutes(other) |
计算分钟差 | number |
diffSeconds(other) |
计算秒数差 | number |
实例方法 - 时间比较
Section titled “实例方法 - 时间比较”| 方法 | 说明 | 返回值 |
|---|---|---|
equal(other) |
是否相等 | boolean |
before(other) |
是否早于 | boolean |
after(other) |
是否晚于 | boolean |
isZero() |
是否为零值 | boolean |
实例方法 - 时间判断
Section titled “实例方法 - 时间判断”| 方法 | 说明 | 返回值 |
|---|---|---|
isToday() |
是否是今天 | boolean |
isYesterday() |
是否是昨天 | boolean |
isTomorrow() |
是否是明天 | boolean |
isThisWeek() |
是否是本周 | boolean |
isThisMonth() |
是否是本月 | boolean |
isThisYear() |
是否是今年 | boolean |
isBetween(start, end) |
是否在范围内 | boolean |
isInRange(start, end) |
是否在范围内 | boolean |
实例方法 - 格式化
Section titled “实例方法 - 格式化”| 方法 | 说明 | 返回值 |
|---|---|---|
format(layout) |
自定义格式化 | string |
toString() |
转为字符串 | string |
toDateTimeString() |
日期时间格式 | string |
toDateString() |
日期格式 | string |
toTimeString() |
时间格式 | string |
toYearString() |
年份 | string |
toMonthString() |
月份 | string |
toDayString() |
日期 | string |
toHourString() |
小时 | string |
toMinuteString() |
分钟 | string |
toSecondString() |
秒 | string |
实例方法 - Unix 时间戳
Section titled “实例方法 - Unix 时间戳”| 方法 | 说明 | 返回值 |
|---|---|---|
unix() |
Unix 秒时间戳 | number |
unixMilli() |
Unix 毫秒时间戳 | number |
unixMicro() |
Unix 微秒时间戳 | number |
unixNano() |
Unix 纳秒时间戳 | number |
实例方法 - 时区
Section titled “实例方法 - 时区”| 方法 | 说明 | 返回值 |
|---|---|---|
utc() |
转为 UTC 时区 | OffsetDateTime |
local() |
转为本地时区 | OffsetDateTime |
in(location) |
转为指定时区 | OffsetDateTime | (nil, err) |
实例方法 - 其他
Section titled “实例方法 - 其他”| 方法 | 说明 | 返回值 |
|---|---|---|
truncate(durationStr) |
截断到指定精度 | OffsetDateTime | (nil, err) |
round(durationStr) |
舍入到指定精度 | OffsetDateTime | (nil, err) |
toTime() |
转为 Go time.Time | time.Time |
local layouts = OffsetDateTime.Layout-- layouts.DateTime = "2006-01-02 15:04:05"-- layouts.Date = "2006-01-02"-- layouts.Time = "15:04:05"local OffsetDateTime = require("OffsetDateTime")local Logger = require("Logger")
-- 获取当前时间local now = OffsetDateTime.now()Logger.warn(now:toString())
-- 解析时间local dt = OffsetDateTime.parse("2024-01-15T10:30:00.000Z")Logger.warn("年份: " .. dt:year())Logger.warn("月份: " .. dt:month())
-- 时间计算local tomorrow = now:addDays(1)local nextWeek = now:addDays(7)Logger.warn("明天: " .. tomorrow:toDateString())
-- 时间比较if now:isToday() then Logger.warn("今天!")end
-- 时间差local hours = nextWeek:diffHours(now)Logger.warn("相差小时: " .. hours)
-- 格式化Logger.warn(now:format("2006-01-02 15:04:05"))Logger.warn(now:toDateTimeString())LocalTime 模块
Section titled “LocalTime 模块”只包含时分秒的时间类型,不含日期和时区。
local LocalTime = require("LocalTime")| 方法 | 说明 | 返回值 |
|---|---|---|
new(hour, minute, second) |
创建时间 | LocalTime | (nil, err) |
now() |
获取当前时间 | LocalTime |
parse(str) |
解析 “HH:mm:ss” | LocalTime | (nil, err) |
fromTime(time.Time) |
从 time.Time 创建 | LocalTime | (nil, err) |
fromDuration(durationStr) |
从时间间隔创建 | LocalTime | (nil, err) |
| 方法 | 说明 | 返回值 |
|---|---|---|
hour() |
获取小时 | number |
minute() |
获取分钟 | number |
second() |
获取秒 | number |
toString() |
转为 “HH:mm:ss” | string |
toDuration() |
转为时间间隔字符串 | string |
equal(other) |
是否相等 | boolean |
before(other) |
是否早于 | boolean |
after(other) |
是否晚于 | boolean |
beforeOrEqual(other) |
是否早于或等于 | boolean |
afterOrEqual(other) |
是否晚于或等于 | boolean |
isZero() |
是否为 00:00:00 | boolean |
diffSeconds(other) |
秒数差 | number |
diffMinutes(other) |
分钟差 | number |
diffHours(other) |
小时差 | number |
addSeconds(n) |
增加秒 | LocalTime |
addMinutes(n) |
增加分钟 | LocalTime |
addHours(n) |
增加小时 | LocalTime |
subSeconds(n) |
减少秒 | LocalTime |
subMinutes(n) |
减少分钟 | LocalTime |
subHours(n) |
减少小时 | LocalTime |
local LocalTime = require("LocalTime")local Logger = require("Logger")
-- 创建时间local workStart = LocalTime.new(9, 0, 0) -- 09:00:00local workEnd = LocalTime.new(17, 30, 0) -- 17:30:00
-- 获取当前时间local now = LocalTime.now()Logger.warn("当前时间: " .. now:toString())
-- 时间比较if now:isBetween(workStart, workEnd) then Logger.warn("工作时间")else Logger.warn("非工作时间")end
-- 时间计算local breakTime = workStart:addHours(3):addMinutes(30) -- 12:30:00Logger.warn("午休时间: " .. breakTime:toString())
-- 时间差local workHours = workEnd:diffHours(workStart)Logger.warn("工作时长: " .. workHours .. " 小时")通用工具模块
Section titled “通用工具模块”Logger 模块
Section titled “Logger 模块”日志输出模块,对接系统日志。
local Logger = require("Logger")| 方法 | 说明 | 参数 |
|---|---|---|
info(msg) |
输出 INFO 日志 | string |
warn(msg) |
输出 WARN 日志 | string |
error(msg) |
输出 ERROR 日志 | string |
debug(msg) |
输出 DEBUG 日志 | string |
infof(fmt, ...) |
格式化 INFO 日志 | string, … |
warnf(fmt, ...) |
格式化 WARN 日志 | string, … |
errorf(fmt, ...) |
格式化 ERROR 日志 | string, … |
debugf(fmt, ...) |
格式化 DEBUG 日志 | string, … |
local Logger = require("Logger")
Logger.info("系统启动")Logger.warn("磁盘空间不足")Logger.error("数据库连接失败")Logger.debug("变量值: x=10")
-- 格式化输出local user = "admin"local action = "login"Logger.infof("用户 %s 执行操作: %s", user, action)Logger.warnf("重试次数: %s", 3)注:Edge-EMS Builder的默认日志输出级别是WARN,只有WARN和ERROR日志会输出。
JSON 模块
Section titled “JSON 模块”JSON 序列化/反序列化及操作模块(基于 bytedance/sonic)。
local JSON = require("JSON")基础 API
Section titled “基础 API”| 方法 | 说明 | 返回值 |
|---|---|---|
encode(value) |
序列化为 JSON | string | (nil, err) |
decode(text) |
反序列化 | table | (nil, err) |
扩展 API
Section titled “扩展 API”| 方法 | 说明 | 返回值 |
|---|---|---|
toJSONString(value) |
序列化(无错误返回) | string |
toJSONStringIndent(value, prefix?, indent?) |
格式化序列化 | string |
toMap(jsonStr) |
转为 map | table | (nil, err) |
toStringMap(jsonStr) |
转为 string map | table | (nil, err) |
toSlice(jsonStr) |
转为数组 | table | (nil, err) |
isValid(jsonStr) |
验证 JSON 格式 | boolean |
pretty(jsonStr) |
美化 JSON | string |
merge(json1, json2) |
合并两个 JSON | string | (nil, err) |
get(jsonStr, key) |
获取值 | any | (nil, err) |
set(jsonStr, key, value) |
设置值 | string | (nil, err) |
remove(jsonStr, key) |
删除键 | string | (nil, err) |
clone(value) |
深拷贝 | any | (nil, err) |
local JSON = require("JSON")local Logger = require("Logger")
-- 基础序列化/反序列化local obj = {name = "张三", age = 30, tags = {"developer", "golang"}}local jsonStr = JSON.encode(obj)Logger.warn(jsonStr) -- {"name":"张三","age":30,"tags":["developer","golang"]}
local decoded, err = JSON.decode(jsonStr)if not decoded then Logger.warn("解析失败: " .. err)else Logger.warn("姓名: " .. decoded.name)end
-- 格式化输出local pretty = JSON.pretty(jsonStr)Logger.warn(pretty)
-- 验证 JSONif JSON.isValid(jsonStr) then Logger.warn("有效的 JSON")end
-- 操作 JSONlocal newJson = JSON.set(jsonStr, "city", "北京")Logger.warn(newJson) -- {"name":"张三","age":30,"tags":[...],"city":"北京"}
local age = JSON.get(newJson, "age")Logger.warn("年龄: " .. age) -- 30
local removed = JSON.remove(newJson, "age")Logger.warn(removed) -- {"name":"张三","tags":[...],"city":"北京"}
-- 合并 JSONlocal json1 = '{"a":1}'local json2 = '{"b":2}'local merged = JSON.merge(json1, json2)Logger.warn(merged) -- {"a":1,"b":2}
-- 深拷贝local original = {data = {x = 10}}local copied = JSON.clone(original)Regex 模块
Section titled “Regex 模块”正则表达式模块,支持匹配、查找、替换、分割等。
local Regex = require("Regex")| 方法 | 说明 | 返回值 |
|---|---|---|
match(text, pattern) |
是否匹配 | boolean |
findAll(text, pattern, limit?) |
查找所有匹配(含捕获组) | {{full, g1, g2, …}, …} | (nil, err) |
replace(text, pattern, repl) |
替换(支持 $1 等分组引用) | string | (nil, err) |
split(text, pattern, limit?) |
正则分割 | {string, …} | (nil, err) |
isEmail(text) |
是否是邮箱 | boolean |
isPhone(text) |
是否是手机号(中国) | boolean |
isIP(text) |
是否是 IP 地址 | boolean |
isURL(text) |
是否是 URL | boolean |
local Regex = require("Regex")local Logger = require("Logger")
-- 匹配if Regex.match("abc123", "\\d+") then Logger.warn("包含数字")end
-- 查找所有匹配(含捕获组)local matches = Regex.findAll("a1 b22 c333", "(\\w)(\\d+)")-- matches = {{"a1","a","1"}, {"b22","b","22"}, {"c333","c","333"}}for i, m in ipairs(matches) do Logger.warn("匹配 " .. i .. ": " .. m[1] .. ", 字母=" .. m[2] .. ", 数字=" .. m[3])end
-- 替换(支持分组引用)local s = Regex.replace("abc-123-def", "(\\d+)", "[$1]")Logger.warn(s) -- "abc-[123]-def"
-- 分割local parts = Regex.split("a,b,,c", ",", -1)-- parts = {"a", "b", "", "c"}for i, p in ipairs(parts) do Logger.warn("部分 " .. i .. ": '" .. p .. "'")end
-- 验证Logger.warn(Regex.isEmail("test@example.com")) -- trueLogger.warn(Regex.isPhone("13812345678")) -- trueLogger.warn(Regex.isIP("192.168.1.1")) -- trueLogger.warn(Regex.isURL("https://example.com")) -- trueString 模块
Section titled “String 模块”字符串处理工具。
local String = require("String")| 方法 | 说明 | 返回值 |
|---|---|---|
trim(s) |
去除首尾空白 | string |
upper(s) |
转大写 | string |
lower(s) |
转小写 | string |
contains(s, sub) |
是否包含子串 | boolean |
startsWith(s, prefix) |
是否以指定前缀开头 | boolean |
endsWith(s, suffix) |
是否以指定后缀结尾 | boolean |
local String = require("String")
local s = " Hello World "Logger.warn(String.trim(s)) -- "Hello World"Logger.warn(String.upper(s)) -- " HELLO WORLD "Logger.warn(String.lower(s)) -- " hello world "
Logger.warn(String.contains("hello", "ll")) -- trueLogger.warn(String.startsWith("hello", "he")) -- trueLogger.warn(String.endsWith("hello", "lo")) -- trueMath 模块
Section titled “Math 模块”数学计算工具。
local Math = require("Math")| 方法 | 说明 | 返回值 |
|---|---|---|
round(n) |
四舍五入 | number |
floor(n) |
向下取整 | number |
ceil(n) |
向上取整 | number |
abs(n) |
绝对值 | number |
max(a, b) |
最大值 | number |
min(a, b) |
最小值 | number |
local Math = require("Math")
Logger.warn(Math.round(3.6)) -- 4Logger.warn(Math.floor(3.9)) -- 3Logger.warn(Math.ceil(3.1)) -- 4Logger.warn(Math.abs(-5)) -- 5Logger.warn(Math.max(10, 20)) -- 20Logger.warn(Math.min(10, 20)) -- 10TableUtils 模块
Section titled “TableUtils 模块”表(table)操作工具,支持数组和键值对遍历。
local TableUtils = require("TableUtils")| 方法 | 说明 | 返回值 |
|---|---|---|
keys(tbl) |
获取所有键 | {string, …} |
values(tbl) |
获取所有值 | {any, …} |
map(tbl, fn) |
映射(fn(value, key)) | {any, …} |
filter(tbl, fn) |
过滤(fn(value, key)) | {any, …} |
reduce(tbl, fn, init) |
归约(fn(acc, value, key)) | any |
sortBy(tblOfMaps, key) |
按键排序(稳定排序) | {map, …} |
local T = require("TableUtils")
-- keys/valueslocal obj = {a = 1, b = 2, c = 3}local keys = T.keys(obj) -- {"a", "b", "c"}local values = T.values(obj) -- {1, 2, 3}
-- map(数组)local arr = {1, 2, 3}local doubled = T.map(arr, function(v, i) return v * 2end)-- doubled = {2, 4, 6}
-- map(键值对)local mapped = T.map({a=1, b=2}, function(v, k) return k .. ":" .. vend)-- mapped = {"a:1", "b:2"}
-- filterlocal arr = {1, 2, 3, 4, 5}local even = T.filter(arr, function(v, i) return v % 2 == 0end)-- even = {2, 4}
-- reducelocal sum = T.reduce({1, 2, 3}, function(acc, v, i) return acc + vend, 0)-- sum = 6
-- sortBylocal users = { {name="张三", age=30}, {name="李四", age=25}, {name="王五", age=35}}local sorted = T.sortBy(users, "age")-- sorted = {{name="李四",age=25}, {name="张三",age=30}, {name="王五",age=35}}以下函数直接注册到全局作用域,无需 require。
CP56Time2a 时间转换
Section titled “CP56Time2a 时间转换”| 函数 | 用途 |
|---|---|
cp56Time2aToOffsetDateTime(hex[, byteOrder]) |
解码 IEC 60870-5 时间,返回 OffsetDateTime |
offsetDateTimeToCP56Time2a(time[, byteOrder]) |
将时间编码为十六进制载荷 |
byteOrder 支持 AB / BA;未指定时采用标准 AB。显式指定时支持四寄存器载荷,补零位置有歧义时返回错误,应按设备寄存器布局核对。
数据解析函数
Section titled “数据解析函数”| 函数 | 说明 | 返回值 |
|---|---|---|
jsonToMap(str) |
JSON 转 map | table | (nil, err) |
jsonToList(str) |
JSON 转 list | table | (nil, err) |
jsonToListMap(str) |
JSON 转 list of map | table | (nil, err) |
completeDateTime(str) |
补全日期时间字符串 | string | (nil, err) |
quoteJson(str) |
引号转义 JSON | string |
simpleUUID() |
生成简单 UUID | string |
convertString(str) |
字符串类型转换 | any |
isNull(any) |
判断值是否为空 | bool |
isNotNull(any) |
判断值是否不为空 | bool |
isNull将 nil、空字符串、大小写不敏感的 “null” 及哨兵__Null__视为空;Lua 的or 0不能处理该哨兵。
local Logger = require("Logger")
-- JSON 解析local map, err = jsonToMap('{"a":1,"b":2}')if map then Logger.warn(map.a) -- 1end
local list = jsonToList('[1,2,3]')-- list = {1, 2, 3}
-- 时间补全local fullTime = completeDateTime("2024-01-15")-- fullTime = "2024-01-15T00:00:00.000+08:00"
-- UUID 生成local id = simpleUUID()Logger.warn(id) -- 32位UUID字符串缓存访问函数
Section titled “缓存访问函数”| 函数 | 说明 | 返回值 |
|---|---|---|
getLatestDataValue(dataKey) |
获取最新数据值 | any |
getAccountCache(key) |
获取账户缓存 | any |
getEMSDataCache(key) |
获取 EMS 数据缓存 | any |
getShareCache(key) |
获取共享缓存 | any |
getMqttCache(key) |
获取 MQTT 缓存 | any |
getTriggerCache(key) |
获取触发器缓存 | any |
getDeviceShareValue(deviceCode, dataKey) |
通过单个 deviceCode 和 dataKey 获取该设备共享数据的最新值 | string | nil |
getDeviceShareValues(deviceCodes, dataKey) |
通过设备列表和 dataKey 获取各设备该数据的最新值 | table |
getAllDeviceShareValues(dataKey) |
通过 dataKey 获取共享空间中所有设备该数据的最新值 | table |
local Logger = require("Logger")
-- 获取设备最新数据local value = getLatestDataValue("device1.temperature")Logger.warn("当前温度: " .. value)
-- 获取账户信息local account = getAccountCache("user123")if account then Logger.warn("用户名: " .. account.username)end
-- 获取共享数据local sharedData = getShareCache("shared_config")
-- 获取单个设备的共享数据最新值local val = getDeviceShareValue("device1", "temperature")if val ~= nil then Logger.warn("设备 device1 温度: " .. val)end
-- 通过设备列表获取各设备的共享数据值local deviceCodes = {"device1", "device2"}local shareValues = getDeviceShareValues(deviceCodes, "temperature")if shareValues then for deviceCode, dataValue in pairs(shareValues) do Logger.warn("设备 " .. deviceCode .. " 温度: " .. dataValue) endend
-- 获取所有设备的共享数据值local allShareValues = getAllDeviceShareValues("temperature")if allShareValues then for deviceCode, dataValue in pairs(allShareValues) do Logger.warn("设备 " .. deviceCode .. " 温度: " .. dataValue) endend按 dataKey 模式批量查询最新值
Section titled “按 dataKey 模式批量查询最新值”以下函数均从本机最新值缓存中扫描,按 dataKey 的前缀、后缀或关键字过滤后返回匹配的点位信息,返回值为 {dataKey: FrontDataDTO} table。
返回值字段说明(每个值为 FrontDataDTO 对象,含以下常用字段):
| 字段 | 类型 | 说明 |
|---|---|---|
DataKey |
string | 数据唯一键 |
DataValue |
string | 最新值 |
DataType |
string | 数据类型 |
DataName |
string | 数据名称 |
DataUnit |
string | 单位 |
CollectionTime |
OffsetDateTime | 采集时间 |
注意:返回
nil表示缓存中无任何匹配项。dataType参数应与枚举值完全匹配(Collection/Customization/Aggregation/Share)。
按 suffix 查询
Section titled “按 suffix 查询”| 函数 | 说明 | 返回值 |
|---|---|---|
getLatestDataValuesBySuffix(dataType, suffix) |
查询指定类型中 dataKey 以 suffix 结尾的最新值 | table | nil |
getAllLatestDataValuesBySuffix(suffix) |
查询所有类型中 dataKey 以 suffix 结尾的最新值 | table | nil |
按 prefix 查询
Section titled “按 prefix 查询”| 函数 | 说明 | 返回值 |
|---|---|---|
getLatestDataValuesByPrefix(dataType, prefix) |
查询指定类型中 dataKey 以 prefix 开头的最新值 | table | nil |
getAllLatestDataValuesByPrefix(prefix) |
查询所有类型中 dataKey 以 prefix 开头的最新值 | table | nil |
按 prefix + suffix 查询
Section titled “按 prefix + suffix 查询”| 函数 | 说明 | 返回值 |
|---|---|---|
getLatestDataValuesByPrefixAndSuffix(dataType, prefix, suffix) |
查询指定类型中 dataKey 同时满足 prefix 和 suffix 的最新值 | table | nil |
getAllLatestDataValuesByPrefixAndSuffix(prefix, suffix) |
查询所有类型中 dataKey 同时满足 prefix 和 suffix 的最新值 | table | nil |
模糊搜索(关键字包含)
Section titled “模糊搜索(关键字包含)”| 函数 | 说明 | 返回值 |
|---|---|---|
getLatestDataValuesByFuzzy(dataType, keyword) |
查询指定类型中 dataKey 包含 keyword 的最新值 | table | nil |
getAllLatestDataValuesByFuzzy(keyword) |
查询所有类型中 dataKey 包含 keyword 的最新值 | table | nil |
local Logger = require("Logger")
-- 查询所有以 "_power" 结尾的采集数据最新值local powerValues = getLatestDataValuesBySuffix("Collection", "_power")if powerValues then for dataKey, dto in pairs(powerValues) do Logger.warn(dataKey .. " = " .. dto.DataValue) endend
-- 查询所有类型中以 "_power" 结尾的最新值(不限数据类型)local allPower = getAllLatestDataValuesBySuffix("_power")
-- 查询以 "meter1." 开头的所有采集数据local meterValues = getLatestDataValuesByPrefix("Collection", "meter1.")if meterValues then for dataKey, dto in pairs(meterValues) do Logger.warnf("%s = %s (%s)", dataKey, dto.DataValue, dto.DataUnit) endend
-- 查询所有类型中以 "meter1." 开头的数据local allMeter = getAllLatestDataValuesByPrefix("meter1.")
-- 查询 dataKey 以 "meter1." 开头且以 "_voltage" 结尾的采集数据local voltages = getLatestDataValuesByPrefixAndSuffix("Collection", "meter1.", "_voltage")
-- 查询所有类型中同时满足 prefix 和 suffix 的数据local allVoltages = getAllLatestDataValuesByPrefixAndSuffix("meter1.", "_voltage")
-- 模糊搜索:查询聚合数据中 dataKey 包含 "temp" 的最新值local tempValues = getLatestDataValuesByFuzzy("Aggregation", "temp")if tempValues then for dataKey, dto in pairs(tempValues) do Logger.warn("温度点位: " .. dataKey .. " = " .. dto.DataValue) endend
-- 模糊搜索:查询所有类型中 dataKey 包含 "temp" 的最新值local allTemp = getAllLatestDataValuesByFuzzy("temp")设备列表函数
Section titled “设备列表函数”| 函数 | 说明 | 返回值 |
|---|---|---|
getDeviceList(ignoreLocal) |
获取设备列表,ignoreLocal=true 时排除本机 | table |
getDeviceCodeList(ignoreLocal) |
获取 deviceCode 列表,ignoreLocal=true 时排除本机 | table |
local Logger = require("Logger")
-- 获取所有设备列表local allDevices = getDeviceList(false)if allDevices then for i, device in ipairs(allDevices) do Logger.warn("设备: " .. device.deviceCode .. " - " .. device.deviceName) endend
-- 获取除本机外的设备列表local otherDevices = getDeviceList(true)if otherDevices then for i, device in ipairs(otherDevices) do Logger.warn("共享设备: " .. device.deviceCode) endend
-- 获取所有设备编码列表(比获取完整设备列表更快)local deviceCodes = getDeviceCodeList(false)if deviceCodes then for i, code in ipairs(deviceCodes) do Logger.warn("设备编码: " .. code) endend
-- 获取除本机外的设备编码列表local otherDeviceCodes = getDeviceCodeList(true)历史数据查询函数
Section titled “历史数据查询函数”| 函数 | 说明 | 返回值 |
|---|---|---|
getHistoryData(dataType, dataKey, startTime?, endTime?, formatMap?) |
获取历史数据 | table |
getShareHistoryData(deviceCode, dataKey, startTime?, endTime?, formatMap?) |
获取指定设备的共享历史数据 | table |
getTimeData(dataKey, time?, interval?) |
获取指定时间数据 | table |
getShareTimeData(deviceCode, dataKey, time?, interval?) |
获取共享指定时间数据 | table |
deleteCustomizationData(dataKey, startTime?, endTime?) |
删除自定义数据 | boolean |
参数说明:
startTime/endTime/time: 支持以下格式- OffsetDateTime 对象(推荐)
- 时间字符串(如 “2024-01-15T10:00:00.000Z”)
- 简写字符串(如 “2024-01-15”,会自动补全)
formatMap: 可选参数,用于自定义返回结果中的字段名(table 类型)dataKey: 自定义数据键字段名(默认: “dataKey”)dataValue: 自定义数据值字段名(默认: “dataValue”)collectionTime: 自定义采集时间字段名(默认: “collectionTime”)
Customization 类型返回字段说明:
getHistoryData / getTimeData 对 Customization 数据返回的时间字段取决于排班类型:
- DailyChange:返回
availableTime(ISO 8601 完整日期时间)和expiredTime - DailyRepeat:返回
availableTime(HH:mm:ss字符串)和expiredTime(HH:mm:ss字符串)
local OffsetDateTime = require("OffsetDateTime")local Logger = require("Logger")
-- 方式1: 使用 OffsetDateTime 对象(推荐)local now = OffsetDateTime.now()local startTime = now:addDays(-7)local endTime = nowlocal data = getHistoryData("Collection", "temperature", startTime, endTime)
-- 方式1扩展: 使用 formatMap 自定义返回字段名local formatMap = { dataKey = "key", dataValue = "value", collectionTime = "time"}local data = getHistoryData("Collection", "temperature", startTime, endTime, formatMap)
-- 方式2: 使用时间字符串local data = getHistoryData("Collection", "temperature", "2024-01-01T00:00:00.000Z", "2024-01-31T23:59:59.000Z")
-- 方式3: 使用简写字符串(自动补全)local data = getHistoryData("Collection", "temperature", "2024-01-01", "2024-01-31")
-- 查询共享历史数据local sharedData = getShareHistoryData("space1", "pressure", startTime, endTime)
-- 查询指定时间点数据local value = getTimeData("temperature", now, "5m")
-- 删除自定义数据local deleted = deleteCustomizationData("data1", startTime, endTime)Logger.warn("删除成功: " .. tostring(deleted))构建辅助函数
Section titled “构建辅助函数”| 函数 | 说明 | 返回值 |
|---|---|---|
buildCommonWriteMap(dataType, dataKey, dataValue, availableDate, expiredDate, changeMod) |
构建通用写入 map | table |
buildGeneralWriteMap(dataType, dataKey, dataValue, changeMod) |
构建通用写入 map(简化版,无时间参数) | table |
buildCustomizationWriteMap(dataKey, dataValue, availableDate, expiredDate) |
构建 DailyChange 分时数据写入 map(隐式 dataType=Customization) | table |
buildDailyRepeatWriteMap(dataKey, dataValue, availableTime, expiredTime) |
构建 DailyRepeat 分时数据写入 map(隐式 dataType=Customization,时间参数为 HH:mm:ss 字符串) |
table |
updateDailyRepeatSchedule(dataKey, scheduleAvailableDate, scheduleExpiredDate) |
更新 DailyRepeat 配置的整体生效区间;两个日期参数均可传 nil,nil 表示无限制(永久有效) |
boolean |
buildAlarmObservationMap(sourceCode, alarmKey, state, alarmType, alarmLevel, alarmContent[, detailKey]) |
构建告警事件观测;state 为 ACTIVE / NORMAL / UNKNOWN | table |
buildCommonAlarmMap(alarmType, alarmContent) |
构建通用告警 map | table |
buildMqttAlarmMap(alarmType, alarmContent, mqttConnectionConfigId, topic, qos) |
构建 MQTT 告警 map | table |
buildSlaveWriteMap(deviceCode, dataType, dataKey, dataValue, availableDate, expiredDate, changeMod) |
构建从机写入 map | table |
告警观测使用稳定的 sourceCode + alarmKey,正常时发送 NORMAL,缺值或离线时发送 UNKNOWN。事件状态与观测状态不同,完整流程见 告警生命周期。旧告警构建函数仍生成独立记录。
采集写入的系数反算由 CommBridge 处理;旧 buildCollectionWriteMap 已移除,使用通用写入构建函数,不重复换算。
参数说明:
dataType:操作的数据类型,可选值:Collection(采集)/Customization(自定义/分时)/Aggregation(聚合)/Share(共享)/Alarm(告警)availableDate/expiredDate:仅Customization(DailyChange 类型)需要,可为 ISO 8601 字符串或 OffsetDateTime 对象,其他类型传nilavailableTime/expiredTime:仅Customization(DailyRepeat 类型)需要,格式为"HH:mm:ss"(如"08:00:00"),不得跨午夜changeMod:布尔值,true表示仅在值发生变化时写入
local OffsetDateTime = require("OffsetDateTime")
-- 写入采集点位local writeCollection = buildCommonWriteMap("Collection", "temperature", 25.5, nil, nil, false)
-- 写入自定义点位(DailyChange:带完整日期时间区间)local writeCustom = buildCommonWriteMap( "Customization", "mode", "1", "2024-01-15T07:00:00+08:00", "2024-01-15T18:00:00+08:00", false)
-- 写入自定义点位(DailyChange:使用专用简写函数)local writeCustom2 = buildCustomizationWriteMap( "mode", "1", "2024-01-15T07:00:00+08:00", "2024-01-15T18:00:00+08:00")
-- 写入自定义点位(DailyRepeat:每日循环时段,格式 HH:mm:ss)local writeDailyRepeat = buildDailyRepeatWriteMap("charge_mode", "1", "08:00:00", "18:00:00")
-- 更新 DailyRepeat 配置的整体生效区间(设定有效期范围)local OffsetDateTime = require("OffsetDateTime")local ok = updateDailyRepeatSchedule("charge_mode", OffsetDateTime.parse("2026-01-01T00:00:00+08:00"), OffsetDateTime.parse("2026-12-31T23:59:59+08:00"))
-- 更新为永久有效(两个日期均传 nil)local ok2 = updateDailyRepeatSchedule("charge_mode", nil, nil)
-- 设定开始时间,不设截止(nil 表示永不过期)local ok3 = updateDailyRepeatSchedule("charge_mode", "2026-01-01", nil)
-- 写入聚合点位(简化版,无时间参数)local writeAgg = buildGeneralWriteMap("Aggregation", "avg_temp", 22.5, false)
-- 构建告警(写入本机告警记录)local alarm = buildCommonAlarmMap("TEMP_HIGH", "温度超过80°C")
-- 构建 MQTT 告警(需绑定 MQTT 连接ID,告警同时上报至 MQTT Broker)local mqttAlarm = buildMqttAlarmMap("TEMP_HIGH", "温度超过80°C", 1, "alarm/upload", 1)
-- 写入从机共享数据local slaveWrite = buildSlaveWriteMap("DeviceB", "Share", "shared_temp", 25.5, nil, nil, false)进制转换函数
Section titled “进制转换函数”| 函数 | 说明 | 返回值 |
|---|---|---|
toFixedLengthBinary(value, length) |
转固定长度二进制 | string | (nil, err) |
toDecimal(binaryStr) |
二进制转十进制 | number | (nil, err) |
-- 十进制转二进制local binary = toFixedLengthBinary(10, 8)Logger.warn(binary) -- "00001010"
-- 二进制转十进制local decimal = toDecimal("00001010")Logger.warn(decimal) -- 10设备监控脚本
Section titled “设备监控脚本”local Logger = require("Logger")local JSON = require("JSON")local OffsetDateTime = require("OffsetDateTime")local Math = require("Math")local Logger = require("Logger")
Logger.info("设备监控脚本启动")
-- 获取设备最新数据local temperature = getLatestDataValue("device1.temperature")local humidity = getLatestDataValue("device1.humidity")
Logger.infof("当前温度: %.1f°C, 湿度: %.1f%%", temperature, humidity)
-- 温度告警判断if temperature > 80 then local alarm = buildCommonAlarmMap("TEMP_HIGH", "温度超过80°C") Logger.error("温度告警: " .. JSON.toJSONString(alarm))end
-- 查询历史数据local now = OffsetDateTime.now()local startTime = now:addHours(-24)local history = getHistoryData( "device1", "temperature", startTime:toString(), now:toString())
Logger.infof("获取到 %d 条历史数据", #history)
-- 计算平均值local sum = 0for i, record in ipairs(history) do sum = sum + record.valueendlocal avg = sum / #historyLogger.infof("24小时平均温度: %.2f°C", Math.round(avg * 100) / 100)数据处理脚本
Section titled “数据处理脚本”local JSON = require("JSON")local Regex = require("Regex")local TableUtils = require("TableUtils")local String = require("String")local Logger = require("Logger")
-- 从缓存获取配置local configJson = getShareCache("device_config")local config = JSON.decode(configJson)
-- 过滤启用的设备local enabledDevices = TableUtils.filter(config.devices, function(device, index) return device.enabled == trueend)
-- 提取设备名称local deviceNames = TableUtils.map(enabledDevices, function(device, index) return device.nameend)
-- 数据清洗local cleanedNames = TableUtils.map(deviceNames, function(name, index) -- 去除空白,转大写 return String.upper(String.trim(name))end)
-- 验证设备编号格式for i, device in ipairs(enabledDevices) do if not Regex.match(device.id, "^DEV\\d{6}$") then Logger.warnf("设备编号格式错误: %s", device.id) endend
-- 输出结果Logger.info("处理完成: " .. JSON.toJSONString(cleanedNames))- 错误处理: 大部分函数返回
(result, error)形式,使用时注意检查错误 - 时间格式: 时间字符串使用 ISO 8601 格式
- 正则表达式: 使用 Go 的正则语法,与 Lua 原生 pattern 不同
- 表遍历: TableUtils 的 map/filter/reduce 先遍历数组部分(1..n),再遍历键值对
- 日志级别: Logger 的输出级别由系统配置决定
- JSON 性能: 运行时采用高性能 JSON 处理,适合大批量序列化场景
判断点位是否有值
Section titled “判断点位是否有值”if isNotNull(${some_key}) then return {}endreturn { buildCommonWriteMap("Collection", "target_key", ${some_key}, nil, nil, false) }- 表达式引擎的整体介绍与聚合点位示例:表达式引擎
- 触发方案中如何组织条件与动作脚本:触发方案
- EXPRESSION 触发方案的写入动作详细手册:EXPRESSION 触发方案脚本手册
- MQTT 发布/订阅脚本详细手册:MQTT 发布/订阅脚本手册