kalibrace per pole
Some checks failed
CI and deploy / migration-check (push) Failing after 9s
CI and deploy / deploy (push) Has been skipped

This commit is contained in:
Dusan Vojacek
2026-04-22 22:17:28 +02:00
parent 3cd8e44d37
commit 568b584748
12 changed files with 705 additions and 267 deletions

View File

@@ -604,6 +604,93 @@ async def get_site_forecast_pv_slots_range_corrected(
return {"slots": [s for s in slots if isinstance(s, dict)]}
@router.get("/{site_id}/forecast/pv-delta-profile")
async def get_site_forecast_pv_delta_profile(
site_id: int,
db: Annotated[asyncpg.Pool, Depends(get_pg_pool)],
from_ts: datetime = Query(
...,
alias="from",
description="Začátek okna historie pro výpočet delty [from, to)",
),
to_ts: datetime = Query(
...,
alias="to",
description="Konec okna (max. 120 dní za from; typicky now)",
),
half_life_days: float = Query(
14,
ge=1,
le=90,
description="Half-life vážení (dny) pro delta profil",
),
threshold_w: int = Query(
150,
ge=0,
le=10_000,
description="Ignorovat sloty s nízkou výrobou (W) při odhadu profilu",
),
top_n_days: int | None = Query(
None,
ge=0,
le=31,
description="Top N kalendářních dní podle day_score (NULL = z kalibrace / výchozí funkce)",
),
non_top_day_factor: float | None = Query(
None,
ge=0,
le=1,
description="Ztlumení vah mimo top N (NULL = z kalibrace / default)",
),
day_weight_gamma: float | None = Query(
None,
ge=0.25,
le=8,
description="Exponent na day_weight (NULL = z kalibrace / default)",
),
) -> dict[str, Any]:
"""JSON z `ems.fn_pv_forecast_delta_profile` (`deltas`, `deltas_by_array`, cutoff z DB)."""
if to_ts <= from_ts:
raise HTTPException(status_code=422, detail="'to' must be after 'from'")
if to_ts - from_ts > timedelta(days=120):
raise HTTPException(
status_code=422,
detail="Span between 'from' and 'to' must be at most 120 days",
)
async with db.acquire() as conn:
site_ok = await conn.fetchval(
"SELECT EXISTS(SELECT 1 FROM ems.site WHERE id = $1)", site_id
)
if not site_ok:
raise HTTPException(status_code=404, detail="Site not found")
raw = await fetch_json(
conn,
"""
select ems.fn_pv_forecast_delta_profile(
$1::int,
$2::timestamptz,
$3::timestamptz,
$4::numeric,
$5::int,
$6::int,
$7::numeric,
$8::numeric
)
""",
site_id,
from_ts,
to_ts,
half_life_days,
threshold_w,
top_n_days,
non_top_day_factor,
day_weight_gamma,
)
if not isinstance(raw, dict):
return {}
return raw
@router.get("/{site_id}/timeseries/telemetry-15m")
async def get_site_telemetry_15m_range(
site_id: int,