Files
ems/db/routines/R__065_fn_site_full_status.sql
2026-04-19 20:15:46 +02:00

159 lines
4.8 KiB
SQL

create or replace function ems.fn_site_full_status(p_site_id int)
returns jsonb
language sql
stable
as $fn$
select
case
when not exists (select 1 from ems.site s0 where s0.id = p_site_id) then
jsonb_build_object('error', 'not_found')
else jsonb_build_object(
'site',
(
select jsonb_build_object(
'id', s.id,
'code', s.code,
'name', s.name,
'timezone', s.timezone
)
from ems.site s
where s.id = p_site_id
),
'operating_mode',
(
select jsonb_build_object(
'mode_code', m.mode_code,
'mode_name', d.name,
'activated_at', m.activated_at,
'activated_by', m.activated_by
)
from ems.site_operating_mode m
join ems.operating_mode_def d on d.code = m.mode_code
where m.site_id = p_site_id
),
'heartbeat',
(
select jsonb_build_object(
'last_seen', hb.last_seen,
'status', hb.status
)
from ems.site_heartbeat hb
where hb.site_id = p_site_id
),
'inverter_latest',
(
select to_jsonb(li.*)
from ems.vw_latest_inverter li
where li.site_id = p_site_id
order by li.measured_at desc nulls last
limit 1
),
'ev_chargers',
coalesce(
(
select jsonb_agg(
jsonb_build_object(
'code', v.code,
'status', v.status,
'power_w', v.power_w,
'measured_at', v.measured_at
)
order by v.measured_at desc nulls last
)
from (
select distinct on (evc.charger_id)
evc.charger_code as code,
evc.status,
evc.power_w,
evc.measured_at
from ems.vw_latest_ev_charger evc
where evc.site_id = p_site_id
order by evc.charger_id, evc.measured_at desc nulls last
) v
),
'[]'::jsonb
),
'heat_pump_latest',
(
select jsonb_build_object(
'power_w', hp.power_w,
'tuv_tank_temp_c', hp.tuv_tank_temp_c,
'measured_at', hp.measured_at
)
from ems.vw_latest_heat_pump hp
where hp.site_id = p_site_id
order by hp.measured_at desc nulls last
limit 1
),
'battery_limits',
(
select jsonb_build_object(
'reserve_soc', min(ab.reserve_soc_percent)::float,
'min_soc', min(ab.min_soc_percent)::float
)
from ems.asset_battery ab
where ab.site_id = p_site_id
),
'active_plan',
(
select jsonb_build_object(
'id', pr.id,
'created_at', pr.created_at
)
from ems.planning_run pr
where pr.site_id = p_site_id
and pr.status = 'active'
order by pr.created_at desc
limit 1
),
'planning_intervals',
coalesce(
(
select jsonb_agg(
jsonb_build_object(
'interval_start', pi.interval_start,
'battery_setpoint_w', pi.battery_setpoint_w,
'load_baseline_w', pi.load_baseline_w,
'pv_a_forecast_raw_w', pi.pv_a_forecast_raw_w,
'pv_b_forecast_raw_w', pi.pv_b_forecast_raw_w,
'pv_a_forecast_solver_w', pi.pv_a_forecast_solver_w,
'pv_b_forecast_solver_w', pi.pv_b_forecast_solver_w
)
order by pi.interval_start
)
from ems.planning_interval pi
where pi.run_id = (
select pr2.id
from ems.planning_run pr2
where pr2.site_id = p_site_id
and pr2.status = 'active'
order by pr2.created_at desc
limit 1
)
),
'[]'::jsonb
),
'tomorrow_price_slot_count',
(
select count(*)::int
from ems.vw_site_effective_price vep
where vep.site_id = p_site_id
and (vep.interval_start at time zone coalesce(
nullif(trim((select s2.timezone from ems.site s2 where s2.id = p_site_id)), ''),
'Europe/Prague'
))::date = (
(
current_timestamp at time zone coalesce(
nullif(trim((select s3.timezone from ems.site s3 where s3.id = p_site_id)), ''),
'Europe/Prague'
)
)::date + 1
)
)
)
end;
$fn$;
comment on function ems.fn_site_full_status(int) is
'Raw data pro GET /status/full (věk telemetrie a alerty dopočítá Python).';