Storage (KV Store)#
vCLU udostępnia persystentny key-value store dostępny z Lua. Dane przetrwają restart silnika i są zapisywane na dysku jako pliki JSON.
API z poziomu Lua#
kv:set(key, value, secure, ttl)#
Zapisz wartość.
-- Podstawowy zapis
kv:set("sensor_threshold", 22)
-- Zapis stringa
kv:set("last_scene", "wieczor")
-- Zapis tablicy (automatyczna serializacja)
kv:set("config", {temp_min = 18, temp_max = 25})kv:get(key)#
Odczytaj wartość. Zwraca (value, exists).
local val, exists = kv:get("sensor_threshold")
if exists then
log.info("Próg: " .. val)
end
-- Z wartością domyślną
local threshold = kv:get("sensor_threshold") or 22kv:has(key)#
Sprawdź czy klucz istnieje (i nie wygasł).
if kv:has("api_token") then
-- token jest dostępny
endkv:delete(key)#
Usuń klucz.
kv:delete("session_token")kv:list(prefix)#
Lista kluczy z opcjonalnym prefixem.
local keys = kv:list("sensor_")
-- {"sensor_threshold", "sensor_interval", "sensor_last_read"}
local all = kv:list() -- wszystkie kluczekv:getAll()#
Pobierz wszystkie pary klucz-wartość. Wartości zaszyfrowane są zastępowane przez "[SECURE]".
local all = kv:getAll()
for k, v in pairs(all) do
log.info(k .. " = " .. tostring(v))
endSzyfrowanie#
Wrażliwe dane (tokeny API, hasła) można zapisać zaszyfrowane:
-- Trzeci parametr = secure
kv:set("api_secret", "s3cret_token_123", true)
-- Odczyt działa normalnie
local secret = kv:get("api_secret") -- "s3cret_token_123"
-- Ale getAll() maskuje wartość
local all = kv:getAll()
-- all.api_secret = "[SECURE]"W logach wartość też jest ukryta:
[KV] Set myplugin.api_secret = [REDACTED] (secure, ttl=0)TTL (Time-to-Live)#
Klucze mogą wygasać automatycznie po zadanym czasie:
-- Czwarty parametr = TTL w sekundach
kv:set("session_token", token, false, 3600) -- wygaśnie po 1 godzinie
kv:set("cache_data", data, false, 300) -- wygaśnie po 5 minutach
-- Szyfrowane + z TTL
kv:set("oauth_token", token, true, 7200) -- szyfrowane, wygasa po 2hPo wygaśnięciu klucz jest usuwany przy następnym odczycie (lazy expiration):
kv:set("temp", "wartosc", false, 5) -- 5 sekund TTL
-- Po 5 sekundach:
local val, exists = kv:get("temp")
-- val = nil, exists = falseScope — izolacja per plugin#
Każdy plugin ma własny namespace w KV store. Pluginy nie widzą kluczy innych pluginów:
-- W pluginie "weather":
kv:set("api_key", "abc123") -- zapisane w pliku kv/weather.json
kv:get("api_key") -- "abc123"
-- W pluginie "lights":
kv:get("api_key") -- nil (nie widzi kluczy "weather")Pliki na dysku:
kv/
weather.json
lights.json
vclu--my-plugin.json -- @vclu/my-plugin → vclu--my-pluginZapis na dysk#
Dane są zapisywane atomowo (zapis do pliku tymczasowego, potem rename) przy każdej operacji set() i delete(). Format pliku:
{
"_meta": {
"version": 1,
"updated": 1708617600
},
"entries": {
"sensor_threshold": {
"v": 22,
"created": 1708617500
},
"api_secret": {
"v": "zaszyfrowana_wartosc",
"secure": true,
"created": 1708617550
},
"cache": {
"v": "dane",
"ttl": 300,
"exp": 1708617900,
"created": 1708617600
}
}
}Przykłady#
Zapamiętanie ostatniej sceny#
scene("wieczor", function()
_:get("CLU.DOU5048"):execute(DOUT.METHOD_SWITCH_ON)
_:get("CLU.DOU4458"):execute(DOUT.METHOD_SWITCH_OFF)
kv:set("last_scene", "wieczor")
end)
scene("poranek", function()
_:get("CLU.DOU5048"):execute(DOUT.METHOD_SWITCH_OFF)
_:get("CLU.DOU4458"):execute(DOUT.METHOD_SWITCH_ON)
kv:set("last_scene", "poranek")
end)
-- Po restarcie — przywróć ostatnią scenę
local last = kv:get("last_scene")
if last then
runScene(last)
endLicznik włączeń#
_:get("CLU.DOU5048"):add_event(DOUT.EVENT_ON_SWITCH_ON, function()
local count = kv:get("relay1_count") or 0
kv:set("relay1_count", count + 1)
end)Cache z automatycznym wygasaniem#
local function getWeather()
local cached = kv:get("weather_data")
if cached then
return cached -- zwróć z cache
end
-- Pobierz z API
local http = HTTP:new()
http:asyncGET("https://api.weather.com/current", function(response)
if response and response.status == 200 then
kv:set("weather_data", response.body, false, 600) -- cache na 10 minut
end
end)
endPrzechowywanie konfiguracji użytkownika#
-- Zapisz progi z panelu webowego
kv:set("config", {
temp_min = 18,
temp_max = 25,
auto_mode = true
})
-- Odczytaj
local cfg = kv:get("config") or {temp_min = 20, temp_max = 24, auto_mode = false}
if cfg.auto_mode then
-- ...
endPlugin API (kvGet / kvSet)#
Pluginy używają metod na obiekcie plugin zamiast globalnego kv:
-- W pluginie:
function Plugin:onInit()
local token = self:kvGet("api_token", "")
if token == "" then
self:log("warn", "Brak tokenu API")
end
end
-- Zapis
self:kvSet("cache", data, {secure = false, ttl = 300})
-- Sprawdzenie
if self:kvHas("token") then ... end
-- Lista kluczy
local keys = self:kvList("cache:")
-- Usuń
self:kvDelete("old_key")Go bridge#
| Lua | Go | Opis |
|---|---|---|
kv:get(key) | __go_kv_get(pluginID, key) | Zwraca (value, exists) |
kv:set(key, val, secure, ttl) | __go_kv_set(pluginID, key, val, secure, ttl) | Zapis |
kv:delete(key) | __go_kv_delete(pluginID, key) | Usuwanie |
kv:has(key) | __go_kv_has(pluginID, key) | Sprawdzenie |
kv:list(prefix) | __go_kv_list(pluginID, prefix) | Lista kluczy |
kv:getAll() | __go_kv_get_all(pluginID) | Wszystkie pary |