-- EV spotřební forecast: pozorování (odometer+SoC při příjezdu/odjezdu, auto je -- vzhůru — žádné buzení navíc), jízdy, statistiky per den v týdnu. Cíl: target -- SoC a deadline session z reálného týdenního rytmu (pondělí služebka ~150 km -- → skoro plná; konec týdne míň; víkend = levné sloty na přípravu pondělka). -- Zapnutí per vozidlo: target_soc_forecast_enabled (default false = sbírá se, -- session jedou na defaultech). alter table ems.asset_vehicle add column if not exists target_soc_forecast_enabled boolean not null default false, add column if not exists min_target_soc_pct numeric(5,2) not null default 30.0; comment on column ems.asset_vehicle.target_soc_forecast_enabled is 'true = target SoC + deadline session z ev_usage_stats (fn_ev_required_soc); false = default_target_soc_pct/default_deadline_hour. Forecast vyžaduje >= 4 vzorky pro daný den v týdnu, jinak fallback.'; comment on column ems.asset_vehicle.min_target_soc_pct is 'Komfortní spodní mez forecast targetu (%). Forecast smí jít pod default_target_soc_pct (např. pátek), ne pod tuto mez.'; create table ems.ev_vehicle_obs ( id bigserial primary key, site_id int not null references ems.site (id), vehicle_id int not null references ems.asset_vehicle (id), observed_at timestamptz not null default now(), trigger text not null check (trigger in ('arrival', 'departure', 'manual')), odometer_km numeric(10, 1), soc_pct numeric(5, 2), charging_state text ); create index idx_ev_vehicle_obs_vehicle_time on ems.ev_vehicle_obs (vehicle_id, observed_at desc); comment on table ems.ev_vehicle_obs is 'Pozorování vozidla z API výrobce (Tesla Fleet) při příjezdu/odjezdu — auto je v těch okamžicích vzhůru, čtení nebudí. Zdroj pro ev_trip.'; create table ems.ev_trip ( id serial primary key, vehicle_id int not null references ems.asset_vehicle (id), departure_obs_id bigint not null references ems.ev_vehicle_obs (id), arrival_obs_id bigint not null references ems.ev_vehicle_obs (id), departed_at timestamptz not null, arrived_at timestamptz not null, km numeric(8, 1), kwh_est numeric(7, 2), charged_away boolean not null default false, constraint uq_ev_trip_departure unique (departure_obs_id) ); comment on table ems.ev_trip is 'Jízda = pár odjezd→příjezd: km z odometru, kWh z ΔSoC × kapacita. charged_away = SoC po cestě vzrostlo (nabíjení mimo dům) — kWh nevypovídá, vyloučit ze statistik.'; create table ems.ev_usage_stats ( vehicle_id int not null references ems.asset_vehicle (id), day_of_week int not null check (day_of_week between 0 and 6), avg_day_kwh numeric(7, 2), stddev_day_kwh numeric(7, 2), avg_day_km numeric(8, 1), avg_departure_hour numeric(4, 2), sample_count int not null default 0, last_updated timestamptz not null default now(), primary key (vehicle_id, day_of_week) ); comment on table ems.ev_usage_stats is 'Týdenní rytmus vozidla per den v týdnu (0=neděle, Europe/Prague): průměrná denní spotřeba jízdou (kWh), km, typická hodina prvního odjezdu. Plní fn_update_ev_usage_stats (job 00:50). Vstup fn_ev_required_soc / fn_ev_expected_departure.';