from __future__ import annotations from dataclasses import dataclass from os import environ @dataclass(frozen=True) class EnergyForecastConfig: horizon_hours: int = 24 oracle_step_minutes: int = 15 fallback_solar_peak_w: float = 10000 solar_peak_headroom: float = 1.05 solar_scale: float = 1.0 solar_training_days: int = 30 solar_min_training_samples: int = 24 solar_ridge_lambda: float = 0.1 load_lookback_minutes: int = 30 load_profile_days: int = 30 load_profile_bucket_minutes: int = 15 load_profile_min_samples: int = 5 load_recent_blend: float = 0.35 local_timezone: str = "Europe/Stockholm" @classmethod def from_env(cls) -> "EnergyForecastConfig": return cls( horizon_hours=int(environ.get("ASTRAPE_ENERGY_FORECAST_HOURS", "24")), oracle_step_minutes=int(environ.get("ASTRAPE_ORACLE_STEP_MINUTES", "15")), fallback_solar_peak_w=float( environ.get("ASTRAPE_SOLAR_PEAK_W", "10000") ), solar_peak_headroom=float( environ.get("ASTRAPE_SOLAR_PEAK_HEADROOM", "1.05") ), solar_scale=float(environ.get("ASTRAPE_SOLAR_FORECAST_SCALE", "1.0")), solar_training_days=int( environ.get("ASTRAPE_SOLAR_TRAINING_DAYS", "30") ), solar_min_training_samples=int( environ.get("ASTRAPE_SOLAR_MIN_TRAINING_SAMPLES", "24") ), solar_ridge_lambda=float( environ.get("ASTRAPE_SOLAR_RIDGE_LAMBDA", "0.1") ), load_lookback_minutes=int( environ.get("ASTRAPE_LOAD_LOOKBACK_MINUTES", "30") ), load_profile_days=int(environ.get("ASTRAPE_LOAD_PROFILE_DAYS", "30")), load_profile_bucket_minutes=int( environ.get("ASTRAPE_LOAD_PROFILE_BUCKET_MINUTES", "15") ), load_profile_min_samples=int( environ.get("ASTRAPE_LOAD_PROFILE_MIN_SAMPLES", "5") ), load_recent_blend=float(environ.get("ASTRAPE_LOAD_RECENT_BLEND", "0.35")), local_timezone=environ.get( "ASTRAPE_LOCAL_TIMEZONE", environ.get("TZ", "Europe/Stockholm"), ), )