-- ============================================================= -- R__059_vw_operating_mode.sql -- EMS Platform – views pro provozní režimy a heartbeat -- Repeatable migration -- ============================================================= -- Aktuální EMS provozní režim per lokalita (PostgREST / UI) CREATE OR REPLACE VIEW ems.vw_operating_mode AS SELECT s.id AS site_id, s.code AS site_code, m.mode_code AS active_mode, d.name AS mode_name, d.description AS mode_description, d.is_autonomous, m.activated_at, m.activated_by, m.valid_until, m.previous_mode, m.notes AS mode_notes FROM ems.site s LEFT JOIN ems.site_operating_mode m ON m.site_id = s.id LEFT JOIN ems.operating_mode_def d ON d.code = m.mode_code WHERE s.active = true; COMMENT ON VIEW ems.vw_operating_mode IS 'Aktuální provozní režim EMS per aktivní lokalita (bez telemetrie/heartbeat).'; -- Aktuální stav všech lokalit (pro dashboard a PostgREST) CREATE OR REPLACE VIEW ems.vw_site_status AS SELECT s.id AS site_id, s.code AS site_code, s.name AS site_name, m.mode_code AS active_mode, d.name AS mode_name, d.description AS mode_description, d.is_autonomous, m.activated_at, m.activated_by, m.valid_until, m.previous_mode, m.notes AS mode_notes, -- Heartbeat hb.last_seen AS ems_last_seen, hb.status AS ems_status, EXTRACT(EPOCH FROM (now() - hb.last_seen))::INT AS ems_age_seconds, -- Varování pokud EMS dlouho nepingoval CASE WHEN hb.last_seen IS NULL THEN 'never_seen' WHEN now() - hb.last_seen > INTERVAL '5 minutes' THEN 'stale' WHEN now() - hb.last_seen > INTERVAL '2 minutes' THEN 'delayed' ELSE 'ok' END AS ems_heartbeat_status, -- Aktuální telemetrie (snapshot) li.pv_power_w, li.battery_soc_percent, li.battery_power_w, li.grid_power_w, li.load_power_w, li.measured_at AS telemetry_at FROM ems.site s LEFT JOIN ems.site_operating_mode m ON m.site_id = s.id LEFT JOIN ems.operating_mode_def d ON d.code = m.mode_code LEFT JOIN ems.site_heartbeat hb ON hb.site_id = s.id LEFT JOIN ems.vw_latest_inverter li ON li.site_id = s.id WHERE s.active = true; COMMENT ON VIEW ems.vw_site_status IS 'Kompletní stavový přehled lokality: aktivní režim, heartbeat EMS, aktuální telemetrie. Primární view pro dashboard a health check endpoint. Jeden řádek na aktivní lokalitu. ems_heartbeat_status slouží pro EMS vlastní alerting – Loxone watchdog tuto tabulku nečte, sleduje HTTP pulzy přímo (viz docs/loxone-integration.md).'; -- ============================================================ -- Log přepnutí režimů (pro UI historii) CREATE OR REPLACE VIEW ems.vw_mode_log_recent AS SELECT l.id, l.site_id, s.code AS site_code, l.mode_code, d.name AS mode_name, l.activated_at, l.deactivated_at, EXTRACT(EPOCH FROM COALESCE(l.deactivated_at, now()) - l.activated_at)::INT AS duration_sec, l.activated_by, l.notes FROM ems.site_operating_mode_log l JOIN ems.site s ON s.id = l.site_id JOIN ems.operating_mode_def d ON d.code = l.mode_code WHERE l.activated_at >= now() - INTERVAL '7 days' ORDER BY l.activated_at DESC; COMMENT ON VIEW ems.vw_mode_log_recent IS 'Posledních 7 dní přepnutí provozních režimů. Slouží pro audit log v UI.';