Model runtime#
Silnik Lua#
vCLU używa gopher-lua — czystej implementacji Lua 5.1 w Go. Silnik jest jednowątkowy — cały dostęp do LState chroniony jest mutexem.
Główna struktura to LuaEngine w pkg/lua/lua.go:
type LuaEngine struct {
state *lua.LState
mu sync.RWMutex
timerManager *TimerManager
httpManager *HTTPManager
gpioManager *GPIOManager
kvManager *KVManager
customGlobals map[string]interface{}
stopChan chan struct{}
}Inicjalizacja#
Tworzenie silnika:
engine := lua.NewLuaEngine()
// lub z niestandardową ścieżką runtime:
engine := lua.NewLuaEngineWithRuntimePath(cluName, runtimePath)initializeLuaState() wykonuje następujące kroki:
- Tworzy nowy
LStatevialua.NewState() - Blokuje niebezpieczne funkcje —
dofile()iloadfile()ustawiane nalua.LNil - Rejestruje Go functions — bridże do timerów, HTTP, MQTT, KV, GPIO
- Ładuje bootstrap —
bootstrap_go.luainicjalizuje cały runtime Lua
Bootstrap — 12 warstw#
Plik pkg/lua/runtime/bootstrap_go.lua ładuje runtime w określonej kolejności:
| Warstwa | Co ładuje | Opis |
|---|---|---|
| 1 | Utils | Logger, EventBus, StateBus, JSON, ModuleData, Module |
| 2 | OM Modules | CLU, Timer, DIN, DOUT, ANALOG_IN/OUT, UNDEFINED |
| 3 | ExposedObjects | API ekspozycji obiektów (MQTT, HomeKit) |
| 4 | AccessControl | Unified access control |
| 5 | Integrations | HTTP client, MQTT, Home Assistant |
| 5b | GPIO | Polling wejść via setInterval |
| 6 | RemoteSubscription | Protokół zdalnej subskrypcji |
| 7 | Core | LuaAPI, PluginSandbox, Plugin API |
| 8 | Factories | OBJECT, GATE |
| 9 | Remote Objects | Hierarchia RemoteObject |
| 10 | Registry | Centralny rejestr + RemoteGroup |
| 11 | Helpers | Funkcje pomocnicze |
| 12 | SYSTEM | Singleton SYSTEM, inicjalizacja modułów |
Ładowanie danych CLU#
Po bootstrapie, LoadCLUData() ładuje konkretną konfigurację:
1. user.lua → pcall(require "user") — opcjonalny, błędy logowane
2. om.lua → state.DoFile(omPath) — wymagany
3. main.lua → parsowanie checkAlive — tylko serial, nie wykonywany
4. SYSTEM.Init() — uruchomienie EVENT_ON_INITPętla główna — RunLoop#
RunLoop() działa na tickerze 10ms i nie blokuje:
func (le *LuaEngine) RunLoop() {
ticker := time.NewTicker(10 * time.Millisecond)
for {
select {
case <-le.stopChan:
return
case <-ticker.C:
le.ProcessTimers()
le.ProcessHTTPServer()
le.PollGPIOInputs()
}
}
}Każdy tick:
- ProcessTimers — sprawdza kolejkę gotowych timerów, wykonuje callbacki Lua
- ProcessHTTPServer — obsługuje przychodzące requesty do wbudowanego serwera
- PollGPIOInputs — odczytuje piny wejściowe, wykrywa zmiany stanu
Go → Lua Bridge#
Silnik rejestruje zestaw funkcji Go dostępnych z poziomu Lua:
| Funkcja Go | Cel |
|---|---|
__go_setTimeout(cb, ms) | Jednorazowy timer |
__go_setInterval(cb, ms) | Powtarzający się timer |
__go_clearTimer(id) | Anulowanie timera |
__go_time_ms() | Timestamp w ms |
__go_http_request(...) | Synchroniczny HTTP |
__go_http_async_request(...) | Asynchroniczny HTTP |
__go_http_poll_async() | Polling async HTTP |
__go_kv_get/set/delete/has/list(...) | KV store |
__go_gpio_setup/write/read(...) | Operacje GPIO |
__go_send_command(ip, script) | Zdalne wykonanie na innym CLU |
__go_homekit_notify(path, val, type) | Powiadomienie HomeKit |
Te funkcje nie są wywoływane bezpośrednio — opakowane są przez moduły Lua (EventBus, HttpClient, itd.).
Reset i reinicjalizacja#
vCLU może zrestartować silnik Lua bez restartowania procesu Go:
- Zamyka stary
LState - Tworzy nowy (pełna reinicjalizacja)
- Przywraca
customGlobals - Ponownie rejestruje Go callbacki
- Ładuje dane CLU od nowa
Przydatne po zmianie konfiguracji w kreatorze lub po aktualizacji om.lua z OM.