Parsery#

vCLU udostepnia z poziomu Lua cztery moduly do przetwarzania danych: json, xml, datetime i color. Wszystkie zaimplementowane w Go i dostepne jako globalne obiekty.

json#

json.decode(str)#

Dekoduje string JSON do tabeli Lua.

local data = json.decode('{"name":"test","value":42,"active":true}')
log.info(data.name)    -- "test"
log.info(data.value)   -- 42
log.info(data.active)  -- true

-- Tablice
local arr = json.decode('[1, 2, 3]')
log.info(arr[1])  -- 1 (tablice Lua sa 1-indeksowane)

-- Zagniezdzenie
local nested = json.decode('{"user":{"name":"Jan","age":30}}')
log.info(nested.user.name)  -- "Jan"

Obsluga bledow:

local data, err = json.decode("invalid json")
if not data then
    log.error("JSON error: %s", err)
end

json.encode(table, pretty)#

Koduje tabele Lua do stringa JSON.

local str = json.encode({name = "test", value = 42, active = true})
-- '{"active":true,"name":"test","value":42}'

-- Pretty print (z wciecia)
local pretty = json.encode({name = "test", value = 42}, true)
-- {
--   "name": "test",
--   "value": 42
-- }

Automatyczne wykrywanie tablic:

-- Tablica (klucze numeryczne)
json.encode({1, 2, 3})        -- "[1,2,3]"

-- Obiekt (klucze string)
json.encode({a = 1, b = 2})   -- '{"a":1,"b":2}'

Konwersja typow#

JSONLua
nullnil
true/falsetrue/false
123number (integer)
3.14number (float)
"text"string
[1,2,3]table (1-indeksowana)
{"a":1}table (klucze string)

Przyklady#

-- Parsowanie odpowiedzi API
local resp = HttpClient:GET("https://api.example.com/data")
local data = json.decode(resp.body)

-- Wysylanie JSON
local payload = json.encode({
    sensor = "temp1",
    value = 22.5,
    timestamp = os.time()
})
HttpClient:POST("https://api.example.com/data", payload)

-- MQTT z JSON
mqtt:publish("home/status", json.encode({
    lights = _:get("CLU.DOU5048"):get(DOUT.FEATURE_VALUE),
    temperature = _:get("CLU.ANA1"):get(0)
}))

xml#

xml.decode(str)#

Dekoduje string XML do zagniezdzonej tabeli Lua.

local data = xml.decode('<root><name>test</name><value>42</value></root>')
log.info(data.root.name)   -- "test"
log.info(data.root.value)  -- 42 (automatyczna konwersja typow)

Struktura wynikowa#

Prosty element:

xml.decode('<item>hello</item>')
-- {item = "hello"}

Element z atrybutami:

xml.decode('<item id="42" active="true">content</item>')
-- {item = {_text = "content", _attr = {id = 42, active = true}}}

Elementy zagniezdzone:

xml.decode('<root><a>1</a><b>2</b></root>')
-- {root = {a = 1, b = 2}}

Wiele elementow o tej samej nazwie (automatyczna tablica):

xml.decode('<list><item>first</item><item>second</item></list>')
-- {list = {item = {"first", "second"}}}

-- Dostep:
data.list.item[1]  -- "first"
data.list.item[2]  -- "second"

Element z dziecmi i atrybutami:

xml.decode('<root version="1"><name>test</name></root>')
-- {root = {name = "test", _attr = {version = 1}}}

Automatyczna konwersja typow#

Wartosci tekstowe sa automatycznie konwertowane:

XMLLua
"true"true
"false"false
"42"42 (integer)
"3.14"3.14 (float)
"text""text" (string)

Przyklady#

-- Parsowanie danych pogodowych (XML API)
local resp = HttpClient:GET("https://api.weather.com/current.xml")
local weather = xml.decode(resp.body)
local temp = weather.current.temperature
log.info("Temperatura: %s", tostring(temp))

