Data i czas#

Lua w vCLU udostepnia standardowe funkcje os.time(), os.date() i os.clock() do pracy z czasem. Czas pochodzi z systemu operacyjnego hosta (Raspberry Pi, serwer).

os.time() - aktualny czas#

Zwraca aktualny czas jako Unix timestamp (liczba sekund od 1 stycznia 1970 UTC).

local now = os.time()
log.info("Timestamp: %d", now)
-- Timestamp: 1740268800

Mozna tez uzyskac timestamp dla konkretnej daty:

-- Timestamp dla 1 marca 2026, 14:30:00
local ts = os.time({year = 2026, month = 3, day = 1, hour = 14, min = 30, sec = 0})

os.date() - formatowanie daty#

Formatuje timestamp do czytelnej postaci. Bez argumentu formatuje aktualny czas.

Tabela daty#

local t = os.date("*t")
-- t = {
--   year = 2026, month = 2, day = 22,
--   hour = 14, min = 30, sec = 15,
--   wday = 1,   -- dzien tygodnia (1=niedziela, 2=poniedzialek, ..., 7=sobota)
--   yday = 53,  -- dzien roku
--   isdst = false
-- }

log.info("Godzina: %d:%02d", t.hour, t.min)
log.info("Dzien tygodnia: %d", t.wday)

Formatowanie stringow#

-- Pelna data i czas
log.info(os.date("%Y-%m-%d %H:%M:%S"))
-- "2026-02-22 14:30:15"

-- Tylko godzina
log.info(os.date("%H:%M"))
-- "14:30"

-- Tylko data
log.info(os.date("%Y-%m-%d"))
-- "2026-02-22"

-- Formatowanie historycznego timestampu
local ts = os.time() - 3600  -- godzine temu
log.info("Godzine temu: %s", os.date("%H:%M:%S", ts))

Kody formatu#

KodOpisPrzyklad
%YRok (4 cyfry)2026
%mMiesiac (01-12)02
%dDzien miesiaca (01-31)22
%HGodzina 24h (00-23)14
%MMinuta (00-59)30
%SSekunda (00-59)15
%ANazwa dnia tygodniaSunday
%aSkrot dniaSun
%BNazwa miesiacaFebruary
%bSkrot miesiacaFeb
%wDzien tygodnia (0=niedziela)0
%jDzien roku (001-366)053
%XCzas lokalny14:30:15
%xData lokalna02/22/26
%%Literalny %%

Czas UTC#

Prefix ! daje czas UTC zamiast lokalnego:

local utc = os.date("!*t")
local local_time = os.date("*t")

log.info("UTC: %s", os.date("!%H:%M:%S"))
log.info("Lokalny: %s", os.date("%H:%M:%S"))

os.clock() - czas CPU#

Zwraca czas CPU procesu w sekundach (z dokladnoscia do milisekund). Przydatny do mierzenia czasu wykonania.

local start = os.clock()
-- ... jakas operacja ...
local elapsed = os.clock() - start
log.info("Czas wykonania: %.3f ms", elapsed * 1000)
`os.clock()` mierzy czas CPU, nie czas scienny. Do mierzenia odstepow czasu w sekundach uzyj `os.time()`. Do precyzyjnych pomiarow w milisekundach uzyj `os.clock() * 1000`.

os.difftime(t2, t1) - roznica czasu#

Zwraca roznice miedzy dwoma timestampami w sekundach.

local start = os.time()
-- ... po jakims czasie ...
local elapsed = os.difftime(os.time(), start)
log.info("Minelo %d sekund", elapsed)

Przyklady#

Akcje o okreslonej godzinie#

-- Sprawdzaj co minute czy jest pora na akcje
every(60000, function()
    local t = os.date("*t")

    -- Wlacz swiatla o 18:00
    if t.hour == 18 and t.min == 0 then
        runScene("wieczor")
    end

    -- Wylacz swiatla o 23:00
    if t.hour == 23 and t.min == 0 then
        runScene("wylacz_wszystko")
    end
end)

Harmonogram dzienny#

local schedule = {
    {hour = 7, min = 0, scene = "poranek"},
    {hour = 18, min = 0, scene = "wieczor"},
    {hour = 22, min = 30, scene = "noc"},
}

every(60000, function()
    local t = os.date("*t")
    for _, entry in ipairs(schedule) do
        if t.hour == entry.hour and t.min == entry.min then
            runScene(entry.scene)
            log.info("Harmonogram: %s o %02d:%02d", entry.scene, t.hour, t.min)
        end
    end
end)

Akcje tylko w dni robocze#

local function isWeekday()
    local wday = os.date("*t").wday
    -- 1=niedziela, 7=sobota
    return wday >= 2 and wday <= 6
end

every(60000, function()
    local t = os.date("*t")

    -- Pobudka o 6:30 tylko w dni robocze
    if isWeekday() and t.hour == 6 and t.min == 30 then
        runScene("pobudka")
    end
end)

