Files
ems/db/migration/V043__site_25a_fixed_buy_seed.sql
Dusan Vojacek 71d8405cee
All checks were successful
deploy / deploy (push) Successful in 23s
test / smoke-test (push) Successful in 5s
new site BA81, tuyne forecast
2026-04-12 20:11:50 +02:00

389 lines
14 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- =============================================================
-- V043__site_25a_fixed_buy_seed.sql
-- Sloupce pro fixní nákupní energii (NT + příplatek VT) a seed lokality site-25a.
--
-- Jedna verzovaná migrace: čtyři FVE pole (různá orientace), žádný mezikrok pv-a/pv-b.
--
-- Obnova / přepnutí checksum na DB, kde už běžela starší varianta V043 nebo V044:
-- DELETE FROM flyway_schema_history WHERE version IN ('043', '044');
-- Potom: flyway migrate
-- (Sloupce buy_fixed_* zůstanou díky ADD COLUMN IF NOT EXISTS; DO blok smaže legacy pv-a/pv-b
-- a doplní pv-str-*/pv-mi-* pokud chybí.)
-- =============================================================
-- Fixní složka nákupu bez DPH (k distribuci / poplatkům / marži / DPH dle fn_effective_buy_price)
ALTER TABLE ems.site_market_config
ADD COLUMN IF NOT EXISTS buy_fixed_energy_nt_czk_kwh NUMERIC(10,6),
ADD COLUMN IF NOT EXISTS buy_fixed_vt_surcharge_czk_kwh NUMERIC(10,6) NOT NULL DEFAULT 0;
COMMENT ON COLUMN ems.site_market_config.buy_fixed_energy_nt_czk_kwh IS
'Při purchase_pricing_mode = fixed: základní nákupní cena energie Kč/kWh bez DPH v NT hodinách. VT = tato hodnota + buy_fixed_vt_surcharge_czk_kwh podle HDO oken.';
COMMENT ON COLUMN ems.site_market_config.buy_fixed_vt_surcharge_czk_kwh IS
'Při purchase_pricing_mode = fixed: příplatek Kč/kWh bez DPH k NT ceně ve VT oknech dle hdo_code_id.';
-- =============================================================
-- Seed lokality (idempotentní DO blok)
-- Viz docs/new-site-setup-template.md ev-charger-1 pro planner/telemetrii.
-- FVE: čtyři záznamy asset_pv_array (forecast service běží per pole; planner sčítá controllable / !controllable).
-- =============================================================
DO $$
DECLARE
v_site_code TEXT := 'BA81';
v_host_modbus TEXT := '109.164.83.155';
v_port_modbus INT := 502;
v_host_loxone TEXT := '109.164.83.155';
v_port_loxone INT := 8080;
v_site_id INT;
v_ep_deye INT;
v_ep_ev INT;
v_ep_loxone INT;
v_inv_main INT;
v_inv_gen INT;
v_hdo_id INT;
v_ch_id INT;
BEGIN
SELECT hc.id INTO v_hdo_id
FROM ems.hdo_code hc
WHERE hc.distributor = 'EGD' AND hc.code = 'custom_fve_home01'
ORDER BY hc.valid_from DESC NULLS LAST
LIMIT 1;
INSERT INTO ems.site (code, name, timezone, latitude, longitude, active, notes)
VALUES (
v_site_code,
'Lokalita 25A / 17 kW příkon',
'Europe/Prague',
49.24368977130069,
17.425553019721196,
true,
'Připojení 3×25 A → import max 17 kW, export max 16 kW. '
'Při omezení exportu do DS nastavit v Deye SmartLoad: „MI export to Grid cutoff“ = enable; '
'po uvolnění exportu znovu disable. Veřejná IP tunelovaná z EMS serveru.'
)
ON CONFLICT (code) DO UPDATE SET
name = EXCLUDED.name,
timezone = EXCLUDED.timezone,
latitude = EXCLUDED.latitude,
longitude = EXCLUDED.longitude,
active = EXCLUDED.active,
notes = EXCLUDED.notes
RETURNING id INTO v_site_id;
SELECT se.id INTO v_ep_deye
FROM ems.site_endpoint se
WHERE se.site_id = v_site_id
AND se.endpoint_type = 'modbus_tcp'
AND se.notes ILIKE '%Deye%'
ORDER BY se.id
LIMIT 1;
IF v_ep_deye IS NULL THEN
INSERT INTO ems.site_endpoint (
site_id, endpoint_type, host, port, protocol, unit_id, enabled, notes
)
VALUES (
v_site_id, 'modbus_tcp', v_host_modbus, v_port_modbus, 'modbus_tcp', 1, true,
'Deye 12kW LV Modbus TCP (Waveshare).'
)
RETURNING id INTO v_ep_deye;
END IF;
SELECT se.id INTO v_ep_ev
FROM ems.site_endpoint se
WHERE se.site_id = v_site_id
AND se.endpoint_type = 'modbus_tcp'
AND se.notes ILIKE '%Teltonika%'
ORDER BY se.id
LIMIT 1;
IF v_ep_ev IS NULL THEN
INSERT INTO ems.site_endpoint (
site_id, endpoint_type, host, port, protocol, unit_id, enabled, notes
)
VALUES (
v_site_id, 'modbus_tcp', v_host_modbus, v_port_modbus, 'modbus_tcp', 2, true,
'Teltonika TeltoCharge 22kW stejná IP jako Deye, unit_id 2 (upřesni dle zapojení).'
)
RETURNING id INTO v_ep_ev;
END IF;
SELECT se.id INTO v_ep_loxone
FROM ems.site_endpoint se
WHERE se.site_id = v_site_id
AND se.endpoint_type = 'loxone_http'
ORDER BY se.id
LIMIT 1;
IF v_ep_loxone IS NULL THEN
INSERT INTO ems.site_endpoint (
site_id, endpoint_type, host, port, protocol, unit_id, enabled, notes
)
VALUES (
v_site_id, 'loxone_http', v_host_loxone, v_port_loxone, 'http', NULL, true,
'Loxone Miniserver (HTTP Virtual Inputs).'
)
RETURNING id INTO v_ep_loxone;
END IF;
INSERT INTO ems.site_grid_connection (
site_id, max_import_power_w, max_export_power_w, no_export, reserved_capacity_w, notes
)
VALUES (
v_site_id, 17000, 16000, false, 0,
'Max 25 A přívod → cca 17 kW import; přetok / export povolen 16 kW.'
)
ON CONFLICT (site_id) DO UPDATE SET
max_import_power_w = EXCLUDED.max_import_power_w,
max_export_power_w = EXCLUDED.max_export_power_w,
no_export = EXCLUDED.no_export,
reserved_capacity_w = EXCLUDED.reserved_capacity_w,
notes = EXCLUDED.notes;
IF NOT EXISTS (
SELECT 1 FROM ems.site_market_config smc
WHERE smc.site_id = v_site_id AND smc.valid_to IS NULL
) THEN
INSERT INTO ems.site_market_config (
site_id,
purchase_pricing_mode, sale_pricing_mode,
buy_margin_fixed_czk, buy_margin_percent,
sell_margin_fixed_czk, sell_margin_percent,
currency, valid_from, valid_to, notes,
tariff_id, hdo_code_id, system_services_czk_kwh, ote_fee_czk_kwh,
buy_fixed_energy_nt_czk_kwh, buy_fixed_vt_surcharge_czk_kwh
)
VALUES (
v_site_id,
'fixed', 'spot',
0, 0,
-0.020, 0,
'CZK', now(), NULL,
'Nákup fixní 3,67 Kč/kWh bez DPH (NT) + 0,52 Kč/kWh bez DPH ve VT (okna dle HDO jako home-01). '
'Prodej na spotu jako home-01. Distribuce v efektivní ceně 0 (tariff_id NULL) energie jen fix + DPH dle vat_rate výchozí.',
NULL,
v_hdo_id,
0,
0,
3.67,
0.52
);
END IF;
INSERT INTO ems.site_operating_mode (site_id, mode_code, activated_by, notes)
VALUES (
v_site_id,
'MANUAL',
'migration:V043_site_25a',
'Start MANUAL; po ověření přepnout na AUTO.'
)
ON CONFLICT (site_id) DO NOTHING;
SELECT ai.id INTO v_inv_main
FROM ems.asset_inverter ai
WHERE ai.site_id = v_site_id AND ai.code = 'deye-main'
LIMIT 1;
IF v_inv_main IS NULL THEN
INSERT INTO ems.asset_inverter (
site_id, code, manufacturer, model, endpoint_id,
max_charge_power_w, max_discharge_power_w, max_export_power_w,
max_ac_output_w, max_dc_input_w, max_battery_charge_w, max_battery_discharge_w,
gen_port_max_power_w,
controllable, active, notes
)
VALUES (
v_site_id,
'deye-main',
'Deye',
NULL,
v_ep_deye,
6250, 6250, 12000,
12000, 24000, 6250, 6250,
5000,
true, true,
'12kW LV hybrid. Baterie limit 0,5C ≈ 6,25 kW (280 A teoreticky vyšší plánování dle 6,25 kW). '
'GEN port max ~5 kW součet MI.'
)
RETURNING id INTO v_inv_main;
END IF;
SELECT ai.id INTO v_inv_gen
FROM ems.asset_inverter ai
WHERE ai.site_id = v_site_id AND ai.code = 'ongrid-gen'
LIMIT 1;
IF v_inv_gen IS NULL THEN
INSERT INTO ems.asset_inverter (
site_id, code, manufacturer, model, endpoint_id,
max_export_power_w, controllable, active, notes
)
VALUES (
v_site_id,
'ongrid-gen',
NULL, NULL, NULL,
5000, false, true,
'Mikroinvertory na GEN portu (2 skupiny panelů), EMS necurtailuje.'
)
RETURNING id INTO v_inv_gen;
END IF;
IF NOT EXISTS (
SELECT 1 FROM ems.asset_battery ab
WHERE ab.site_id = v_site_id AND ab.code = 'bat-main'
) THEN
INSERT INTO ems.asset_battery (
site_id, inverter_id, code,
usable_capacity_wh, min_soc_percent, reserve_soc_percent, max_soc_percent,
charge_efficiency, discharge_efficiency, degradation_cost_czk_kwh,
max_charge_c_rate, max_discharge_c_rate, bms_max_charge_w, bms_max_discharge_w
)
VALUES (
v_site_id, v_inv_main, 'bat-main',
12500,
10, 15, 95,
0.95, 0.95,
0.50,
0.5, 0.5,
6250, 6250
);
END IF;
-- Odstranění starého agregovaného seedu (pv-a / pv-b), pokud na DB zůstal z dřívější verze.
DELETE FROM ems.forecast_accuracy fa
WHERE fa.pv_array_id IN (
SELECT id FROM ems.asset_pv_array
WHERE site_id = v_site_id AND code IN ('pv-a', 'pv-b')
);
DELETE FROM ems.forecast_pv_interval fpi
USING ems.asset_pv_array apa
WHERE apa.site_id = v_site_id
AND apa.code IN ('pv-a', 'pv-b')
AND fpi.pv_array_id = apa.id;
DELETE FROM ems.forecast_pv_run fpr
WHERE fpr.site_id = v_site_id
AND fpr.pv_array_id IN (
SELECT id FROM ems.asset_pv_array
WHERE site_id = v_site_id AND code IN ('pv-a', 'pv-b')
);
DELETE FROM ems.asset_pv_array
WHERE site_id = v_site_id AND code IN ('pv-a', 'pv-b');
-- String 1: 12×620 Wp @110° / 45° (Deye, řiditelné)
IF NOT EXISTS (
SELECT 1 FROM ems.asset_pv_array ap
WHERE ap.site_id = v_site_id AND ap.code = 'pv-str-1'
) THEN
INSERT INTO ems.asset_pv_array (
site_id, inverter_id, code, name,
nominal_power_wp, azimuth_deg, tilt_deg, module_count, shading_factor,
controllable, telemetry_source, notes
)
VALUES (
v_site_id, v_inv_main, 'pv-str-1', 'String 1 12×620 Wp',
7440, 110, 45, 12, 1.0, true, 'pv_strings',
'Hlavní telemetrie stringů Deye (pv1+pv2); druhý string má telemetry_source NULL.'
);
END IF;
-- String 2: 8×620 Wp @200° / 10° (Deye, řiditelné)
IF NOT EXISTS (
SELECT 1 FROM ems.asset_pv_array ap
WHERE ap.site_id = v_site_id AND ap.code = 'pv-str-2'
) THEN
INSERT INTO ems.asset_pv_array (
site_id, inverter_id, code, name,
nominal_power_wp, azimuth_deg, tilt_deg, module_count, shading_factor,
controllable, telemetry_source, notes
)
VALUES (
v_site_id, v_inv_main, 'pv-str-2', 'String 2 8×620 Wp',
4960, 200, 10, 8, 1.0, true, NULL,
'Vlastní predikce orientace; telemetrie sdílená se stringem 1.'
);
END IF;
-- MI 5×620 Wp @200° / 45° (GEN, neriditelné)
IF NOT EXISTS (
SELECT 1 FROM ems.asset_pv_array ap
WHERE ap.site_id = v_site_id AND ap.code = 'pv-mi-1'
) THEN
INSERT INTO ems.asset_pv_array (
site_id, inverter_id, code, name,
nominal_power_wp, azimuth_deg, tilt_deg, module_count, shading_factor,
controllable, telemetry_source, notes
)
VALUES (
v_site_id, v_inv_gen, 'pv-mi-1', 'Mikroinvertory 5×620 Wp',
3100, 200, 45, 5, 1.0, false, 'gen_port',
'Souhrnná telemetrie GEN portu; druhá MI skupina má telemetry NULL.'
);
END IF;
-- MI 3×620 Wp @110° / 10° (GEN, neriditelné)
IF NOT EXISTS (
SELECT 1 FROM ems.asset_pv_array ap
WHERE ap.site_id = v_site_id AND ap.code = 'pv-mi-2'
) THEN
INSERT INTO ems.asset_pv_array (
site_id, inverter_id, code, name,
nominal_power_wp, azimuth_deg, tilt_deg, module_count, shading_factor,
controllable, telemetry_source, notes
)
VALUES (
v_site_id, v_inv_gen, 'pv-mi-2', 'Mikroinvertory 3×620 Wp',
1860, 110, 10, 3, 1.0, false, NULL,
'Predikce samostatně; gen_port u pv-mi-1.'
);
END IF;
IF NOT EXISTS (
SELECT 1 FROM ems.asset_ev_charger c
WHERE c.site_id = v_site_id AND c.code = 'ev-charger-1'
) THEN
INSERT INTO ems.asset_ev_charger (
site_id, code, manufacturer, model, endpoint_id,
max_power_w, min_power_w, phases, connector_count, schedulable, notes
)
VALUES (
v_site_id, 'ev-charger-1', 'Teltonika', 'TeltoCharge 22kW',
v_ep_ev,
22000, 1380, 3, 1, true,
'Jedna nabíječka; kód ev-charger-1 kvůli planneru / telemetrii.'
)
RETURNING id INTO v_ch_id;
ELSE
SELECT id INTO v_ch_id FROM ems.asset_ev_charger
WHERE site_id = v_site_id AND code = 'ev-charger-1'
LIMIT 1;
END IF;
INSERT INTO ems.asset_vehicle (
site_id, code, name, make, model,
battery_capacity_kwh, max_charge_power_w, default_charger_id, api_type,
default_target_soc_pct, default_deadline_hour, active
)
VALUES (
v_site_id,
'ev-default',
'EV (výchozí)',
NULL, NULL,
60.0,
11000,
v_ch_id,
'none',
80,
7,
true
)
ON CONFLICT (site_id, code) DO NOTHING;
END;
$$;