Wlasne moduly#

vCLU pozwala tworzyc wlasne moduly Lua w katalogu modules/. Moduly sa ladowane po wszystkich plikach systemowych i proxy, wiec maja dostep do calego runtime — registry, obiektow zdalnych, helperow, timerow itd.

Struktura katalogu#

modules/
  init.lua              ← punkt wejscia (ladowany automatycznie)
  lighting.lua          ← modul jako pojedynczy plik
  heating/
    init.lua            ← modul jako katalog (require("heating"))
    zones.lua           ← podmodul (require("heating.zones"))
    schedule.lua        ← podmodul (require("heating.schedule"))

Katalog modules/ jest widoczny i edytowalny w edytorze (/editor). Mozna tam tworzyc pliki, katalogi i podkatalogi.

init.lua#

Plik modules/init.lua jest ladowany automatycznie przy starcie vCLU. Sluzy jako punkt wejscia — tutaj ladujemy wlasne moduly przez require():

-- modules/init.lua

local lighting = require("lighting")
local heating = require("heating")

print("[MODULES] User modules initialized")

Jezeli modules/init.lua nie istnieje, system pomija ladowanie modulow bez bledu.

require()#

require() szuka plikow w katalogu modules/ wedlug dwoch wzorcow:

WywolanieSzukany plik
require("lighting")modules/lighting.lua
require("heating")modules/heating/init.lua
require("heating.zones")modules/heating/zones.lua

Lua cachuje wynik require() w package.loaded — kazdy modul jest wykonywany tylko raz, niezaleznie od tego ile razy go zaimportujemy.

Tworzenie modulu#

Modul to plik Lua, ktory zwraca tablice z funkcjami i danymi:

-- modules/lighting.lua

local M = {}

function M.allOff()
    local lights = _:byTag("lights")
    lights:execute(DOUT.METHOD_SWITCH_OFF)
    log.info("Wszystkie swiatla wylaczone")
end

function M.allOn()
    local lights = _:byTag("lights")
    lights:execute(DOUT.METHOD_SWITCH_ON)
end

function M.toggle(name)
    local obj = _:get(name)
    if obj then
        obj:execute(DOUT.METHOD_SWITCH_TOGGLE)
    end
end

return M

Przyklad: modul ogrzewania#

Modul podzielony na kilka plikow w katalogu:

modules/
  init.lua
  heating/
    init.lua
    zones.lua
    schedule.lua

heating/zones.lua#

-- modules/heating/zones.lua

local M = {}

M.config = {
    salon   = { thermostat = "CLU.THERM1", target = 21.5 },
    sypialnia = { thermostat = "CLU.THERM2", target = 20.0 },
    lazienka  = { thermostat = "CLU.THERM3", target = 23.0 },
}

function M.setTarget(zone, temp)
    local cfg = M.config[zone]
    if not cfg then
        log.warn("Nieznana strefa: %s", zone)
        return
    end
    cfg.target = temp
    local obj = _:get(cfg.thermostat)
    if obj then
        obj:set(0, temp)
        log.info("Strefa %s: cel %.1f°C", zone, temp)
    end
end

function M.getAll()
    local result = {}
    for zone, cfg in pairs(M.config) do
        local obj = _:get(cfg.thermostat)
        result[zone] = {
            target = cfg.target,
            current = obj and obj:get(0) or nil,
        }
    end
    return result
end

return M

heating/schedule.lua#

-- modules/heating/schedule.lua

local zones = require("heating.zones")

local M = {}

function M.nightMode()
    zones.setTarget("salon", 19.0)
    zones.setTarget("sypialnia", 20.0)
    zones.setTarget("lazienka", 19.0)
    log.info("Tryb nocny aktywny")
end

function M.dayMode()
    zones.setTarget("salon", 21.5)
    zones.setTarget("sypialnia", 20.0)
    zones.setTarget("lazienka", 23.0)
    log.info("Tryb dzienny aktywny")
end

return M

heating/init.lua#

-- modules/heating/init.lua

local M = {}

M.zones = require("heating.zones")
M.schedule = require("heating.schedule")

return M

modules/init.lua#

-- modules/init.lua

local lighting = require("lighting")
local heating = require("heating")

-- Harmonogram ogrzewania
after(1000, function()
    local hour = os.date("*t").hour
    if hour >= 23 or hour < 6 then
        heating.schedule.nightMode()
    else
        heating.schedule.dayMode()
    end
end)

print("[MODULES] Loaded: lighting, heating")

Uzycie w user.lua#

Moduly zaladowane w init.lua sa dostepne globalnie jesli przypiszemy je do zmiennych globalnych, albo mozna uzyc require() ponownie (zwroci wersje z cache):

-- user.lua

function onButtonPress()
    local lighting = require("lighting")
    lighting.allOff()
end

function onSceneEvening()
    local heating = require("heating")
    heating.schedule.nightMode()

    local lighting = require("lighting")
    lighting.toggle("LAMPA_SALON")
end

Kolejnosc ladowania#

1. bootstrap       ← runtime (EventBus, Registry, klasy...)
2. user.lua        ← funkcje uzytkownika
3. om.lua          ← obiekty, event bindingi
4. proxy_*.lua     ← obiekty zdalne
5. modules/init.lua  ← wlasne moduly (require)
6. SYSTEM.Init()   ← EVENT_ON_INIT

Moduly laduja sie jako ostatnie przed inicjalizacja — maja dostep do wszystkich obiektow (lokalnych i zdalnych), registry, helperow i timerow.

Dobre praktyki#

  • Kazdy modul zwraca tablice (return M) — nie zanieczyszcza globalnej przestrzeni nazw
  • Logika biznesowa w modulach, funkcje eventowe w user.lua
  • Podprojekty w podkatalogach z wlasnym init.lua
  • require() zamiast kopiowania kodu miedzy plikami