Tryb nocny (zakres godzin)#

local function isNightTime()
    local hour = os.date("*t").hour
    -- Noc = 22:00 - 06:00
    return hour >= 22 or hour < 6
end

-- Czujnik ruchu - inne zachowanie w nocy
_:get("CLU.DIN1"):add_event(DIN.EVENT_ON_CLICK, function()
    if isNightTime() then
        -- Noc: delikatne swiatlo
        _:get("CLU.DIMM1"):set(0, 20)
    else
        -- Dzien: pelna jasnosc
        _:get("CLU.DIMM1"):set(0, 100)
    end
end)

Logowanie z timestamp#

local function logWithTime(msg, ...)
    local time = os.date("%H:%M:%S")
    local formatted = string.format(msg, ...)
    log.info("[%s] %s", time, formatted)
end

logWithTime("Temperatura: %.1f°C", 22.5)
-- [14:30:15] Temperatura: 22.5°C

Obliczanie czasu do zdarzenia#

-- Ile sekund do polnocy?
local function secondsToMidnight()
    local t = os.date("*t")
    local midnight = os.time({
        year = t.year, month = t.month, day = t.day + 1,
        hour = 0, min = 0, sec = 0
    })
    return os.difftime(midnight, os.time())
end

log.info("Do polnocy: %d minut", secondsToMidnight() / 60)

Cykliczny raport#

-- Raport co godzine o pelnej godzinie
every(60000, function()
    local t = os.date("*t")
    if t.min == 0 then
        local report = string.format(
            "Raport %02d:00 - Relay1: %d, Temp: %.1f",
            t.hour,
            _:get("CLU.DOU5048"):get(DOUT.FEATURE_VALUE),
            _:get("CLU.ANA1"):get(0)
        )
        log.info(report)

        -- Wyslij przez HTTP
        HttpClient:asyncPOST("https://hooks.example.com/report",
            JSON.encode({message = report, time = os.time()}),
            function() end
        )
    end
end)

Przechowywanie timestampow w KV#

-- Zapisz czas ostatniej aktywnosci
_:get("CLU.DIN1"):add_event(DIN.EVENT_ON_CLICK, function()
    kv:set("last_motion", os.time())
    kv:set("last_motion_formatted", os.date("%Y-%m-%d %H:%M:%S"))
end)

-- Sprawdz ile minelo od ostatniego ruchu
local function minutesSinceLastMotion()
    local last = kv:get("last_motion")
    if not last then return 999999 end
    return os.difftime(os.time(), last) / 60
end

-- Wylacz swiatla jezeli brak ruchu > 30 minut
every(60000, function()
    if minutesSinceLastMotion() > 30 then
        runScene("wylacz_swiatla")
    end
end)

Sunrise/sunset (przyblizony)#

-- Uproszczony kalkulator wschodu/zachodu slonca
-- Dla dokladnych wartosci uzyj zewnetrznego API
local function estimateSunset()
    local t = os.date("*t")
    local dayOfYear = t.yday

    -- Przyblizenie dla Warszawy (52°N)
    -- Lato ~21:00, zima ~15:30
    local baseHour = 16
    local amplitude = 2.5
    local offset = math.sin((dayOfYear - 80) / 365 * 2 * math.pi)

    return baseHour + amplitude * offset
end

every(60000, function()
    local t = os.date("*t")
    local sunsetHour = estimateSunset()
    local currentHour = t.hour + t.min / 60

    if currentHour >= sunsetHour and currentHour < sunsetHour + 0.02 then
        runScene("wieczor")
        log.info("Zachod slonca - uruchamiam scene wieczorna")
    end
end)

Plugin Time Sync#

Funkcje os.time() / os.date() zwracaja czas systemowy maszyny. Na Raspberry Pi bez RTC (zegar czasu rzeczywistego) czas po restarcie moze byc niepoprawny do momentu synchronizacji NTP. Plugin Time Sync rozwiazuje ten problem - synchronizuje czas z internetowego serwera (WorldTimeAPI) i udostepnia wygodne API do automatyzacji.

Instalacja#

Plugin @vclu/time-sync dostepny w repozytorium vCLU. Instalacja przez panel Plugins w interfejsie webowym.

Konfiguracja#

ParametrTypDomyslnieOpis
timezonestringEurope/WarsawStrefa czasowa IANA
intervalnumber3600Interwal synchronizacji w sekundach (0 = manualny)
autoSyncbooleantrueAutomatyczna synchronizacja przy starcie

Tryby pracy:

autoSyncintervalZachowanie
true3600Sync przy starcie + co godzine (domyslne)
false3600Bez sync przy starcie, potem co godzine
true0Tylko sync przy starcie
false0Tylko manualny sync, fallback na os.time()

API#

local time = Plugin.get("@vclu/time-sync")

