Initial commit

Made-with: Cursor
This commit is contained in:
Dusan Vojacek
2026-03-20 13:27:37 +01:00
commit 8b4af663d8
77 changed files with 13337 additions and 0 deletions

View File

@@ -0,0 +1,137 @@
-- =============================================================
-- R__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.56.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.56.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).';