Lua Transforms
Lua transforms let you write custom logic to process serial data. SerialFlow uses Lua 5.4 via the Luerl interpreter.
Basic Transform
Every Lua transform needs a transform function that receives data and returns the result:
function transform(data)
-- Your processing logic here
return data
end
Return nil to drop the message (it won’t continue down the pipeline).
String Manipulation
Lua has powerful string handling built in:
function transform(data)
-- Convert to uppercase
local upper = string.upper(data)
-- Remove leading/trailing whitespace
local trimmed = data:match("^%s*(.-)%s*$")
-- Extract a pattern
local value = data:match("TEMP:(%d+%.?%d*)")
return trimmed
end
Parsing Sensor Data
A common use case is parsing structured sensor output:
-- Parse "SENSOR:temp=23.5,humidity=45,pressure=1013"
function transform(data)
local readings = {}
-- Extract sensor name
local sensor = data:match("^(%w+):")
if not sensor then return nil end
-- Parse key=value pairs
for key, value in data:gmatch("(%w+)=([%d%.]+)") do
readings[key] = tonumber(value)
end
-- Format as JSON
return string.format(
'{"sensor":"%s","temp":%.1f,"humidity":%d}',
sensor,
readings.temp or 0,
readings.humidity or 0
)
end
Working with State
You can maintain state between messages using global variables:
-- Count messages and add sequence number
local counter = 0
function transform(data)
counter = counter + 1
return string.format("[%d] %s", counter, data)
end
Note: State is reset when you edit the script or reload the page.
Built-in Functions
SerialFlow provides additional functions in the sf namespace:
function transform(data)
-- Get current timestamp
local ts = sf.timestamp()
-- Log to console (for debugging)
sf.log("Processing: " .. data)
-- Access metadata
local source = sf.metadata("source")
return data
end
Error Handling
If your script throws an error, the message is dropped and an error is logged:
function transform(data)
-- This will fail if data isn't a valid number
local num = tonumber(data)
if not num then
sf.log("Invalid number: " .. data)
return nil -- Drop the message gracefully
end
return tostring(num * 2)
end
Performance Tips
- Avoid complex regex - Use Lua patterns instead
- Minimize global state - Keep scripts simple
-
Return early - Drop invalid messages with
return nil - Pre-compile patterns - Store patterns in variables outside the function
-- Good: pattern compiled once
local TEMP_PATTERN = "TEMP:(%d+%.?%d*)"
function transform(data)
local temp = data:match(TEMP_PATTERN)
if temp then return temp end
return nil
end
Next Steps
- Recording & Replay - Debug transforms with recorded data
- Node Types Reference - All available nodes
-
Lua API Reference - Complete
sfnamespace docs