-- Parsowanie konfiguracji
local config = xml.decode([[
<config>
    <mqtt enabled="true">
        <host>192.168.1.10</host>
        <port>1883</port>
    </mqtt>
    <thresholds>
        <min>18</min>
        <max>25</max>
    </thresholds>
</config>
]])

if config.config.mqtt._attr.enabled then
    local host = config.config.mqtt.host
    local port = config.config.mqtt.port
    log.info("MQTT: %s:%d", host, port)
end

datetime#

Modul datetime oferuje zaawansowane parsowanie, formatowanie i operacje na datach - zaimplementowany w Go, z wieksza dokladnoscia niz standardowe os.date().

datetime.now()#

Zwraca biezacy czas jako tabele datetime.

local now = datetime.now()
log.info("%d-%02d-%02d %02d:%02d:%02d",
    now.year, now.month, now.day,
    now.hour, now.minute, now.second)

-- Gotowe sformatowane stringi
log.info(now.iso)   -- "2026-02-22T14:30:15+01:00"
log.info(now.date)  -- "2026-02-22"
log.info(now.time)  -- "14:30:15"

Tabela datetime#

Kazda funkcja datetime zwraca tabele z polami:

PoleTypOpis
yearnumberRok
monthnumberMiesiac (1-12)
daynumberDzien (1-31)
hournumberGodzina (0-23)
minutenumberMinuta (0-59)
secondnumberSekunda (0-59)
weekdaynumberDzien tygodnia ISO (1=poniedzialek, 7=niedziela)
yeardaynumberDzien roku (1-366)
timestampnumberUnix timestamp (sekundy)
timestampMsnumberUnix timestamp (milisekundy)
tzOffsetnumberOffset strefy czasowej (sekundy)
isostringFormat RFC3339
datestringFormat YYYY-MM-DD
timestringFormat HH:MM:SS
monthNamestringNazwa miesiaca (angielska)
weekdayNamestringNazwa dnia tygodnia (angielska)

datetime.parse(str)#

Parsuje string daty - automatycznie wykrywa format. Obsluguje 25+ formatow.

-- ISO 8601
local dt = datetime.parse("2026-02-22T14:30:00+01:00")

-- Data i czas
local dt = datetime.parse("2026-02-22 14:30:00")

-- Tylko data
local dt = datetime.parse("2026-02-22")

-- Format europejski
local dt = datetime.parse("22.02.2026 14:30:00")

-- Format US
local dt = datetime.parse("02/22/2026 14:30:00")

-- Unix timestamp (sekundy)
local dt = datetime.parse("1740268800")

-- Unix timestamp (milisekundy - auto-detekcja)
local dt = datetime.parse("1740268800000")

-- RFC formaty
local dt = datetime.parse("Sat, 22 Feb 2026 14:30:00 CET")

Obsluga bledow:

local dt, err = datetime.parse("not a date")
if not dt then
    log.error("Parse error: %s", err)
end

datetime.fromTimestamp(ts)#

Tworzy datetime z Unix timestamp.

local dt = datetime.fromTimestamp(1740268800)
log.info(dt.iso)  -- "2026-02-22T..."

-- Milisekundy (auto-detekcja gdy > 1e12)
local dt = datetime.fromTimestamp(1740268800000)

datetime.format(dt, pattern)#

Formatuje tabele datetime do stringa. Uzywa Go-style patternow (nie %Y-%m-%d).

local now = datetime.now()

datetime.format(now, "2006-01-02")            -- "2026-02-22"
datetime.format(now, "15:04:05")              -- "14:30:15"
datetime.format(now, "2006-01-02 15:04:05")   -- "2026-02-22 14:30:15"
datetime.format(now, "Mon Jan 2 2006")        -- "Sat Feb 22 2026"
datetime.format(now, "02/01/2006")            -- "22/02/2026"
Go uzywa referencyjnej daty `Mon Jan 2 15:04:05 MST 2006` jako wzorca formatu. Np. `2006` = rok, `01` = miesiac, `02` = dzien, `15` = godzina, `04` = minuta, `05` = sekunda.

datetime.diff(dt1, dt2)#

Oblicza roznice miedzy dwoma datami.

