| name | lua-basics |
| description | Lua language fundamentals for developers new to Lua: types, local vs global variables, conditionals (falsy values: only nil and false), functions (named, anonymous, multiple returns, variadic), tables as arrays and dictionaries (1-indexed!), iterating with ipairs/pairs, strings (pattern matching, format, split), closures, error handling (pcall/xpcall), OOP with the colon syntax, the Fibaro class system, and common gotchas (table reference semantics, # operator limitations, tostring/tonumber). USE FOR: help with Lua syntax, understanding why code behaves unexpectedly, table/string/function patterns, OOP in Lua. |
Lua Basics for QuickApp Developers
A practical Lua reference for developers who are new to Lua but have experience in other programming languages. Focused on patterns you'll actually use in Fibaro QuickApps.
Types
Lua has 8 types: nil, boolean, number, string, table, function, userdata, thread.
print(type(nil))
print(type(true))
print(type(42))
print(type(3.14))
print(type("hello"))
print(type({}))
print(type(print))
Variables: local vs global
Always prefer local. Global variables pollute _G and can collide across files.
x = 10
local y = 20
In a QuickApp, instance state goes on self:
function QuickApp:onInit()
self.myTimer = nil
self.count = 0
end
Conditionals
if x > 10 then
print("big")
elseif x > 5 then
print("medium")
else
print("small")
end
Falsy values: only nil and false. Zero and empty string are truthy!
if 0 then print("truthy") end
if "" then print("truthy") end
if nil then print("truthy") end
if false then print("truthy") end
Ternary idiom:
local label = active and "ON" or "OFF"
Functions
function add(a, b)
return a + b
end
local add = function(a, b)
return a + b
end
local function minmax(a, b)
return math.min(a,b), math.max(a,b)
end
local lo, hi = minmax(10, 3)
local function sum(...)
local total = 0
for _, v in ipairs({...}) do total = total + v end
return total
end
print(sum(1,2,3,4))
Functions must be defined before they are called — Lua runs top to bottom:
local isEven, isOdd
isEven = function(n) return n == 0 or isOdd(n - 1) end
isOdd = function(n) return n ~= 0 and isEven(n - 1) end
Tables
Tables are Lua's only data structure — they act as both arrays and dictionaries.
As array (1-indexed!)
local fruits = {"apple", "banana", "cherry"}
print(fruits[1])
print(#fruits)
table.insert(fruits, "date")
table.insert(fruits, 2, "avocado")
table.remove(fruits, 1)
table.sort(fruits)
As dictionary
local person = { name = "Alice", age = 30 }
person.city = "London"
person["country"] = "UK"
print(person.name)
person.age = nil
Iterating
Ordered integer keys:
for i, v in ipairs(fruits) do print(i, v) end
All keys (unordered):
for key, value in pairs(person) do print(key, "=", value) end
Numeric for:
for i = 1, 10 do print(i) end
for i = 10, 1, -1 do print(i) end
Strings
local s = "Hello, World!"
print(#s)
print(s:upper())
print(s:sub(1, 5))
print(s:find("World"))
local msg = "Temperature: " .. tostring(temp) .. "°C"
local msg = string.format("Device %d: %.1f°C", id, temp)
local year, month, day = ("2024-03-15"):match("(%d+)-(%d+)-(%d+)")
local parts = ("a,b,c"):split(",")
Closures
A function that captures variables from its enclosing scope:
function QuickApp:onInit()
local count = 0
setInterval(function()
count = count + 1
self:debug("Tick", count)
end, 1000)
end
Error Handling
local ok, result = pcall(function()
return json.decode(rawString)
end)
if ok then
print(result.key)
else
self:error("Decode failed:", result)
end
assert(value ~= nil, "value is required")
error("something went wrong")
error({code = 404, msg = "not found"})
Object-Oriented Programming
The colon syntax
obj:method(arg) is syntax sugar for obj.method(obj, arg) — passes the object as self.
self:debug("hello")
QuickApp.debug(self, "hello")
Defining methods on QuickApp
function QuickApp:doSomething(x)
self:debug("doing", x)
return x * 2
end
Creating your own classes (Fibaro class system)
class 'MyHelper'
function MyHelper:__init(name)
self.name = name
self.data = {}
end
function MyHelper:add(item)
table.insert(self.data, item)
end
function MyHelper:count()
return #self.data
end
local h = MyHelper("test")
h:add("item1")
print(h:count())
Inheritance
class 'MySensor'(QuickAppChild)
function MySensor:__init(device)
QuickAppChild.__init(self, device)
end
function MySensor:onInit()
self:debug("MySensor", self.id, "started")
end
Common Gotchas
# is unreliable with holes or non-integer keys
local t = {1, 2, nil, 4}
local t = {a=1, b=2}
Tables are references, not copies
local a = {1, 2, 3}
local b = a
b[1] = 99
print(a[1])
local function copy(t)
local c = {}
for k, v in pairs(t) do c[k] = v end
return c
end
Always use tostring / tonumber for conversions
local s = tostring(42)
local n = tonumber("3.14")
local n = tonumber("abc")
if n then ... end
Build strings efficiently with table.concat
local s = ""
for i = 1, 100 do s = s .. tostring(i) .. "," end
local parts = {}
for i = 1, 100 do parts[i] = tostring(i) end
local s = table.concat(parts, ",")
Useful Standard Library
math.floor(3.7)
math.ceil(3.2)
math.abs(-5)
math.max(1,5,3)
math.random(1,10)
string.format("%.2f", 3.14159)
string.format("%05d", 42)
string.rep("ab", 3)
table.concat({"a","b","c"}, "-")
os.time()
os.date("%Y-%m-%d %H:%M:%S")
os.date("*t")