Files
ems/db/migration/V089__ev_usage_forecast.sql
Dusan Vojacek 4095f0f912
All checks were successful
CI and deploy / migration-check (push) Successful in 19s
CI and deploy / deploy (push) Successful in 56s
EV spotřební forecast: týdenní rytmus vozidla → target SoC a deadline session
Myšlenka uživatele: pondělní služebka ~150 km (~35 kWh) chce skoro plnou,
konec týdne stačí míň, víkend = levné sloty na přípravu pondělka.

- V089: ev_vehicle_obs (odometer+SoC při příjezdu/ODJEZDU — auto v obou
  okamžicích vzhůru, žádné buzení navíc), ev_trip (km z odometru, kWh z ΔSoC;
  nabíjení cestou → charged_away flag), ev_usage_stats per (vozidlo, DOW);
  asset_vehicle: target_soc_forecast_enabled (default false), min_target_soc_pct
- R__096: fn_ev_build_trips (párování), fn_update_ev_usage_stats (job 00:50),
  fn_ev_next_departure (příští typický odjezd, >=4 vzorky, >=3 km),
  fn_ev_required_soc (P80 spotřeby dne + 10 p.b., clamp [min_target, 100])
- R__016: session při příjezdu bere forecast target+deadline (za per-vozidlo
  flagem, fallback defaulty, ruční patch vždy vyhrává) → víkendová session
  s pondělním deadline = v2 solver přirozeně nabije v levných slotech
- tesla_client: + vehicle_state endpoint (odometer v MÍLÍCH → km), collector:
  departure hook, lifespan: job 00:50

Aktivace po nasbírání dat: update asset_vehicle set target_soc_forecast_enabled=true.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-12 09:06:10 +02:00

64 lines
3.1 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- 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.';