local start = datetime.parse("2026-02-01")
local end_date = datetime.parse("2026-02-22")
local diff = datetime.diff(start, end_date)

log.info("Dni: %d", diff.days)              -- 21
log.info("Godziny: %d", diff.totalHours)    -- 504
log.info("Minuty: %d", diff.totalMinutes)   -- 30240
log.info("Sekundy: %d", diff.totalSeconds)  -- 1814400

Zwracane pola:

PoleOpis
daysPelne dni
hoursPozostale godziny (po odjieciu dni)
minutesPozostale minuty
secondsPozostale sekundy
totalSecondsCalkowita roznica w sekundach
totalMinutesCalkowita w minutach
totalHoursCalkowita w godzinach
totalDaysCalkowita w dniach

datetime.add(dt, duration)#

Dodaje czas do daty. Zwraca nowa tabele datetime.

local now = datetime.now()

-- Dodaj 7 dni
local nextWeek = datetime.add(now, {days = 7})

-- Dodaj 2 godziny i 30 minut
local later = datetime.add(now, {hours = 2, minutes = 30})

-- Dodaj 1 miesiac
local nextMonth = datetime.add(now, {months = 1})

-- Odejmij (ujemne wartosci)
local yesterday = datetime.add(now, {days = -1})
local lastHour = datetime.add(now, {hours = -1})

Dostepne pola duration: years, months, days, hours, minutes, seconds.

Przyklady datetime#

-- Ile dni do konca roku?
local now = datetime.now()
local endOfYear = datetime.parse(now.year .. "-12-31")
local diff = datetime.diff(now, endOfYear)
log.info("Do konca roku: %d dni", diff.days)

-- Parsowanie timestampu z MQTT
mqtt:subscribe("sensors/temp", function(topic, payload)
    local data = json.decode(payload)
    local dt = datetime.fromTimestamp(data.timestamp)
    log.info("Pomiar z %s: %.1f°C", dt.time, data.value)
end)

-- Formatowanie dla logów
local now = datetime.now()
log.info("[%s %s] System started", now.weekdayName, now.time)
-- "[Saturday 14:30:15] System started"

color#

Modul color do konwersji i manipulacji kolorami - przydatny przy sterowaniu oswietleniem LED RGB.

Konwersje#

-- HEX -> RGB
local rgb = color.hexToRGB("#FF5500")
-- {r = 255, g = 85, b = 0}

-- RGB -> HEX
local hex = color.rgbToHex(255, 85, 0)   -- "#FF5500"
local hex = color.rgbToHex({r = 255, g = 85, b = 0})  -- tez dziala

-- HSV <-> RGB (h=0-360, s=0-100, v=0-100)
local rgb = color.hsvToRGB(20, 100, 100)  -- {r = 255, g = 85, b = 0}
local hsv = color.rgbToHSV(255, 85, 0)    -- {h = 20, s = 100, v = 100}

-- HSL <-> RGB (h=0-360, s=0-100, l=0-100)
local rgb = color.hslToRGB(20, 100, 50)
local hsl = color.rgbToHSL(255, 85, 0)

Temperatura barwowa#

-- Kelvin -> RGB
local warm = color.kelvinToRGB(2700)    -- cieple biale {r=255, g=169, b=87}
local cool = color.kelvinToRGB(6500)    -- zimne biale  {r=255, g=254, b=250}

-- Typowe wartosci:
-- 2000K = swieczkowe
-- 2700K = zarowka
-- 4000K = neutralne
-- 5500K = dzienne
-- 6500K = pochmurne niebo

Nazwy kolorow#

-- Nazwa -> RGB
local rgb = color.fromName("orange")
-- {r = 255, g = 165, b = 0, name = "orange"}

-- RGB -> najblizszy kolor
local name = color.toName(255, 160, 0)  -- "orange"

-- Lista dostepnych nazw
local names = color.getNames()
-- {"black", "white", "red", "green", "blue", "orange", "warmwhite", ...}

