Add: München als 3. Wetter-Location + Wetter-Detail-Modal
- München als tertiärer Standort (iris-Akzent) hinzugefügt - Klick auf WeatherCard öffnet Detail-Modal mit: - 24h stündliche Prognose (horizontal scrollbar) - 7-Tage-Vorhersage mit Temperaturbalken - Wind, Feuchte, Sonnenauf/-untergang - Backend: 7-Tage statt 3-Tage Forecast, 24 Hourly-Slots pro Standort - Backend: forecast_3day → forecast Feldname-Konsistenz - Dashboard: 3-Spalten Wetter-Grid statt 4 (HourlyForecast → Modal) - Admin: Tertiärer Standort konfigurierbar - THERMAL Design: iris glow, modal animation, Portal-basiertes Modal Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
d9626108e6
commit
2f56be835e
13 changed files with 379 additions and 36 deletions
|
|
@ -1,4 +1,4 @@
|
|||
"""Weather data router -- primary + secondary locations and hourly forecast."""
|
||||
"""Weather data router -- primary, secondary & tertiary locations with hourly forecasts."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
|
@ -31,29 +31,41 @@ async def get_weather() -> Dict[str, Any]:
|
|||
|
||||
# --- cache miss -- fetch all three in parallel ----------------------------
|
||||
cfg = get_settings()
|
||||
logger.info("[WEATHER] Cache miss — fetching '%s' + '%s'",
|
||||
cfg.weather_location, cfg.weather_location_secondary)
|
||||
logger.info("[WEATHER] Cache miss — fetching '%s' + '%s' + '%s'",
|
||||
cfg.weather_location, cfg.weather_location_secondary,
|
||||
cfg.weather_location_tertiary)
|
||||
|
||||
results = await asyncio.gather(
|
||||
_safe_fetch_weather(cfg.weather_location),
|
||||
_safe_fetch_weather(cfg.weather_location_secondary),
|
||||
_safe_fetch_hourly(cfg.weather_location),
|
||||
_safe_fetch_weather(cfg.weather_location_tertiary),
|
||||
_safe_fetch_hourly(cfg.weather_location, max_slots=24),
|
||||
_safe_fetch_hourly(cfg.weather_location_secondary, max_slots=24),
|
||||
_safe_fetch_hourly(cfg.weather_location_tertiary, max_slots=24),
|
||||
return_exceptions=False,
|
||||
)
|
||||
|
||||
primary_data = results[0]
|
||||
secondary_data = results[1]
|
||||
hourly_data = results[2]
|
||||
tertiary_data = results[2]
|
||||
hourly_data = results[3]
|
||||
hourly_secondary = results[4]
|
||||
hourly_tertiary = results[5]
|
||||
|
||||
# Log result summary
|
||||
_log_weather_result("primary", cfg.weather_location, primary_data)
|
||||
_log_weather_result("secondary", cfg.weather_location_secondary, secondary_data)
|
||||
logger.info("[WEATHER] Hourly: %d slots", len(hourly_data))
|
||||
_log_weather_result("tertiary", cfg.weather_location_tertiary, tertiary_data)
|
||||
logger.info("[WEATHER] Hourly: %d + %d + %d slots",
|
||||
len(hourly_data), len(hourly_secondary), len(hourly_tertiary))
|
||||
|
||||
payload: Dict[str, Any] = {
|
||||
"primary": primary_data,
|
||||
"secondary": secondary_data,
|
||||
"tertiary": tertiary_data,
|
||||
"hourly": hourly_data,
|
||||
"hourly_secondary": hourly_secondary,
|
||||
"hourly_tertiary": hourly_tertiary,
|
||||
}
|
||||
|
||||
await cache.set(CACHE_KEY, payload, cfg.weather_cache_ttl)
|
||||
|
|
@ -83,10 +95,10 @@ async def _safe_fetch_weather(location: str) -> Dict[str, Any]:
|
|||
return {"error": True, "message": str(exc), "location": location}
|
||||
|
||||
|
||||
async def _safe_fetch_hourly(location: str) -> List[Dict[str, Any]]:
|
||||
async def _safe_fetch_hourly(location: str, max_slots: int = 8) -> List[Dict[str, Any]]:
|
||||
"""Fetch hourly forecast for *location*, returning ``[]`` on failure."""
|
||||
try:
|
||||
return await fetch_hourly_forecast(location)
|
||||
return await fetch_hourly_forecast(location, max_slots=max_slots)
|
||||
except Exception as exc:
|
||||
logger.exception("[WEATHER] Unhandled error fetching hourly for '%s'", location)
|
||||
return []
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue