Home Assistant#

vCLU integruje się z Home Assistant przez MQTT Discovery - automatycznie publikuje konfigurację urządzeń, więc HA wykrywa je bez ręcznego pisania YAML.

Jak to działa#

                          MQTT Broker
                        (wbudowany vCLU)
                              │
          ┌───────────────────┼───────────────────┐
          │                   │                   │
    Discovery config     State updates       Komendy
    homeassistant/...    vclu/.../state      vclu/.../set
          │                   │                   │
          ▼                   ▼                   ▼
   HA wykrywa urządzenie  HA widzi stan    HA steruje urządzeniem
  1. Discovery - vCLU publikuje wiadomości na topic homeassistant/{typ}/{id}/config z payloadem JSON opisującym urządzenie (nazwa, topiki stanów/komend, typ). HA automatycznie tworzy encję.
  2. Stany - gdy obiekt zmieni wartość, vCLU publikuje nowy stan na vclu/{clu}/{komponent}/{obiekt}/state
  3. Komendy - HA wysyła komendy (ON/OFF, OPEN/CLOSE, brightness) na vclu/{clu}/{komponent}/{obiekt}/set, vCLU odbiera i wywołuje odpowiednią metodę na obiekcie

Wymagania#

  • Wbudowany broker MQTT musi być włączony (patrz MQTT)
  • Home Assistant musi mieć skonfigurowaną integrację MQTT wskazującą na adres IP vCLU, port 1883

Włączenie integracji#

Z panelu webowego#

Na stronie /mqtt kliknij kolejno:

  1. Publish HA Discovery - publikuje konfigurację wszystkich obiektów z OM
  2. Enable HA Commands - włącza nasłuchiwanie na komendy z HA i publikowanie stanów

Przez API#

# 1. Opublikuj discovery (konfiguracja urządzeń)
curl -X POST http://vclu:3000/api/ha/discovery/publish

# 2. Włącz obsługę komend i stanów
curl -X POST http://vclu:3000/api/ha/commands/enable

Odpowiedź discovery:

{
  "success": true,
  "published": 42,
  "states": 42,
  "files": 2,
  "errors": []
}

Obsługiwane typy urządzeń#

Typ GrentonKomponent HASterowanie
DOUTswitchON / OFF
DINbinary_sensortylko odczyt
DIMMERlightON / OFF + brightness
LEDRGBlightON / OFF + brightness + kolor RGB
ROLLER, ROLLER_SHcoverOPEN / CLOSE / STOP + pozycja
AnalogINsensortylko odczyt
AnalogOUTnumberwartość liczbowa
GPIO_DOUTswitchON / OFF
GPIO_DINbinary_sensortylko odczyt
Timer-nie eksponowany

Topiki MQTT#

Wszystkie topiki używają prefixu vclu/ i ID CLU:

# Discovery (retain, publikowane raz)
homeassistant/switch/vclu_clu221000290_dou5048/config

# Stan (retain, aktualizowany przy zmianie)
vclu/clu221000290/switch/dou5048/state          → "ON" / "OFF"

# Komenda (z HA)
vclu/clu221000290/switch/dou5048/set            ← "ON" / "OFF"

Topiki dla poszczególnych typów#

Switch (DOUT):

.../switch/{id}/state    → "ON" / "OFF"
.../switch/{id}/set      ← "ON" / "OFF"

Light (DIMMER):

.../light/{id}/state          → "ON" / "OFF"
.../light/{id}/set            ← "ON" / "OFF"
.../light/{id}/brightness     → 0–100
.../light/{id}/brightness/set ← 0–100

Light (LEDRGB):

.../light/{id}/state     → {"state":"ON","brightness":80,"color":{"r":255,"g":100,"b":50}}
.../light/{id}/set       ← {"state":"ON","brightness":80,"color":{"r":255,"g":100,"b":50}}

Cover (ROLLER):

.../cover/{id}/state         → "open" / "closed"
.../cover/{id}/set           ← "OPEN" / "CLOSE" / "STOP"
.../cover/{id}/position      → 0–100
.../cover/{id}/position/set  ← 0–100

Binary sensor (DIN):

.../binary_sensor/{id}/state → "ON" / "OFF"

Number (AnalogOUT):

.../number/{id}/state        → wartość liczbowa
.../number/{id}/set          ← wartość liczbowa

ExposedObjects - obiekty z pluginów i user.lua#

Obiekty które nie pochodzą z OM (np. z pluginów, GPIO, user.lua) można wyeksponować ręcznie za pomocą expose():

