telemetrie per pv_array, fix predictinos
Some checks failed
CI and deploy / migration-check (push) Failing after 24s
CI and deploy / deploy (push) Has been skipped

This commit is contained in:
Dusan Vojacek
2026-04-29 13:03:41 +02:00
parent afee62ba4e
commit 9d37efb991
6 changed files with 179 additions and 23 deletions

View File

@@ -188,6 +188,8 @@ BEGIN
SELECT AVG(
CASE r_bonus.telemetry_source
WHEN 'gen_port' THEN ti.gen_port_power_w
WHEN 'pv1' THEN ti.pv1_power_w
WHEN 'pv2' THEN ti.pv2_power_w
WHEN 'pv_strings' THEN COALESCE(ti.pv1_power_w, 0)
+ COALESCE(ti.pv2_power_w, 0)
WHEN 'pv_total' THEN ti.pv_power_w

View File

@@ -50,7 +50,9 @@ BEGIN
v.learning_exclude_reason
FROM ems.forecast_pv_interval fpi
JOIN ems.forecast_pv_run fpr ON fpr.id = fpi.run_id
JOIN ems.asset_pv_array pa ON pa.id = fpr.pv_array_id
JOIN ems.asset_pv_array pa
ON pa.id = fpr.pv_array_id
AND pa.site_id = fpr.site_id
LEFT JOIN ems.site_pv_forecast_calibration cal
ON cal.site_id = fpr.site_id
LEFT JOIN LATERAL (
@@ -115,16 +117,47 @@ BEGIN
(flags.is_curtailed_learning_slot OR flags.is_telemetry_derated_slot) AS exclude_actual_for_learning
) v ON true
LEFT JOIN LATERAL (
SELECT AVG(
WITH base AS (
SELECT AVG(
CASE coalesce(pa.telemetry_source, '')
WHEN 'pv1' THEN ti.pv1_power_w::NUMERIC
WHEN 'pv2' THEN ti.pv2_power_w::NUMERIC
WHEN 'pv_strings' THEN (COALESCE(ti.pv1_power_w, 0) + COALESCE(ti.pv2_power_w, 0))::NUMERIC
WHEN 'pv_total' THEN ti.pv_power_w::NUMERIC
WHEN 'gen_port' THEN ti.gen_port_power_w::NUMERIC
ELSE NULL
END
) AS avg_actual_w
FROM ems.telemetry_inverter ti
WHERE ti.site_id = fpr.site_id
AND ti.measured_at >= fpi.interval_start
AND ti.measured_at < fpi.interval_start + INTERVAL '15 minutes'
),
grp AS (
-- Pokud více pv_array sdílí stejné měření (např. GEN port rozdělený do více orientací),
-- rozdělíme actual proporčně podle forecastu v daném slotu.
SELECT
sum(fpi2.power_w)::numeric AS forecast_group_w
FROM ems.forecast_pv_interval fpi2
JOIN ems.forecast_pv_run fpr2 ON fpr2.id = fpi2.run_id
JOIN ems.asset_pv_array pa2
ON pa2.id = fpi2.pv_array_id
AND pa2.site_id = fpr2.site_id
WHERE pa.telemetry_group IS NOT NULL
AND pa2.site_id = fpr.site_id
AND pa2.telemetry_group = pa.telemetry_group
AND pa2.telemetry_source = pa.telemetry_source
AND fpi2.interval_start = fpi.interval_start
AND fpr2.id = fpr.id
)
SELECT
CASE
WHEN pa.controllable = false THEN ti.gen_port_power_w::NUMERIC
ELSE (COALESCE(ti.pv1_power_w, 0) + COALESCE(ti.pv2_power_w, 0))::NUMERIC
END
) AS avg_actual_w
FROM ems.telemetry_inverter ti
WHERE ti.site_id = fpr.site_id
AND ti.measured_at >= fpi.interval_start
AND ti.measured_at < fpi.interval_start + INTERVAL '15 minutes'
WHEN pa.telemetry_group IS NULL THEN (SELECT avg_actual_w FROM base)
WHEN (SELECT forecast_group_w FROM grp) IS NULL THEN NULL
WHEN (SELECT forecast_group_w FROM grp) <= 0 THEN NULL
WHEN (SELECT avg_actual_w FROM base) IS NULL THEN NULL
ELSE (SELECT avg_actual_w FROM base) * (fpi.power_w::numeric / (SELECT forecast_group_w FROM grp))
END AS avg_actual_w
) slot ON true
WHERE fpr.site_id = p_site_id
AND fpr.status = 'ok'

View File

@@ -25,23 +25,30 @@ begin
and ti.measured_at >= p_window_start
and ti.measured_at < p_window_end;
with pv_arrays as (
select apa.id as pv_array_id
from ems.asset_pv_array apa
where apa.site_id = p_site_id
),
latest_run as (
select distinct on (fpr.pv_array_id)
fpr.pv_array_id,
fpr.id as run_id
from pv_arrays pa
join ems.forecast_pv_run fpr
on fpr.pv_array_id = pa.pv_array_id
and fpr.site_id = p_site_id
where fpr.status = 'ok'
and fpr.created_at <= p_window_start
order by fpr.pv_array_id, fpr.created_at desc
)
select coalesce(sum(fpi.power_w) * 0.25 / 1000.0, 0)
into v_forecast
from ems.forecast_pv_interval fpi
join ems.forecast_pv_run fpr on fpr.id = fpi.run_id
where fpr.site_id = p_site_id
and fpi.interval_start >= p_window_start
join latest_run lr on lr.run_id = fpi.run_id
where fpi.interval_start >= p_window_start
and fpi.interval_start < p_window_end
and fpr.status = 'ok'
and fpr.id = (
select fpr2.id
from ems.forecast_pv_run fpr2
where fpr2.site_id = p_site_id
and fpr2.status = 'ok'
and fpr2.created_at <= p_window_start
order by fpr2.created_at desc
limit 1
);
and fpi.pv_array_id = lr.pv_array_id;
if v_forecast < 0.1 or coalesce(v_actual, 0) < 0.05 then
return jsonb_build_object(