DOUT - wyjscie cyfrowe#
DOUT (Digital Output) to obiekt reprezentujacy wyjscie cyfrowe - przekaznik, lampe, zawor. Wystepuje w trzech wariantach:
- Lokalny DOUT - wirtualny modul vCLU, konfigurowany w wizardzie (emuluje fizyczny modul Grenton)
- DOUT z OM - obiekt z Object Manager, po sparowaniu z fizycznym CLU Grenton
- GPIO_DOUT - obiekt tworzony w
user.lua, sterujacy pinem GPIO Raspberry Pi
Wszystkie warianty maja ten sam interfejs API (get/set/execute/add_event) i te same stale.
Lokalny DOUT - moduly wirtualne#
Gdy vCLU dziala jako emulator CLU (tryb CLU w wizardzie), mozna dodac wirtualne moduly wyjsc. Sa to emulacje fizycznych modulow Grenton - nie steruja prawdziwym sprzetem, ale pojawiaja sie w OM i moga byc uzywane do testow, automatyzacji i integracji z Home Assistant / HomeKit.
Konfiguracja w wizardzie#
W kroku 2 wizarda (“Moduly”) mozna dodac moduly z wyjsciami cyfrowymi:
| Typ modulu | Wyjscia DOUT | Wejscia DIN | Analog | HW Type |
|---|---|---|---|---|
| DOUT8T | 8 | 8 | 1 | 0x1e |
| RELAY4 | 4 | - | 1 | 0x15 |
Kazdy modul dostaje unikalna nazwe (np. DOUT8T_1) i numer seryjny. Obiekty I/O sa generowane automatycznie z losowymi identyfikatorami (np. DOU5048, DOU4458).
Jak to dziala#
Wizard → .vclu.json → config.txt + CONFIG.JSON → OM → om.lua → runtime- Uzytkownik dodaje modul w wizardzie
- vCLU zapisuje konfiguracje w
.vclu.json(moduly + obiekty I/O) - Generuje
config.txtiCONFIG.JSONz wpisami TFBus - Object Manager (OM) odczytuje konfiguracje i generuje
om.lua - Przy starcie Lua laduje
om.lua- obiekty DOUT sa dostepne w runtime
Dostep do obiektow#
Obiekty lokalne sa dostepne przez registry, identycznie jak na prawdziwym CLU:
-- Przez nazwe z OM
local lampa = _:get("CLU.DOU5048")
lampa:execute(DOUT.METHOD_SWITCH_ON)
-- Albo przez nazwe nadana w wizardzie
local lampa = _:get("CLU.DOUT8T_1_DOU1").vclu.json#
Moduly i ich I/O sa zapisane w konfiguracji:
{
"device": {
"modules": [
{
"typeId": "dout8t",
"serial": "330000027",
"name": "DOUT8T_1",
"hardwareType": 30
}
],
"ioObjects": [
{
"id": "DOU5048",
"typeId": "dout",
"index": 0,
"name": "DOUT8T_1_DOU1",
"luaType": 4
}
]
}
}Lokalne moduly DOUT nie steruja fizycznym sprzetem - zmiany stanu sa tylko w pamieci. Ale obiekty sa w pelni funkcionalne: emituja zdarzenia, dzialaja z `expose()`, pojawiaja sie w Home Assistant i HomeKit. Do sterowania prawdziwymi przekaznikami na Raspberry Pi uzyj `GPIO_DOUT`.
GPIO_DOUT - tworzenie#
local relay = GPIO_DOUT:new(name, pin, opts)| Parametr | Typ | Opis |
|---|---|---|
name | string | Nazwa globalna (np. "RELAY1") |
pin | number | Numer pinu BCM |
opts | table | Opcje (opcjonalne) |
Opcje#
| Klucz | Typ | Domyslnie | Opis |
|---|---|---|---|
activeLow | boolean | false | Inwersja logiki (LOW = ON, HIGH = OFF) |
name | string | - | Nazwa wyswietlana |
-- Przekaznik z inwersja (typowe dla plyt relay)
local relay = GPIO_DOUT:new("RELAY1", 17, {activeLow = true})
-- LED bez inwersji
local led = GPIO_DOUT:new("LED1", 22)activeLow#
Wiekszosz plyt przekaznikowych uzywa logiki odwroconej - LOW na pinie aktywuje przekaznik, HIGH wylacza. Opcja activeLow = true automatycznie odwraca logike:
| Logika | activeLow = false | activeLow = true |
|---|---|---|
| ON (value=1) | pin HIGH | pin LOW |
| OFF (value=0) | pin LOW | pin HIGH |
| safeState (przy starcie) | LOW | HIGH (przekaznik OFF) |
Przy `activeLow = true` pin startuje w stanie HIGH (przekaznik wylaczony). To zapobiega przypadkowemu wlaczeniu przekaznika przy starcie systemu.
DOUT z OM - obiekty z Object Manager#
Obiekty DOUT z OM sa tworzone automatycznie po sparowaniu z fizycznym CLU Grenton. Dostep przez registry:
local lampa = _:get("CLU.DOUT1")
lampa:execute(DOUT.METHOD_SWITCH_ON)Porownanie wariantow#
| Lokalny DOUT | DOUT z OM | GPIO_DOUT | |
|---|---|---|---|
| Zrodlo | Wizard (vCLU) | Object Manager (OM) | user.lua |
| Sprzet | Brak (w pamieci) | Fizyczny modul Grenton | Pin GPIO Raspberry Pi |
| Konfiguracja | .vclu.json → om.lua | OM generuje om.lua | GPIO_DOUT:new() w kodzie |
| Zastosowanie | Testowanie, emulacja | Produkcja z prawdziwym CLU | Produkcja na Raspberry Pi |
| API | get/set/execute/add_event | get/set/execute/add_event | get/set/execute/add_event |
expose() | tak | tak | tak |
exposeRegistry() | tak (automatycznie) | tak (automatycznie) | tak (po registerObject) |
Stale#
Cechy (Features)#
| Stala | Wartosc | Opis |
|---|---|---|
DOUT.FEATURE_VALUE | 0 | Stan wyjscia: 1=ON, 0=OFF |
DOUT.FEATURE_VOLTAGE_TYPE | 3 | Typ napiecia: 0=AC, 1=DC, 2=Signal |
DOUT.FEATURE_VOLTAGE_VALUE | 4 | Wartosc napiecia |
DOUT.FEATURE_POWER | 5 | Moc chwilowa (tylko odczyt) |
DOUT.FEATURE_OVERLOAD | 7 | Prog przeciazenia |
Metody#
| Stala | Wartosc | Opis |
|---|---|---|
DOUT.METHOD_SWITCH | 0 | Przelacz (toggle) |
DOUT.METHOD_SWITCH_ON | 1 | Wlacz |
DOUT.METHOD_SWITCH_OFF | 2 | Wylacz |
Zdarzenia#
| Stala | Wartosc | Opis |
|---|---|---|
DOUT.EVENT_ON_VALUE_CHANGE | 0 | Zmiana wartosci |
DOUT.EVENT_ON_SWITCH_ON | 1 | Wlaczenie |
DOUT.EVENT_ON_SWITCH_OFF | 2 | Wylaczenie |
DOUT.EVENT_ON_OVERLOAD | 3 | Przeciazenie |
Wartosci#
| Stala | Wartosc |
|---|---|
DOUT.VALUE_ON / DOUT.STATE_ON | 1 |
DOUT.VALUE_OFF / DOUT.STATE_OFF | 0 |
API#
execute(method, time)#
Wykonuje metode na obiekcie. Opcjonalny parametr time (ms) powoduje automatyczne cofniecie po zadanym czasie.
-- Wlacz
relay:execute(DOUT.METHOD_SWITCH_ON)
-- Wylacz
relay:execute(DOUT.METHOD_SWITCH_OFF)
-- Przelacz (toggle)
relay:execute(DOUT.METHOD_SWITCH)
-- Wlacz na 5 sekund, potem wylacz
relay:execute(DOUT.METHOD_SWITCH_ON, 5000)
-- Wylacz na 3 sekundy, potem wlacz
relay:execute(DOUT.METHOD_SWITCH_OFF, 3000)get(feature)#
Odczytuje wartosc cechy.
local stan = relay:get(DOUT.FEATURE_VALUE) -- 0 lub 1set(feature, value)#
Ustawia wartosc cechy.
relay:set(DOUT.FEATURE_VALUE, 1) -- wlacz
relay:set(DOUT.FEATURE_VALUE, 0) -- wylaczadd_event(event, callback)#
Rejestruje callback na zdarzenie.
relay:add_event(DOUT.EVENT_ON_SWITCH_ON, function()
log.info("Przekaznik wlaczony!")
end)
relay:add_event(DOUT.EVENT_ON_SWITCH_OFF, function()
log.info("Przekaznik wylaczony!")
end)
relay:add_event(DOUT.EVENT_ON_VALUE_CHANGE, function()
local v = relay:get(DOUT.FEATURE_VALUE)
log.info("Nowa wartosc: " .. v)
end)onChange(callback)#
Rejestruje callback na zmiane wartosci. Zwraca funkcje unsubscribe. Uzywany przez system expose() do automatycznej aktualizacji stanow w Home Assistant i HomeKit.
local unsub = relay:onChange(function(newValue, oldValue)
log.info("Zmiana: " .. oldValue .. " → " .. newValue)
end)
-- Pozniej: wyrejestruj callback
unsub()Przyklady#
Przekaznik GPIO z eksponowaniem#
local relay = GPIO_DOUT:new("RELAY1", 17, {activeLow = true})
expose(relay, "switch", {name = "Lampa salon"})Toggle na przycisk#
local relay = GPIO_DOUT:new("RELAY1", 17, {activeLow = true})
local btn = GPIO_DIN:new("BTN1", 27)
btn:add_event(DIN.EVENT_ON_CLICK, function()
relay:execute(DOUT.METHOD_SWITCH)
end)Wlaczenie czasowe (np. oswietlenie klatki schodowej)#
local swiatlo = GPIO_DOUT:new("SWIATLO_KLATKA", 17, {activeLow = true})
local przycisk = GPIO_DIN:new("BTN_KLATKA", 27)
przycisk:add_event(DIN.EVENT_ON_CLICK, function()
swiatlo:execute(DOUT.METHOD_SWITCH_ON, 60000) -- 60 sekund
end)Sterowanie obiektem z OM#
-- DOUT z fizycznego modulu Grenton
local lampa = _:get("CLU.DOUT1")
-- Te same metody co GPIO_DOUT
lampa:execute(DOUT.METHOD_SWITCH_ON)
lampa:add_event(DOUT.EVENT_ON_SWITCH_ON, function()
log.info("Lampa wlaczona")
end)
expose(lampa, "switch", {name = "Lampa kuchnia"})Kaskada - wlaczanie po kolei#
local r1 = GPIO_DOUT:new("R1", 17, {activeLow = true})
local r2 = GPIO_DOUT:new("R2", 22, {activeLow = true})
local r3 = GPIO_DOUT:new("R3", 24, {activeLow = true})
scene("wszystkie_on", function()
r1:execute(DOUT.METHOD_SWITCH_ON)
after(500, function() r2:execute(DOUT.METHOD_SWITCH_ON) end)
after(1000, function() r3:execute(DOUT.METHOD_SWITCH_ON) end)
end)after() dziala asynchronicznie - rejestruje timer i wraca natychmiast. Scena konczy sie w ulamku milisekundy, a callbacki odpalaja sie pozniej z petli timerowej Go. Nie ma ryzyka zawieszenia CLU.
after(500, ...) ← NIE czeka 500ms, tylko rejestruje callback i idzie dalej
after(1000, ...) ← to samo - rejestruje i wraca
-- scena konczy sie tu, natychmiast
-- po 500ms: r2 wlacza sie
-- po 1000ms: r3 wlacza sieLua w vCLU jest jednowatkowy - **nigdy nie uzywaj petli oczekujacej** (`while`, `repeat`, busy-wait). Zablokuje to caly runtime i zatrzyma przetwarzanie zdarzen, timerow, MQTT i GPIO. Do opoznien zawsze uzywaj `after()` lub `every()`. ```lua -- ZLE - zawiesi CLU! local start = os.clock() while os.clock() - start < 0.5 do end -- busy-wait r2:execute(DOUT.METHOD_SWITCH_ON) -- DOBRZE - asynchronicznie after(500, function() r2:execute(DOUT.METHOD_SWITCH_ON) end) ```
Przyklady mieszane - GPIO + lokalne moduly#
Mozna laczyc rozne warianty - np. fizyczny przycisk GPIO steruje wirtualnym DOUT, albo Tasmota przez MQTT steruje lokalnym modulem.
GPIO_DIN przelacza lokalny DOUT#
Fizyczny przycisk podlaczony do pinu GPIO steruje wirtualnym wyjsciem z wizarda:
-- user.lua
-- Przycisk fizyczny na GPIO
local btn = GPIO_DIN:new("BTN1", 27)
-- Lokalny DOUT z wizarda (ID nadany automatycznie)
local lampa = _:get("CLU.DOU5048")
btn:add_event(DIN.EVENT_ON_CLICK, function()
lampa:execute(DOUT.METHOD_SWITCH)
end)
-- Eksponuj lokalny DOUT do Home Assistant
expose(lampa, "switch", {name = "Lampa salon"})GPIO_DIN - krotkie/dlugie nacisniecie na lokalnych DOUT#
local btn = GPIO_DIN:new("BTN1", 27)
local lampa1 = _:get("CLU.DOU5048")
local lampa2 = _:get("CLU.DOU4458")
-- Krotkie nacisniecie - przelacz lampe 1
btn:add_event(DIN.EVENT_ON_SHORT_PRESS, function()
lampa1:execute(DOUT.METHOD_SWITCH)
end)
-- Dlugie nacisniecie - wylacz obie lampy
btn:add_event(DIN.EVENT_ON_LONG_PRESS, function()
lampa1:execute(DOUT.METHOD_SWITCH_OFF)
lampa2:execute(DOUT.METHOD_SWITCH_OFF)
end)Tasmota steruje lokalnym DOUT przez MQTT#
Gniazdko Tasmota podlaczone do wbudowanego brokera MQTT. Stan gniazdka synchronizowany z lokalnym DOUT - dzieki temu obiekt jest widoczny w Home Assistant i HomeKit jak kazdy inny DOUT:
-- user.lua
local mqtt = MQTT:new("tasmota")
mqtt:setHost("localhost"):setPort(1883):connect()
local gniazdko = _:get("CLU.DOU5048")
-- Tasmota → lokalny DOUT (synchronizacja stanu)
mqtt:subscribe("stat/gniazdko1/POWER", function(topic, payload)
if payload == "ON" then
gniazdko:set(DOUT.FEATURE_VALUE, 1)
else
gniazdko:set(DOUT.FEATURE_VALUE, 0)
end
end)
-- Lokalny DOUT → Tasmota (przekazywanie komend)
gniazdko:add_event(DOUT.EVENT_ON_SWITCH_ON, function()
mqtt:publish("cmnd/gniazdko1/POWER", "ON")
end)
gniazdko:add_event(DOUT.EVENT_ON_SWITCH_OFF, function()
mqtt:publish("cmnd/gniazdko1/POWER", "OFF")
end)
-- Eksponuj do HA/HomeKit - sterowanie przez vCLU
expose(gniazdko, "switch", {name = "Gniazdko kuchnia"})Przeplyw:
Home Assistant / HomeKit
│
▼ (komenda ON)
Lokalny DOUT
│
├─▶ EVENT_ON_SWITCH_ON
│ │
│ ▼
│ mqtt:publish("cmnd/gniazdko1/POWER", "ON")
│ │
│ ▼
│ Tasmota wlacza gniazdko
│ │
│ ▼
│ Tasmota → "stat/gniazdko1/POWER" = "ON"
│ │
│ ▼
└── gniazdko:set(DOUT.FEATURE_VALUE, 1) ← stan zsynchronizowanyShelly jako czujnik temperatury + lokalny DOUT#
Shelly H&T publikuje temperature na MQTT. Gdy temperatura przekroczy prog - wlacz wentylator (lokalny DOUT):
local mqtt = MQTT:new("shelly")
mqtt:setHost("localhost"):setPort(1883):connect()
local wentylator = _:get("CLU.DOU4458")
expose(wentylator, "switch", {name = "Wentylator"})
mqtt:subscribe("shellies/shelly-ht/sensor/temperature", function(topic, payload)
local temp = tonumber(payload)
if temp and temp > 25 then
wentylator:execute(DOUT.METHOD_SWITCH_ON)
elseif temp and temp < 23 then
wentylator:execute(DOUT.METHOD_SWITCH_OFF)
end
end)Wiele Tasmot - fabryka DOUT#
Jesli masz kilka gniazdek Tasmota, mozesz je podpiac pod lokalne DOUT za pomoca petli:
local mqtt = MQTT:new("tasmota")
mqtt:setHost("localhost"):setPort(1883):connect()
-- Mapowanie: nazwa Tasmota → ID lokalnego DOUT
local urzadzenia = {
{tasmota = "gniazdko1", doutId = "CLU.DOU5048", name = "Gniazdko kuchnia"},
{tasmota = "gniazdko2", doutId = "CLU.DOU4458", name = "Gniazdko salon"},
{tasmota = "lampka1", doutId = "CLU.DOU3327", name = "Lampka biurko"},
}
for _, dev in ipairs(urzadzenia) do
local obj = _:get(dev.doutId)
-- Tasmota → DOUT
mqtt:subscribe("stat/" .. dev.tasmota .. "/POWER", function(topic, payload)
if payload == "ON" then
obj:set(DOUT.FEATURE_VALUE, 1)
else
obj:set(DOUT.FEATURE_VALUE, 0)
end
end)
-- DOUT → Tasmota
obj:add_event(DOUT.EVENT_ON_SWITCH_ON, function()
mqtt:publish("cmnd/" .. dev.tasmota .. "/POWER", "ON")
end)
obj:add_event(DOUT.EVENT_ON_SWITCH_OFF, function()
mqtt:publish("cmnd/" .. dev.tasmota .. "/POWER", "OFF")
end)
expose(obj, "switch", {name = dev.name})
endPodejscie "lokalny DOUT + MQTT" pozwala traktowac urzadzenia Tasmota/Shelly jak natywne obiekty Grenton. Dzieki temu pojawiaja sie w Home Assistant i HomeKit, moga byc uzywane w scenach, i maja pelne zdarzenia (`add_event`).