-- Aktualny czas (synchronizowany z serwerem)
time:getTimestamp()        -- Unix timestamp (korygowany o drift)
time:getHour()             -- 0-23
time:getMinute()           -- 0-59
time:getSecond()           -- 0-59
time:getFormatted()        -- "15:30:45"
time:getFormattedDate()    -- "2025-12-30"
time:getFormatted("%H:%M") -- "15:30" (custom format)

-- Informacje o strefie czasowej
time:getTimezone()         -- "Europe/Warsaw"
time:getUtcOffset()        -- "+01:00"
time:isDst()               -- true/false (czas letni)
time:getDayOfWeek()        -- 0=niedziela, 6=sobota
time:getWeekNumber()       -- numer tygodnia w roku

-- Wygodne helpery do automatyzacji
time:isBetween(8, 0, 22, 0)   -- czy miedzy 8:00 a 22:00
time:isBetween(22, 0, 6, 0)   -- dziala tez przez polnoc
time:isWeekday()               -- poniedzialek-piatek
time:isWeekend()               -- sobota/niedziela

-- Kontrola synchronizacji
time:sync()                        -- wymus synchronizacje
time:setTimezone("Europe/London")  -- zmien strefe
time:getDrift()                    -- roznica serwer vs lokalny (sekundy)
time:isReady()                     -- czy czas jest zsynchronizowany
time:getLastSync()                 -- timestamp ostatniej sync
time:getData()                     -- wszystkie dane jako tabela

Zdarzenia#

-- Czas zsynchronizowany
plugin:on("time:synced", function(data)
    log.info("Czas: %s, drift: %+ds", data.datetime, data.drift)
end)

-- Zmiana godziny - idealne do automatyzacji
plugin:on("time:hourChanged", function(data)
    log.info("Nowa godzina: %d", data.hour)

    if data.hour == 18 then
        runScene("wieczor")
    end
end)

-- Blad synchronizacji
plugin:on("time:error", function(data)
    log.warn("Sync error: %s", data.error)
end)

Przyklady z pluginem#

Automatyzacja oparta na godzinie#

-- Uzyj zdarzenia hourChanged zamiast pollowania co minute
plugin:on("time:hourChanged", function(data)
    local time = Plugin.get("@vclu/time-sync")

    -- Wlacz swiatla o 18:00 w dni robocze
    if data.hour == 18 and time:isWeekday() then
        runScene("wieczor")
    end

    -- Wylacz wszystko o 23:00
    if data.hour == 23 then
        runScene("wylacz_wszystko")
    end
end)

Czujnik ruchu z trybem nocnym#

local time = Plugin.get("@vclu/time-sync")

_:get("CLU.DIN1"):add_event(DIN.EVENT_ON_CLICK, function()
    if time:isBetween(22, 0, 6, 0) then
        -- Noc: delikatne swiatlo
        _:get("CLU.DIMM1"):set(0, 20)
    elseif time:isBetween(6, 0, 8, 0) then
        -- Poranek: srednia jasnosc
        _:get("CLU.DIMM1"):set(0, 60)
    else
        -- Dzien: pelna jasnosc
        _:get("CLU.DIMM1"):set(0, 100)
    end
end)

Tryb pracy biurowej#

local time = Plugin.get("@vclu/time-sync")

-- Sprawdz czy godziny pracy
local function isOfficeHours()
    return time:isWeekday() and time:isBetween(8, 0, 17, 0)
end

_:get("CLU.DIN1"):add_event(DIN.EVENT_ON_CLICK, function()
    if isOfficeHours() then
        runScene("biuro_on")
    else
        runScene("po_godzinach")
    end
end)

os.time() vs Plugin Time Sync#

os.time()Plugin Time Sync
ZrodloZegar systemowyWorldTimeAPI (internet)
Strefa czasowaStrefa systemuKonfigurowalna (IANA)
Po restarcie bez RTCMoze byc blednySynchronizuje sie automatycznie
Czas letni (DST)os.date("*t").isdsttime:isDst()
HelperyBrak - trzeba pisac samemuisBetween(), isWeekday(), isWeekend()
ZdarzeniaBraktime:synced, time:hourChanged
Drift detectionBraktime:getDrift()
Dla prostych skryptow `os.time()` / `os.date()` sa wystarczajace. Plugin Time Sync jest zalecany gdy: potrzebujesz pewnosci co do strefy czasowej, urzadzenie nie ma RTC (np. Raspberry Pi), chcesz korzystac z gotowych helperow jak `isBetween()`, lub potrzebujesz zdarzen `hourChanged`.

Podsumowanie#

FunkcjaOpis
os.time()Aktualny Unix timestamp (sekundy)
os.time(table)Timestamp dla podanej daty
os.date("*t")Tabela z rozbita data
os.date(fmt)Sformatowany string daty
os.date(fmt, ts)Formatowanie konkretnego timestampu
os.date("!*t")Tabela daty w UTC
os.clock()Czas CPU procesu (sekundy, precyzja ms)
os.difftime(t2, t1)Roznica dwoch timestampow w sekundach
Plugin time-syncSynchronizowany czas z helperami i zdarzeniami