CREATE SCHEMA IF NOT EXISTS mv_hot; CREATE TABLE IF NOT EXISTS mv_hot.edge_oee_eastron_readings ( id BIGSERIAL PRIMARY KEY, ts TIMESTAMPTZ NOT NULL DEFAULT now(), tenant TEXT NOT NULL DEFAULT 'ucepsa', site TEXT NOT NULL DEFAULT 'demo_edge_oee', asset TEXT NOT NULL DEFAULT 'revpi_eastron_demo', source TEXT NOT NULL DEFAULT 'eastron_reader', meter_model TEXT, meter_id TEXT, machine_id TEXT NULL, order_id TEXT NULL, voltage_l1_v NUMERIC(10,3), voltage_l2_v NUMERIC(10,3), voltage_l3_v NUMERIC(10,3), current_l1_a NUMERIC(10,3), current_l2_a NUMERIC(10,3), current_l3_a NUMERIC(10,3), power_l1_kw NUMERIC(10,3), power_l2_kw NUMERIC(10,3), power_l3_kw NUMERIC(10,3), power_total_kw NUMERIC(10,3), frequency_hz NUMERIC(10,3), import_kwh NUMERIC(14,3), export_kwh NUMERIC(14,3), comm_ok BOOLEAN NOT NULL DEFAULT true, error_text TEXT, payload_json JSONB NOT NULL DEFAULT '{}'::jsonb, ingest_ts TIMESTAMPTZ NOT NULL DEFAULT now() ); CREATE INDEX IF NOT EXISTS idx_edge_oee_eastron_readings_ts ON mv_hot.edge_oee_eastron_readings(ts DESC); CREATE INDEX IF NOT EXISTS idx_edge_oee_eastron_readings_asset_ts ON mv_hot.edge_oee_eastron_readings(asset, ts DESC); CREATE OR REPLACE VIEW mv_hot.edge_oee_eastron_latest AS SELECT DISTINCT ON (asset) * FROM mv_hot.edge_oee_eastron_readings ORDER BY asset, ts DESC; CREATE OR REPLACE VIEW mv_hot.edge_oee_eastron_dashboard AS SELECT ts, EXTRACT(EPOCH FROM (now() - ts))::int AS age_s, tenant, site, asset, meter_model, meter_id, machine_id, voltage_l1_v, voltage_l2_v, voltage_l3_v, current_l1_a, current_l2_a, current_l3_a, power_total_kw, frequency_hz, import_kwh, export_kwh, comm_ok, error_text, CASE WHEN comm_ok = false THEN 2 WHEN EXTRACT(EPOCH FROM (now() - ts)) > 180 THEN 2 WHEN EXTRACT(EPOCH FROM (now() - ts)) > 60 THEN 1 ELSE 0 END AS comm_risk_level, CASE WHEN comm_ok = false THEN 'Sin comunicación Modbus' WHEN EXTRACT(EPOCH FROM (now() - ts)) > 180 THEN 'Lectura antigua' WHEN EXTRACT(EPOCH FROM (now() - ts)) > 60 THEN 'Lectura no reciente' ELSE 'Comunicación correcta' END AS comm_status FROM mv_hot.edge_oee_eastron_latest; CREATE OR REPLACE VIEW mv_hot.edge_oee_eastron_diagnosis_latest AS SELECT 1 AS sort_order, 'Comunicación' AS group_name, 'Edad último dato' AS metric, age_s::numeric AS value, 's' AS unit, CASE WHEN comm_risk_level = 0 THEN 'OK' WHEN comm_risk_level = 1 THEN 'Warning' ELSE 'Peligro' END AS status, CASE WHEN comm_risk_level = 0 THEN 'Lectura reciente desde Eastron' ELSE 'La lectura no es reciente o hay fallo de comunicación' END AS problem, CASE WHEN comm_risk_level = 0 THEN 'La captura industrial está viva' ELSE 'El dashboard puede estar mostrando un valor antiguo' END AS likely_impact, CASE WHEN comm_risk_level = 0 THEN 'Sin acción' ELSE 'Revisar RevPi, RS-485, alimentación del Eastron, parámetros Modbus y logs del lector' END AS recommended_action FROM mv_hot.edge_oee_eastron_dashboard UNION ALL SELECT 2, 'Energía', 'Potencia total', power_total_kw, 'kW', CASE WHEN power_total_kw IS NULL THEN 'Warning' ELSE 'OK' END, CASE WHEN power_total_kw IS NULL THEN 'No hay potencia total disponible' ELSE 'Potencia total leída correctamente' END, CASE WHEN power_total_kw IS NULL THEN 'No se puede validar carga eléctrica' ELSE 'Permite demostrar captura energética industrial' END, CASE WHEN power_total_kw IS NULL THEN 'Revisar mapa de registros Modbus' ELSE 'Sin acción' END FROM mv_hot.edge_oee_eastron_dashboard;