169 lines
5.6 KiB
PL/PgSQL
169 lines
5.6 KiB
PL/PgSQL
-- =============================================================
|
||
-- R__fn_set_mode.sql
|
||
-- EMS Platform – přepínání provozních režimů
|
||
-- Repeatable migration
|
||
-- =============================================================
|
||
|
||
CREATE OR REPLACE FUNCTION ems.fn_set_mode(
|
||
p_site_id INT,
|
||
p_mode_code TEXT,
|
||
p_activated_by TEXT DEFAULT 'system',
|
||
p_valid_until TIMESTAMPTZ DEFAULT NULL,
|
||
p_notes TEXT DEFAULT NULL
|
||
)
|
||
RETURNS TEXT
|
||
LANGUAGE plpgsql
|
||
AS $$
|
||
DECLARE
|
||
v_current_mode TEXT;
|
||
v_mode_exists BOOLEAN;
|
||
BEGIN
|
||
-- Ověřit že režim existuje
|
||
SELECT EXISTS(SELECT 1 FROM ems.operating_mode_def WHERE code = p_mode_code)
|
||
INTO v_mode_exists;
|
||
|
||
IF NOT v_mode_exists THEN
|
||
RAISE EXCEPTION 'Neznámý provozní režim: %', p_mode_code;
|
||
END IF;
|
||
|
||
-- Zjistit aktuální režim (pro log a previous_mode)
|
||
SELECT mode_code INTO v_current_mode
|
||
FROM ems.site_operating_mode
|
||
WHERE site_id = p_site_id;
|
||
|
||
-- Pokud se režim nemění, nic nedělat
|
||
IF v_current_mode = p_mode_code THEN
|
||
RETURN p_mode_code;
|
||
END IF;
|
||
|
||
-- Uzavřít předchozí záznam v logu
|
||
UPDATE ems.site_operating_mode_log
|
||
SET deactivated_at = now()
|
||
WHERE site_id = p_site_id
|
||
AND deactivated_at IS NULL;
|
||
|
||
-- Upsert aktivního režimu
|
||
INSERT INTO ems.site_operating_mode
|
||
(site_id, mode_code, activated_at, activated_by, valid_until, previous_mode, notes)
|
||
VALUES
|
||
(p_site_id, p_mode_code, now(), p_activated_by, p_valid_until, v_current_mode, p_notes)
|
||
ON CONFLICT (site_id) DO UPDATE SET
|
||
mode_code = EXCLUDED.mode_code,
|
||
activated_at = EXCLUDED.activated_at,
|
||
activated_by = EXCLUDED.activated_by,
|
||
valid_until = EXCLUDED.valid_until,
|
||
previous_mode = EXCLUDED.previous_mode,
|
||
notes = EXCLUDED.notes;
|
||
|
||
-- Přidat záznam do logu
|
||
INSERT INTO ems.site_operating_mode_log
|
||
(site_id, mode_code, activated_at, activated_by, notes)
|
||
VALUES
|
||
(p_site_id, p_mode_code, now(), p_activated_by, p_notes);
|
||
|
||
RETURN p_mode_code;
|
||
END;
|
||
$$;
|
||
|
||
COMMENT ON FUNCTION ems.fn_set_mode(INT, TEXT, TEXT, TIMESTAMPTZ, TEXT) IS
|
||
'Přepne provozní režim lokality. Atomicky aktualizuje site_operating_mode a zapíše do audit logu.
|
||
Ignoruje přepnutí na stejný režim. Vyhodí výjimku pro neznámý kód režimu.
|
||
Příklad: SELECT ems.fn_set_mode(1, ''SELF_SUSTAIN'', ''user:jan'', NULL, ''Odjezd na dovolenou'');';
|
||
|
||
-- ============================================================
|
||
|
||
CREATE OR REPLACE FUNCTION ems.fn_restore_previous_mode(
|
||
p_site_id INT,
|
||
p_activated_by TEXT DEFAULT 'system'
|
||
)
|
||
RETURNS TEXT
|
||
LANGUAGE plpgsql
|
||
AS $$
|
||
DECLARE
|
||
v_previous TEXT;
|
||
BEGIN
|
||
SELECT previous_mode INTO v_previous
|
||
FROM ems.site_operating_mode
|
||
WHERE site_id = p_site_id;
|
||
|
||
IF v_previous IS NULL THEN
|
||
-- Fallback na AUTO pokud není předchozí režim
|
||
v_previous := 'AUTO';
|
||
END IF;
|
||
|
||
RETURN ems.fn_set_mode(p_site_id, v_previous, p_activated_by, NULL, 'Obnova předchozího režimu');
|
||
END;
|
||
$$;
|
||
|
||
COMMENT ON FUNCTION ems.fn_restore_previous_mode(INT, TEXT) IS
|
||
'Přepne lokalitu zpět na předchozí provozní režim (uložený v previous_mode).
|
||
Pokud předchozí režim neexistuje, přepne na AUTO. Používat po skončení dočasného přepisu.';
|
||
|
||
-- ============================================================
|
||
|
||
drop function if exists ems.fn_expire_modes();
|
||
|
||
CREATE OR REPLACE FUNCTION ems.fn_expire_modes()
|
||
RETURNS TABLE(site_id INT, site_code TEXT, old_mode TEXT, new_mode TEXT)
|
||
LANGUAGE plpgsql
|
||
AS $$
|
||
DECLARE
|
||
v_rec RECORD;
|
||
v_new_mode TEXT;
|
||
BEGIN
|
||
FOR v_rec IN
|
||
SELECT som.site_id,
|
||
s.code AS site_code,
|
||
som.mode_code AS old_mode,
|
||
som.previous_mode
|
||
FROM ems.site_operating_mode som
|
||
JOIN ems.site s ON s.id = som.site_id
|
||
WHERE som.valid_until IS NOT NULL
|
||
AND som.valid_until <= now()
|
||
AND som.mode_code <> 'AUTO'
|
||
LOOP
|
||
v_new_mode := COALESCE(v_rec.previous_mode, 'AUTO');
|
||
PERFORM ems.fn_set_mode(
|
||
v_rec.site_id,
|
||
v_new_mode,
|
||
'system:expiry',
|
||
NULL,
|
||
'Automatické vypršení dočasného režimu'
|
||
);
|
||
site_id := v_rec.site_id;
|
||
site_code := v_rec.site_code;
|
||
old_mode := v_rec.old_mode;
|
||
new_mode := v_new_mode;
|
||
RETURN NEXT;
|
||
END LOOP;
|
||
END;
|
||
$$;
|
||
|
||
COMMENT ON FUNCTION ems.fn_expire_modes() IS
|
||
'Zkontroluje všechny lokality s dočasným režimem (valid_until IS NOT NULL) a přepne zpět ty s prosahlým časem.
|
||
Volat každou minutu jako scheduled task. Vrátí řádky (site_id, site_code, old_mode, new_mode) pro každé provedené přepnutí — backend z toho pošle Discord notifikace.';
|
||
|
||
-- ============================================================
|
||
|
||
CREATE OR REPLACE FUNCTION ems.fn_update_heartbeat(
|
||
p_site_id INT,
|
||
p_status TEXT DEFAULT 'ok',
|
||
p_ems_version TEXT DEFAULT NULL
|
||
)
|
||
RETURNS VOID
|
||
LANGUAGE sql
|
||
AS $$
|
||
INSERT INTO ems.site_heartbeat (site_id, last_seen, status, ems_version)
|
||
VALUES (p_site_id, now(), p_status, p_ems_version)
|
||
ON CONFLICT (site_id) DO UPDATE SET
|
||
last_seen = now(),
|
||
status = EXCLUDED.status,
|
||
ems_version = COALESCE(EXCLUDED.ems_version, ems.site_heartbeat.ems_version);
|
||
$$;
|
||
|
||
COMMENT ON FUNCTION ems.fn_update_heartbeat(INT, TEXT, TEXT) IS
|
||
'Aktualizuje informační heartbeat záznam EMS pro danou lokalitu.
|
||
Volat každou minutu z backend service po úspěšném odeslání pulzu do Loxone.
|
||
Slouží pouze pro EMS dashboard – Loxone watchdog nezávisí na této tabulce,
|
||
sleduje HTTP pulzy přímo a nezávisle na dostupnosti DB.';
|