Dostepne nazwy: black, white, red, green, blue, yellow, cyan, magenta, orange, pink, purple, brown, gray, silver, gold, navy, teal, coral, salmon, crimson, indigo, turquoise, skyblue, lavender, warmwhite, coolwhite, daylight i wiecej.

Manipulacja#

-- Jasnosc (0-100%)
local dimmed = color.setBrightness("#FF5500", 50)
-- {r = 127, g = 42, b = 0, hex = "#7F2A00"}

-- Mieszanie dwoch kolorow (ratio 0-1)
local mixed = color.blend("#FF0000", "#0000FF", 0.5)
-- {r = 127, g = 0, b = 127, hex = "#7F007F"}

-- Kolor komplementarny (przesuniety o 180°)
local comp = color.complement("#FF5500")
-- {r = 0, g = 170, b = 255, hex = "#00AAFF"}

-- Inwersja
local inv = color.invert("#FF5500")
-- {r = 0, g = 170, b = 255, hex = "#00AAFF"}

Auto-detekcja formatu#

-- Parsuje dowolny format koloru
color.parse("#FF5500")        -- {r=255, g=85, b=0, hex="#FF5500", format="hex"}
color.parse("rgb(255,85,0)")  -- {r=255, g=85, b=0, hex="#FF5500", format="rgb"}
color.parse("orange")         -- {r=255, g=165, b=0, hex="#FFA500", format="name"}

Przyklady z LED#

-- Ustaw kolor LED na podstawie temperatury
local function tempToColor(temp)
    if temp < 18 then
        return color.fromName("blue")
    elseif temp < 22 then
        return color.fromName("green")
    elseif temp < 26 then
        return color.fromName("orange")
    else
        return color.fromName("red")
    end
end

every(60000, function()
    local temp = _:get("CLU.ANA1"):get(0)
    local c = tempToColor(temp)
    _:get("CLU.LED1"):set(0, c.r)
    _:get("CLU.LED1"):set(1, c.g)
    _:get("CLU.LED1"):set(2, c.b)
end)

-- Animacja sunrise (2700K -> 6500K w 30 minut)
local step = 0
local steps = 180  -- co 10 sekund przez 30 minut

every(10000, function()
    if step >= steps then return end
    step = step + 1

    local kelvin = 2700 + (6500 - 2700) * (step / steps)
    local c = color.kelvinToRGB(kelvin)
    local brightness = math.floor(step / steps * 100)

    local dimmed = color.setBrightness(c, brightness)
    _:get("CLU.LED1"):set(0, dimmed.r)
    _:get("CLU.LED1"):set(1, dimmed.g)
    _:get("CLU.LED1"):set(2, dimmed.b)
end)

Podsumowanie#

ModulFunkcjaOpis
jsondecode(str)JSON string -> tabela Lua
jsonencode(table, pretty)Tabela Lua -> JSON string
xmldecode(str)XML string -> tabela Lua
datetimenow()Biezacy czas jako tabela
datetimeparse(str)Parsuj date (auto-detekcja formatu)
datetimefromTimestamp(ts)Unix timestamp -> tabela
datetimeformat(dt, pattern)Formatuj date (Go patterns)
datetimediff(dt1, dt2)Roznica dwoch dat
datetimeadd(dt, duration)Dodaj czas do daty
colorhexToRGB(hex)HEX -> {r, g, b}
colorrgbToHex(r, g, b)RGB -> “#RRGGBB”
colorhsvToRGB(h, s, v)HSV -> RGB
colorrgbToHSV(r, g, b)RGB -> HSV
colorhslToRGB(h, s, l)HSL -> RGB
colorrgbToHSL(r, g, b)RGB -> HSL
colorkelvinToRGB(K)Temperatura -> RGB
colorfromName(name)Nazwa -> RGB
colortoName(r, g, b)RGB -> najblizszy kolor
colorsetBrightness(c, %)Zmien jasnosc
colorblend(c1, c2, ratio)Mieszaj kolory
colorcomplement(c)Kolor komplementarny
colorinvert(c)Inwersja koloru
colorparse(str)Auto-detekcja formatu