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#

graph TD
    broker["MQTT Broker<br/>(wbudowany vCLU)"]
    disc["Discovery config<br/>homeassistant/..."]
    state["State updates<br/>vclu/.../state"]
    cmd["Komendy<br/>vclu/.../set"]
    ha1["HA wykrywa<br/>urządzenie"]
    ha2["HA widzi stan"]
    ha3["HA steruje<br/>urządzeniem"]

    broker --- disc
    broker --- state
    broker --- cmd
    disc --> ha1
    state --> ha2
    cmd --> ha3
  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 obiektuKomponent 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)#

graph TD
    A["Go: omparser.Parse()<br/>→ ParsedOM (obiekty z plików OM)"]
    B["Go: omparser.GenerateHADiscovery<br/>(parsed, config) → []HADiscoveryMessage"]
    C["Go: AccessControl<br/>filtruje ukryte obiekty"]
    D["Go: broker.Publish()<br/>→ homeassistant/{typ}/{id}/config"]
    E["Go: GenerateInitialStates()<br/>→ vclu/{clu}/{typ}/{id}/state"]

    A --> B --> C --> D --> E

Stany (ciągłe)#

graph TD
    A["Obiekt Lua zmienia wartość<br/>(np. DOUT przełączony)"]
    B["StateBus:emit('state_changed',<br/>{path, value, type})"]
    C["HAStatePublisher:<br/>nasłuchuje 'state_changed'"]
    D["Formatuje stan<br/>(0/1 → OFF/ON, pozycja, brightness, JSON RGB)"]
    E["MQTT:publish<br/>('vclu/{clu}/{typ}/{id}/state', stan)"]
    F["HA odbiera i aktualizuje encję"]

    A --> B --> C --> D --> E --> F

Komendy (ciągłe)#

graph TD
    A["HA wysyła komendę<br/>na vclu/{clu}/{typ}/{id}/set"]
    B["HACommands: subskrybuje<br/>vclu/+/+/+/set"]
    C["Parsuje topic →<br/>(cluId, component, objectId, subpath)"]
    D["Szuka obiektu w registry:<br/>_:get('CLU_ID.OBJECT_ID')"]
    E["Sprawdza AccessControl"]
    F["Wywołuje metodę:<br/>switch: switchOn/Off<br/>light: set brightness<br/>cover: up/down/stop"]

    A --> B --> C --> D --> E --> F