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) | 陣列形式的 Lua 表(下標從 1 開始連續),元素為 buildCommonWriteMap(...) 等函式回傳的 map;空表 {} 視為「無寫入項」 |
| 觸發動作(混合寫入類觸發方案) | 每個 dataKey 單獨繫結的動作 |
單個值(字串/數字/布林),作為該 dataKey 的寫入內容;不要回傳 buildCommonWriteMap 陣列 |
| 後處理動作 | 觸發動作執行完成後的收尾指令碼 | 與運算式類觸發動作相同:由寫入描述組成的陣列形式 Lua 表;可透過固定變數 ${trigger_result}(布林)、${trigger_write_result}(JSON 字串,需 jsonToMap 解析)判斷主流程執行結果 |
| 聚合點位運算式 | 聚合資料計算運算式 | 單個值(數字/字串等),作為該聚合點位的最新值 |
| MQTT 釋出內容(publishContent) | MQTT 釋出設定 | Lua 表,將被序列化為 JSON 作為釋出載荷 |
| MQTT 訂閱動作(actionContent) | MQTT 訂閱設定 | 與運算式類觸發動作相同:由寫入描述組成的陣列形式 Lua 表 |
| 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 釋出/訂閱指令碼手冊