AccessControl & Expose#
System eksponowania obiektów (expose) i kontroli dostępu (AccessControl) decyduje o tym, które obiekty vCLU są widoczne w Home Assistant (MQTT) i HomeKit, oraz czy można je sterować czy tylko odczytywać.
expose() - eksponowanie obiektu#
expose() rejestruje obiekt Lua w systemie integracji. Bez wywołania expose() obiekt nie pojawi się ani w HA ani w HomeKit.
local handle = expose(obj, typ, opcje)| Parametr | Typ | Opis |
|---|---|---|
obj | table | Obiekt z metodą get(0), opcjonalnie set(0, v), onChange(cb) |
typ | string | Typ eksponowania (patrz tabela niżej) |
opcje | table | Opcje (opcjonalne) |
Opcje#
| Klucz | Typ | Domyślnie | Opis |
|---|---|---|---|
name | string | — | Nazwa wyświetlana w HA/HomeKit |
id | string | — | Identyfikator do generowania ścieżki |
path | string | — | Jawna ścieżka (zamiast generowanej) |
readonly | boolean | false | Tylko odczyt |
hidden | boolean | false | Nie eksponuj (zwraca nieaktywny handle) |
mqtt | boolean | true | Eksponuj przez MQTT (Home Assistant) |
homekit | boolean | true | Eksponuj w HomeKit |
group | string | — | Grupa (do przyszłego użytku) |
area | string | — | Sugerowany pokój w Home Assistant |
Typy#
| Typ | HA | HomeKit | Opis |
|---|---|---|---|
switch | switch | Switch | przełącznik ON/OFF |
light | light | Lightbulb | lampa ON/OFF |
dimmer | light | Lightbulb | lampa z jasnością 0-100 |
cover | cover | WindowCovering | roleta z pozycją |
sensor | binary_sensor | ContactSensor | czujnik binarny |
motion | binary_sensor | MotionSensor | czujnik ruchu |
temperature | sensor | TemperatureSensor | temperatura |
humidity | sensor | TemperatureSensor | wilgotność |
number | number | Switch | wartość liczbowa |
scene | switch | Switch (bezstanowy) | scena |
button | button | — | przycisk (zdarzenie) |
lock | lock | — | zamek |
fan | fan | — | wentylator |
garage_door | cover | — | brama garażowa |
Przykłady#
-- Przekaźnik GPIO
local relay = GPIO_DOUT:new("RELAY1", 17, {activeLow = true})
expose(relay, "switch", {name = "Lampa salon"})
-- Obiekt z OM registry
expose(_:get("CLU.DOUT1"), "switch", {name = "Lampa kuchnia"})
-- Czujnik temperatury (wartość statyczna lub dynamiczna)
expose({value = 0, get = function(self) return self.value end}, "temperature", {
name = "Temperatura salon"
})
-- Scena
scene("wieczor", function()
_:get("CLU.DOUT1"):execute(DOUT.METHOD_SWITCH_ON)
_:get("CLU.DOUT2"):execute(DOUT.METHOD_SWITCH_OFF)
end)
expose(getScene("wieczor"), "scene", {name = "Tryb wieczorny"})ExposedHandle - API uchwytu#
expose() zwraca handle, przez który można dynamicznie zmieniać obiekt.
Metody fluent (chainable)#
local h = expose(obj, "switch", {name = "Lampa"})
h:name("Nowa nazwa") -- zmień nazwę
h:readonly() -- ustaw jako tylko-odczyt
h:mqttOnly() -- wyłącz HomeKit
h:homekitOnly() -- wyłącz MQTT
h:group("salon") -- ustaw grupęChaining:
expose(obj, "switch"):name("Lampa"):readonly():mqttOnly()Wartość#
h:getValue() -- odczytaj aktualną wartość
h:setValue(1) -- ustaw wartość (emituje state_changed)
-- nie działa gdy readonlyAktualizacja w runtime#
-- Zmień nazwę (aktualizuje discovery w HA i HomeKit)
h:rename("Zmieniona nazwa")
-- Zmień opcje (merge)
h:update({readonly = true})
h:update({mqtt = false}) -- ukryj z MQTT, zostaw HomeKit
h:update({homekit = false}) -- ukryj z HomeKit, zostaw MQTTUsunięcie#
h:unexpose() -- usuń obiekt z HA i HomeKit
h:isExposed() -- sprawdź czy nadal wyeksponowany (true/false)Ścieżka#
h:getPath() -- zwraca ścieżkę, np. "vclu:switch1" lub "CLU.DOU123"exposeRegistry() - automatyczne eksponowanie#
exposeRegistry() eksponuje wszystkie obiekty z registry (z OM) jednym wywołaniem:
local count = exposeRegistry()
-- Zwraca: liczba nowo wyeksponowanych obiektówReguły#
- Obiekty już wyeksponowane ręcznie przez
expose()sa pomijane - ręczny expose zawsze wygrywa - AccessControl jest respektowany - ukryte obiekty nie są eksponowane
- Typ jest wykrywany automatycznie z TypeMap (DOUT → switch, DIN → sensor, ROLLER → cover, itd.)
Priorytet#
1. Ręczny expose() w user.lua (najwyższy)
2. Reguły AccessControl (środkowy)
3. exposeRegistry() automatyczne (najniższy)Jeśli w user.lua wyeksponujesz obiekt ręcznie, exposeRegistry() go nie nadpisze:
-- user.lua
expose(_:get("CLU.DOUT1"), "switch", {name = "Moja lampa", readonly = true})
-- Później (np. w bootstrap)
exposeRegistry() -- pominie CLU.DOUT1, bo już wyeksponowanyAccessControl - kontrola dostępu#
AccessControl pozwala osobno kontrolować widoczność i sterowanie dla każdej integracji (MQTT / HomeKit).
Poziomy dostępu#
| Poziom | Widoczność | Sterowanie | Opis |
|---|---|---|---|
full | tak | tak | Pełny dostęp (domyślnie) |
readonly | tak | nie | Widoczny ale nie sterowalny |
hidden | nie | nie | Ukryty - nie pojawia się w integracji |
Lua API#
-- Odczytaj dostęp
local level = AccessControl.get("mqtt", "CLU.DOUT1") -- "full"/"readonly"/"hidden"
-- Helpersy
AccessControl.isHidden("mqtt", "CLU.DOUT1") -- true/false
AccessControl.isReadonly("mqtt", "CLU.DOUT1") -- true/false
AccessControl.canControl("mqtt", "CLU.DOUT1") -- true = level == "full"
AccessControl.canPublish("mqtt", "CLU.DOUT1") -- true = level ~= "hidden"
-- Pobierz wszystkie reguły
local all = AccessControl.getAll()
-- { ["CLU.DOU1"] = { mqtt = "full", homekit = "hidden" }, ... }`AccessControl` wpływa na `exposeRegistry()` - decyduje co i jak zostanie wyeksponowane. Ale nie zmienia obiektów które **już są wyeksponowane**. Do dynamicznych zmian na żywym obiekcie używaj `handle:update()`.
Plik konfiguracji#
Reguły zapisywane są w access_control.yaml:
objects:
CLU221000290.DOU0001:
mqtt: full
homekit: hidden
CLU221000290.DIMM0001:
mqtt: readonly
homekit: full
CLU221000290.DOU0003:
mqtt: hidden
homekit: hiddenObiekty bez wpisu mają domyślny poziom full.
Scenariusze#
Ukryj obiekt z Home Assistant (MQTT), zostaw HomeKit#
-- Przy eksponowaniu
expose(obj, "switch", {name = "Lampa", mqtt = false})
-- Albo w runtime na istniejącym handle
h:update({mqtt = false})Ukryj z HomeKit, zostaw HA#
-- Przy eksponowaniu
expose(obj, "switch", {name = "Lampa", homekit = false})
-- Albo w runtime
h:update({homekit = false})Zmień z pełnego dostępu na readonly#
-- Dla obu integracji naraz
h:update({readonly = true})Całkowicie usuń obiekt z HA i HomeKit#
h:unexpose()Po unexpose():
- MQTT: publikuje pusty payload na topic discovery (HA usuwa encję)
- HomeKit: akcesorium znika po restarcie bridge
Zmień nazwę wyświetlaną#
h:rename("Nowa nazwa")
-- HA: re-publikuje discovery z nową nazwą
-- HomeKit: aktualizuje przy następnym odświeżeniuDynamicznie przełączaj dostęp w zależności od pory dnia#
local lock = expose(_:get("CLU.LOCK1"), "lock", {name = "Zamek drzwi"})
-- Scena "nocny" - wyłącz sterowanie zamkiem
scene("tryb_nocny", function()
lock:update({readonly = true})
end)
-- Scena "dzienny" - przywróć pełne sterowanie
scene("tryb_dzienny", function()
lock:update({readonly = false})
end)Ręczny expose przed exposeRegistry#
-- user.lua
-- 1. Ręcznie eksponuj z własną nazwą i ustawieniami
expose(_:get("CLU.DOUT1"), "switch", {
name = "Lampa salon",
readonly = true,
homekit = false
})
-- 2. Reszta obiektów z registry - automatycznie
exposeRegistry()
-- CLU.DOUT1 jest pominięty (już wyeksponowany ręcznie)
-- Reszta obiektów eksponowana z domyślnymi nazwamiObiekt z onChange - automatyczna aktualizacja stanu#
Jeśli obiekt implementuje onChange(callback), expose automatycznie subskrybuje zmiany:
local MySwitch = {}
function MySwitch:new()
return setmetatable({_value = 0, _cbs = {}}, {__index = self})
end
function MySwitch:get(f) return self._value end
function MySwitch:set(f, v) self._value = v; self:_notify() end
function MySwitch:onChange(cb)
table.insert(self._cbs, cb)
return function() -- MUSI zwrócić funkcję unsubscribe!
for i, c in ipairs(self._cbs) do
if c == cb then table.remove(self._cbs, i); break end
end
end
end
function MySwitch:_notify()
for _, cb in ipairs(self._cbs) do cb(self._value) end
end
local sw = MySwitch:new()
expose(sw, "switch", {name = "Mój przełącznik"})
-- Teraz sw:set(0, 1) automatycznie aktualizuje stan w HA/HomeKitMetoda `onChange()` **musi zwrócić funkcję unsubscribe**. Bez tego `unexpose()` nie usunie callbacka i dojdzie do wycieku pamięci.
Tymczasowe eksponowanie#
-- Eksponuj obiekt na 5 minut (np. do testów)
local h = expose(obj, "switch", {name = "Tymczasowy"})
after(5 * 60 * 1000, function()
h:unexpose()
log.info("Tymczasowy obiekt usunięty")
end)Jak AccessControl wpływa na exposeRegistry#
Przykład pliku access_control.yaml:
objects:
CLU.DOU0001:
mqtt: hidden
CLU.DOU0002:
mqtt: readonly
CLU.DOU0003:
mqtt: hidden
homekit: hiddenWynik exposeRegistry():
| Obiekt | MQTT | HomeKit | Efekt |
|---|---|---|---|
CLU.DOU0001 | hidden | full | expose z mqtt = false (tylko HomeKit) |
CLU.DOU0002 | readonly | full | expose z readonly = true |
CLU.DOU0003 | hidden | hidden | pominięty - nie eksponowany wcale |
CLU.DOU0004 | full | full | expose normalnie (pełny dostęp) |