-- ============================================================= -- R__005_fn_cop_estimate.sql -- EMS Platform – odhad COP tepelného čerpadla dle venkovní teploty -- Repeatable migration -- ============================================================= CREATE OR REPLACE FUNCTION ems.fn_cop_estimate( p_heat_pump_id INT, p_outdoor_temp_c NUMERIC ) RETURNS NUMERIC(4,2) LANGUAGE plpgsql STABLE AS $$ DECLARE v_cop_rated NUMERIC; v_cop_ref_temp NUMERIC; v_cop_estimated NUMERIC; BEGIN -- Načíst referenční COP a teplotu z konfigurace čerpadla SELECT cop_rated, cop_temp_reference_c INTO v_cop_rated, v_cop_ref_temp FROM ems.asset_heat_pump WHERE id = p_heat_pump_id; IF v_cop_rated IS NULL OR v_cop_ref_temp IS NULL THEN -- Fallback: obecný odhad pro vzduch-voda TČ bez konfigurace -- Zdroj: přibližná lineární závislost COP na venkovní teplotě -- COP ≈ 2.0 při -10°C, COP ≈ 4.5 při +15°C v_cop_estimated := 2.0 + (p_outdoor_temp_c + 10.0) * (4.5 - 2.0) / 25.0; ELSE -- Lineární interpolace od referenčního bodu -- COP klesá přibližně o 0.10 na každý stupeň poklesu venkovní teploty -- Toto je zjednodušený model – zpřesnit dle skutečných dat z tepelky v_cop_estimated := v_cop_rated + (p_outdoor_temp_c - v_cop_ref_temp) * 0.10; END IF; -- Omezit na rozumné hodnoty (COP vzduch-voda reálně 1.5–6.0) v_cop_estimated := GREATEST(1.5, LEAST(6.0, v_cop_estimated)); RETURN ROUND(v_cop_estimated, 2); END; $$; COMMENT ON FUNCTION ems.fn_cop_estimate(INT, NUMERIC) IS 'Odhadne COP tepelného čerpadla pro danou venkovní teplotu. Používá lineární model od referenčního bodu (cop_rated při cop_temp_reference_c). Výstup slouží k rozhodnutí zda je výhodné spustit TČ v daném intervalu. Přesnost modelu zlepšit kalibrací na historická data (cop_actual z telemetrie). Výsledek omezen na rozsah 1.5–6.0.'; -- ------------------------------------------------------------ CREATE OR REPLACE FUNCTION ems.fn_heat_pump_cost_per_kwh_heat( p_heat_pump_id INT, p_outdoor_temp_c NUMERIC, p_buy_price_czk_kwh NUMERIC ) RETURNS NUMERIC(8,4) LANGUAGE sql STABLE AS $$ -- Cena za 1 kWh tepla = cena elektřiny / COP -- Čím vyšší COP, tím levnější teplo SELECT ROUND( p_buy_price_czk_kwh / NULLIF(ems.fn_cop_estimate(p_heat_pump_id, p_outdoor_temp_c), 0), 4 ); $$; COMMENT ON FUNCTION ems.fn_heat_pump_cost_per_kwh_heat(INT, NUMERIC, NUMERIC) IS 'Vypočte efektivní cenu za 1 kWh dodaného tepla v Kč. Vstup: ID tepelného čerpadla, venkovní teplota, nákupní cena elektřiny. Výstup slouží k porovnání výhodnosti ohřevu v různých časových intervalech. Nižší hodnota = výhodnější čas pro provoz TČ.'; -- ------------------------------------------------------------ CREATE OR REPLACE FUNCTION ems.fn_heat_pump_should_run( p_heat_pump_id INT, p_interval_start TIMESTAMPTZ, p_outdoor_temp_c NUMERIC, p_tuv_tank_temp_c NUMERIC, p_buy_price_czk_kwh NUMERIC, p_max_cost_threshold NUMERIC DEFAULT 3.0 -- Kč/kWh tepla – maximální akceptovatelná cena ) RETURNS BOOLEAN LANGUAGE plpgsql STABLE AS $$ DECLARE v_hp ems.asset_heat_pump%ROWTYPE; v_cost_per_kwh NUMERIC; v_override BOOLEAN; BEGIN SELECT * INTO v_hp FROM ems.asset_heat_pump WHERE id = p_heat_pump_id; -- Kontrola override (blokování TČ) SELECT EXISTS( SELECT 1 FROM ems.site_override WHERE site_id = v_hp.site_id AND override_type = 'block_heat_pump' AND valid_from <= p_interval_start AND (valid_to IS NULL OR valid_to > p_interval_start) ) INTO v_override; IF v_override THEN RETURN false; END IF; -- Povinný ohřev: teplota pod minimem IF p_tuv_tank_temp_c IS NOT NULL AND p_tuv_tank_temp_c < v_hp.tuv_min_temp_c THEN RETURN true; END IF; -- Zásobník je plný IF p_tuv_tank_temp_c IS NOT NULL AND p_tuv_tank_temp_c >= v_hp.tuv_max_temp_c THEN RETURN false; END IF; -- Ekonomické rozhodnutí: spustit pokud cena tepla je pod prahem v_cost_per_kwh := ems.fn_heat_pump_cost_per_kwh_heat( p_heat_pump_id, p_outdoor_temp_c, p_buy_price_czk_kwh ); RETURN v_cost_per_kwh <= p_max_cost_threshold; END; $$; COMMENT ON FUNCTION ems.fn_heat_pump_should_run(INT, TIMESTAMPTZ, NUMERIC, NUMERIC, NUMERIC, NUMERIC) IS 'Rozhodne zda má tepelné čerpadlo v daném intervalu běžet. Logika priorit: 1. Pokud existuje override block_heat_pump → false. 2. Pokud teplota zásobníku pod tuv_min_temp_c → true (povinný ohřev). 3. Pokud zásobník nad tuv_max_temp_c → false. 4. Jinak ekonomické rozhodnutí: spustit pokud cena tepla ≤ p_max_cost_threshold Kč/kWh. Výhodné časy jsou přes poledne v chladných měsících (vyšší venkovní teplota = lepší COP).';