uprava adutiu - nacitani dalsich registru, uprava ekonomiky
This commit is contained in:
38
db/migration/V040__energy_wh_columns.sql
Normal file
38
db/migration/V040__energy_wh_columns.sql
Normal file
@@ -0,0 +1,38 @@
|
||||
-- =============================================================
|
||||
-- V040 – Energy Wh columns
|
||||
-- Přidává kumulativní čítače grid energie do telemetrie
|
||||
-- a per-slot Wh sloupce do audit_interval pro přesné
|
||||
-- import/export měření (Deye reg 522-525 + per-minute fallback).
|
||||
-- =============================================================
|
||||
|
||||
-- 1. telemetry_inverter: kumulativní Deye lifetime čítače
|
||||
ALTER TABLE ems.telemetry_inverter
|
||||
ADD COLUMN IF NOT EXISTS grid_import_total_wh BIGINT,
|
||||
ADD COLUMN IF NOT EXISTS grid_export_total_wh BIGINT;
|
||||
|
||||
COMMENT ON COLUMN ems.telemetry_inverter.grid_import_total_wh IS
|
||||
'Kumulativní import ze sítě (Wh) z Deye reg 522+523 (32-bit × 0.1 kWh). Lifetime čítač, monotónně rostoucí.';
|
||||
COMMENT ON COLUMN ems.telemetry_inverter.grid_export_total_wh IS
|
||||
'Kumulativní export do sítě (Wh) z Deye reg 524+525 (32-bit × 0.1 kWh). Lifetime čítač, monotónně rostoucí.';
|
||||
|
||||
-- 2. audit_interval: 6 základních energetických veličin (Wh za 15min slot)
|
||||
ALTER TABLE ems.audit_interval
|
||||
ADD COLUMN IF NOT EXISTS actual_grid_import_wh NUMERIC(10,1),
|
||||
ADD COLUMN IF NOT EXISTS actual_grid_export_wh NUMERIC(10,1),
|
||||
ADD COLUMN IF NOT EXISTS actual_batt_charge_wh NUMERIC(10,1),
|
||||
ADD COLUMN IF NOT EXISTS actual_batt_discharge_wh NUMERIC(10,1),
|
||||
ADD COLUMN IF NOT EXISTS actual_pv_production_wh NUMERIC(10,1),
|
||||
ADD COLUMN IF NOT EXISTS actual_load_consumption_wh NUMERIC(10,1);
|
||||
|
||||
COMMENT ON COLUMN ems.audit_interval.actual_grid_import_wh IS
|
||||
'Import ze sítě za 15min slot (Wh). Primárně z delta Deye total counterů (reg 522+523), fallback per-minutový split z grid_power_w.';
|
||||
COMMENT ON COLUMN ems.audit_interval.actual_grid_export_wh IS
|
||||
'Export do sítě za 15min slot (Wh). Primárně z delta Deye total counterů (reg 524+525), fallback per-minutový split z grid_power_w.';
|
||||
COMMENT ON COLUMN ems.audit_interval.actual_batt_charge_wh IS
|
||||
'Nabití baterie za 15min slot (Wh). Per-minutový split z battery_power_w (záporné = nabíjení).';
|
||||
COMMENT ON COLUMN ems.audit_interval.actual_batt_discharge_wh IS
|
||||
'Vybití baterie za 15min slot (Wh). Per-minutový split z battery_power_w (kladné = vybíjení).';
|
||||
COMMENT ON COLUMN ems.audit_interval.actual_pv_production_wh IS
|
||||
'FVE výroba za 15min slot (Wh). SUM(pv_power_w) / 60 z minutových vzorků.';
|
||||
COMMENT ON COLUMN ems.audit_interval.actual_load_consumption_wh IS
|
||||
'Celková spotřeba za 15min slot (Wh). SUM(load_power_w) / 60 z minutových vzorků.';
|
||||
13
db/migration/V041__audit_day_lock_grid_direction.sql
Normal file
13
db/migration/V041__audit_day_lock_grid_direction.sql
Normal file
@@ -0,0 +1,13 @@
|
||||
-- =============================================================
|
||||
-- V041 – audit_day_lock: směrové cashflow sloupce
|
||||
-- Snapshot pro zamknuté dny rozšířen o cashflow podle směru energie.
|
||||
-- =============================================================
|
||||
|
||||
ALTER TABLE ems.audit_day_lock
|
||||
ADD COLUMN IF NOT EXISTS grid_import_cashflow_czk NUMERIC(12,2),
|
||||
ADD COLUMN IF NOT EXISTS grid_export_revenue_czk NUMERIC(12,2);
|
||||
|
||||
COMMENT ON COLUMN ems.audit_day_lock.grid_import_cashflow_czk IS
|
||||
'Snapshot: celková cena za import ze sítě v Kč (může být záporná při záporné spotové ceně).';
|
||||
COMMENT ON COLUMN ems.audit_day_lock.grid_export_revenue_czk IS
|
||||
'Snapshot: celkový příjem z exportu do sítě v Kč.';
|
||||
@@ -29,6 +29,22 @@ DECLARE
|
||||
v_pv_b_production_wh NUMERIC;
|
||||
v_array_prod_wh NUMERIC;
|
||||
r_bonus RECORD;
|
||||
|
||||
-- per-minute Wh veličiny
|
||||
v_grid_import_wh NUMERIC;
|
||||
v_grid_export_wh NUMERIC;
|
||||
v_batt_charge_wh NUMERIC;
|
||||
v_batt_discharge_wh NUMERIC;
|
||||
v_pv_production_wh NUMERIC;
|
||||
v_load_consumption_wh NUMERIC;
|
||||
|
||||
-- Deye counter delta
|
||||
v_counter_import_first BIGINT;
|
||||
v_counter_import_last BIGINT;
|
||||
v_counter_export_first BIGINT;
|
||||
v_counter_export_last BIGINT;
|
||||
v_delta_import NUMERIC;
|
||||
v_delta_export NUMERIC;
|
||||
BEGIN
|
||||
-- Najít aktivní plán pro tento interval
|
||||
SELECT pi.* INTO v_plan
|
||||
@@ -42,24 +58,58 @@ BEGIN
|
||||
|
||||
v_run_id := v_plan.run_id;
|
||||
|
||||
-- Agregovat telemetrii střídače (průměr za 15min; agregace bez GROUP BY vrací vždy 1 řádek)
|
||||
-- Agregovat telemetrii střídače: průměry (pro zpětnou kompatibilitu) + per-minute split pro Wh
|
||||
SELECT
|
||||
AVG(pv_power_w)::INT,
|
||||
AVG(battery_power_w)::INT,
|
||||
AVG(grid_power_w)::INT,
|
||||
AVG(load_power_w)::INT,
|
||||
LAST(battery_soc_percent, measured_at)
|
||||
LAST(battery_soc_percent, measured_at),
|
||||
-- Per-minute split: každý vzorek × 1/60 h = Wh
|
||||
ROUND(SUM(GREATEST(grid_power_w, 0))::NUMERIC / 60, 1),
|
||||
ROUND(SUM(ABS(LEAST(grid_power_w, 0)))::NUMERIC / 60, 1),
|
||||
ROUND(SUM(ABS(LEAST(battery_power_w, 0)))::NUMERIC / 60, 1),
|
||||
ROUND(SUM(GREATEST(battery_power_w, 0))::NUMERIC / 60, 1),
|
||||
ROUND(SUM(GREATEST(pv_power_w, 0))::NUMERIC / 60, 1),
|
||||
ROUND(SUM(GREATEST(load_power_w, 0))::NUMERIC / 60, 1),
|
||||
-- Deye total energy counter delta
|
||||
FIRST(grid_import_total_wh, measured_at),
|
||||
LAST(grid_import_total_wh, measured_at),
|
||||
FIRST(grid_export_total_wh, measured_at),
|
||||
LAST(grid_export_total_wh, measured_at)
|
||||
INTO
|
||||
v_avg_pv_power_w,
|
||||
v_avg_battery_power_w,
|
||||
v_avg_grid_power_w,
|
||||
v_avg_load_power_w,
|
||||
v_last_soc
|
||||
v_last_soc,
|
||||
v_grid_import_wh,
|
||||
v_grid_export_wh,
|
||||
v_batt_charge_wh,
|
||||
v_batt_discharge_wh,
|
||||
v_pv_production_wh,
|
||||
v_load_consumption_wh,
|
||||
v_counter_import_first,
|
||||
v_counter_import_last,
|
||||
v_counter_export_first,
|
||||
v_counter_export_last
|
||||
FROM ems.telemetry_inverter
|
||||
WHERE site_id = p_site_id
|
||||
AND measured_at >= p_interval_start
|
||||
AND measured_at < v_interval_end;
|
||||
|
||||
-- Deye counter delta (primární zdroj pro grid import/export, pokud jsou čítače dostupné)
|
||||
IF v_counter_import_first IS NOT NULL AND v_counter_import_last IS NOT NULL
|
||||
AND v_counter_import_last >= v_counter_import_first THEN
|
||||
v_delta_import := v_counter_import_last - v_counter_import_first;
|
||||
v_grid_import_wh := v_delta_import;
|
||||
END IF;
|
||||
IF v_counter_export_first IS NOT NULL AND v_counter_export_last IS NOT NULL
|
||||
AND v_counter_export_last >= v_counter_export_first THEN
|
||||
v_delta_export := v_counter_export_last - v_counter_export_first;
|
||||
v_grid_export_wh := v_delta_export;
|
||||
END IF;
|
||||
|
||||
-- Agregovat EV nabíječky (součet průměrů po charger_id)
|
||||
SELECT COALESCE(SUM(avg_power), 0)::INT
|
||||
INTO v_sum_ev_power_w
|
||||
@@ -84,12 +134,10 @@ BEGIN
|
||||
v_buy_price := ems.fn_effective_buy_price(p_site_id, p_interval_start);
|
||||
v_sell_price := ems.fn_effective_sell_price(p_site_id, p_interval_start);
|
||||
|
||||
-- Skutečné náklady (kladný grid = nákup, záporný = prodej)
|
||||
IF v_avg_grid_power_w IS NOT NULL THEN
|
||||
v_actual_cost := (v_avg_grid_power_w::NUMERIC / 1000.0 / 4.0)
|
||||
* CASE WHEN v_avg_grid_power_w >= 0
|
||||
THEN COALESCE(v_buy_price, 0)
|
||||
ELSE COALESCE(v_sell_price, 0) END;
|
||||
-- Skutečné náklady per-direction (import × buy - export × sell)
|
||||
IF v_grid_import_wh IS NOT NULL OR v_grid_export_wh IS NOT NULL THEN
|
||||
v_actual_cost := COALESCE(v_grid_import_wh, 0) / 1000.0 * COALESCE(v_buy_price, 0)
|
||||
- COALESCE(v_grid_export_wh, 0) / 1000.0 * COALESCE(v_sell_price, 0);
|
||||
END IF;
|
||||
|
||||
-- Zelený bonus: výroba bonusových polí z reálné telemetrie (Wh = průměr W × 0,25 h)
|
||||
@@ -122,7 +170,6 @@ BEGIN
|
||||
AND ti.measured_at < v_interval_end;
|
||||
END IF;
|
||||
|
||||
-- Fallback na forecast pokud telemetrie není k dispozici
|
||||
IF v_array_prod_wh IS NULL THEN
|
||||
SELECT fpi.power_w * 0.25
|
||||
INTO v_array_prod_wh
|
||||
@@ -160,7 +207,13 @@ BEGIN
|
||||
pv_b_production_wh,
|
||||
green_bonus_czk,
|
||||
deviation_grid_w,
|
||||
deviation_cost_czk
|
||||
deviation_cost_czk,
|
||||
actual_grid_import_wh,
|
||||
actual_grid_export_wh,
|
||||
actual_batt_charge_wh,
|
||||
actual_batt_discharge_wh,
|
||||
actual_pv_production_wh,
|
||||
actual_load_consumption_wh
|
||||
) VALUES (
|
||||
p_site_id, p_interval_start, v_run_id,
|
||||
v_avg_pv_power_w,
|
||||
@@ -178,7 +231,13 @@ BEGIN
|
||||
ELSE NULL END,
|
||||
CASE WHEN v_plan.run_id IS NOT NULL
|
||||
THEN ROUND(v_actual_cost - COALESCE(v_plan.expected_cost_czk, 0), 4)
|
||||
ELSE NULL END
|
||||
ELSE NULL END,
|
||||
v_grid_import_wh,
|
||||
v_grid_export_wh,
|
||||
v_batt_charge_wh,
|
||||
v_batt_discharge_wh,
|
||||
v_pv_production_wh,
|
||||
v_load_consumption_wh
|
||||
)
|
||||
ON CONFLICT (site_id, interval_start) DO UPDATE SET
|
||||
planning_run_id = EXCLUDED.planning_run_id,
|
||||
@@ -193,15 +252,23 @@ BEGIN
|
||||
pv_b_production_wh = EXCLUDED.pv_b_production_wh,
|
||||
green_bonus_czk = EXCLUDED.green_bonus_czk,
|
||||
deviation_grid_w = EXCLUDED.deviation_grid_w,
|
||||
deviation_cost_czk = EXCLUDED.deviation_cost_czk;
|
||||
deviation_cost_czk = EXCLUDED.deviation_cost_czk,
|
||||
actual_grid_import_wh = EXCLUDED.actual_grid_import_wh,
|
||||
actual_grid_export_wh = EXCLUDED.actual_grid_export_wh,
|
||||
actual_batt_charge_wh = EXCLUDED.actual_batt_charge_wh,
|
||||
actual_batt_discharge_wh = EXCLUDED.actual_batt_discharge_wh,
|
||||
actual_pv_production_wh = EXCLUDED.actual_pv_production_wh,
|
||||
actual_load_consumption_wh = EXCLUDED.actual_load_consumption_wh;
|
||||
END;
|
||||
$$;
|
||||
|
||||
COMMENT ON FUNCTION ems.fn_fill_audit_interval(INT, TIMESTAMPTZ) IS
|
||||
'Naplní nebo aktualizuje jeden řádek v audit_interval pro danou lokalitu a 15min interval.
|
||||
Agreguje průměry z telemetrie (střídač, EV, TČ), porovná se skutečným plánem a spočítá odchylky.
|
||||
Zelený bonus: součet přes pole s green_bonus_czk_kwh; výroba primárně z reálné telemetrie
|
||||
(dle asset_pv_array.telemetry_source), fallback na forecast_pv_interval pokud telemetrie chybí.
|
||||
Nově: per-minutový split pro 6 energetických veličin (import/export/batt/PV/load Wh);
|
||||
grid import/export primárně z delta Deye total counterů (reg 522-525), fallback per-minute.
|
||||
actual_cost_czk = per-direction (import_wh × buy - export_wh × sell).
|
||||
Zelený bonus: součet přes pole s green_bonus_czk_kwh.
|
||||
Volat každých 15 minut pro interval který právě skončil.';
|
||||
|
||||
-- ============================================================
|
||||
|
||||
@@ -9,14 +9,27 @@ CREATE OR REPLACE VIEW ems.vw_economics_interval AS
|
||||
SELECT
|
||||
ai.site_id,
|
||||
ai.interval_start,
|
||||
ROUND(GREATEST(ai.actual_grid_power_w, 0)::NUMERIC / 4000, 4) AS import_kwh,
|
||||
ROUND(ABS(LEAST(ai.actual_grid_power_w, 0))::NUMERIC / 4000, 4) AS export_kwh,
|
||||
CASE WHEN ai.actual_grid_power_w >= 0
|
||||
THEN ROUND((ai.actual_grid_power_w::NUMERIC / 4000)
|
||||
* COALESCE(ep.effective_buy_price_czk_kwh, 0), 4)
|
||||
ELSE ROUND((ai.actual_grid_power_w::NUMERIC / 4000)
|
||||
* COALESCE(ep.effective_sell_price_czk_kwh, 0), 4)
|
||||
END AS dynamic_cost_czk,
|
||||
-- Wh-based kWh (per-direction, zachytí bidirectional flow)
|
||||
ROUND(COALESCE(ai.actual_grid_import_wh, GREATEST(ai.actual_grid_power_w, 0)::NUMERIC / 4) / 1000, 4)
|
||||
AS import_kwh,
|
||||
ROUND(COALESCE(ai.actual_grid_export_wh, ABS(LEAST(ai.actual_grid_power_w, 0))::NUMERIC / 4) / 1000, 4)
|
||||
AS export_kwh,
|
||||
-- Směrové cashflow: kolik Kč za import ze sítě / kolik Kč za export do sítě
|
||||
ROUND(
|
||||
COALESCE(ai.actual_grid_import_wh, GREATEST(ai.actual_grid_power_w, 0)::NUMERIC / 4)
|
||||
/ 1000.0 * COALESCE(ep.effective_buy_price_czk_kwh, 0), 4
|
||||
) AS grid_import_cashflow_czk,
|
||||
ROUND(
|
||||
COALESCE(ai.actual_grid_export_wh, ABS(LEAST(ai.actual_grid_power_w, 0))::NUMERIC / 4)
|
||||
/ 1000.0 * COALESCE(ep.effective_sell_price_czk_kwh, 0), 4
|
||||
) AS grid_export_revenue_czk,
|
||||
-- Net cost (zpětná kompatibilita): import_cashflow - export_revenue
|
||||
ROUND(
|
||||
COALESCE(ai.actual_grid_import_wh, GREATEST(ai.actual_grid_power_w, 0)::NUMERIC / 4)
|
||||
/ 1000.0 * COALESCE(ep.effective_buy_price_czk_kwh, 0)
|
||||
- COALESCE(ai.actual_grid_export_wh, ABS(LEAST(ai.actual_grid_power_w, 0))::NUMERIC / 4)
|
||||
/ 1000.0 * COALESCE(ep.effective_sell_price_czk_kwh, 0), 4
|
||||
) AS dynamic_cost_czk,
|
||||
ai.actual_cost_czk AS stored_cost_czk,
|
||||
ai.green_bonus_czk,
|
||||
pi.expected_cost_czk AS planned_cost_czk,
|
||||
@@ -31,7 +44,13 @@ SELECT
|
||||
ai.actual_ev_power_w,
|
||||
ai.actual_heat_pump_power_w,
|
||||
ai.actual_battery_power_w,
|
||||
ai.actual_battery_soc_pct
|
||||
ai.actual_battery_soc_pct,
|
||||
ai.actual_grid_import_wh,
|
||||
ai.actual_grid_export_wh,
|
||||
ai.actual_batt_charge_wh,
|
||||
ai.actual_batt_discharge_wh,
|
||||
ai.actual_pv_production_wh,
|
||||
ai.actual_load_consumption_wh
|
||||
FROM ems.audit_interval ai
|
||||
LEFT JOIN ems.vw_site_effective_price ep
|
||||
ON ep.site_id = ai.site_id AND ep.interval_start = ai.interval_start
|
||||
@@ -39,7 +58,10 @@ LEFT JOIN ems.planning_interval pi
|
||||
ON pi.run_id = ai.planning_run_id AND pi.interval_start = ai.interval_start;
|
||||
|
||||
COMMENT ON VIEW ems.vw_economics_interval IS
|
||||
'Dynamické ekonomické vyhodnocení per 15min slot (závisí na vw_site_effective_price).';
|
||||
'Dynamické ekonomické vyhodnocení per 15min slot.
|
||||
import/export kWh primárně z per-direction Wh sloupců audit_interval (Deye counter / per-minute split),
|
||||
fallback na průměrný výkon pro zpětnou kompatibilitu se starými daty.
|
||||
grid_import_cashflow_czk / grid_export_revenue_czk = směrové cashflow podle skutečného toku energie.';
|
||||
|
||||
CREATE OR REPLACE VIEW ems.vw_economics_daily AS
|
||||
SELECT
|
||||
@@ -53,7 +75,11 @@ SELECT
|
||||
ROUND(SUM(GREATEST(actual_ev_power_w, 0)::NUMERIC / 4000), 3) AS ev_kwh,
|
||||
ROUND(SUM(GREATEST(actual_heat_pump_power_w, 0)::NUMERIC / 4000), 3) AS hp_kwh,
|
||||
ROUND(SUM(GREATEST(actual_pv_power_w, 0)::NUMERIC / 4000)
|
||||
- SUM(export_kwh), 3) AS self_consumption_kwh,
|
||||
- SUM(export_kwh), 3) AS pv_self_consumption_kwh,
|
||||
-- Směrové cashflow (podle směru energie, ne znaménka peněz)
|
||||
ROUND(SUM(grid_import_cashflow_czk), 2) AS grid_import_cashflow_czk,
|
||||
ROUND(SUM(grid_export_revenue_czk), 2) AS grid_export_revenue_czk,
|
||||
-- Staré sloupce (podle znaménka peněz – zpětná kompatibilita)
|
||||
ROUND(SUM(CASE WHEN dynamic_cost_czk > 0
|
||||
THEN dynamic_cost_czk ELSE 0 END), 2) AS import_cost_czk,
|
||||
ROUND(SUM(CASE WHEN dynamic_cost_czk < 0
|
||||
@@ -63,8 +89,7 @@ SELECT
|
||||
ROUND(-SUM(dynamic_cost_czk)
|
||||
+ COALESCE(SUM(green_bonus_czk), 0), 2) AS total_balance_czk,
|
||||
ROUND(SUM(planned_cost_czk), 2) AS planned_net_cost_czk,
|
||||
ROUND(-COALESCE(SUM(planned_cost_czk), 0)
|
||||
+ COALESCE(SUM(green_bonus_czk), 0), 2) AS planned_balance_czk,
|
||||
ROUND(-COALESCE(SUM(planned_cost_czk), 0), 2) AS planned_balance_czk,
|
||||
ROUND(SUM(dynamic_cost_czk)
|
||||
- COALESCE(SUM(planned_cost_czk), 0), 2) AS deviation_cost_czk
|
||||
FROM ems.vw_economics_interval
|
||||
@@ -72,4 +97,5 @@ GROUP BY site_id,
|
||||
date_trunc('day', interval_start AT TIME ZONE 'Europe/Prague')::date;
|
||||
|
||||
COMMENT ON VIEW ems.vw_economics_daily IS
|
||||
'Denní souhrn ekonomiky (závisí na vw_economics_interval).';
|
||||
'Denní souhrn ekonomiky. planned_balance_czk = jen síťové náklady (bez zeleného bonusu).
|
||||
grid_import_cashflow_czk / grid_export_revenue_czk = směrové cashflow podle skutečného toku energie.';
|
||||
|
||||
Reference in New Issue
Block a user