Automatyki w Lua#
W vCLU automatyki, sceny i dashboardy to zwykłe pliki Lua. Ten tutorial pokazuje kilka wzorców na prawdziwym przykładzie: w nocy ruch w wiatrołapie zapala światło na minutę, ale jeśli ktoś zgasi je ręcznie, automatyka milknie na 10 minut.
Zakładamy, że vCLU już działa (z Grentonem albo bez).
1. Gdzie leży kod#
Kod piszesz w edytorze (Editor), w katalogu modules/:
- każdy plik leżący bezpośrednio w
modules/ładuje się sam (najpierwinit.lua, potem reszta alfabetycznie), - pliki w podkatalogach trzeba załadować przez
require("satel/wiatrolap"), - po zmianie: Ctrl+S, potem Reload.
Identyfikatory obiektów (np. CLU220000592.DOU4992 albo satel.zone.2) znajdziesz w Narzędzia → Debug → Registry. W przykładach podmień je na swoje.
2. Reakcja na zdarzenie#
StateBus:watch wywołuje funkcję przy każdej zmianie obiektu. Opcje from i to zawężają wywołanie do konkretnego przejścia:
-- Czujka ruchu przechodzi w 1: zapal światło na minutę
local LIGHT = _:get("CLU220000592.DOU4992")
StateBus:watch("satel.zone.2", function()
LIGHT:switchOn(60 * 1000) -- CLU sam je zgasi po 60 s
end, { to = 1 })_:get(...) zwraca obiekt z rejestru: wyjście Grentona, wejście Satela, obiekt wirtualny albo z pluginu.
3. Kto to zmienił#
Każda zmiana stanu niesie sprawcę (actor): włącznik ścienny, użytkownika panelu, agenta AI, Home Assistant albo Twoją automatykę. Dzięki temu automatyka może odróżnić swoje działanie od ręcznego:
-- modules/wiatrolap.lua
local LIGHT = _:get("CLU220000592.DOU4992")
local ME = "automation:wiatrolap"
-- Stan automatyki, który przetrwa reload i restart
local state = persist("wiatrolap", { pauseUntil = 0 })
StateBus:watch("satel.zone.2", function()
if not datetime.between("21:00", "06:00") or os.time() < state.pauseUntil then return end
-- Światło zapalił ktoś inny: nie ruszamy
local last = LIGHT:lastChange()
if LIGHT:getValue() == 1 and not (last and last.actor == ME) then return end
LIGHT:switchOn(60 * 1000)
end, { to = 1, runAs = ME })
-- Zgaszone przez kogokolwiek poza nami: pauza na 10 minut
StateBus:watch("CLU220000592.DOU4992", function(e)
if e.actor == ME then return end
state.pauseUntil = os.time() + 600
end, { from = 1, to = 0 })runAs = ME sprawia, że zmiany zrobione w tej funkcji są zapisane jako zrobione przez automation:wiatrolap. W Narzędzia → Historia i audyt zobaczysz potem przy każdym zapaleniu, kto to zrobił.
4. Stan po restarcie#
Dwa sposoby, żeby coś przetrwało restart:
-- Ustawienie widoczne na zewnątrz (HA, HomeKit, dashboard)
local nightMode = VirtualSwitch:new("night_mode", { initial = 0, persist = true })
expose(nightMode, "switch", { name = "Tryb nocny" })
-- Wewnętrzny stan automatyki: tabela zapisywana automatycznie
local state = persist("podlewanie", { lastRun = 0 })5. Timery#
local id = after(5 * 60 * 1000, function() print("minęło 5 minut") end)
cancel(id) -- anulowanie
every(60 * 1000, function() print("co minutę") end)Czas zawsze w milisekundach. Strefę czasową ustaw raz, na początku modules/init.lua: datetime.setTimezone("Europe/Warsaw").
6. Scena#
Scena to obiekt z metodą execute, wystawiony jako scene. Uruchomisz ją z dashboardu, HomeKit, Home Assistant albo przez agenta AI:
local scene = { execute = function(self)
_:get("CLU220000592.DOU0789"):switchOff()
_:get("CLU220000592.DOU4992"):switchOff()
end }
expose(scene, "scene", { name = "Wyjście z domu", path = "scene:wyjscie" })7. Dashboard na tablet#
Dashboard też jest kodem. Ten trafi pod /d/home, z dostępem na PIN:
-- modules/dashboard_home.lua
local r = _registry
Dashboard.new("home")
:name("Dom"):icon("house-door"):auth("pin"):pin("1234") -- ustaw własny PIN
:section("Salon", "lamp")
:toggle("sofa", "Sofa", "lamp",
function() return r:get("CLU220000592.DOU0789"):getValue() end,
function(v) local o = r:get("CLU220000592.DOU0789"); if v then o:switchOn() else o:switchOff() end end)
:status("temp", "Temperatura", "thermometer-half",
function() return r:get("CLU220000592.ONE6305"):getValue() end, "°C")
:build()Pełny dashboard z alarmem, światłami i temperaturami jest w kroku 16 tutoriala vCLU w instalacji Grenton.
Co dalej?#
- Agent AI pisze automatykę - ta sama automatyka, napisana i przetestowana przez agenta
- Pełne API: Lua API