-- audit „ekvivalent plných cyklů“ z 1min telemetrie battery_power_w (bez LP constraintu) create or replace function ems.fn_battery_cycle_audit( p_site_id int, p_from timestamptz, p_to timestamptz ) returns jsonb language plpgsql stable as $fn$ declare v_usable numeric; v_throughput_wh numeric; v_full_cycles numeric; begin select coalesce(sum(ab.usable_capacity_wh), 0)::numeric into v_usable from ems.asset_battery ab where ab.site_id = p_site_id; if v_usable is null or v_usable <= 0 then return jsonb_build_object('error', 'no_battery', 'full_cycles', 0); end if; select coalesce( sum(abs(ti.battery_power_w::numeric) / 60.0), 0 ) into v_throughput_wh from ems.telemetry_inverter ti where ti.site_id = p_site_id and ti.measured_at >= p_from and ti.measured_at < p_to and ti.battery_power_w is not null; v_full_cycles := case when v_usable * 2 > 0 then v_throughput_wh / (v_usable * 2) else 0 end; return jsonb_build_object( 'full_cycles', round(v_full_cycles::numeric, 4), 'throughput_wh', round(v_throughput_wh, 2), 'throughput_vs_usable_ratio', round((v_throughput_wh / nullif(v_usable, 0))::numeric, 4), 'usable_capacity_wh', v_usable, 'window_start', p_from, 'window_end', p_to ); end; $fn$;