create or replace function ems.fn_ev_session_transition( p_site_id int, p_charger_id int, p_prev_status text, p_new_status text, p_measured_at timestamptz ) returns jsonb language plpgsql as $fn$ declare v_vehicle_id int; begin if p_prev_status is not distinct from p_new_status then return jsonb_build_object('action', 'none'); end if; if p_prev_status = 'available' and p_new_status is distinct from 'available' then select av.id into v_vehicle_id from ems.asset_vehicle av where av.site_id = p_site_id and av.default_charger_id = p_charger_id and av.active = true order by av.id limit 1; perform ems.fn_update_ev_arrival_stats( p_site_id, p_charger_id, v_vehicle_id, p_measured_at ); insert into ems.ev_session ( site_id, charger_id, vehicle_id, session_start, target_soc_pct, target_deadline ) select ac.site_id, ac.id, av.id, now(), -- forecast z týdenního rytmu (ev_usage_stats), fallback defaulty; -- ruční přepis přes fn_ev_session_apply_patch vždy vyhrává. coalesce(fc.required_soc, av.default_target_soc_pct), coalesce( fc.expected_departure, case when av.default_deadline_hour is not null then ( (timezone('Europe/Prague', now()))::date + interval '1 day' + make_interval(hours => av.default_deadline_hour) )::timestamp at time zone 'Europe/Prague' end ) from ems.asset_ev_charger ac left join lateral ( select v.id, v.default_target_soc_pct, v.default_deadline_hour, v.target_soc_forecast_enabled from ems.asset_vehicle v where v.default_charger_id = ac.id and v.site_id = ac.site_id and v.active = true order by v.id limit 1 ) av on true left join lateral ( select dep.expected_departure, ems.fn_ev_required_soc(av.id, dep.expected_departure) as required_soc from ( select ems.fn_ev_next_departure(av.id, now()) as expected_departure ) dep where av.target_soc_forecast_enabled and dep.expected_departure is not null ) fc on true where ac.id = p_charger_id and ac.site_id = p_site_id on conflict (charger_id) where session_end is null do nothing; return jsonb_build_object('action', 'arrival'); end if; if p_prev_status is distinct from 'available' and p_new_status = 'available' then update ems.ev_session es set session_end = now() where es.charger_id = p_charger_id and es.session_end is null; return jsonb_build_object('action', 'departure'); end if; return jsonb_build_object('action', 'none'); end; $fn$; comment on function ems.fn_ev_session_transition(int, int, text, text, timestamptz) is 'Detekce příjezdu/odjezdu EV po změně statusu nabíječky (telemetry_collector).';