-- Przekaźnik GPIO jako switch w HA
local relay = GPIO_DOUT:new("RELAY1", 17, {activeLow = true})
expose(relay, "switch", {name = "Przekaźnik GPIO"})

-- Przycisk GPIO jako binary_sensor
local btn = GPIO_DIN:new("BTN1", 27)
expose(btn, "sensor", {name = "Przycisk"})

-- Czujnik temperatury (wartość liczbowa)
expose({value = 22.5}, "temperature", {name = "Temp 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"})

Obiekty wyeksponowane przez expose() pojawiają się w HA na topikach:

vclu/exposed/{base}/{komponent}/{id}/state
vclu/exposed/{base}/{komponent}/{id}/set

exposeRegistry - auto-expose z OM#

-- Wyeksponuj wszystkie obiekty z registry (z OM)
-- Respektuje AccessControl - ukryte obiekty są pomijane
exposeRegistry()

Obsługiwane typy expose#

TypHA komponentOpis
switchswitchON/OFF
lightlightON/OFF + brightness
dimmerlightON/OFF + brightness (0–100)
sensorbinary_sensorON/OFF (odczyt)
motionbinary_sensorczujnik ruchu
temperaturesensortemperatura (°C)
humiditysensorwilgotność (%)
covercoverroleta z pozycją
numbernumberwartość liczbowa
sceneswitchscena (bezstanowa)
buttonbuttonprzycisk (zdarzenie)
locklockzamek
fanfanwentylator z prędkością
garage_doorcoverbrama garażowa

AccessControl#

Obiekty mogą mieć ograniczony dostęp przez MQTT:

PoziomStanyKomendy
fullpublikowaneobsługiwane
readonlypublikowaneignorowane
hiddenpomijanepomijane

Ukryte obiekty nie generują discovery - nie pojawiają się w HA.

Więcej: AccessControl

Przykład discovery payload#

Tak wygląda wiadomość discovery dla przełącznika DOUT:

{
  "name": "P1_DACHOWE_ROZA",
  "unique_id": "vclu_clu221000290_dou5048",
  "object_id": "vclu_clu221000290_dou5048",
  "command_topic": "vclu/clu221000290/switch/dou5048/set",
  "state_topic": "vclu/clu221000290/switch/dou5048/state",
  "payload_on": "ON",
  "payload_off": "OFF",
  "state_on": "ON",
  "state_off": "OFF",
  "availability_topic": "vclu/status",
  "device": {
    "identifiers": ["clu221000290"],
    "name": "DOM20",
    "manufacturer": "VCLU",
    "model": "vclu"
  }
}

HA po odebraniu tej wiadomości na topiku homeassistant/switch/vclu_clu221000290_dou5048/config automatycznie tworzy encję switch.p1_dachowe_roza.

Jak działa pod spodem#

Publish discovery (jednorazowo)#

Go: omparser.Parse() → ParsedOM (obiekty z plików OM)
  ↓
Go: omparser.GenerateHADiscovery(parsed, config) → []HADiscoveryMessage
  ↓
Go: AccessControl filtruje ukryte obiekty
  ↓
Go: broker.Publish() → homeassistant/{typ}/{id}/config
  ↓
Go: GenerateInitialStates() → vclu/{clu}/{typ}/{id}/state

Stany (ciągłe)#

Obiekt Lua zmienia wartość (np. DOUT przełączony)
  ↓
StateBus:emit("state_changed", {path, value, type})
  ↓
HAStatePublisher: nasłuchuje "state_changed"
  ↓
Formatuje stan (0/1 → "OFF"/"ON", pozycja, brightness, JSON RGB)
  ↓
MQTT:publish("vclu/{clu}/{typ}/{id}/state", stan)
  ↓
HA odbiera i aktualizuje encję

Komendy (ciągłe)#

HA wysyła komendę na vclu/{clu}/{typ}/{id}/set
  ↓
HACommands: subskrybuje vclu/+/+/+/set (i /brightness/set, /position/set)
  ↓
Parsuje topic → (cluId, component, objectId, subpath)
  ↓
Szuka obiektu w registry: _:get("CLU_ID.OBJECT_ID")
  ↓
Sprawdza AccessControl
  ↓
Wywołuje odpowiednią metodę:
  switch: obj:execute(METHOD_SWITCH_ON) / obj:execute(METHOD_SWITCH_OFF)
  light:  obj:set(FEATURE_VALUE, brightness)
  cover:  obj:execute(METHOD_UP) / obj:execute(METHOD_DOWN) / obj:execute(METHOD_STOP)
  number: obj:set(FEATURE_VALUE, value)