from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select from datetime import datetime, timedelta import urllib.request import urllib.parse import urllib.error import json from app.database import get_db from app.models.settings import Settings from app.config import settings as app_settings from app.routers.auth import get_current_session router = APIRouter() _cache: dict = {} @router.get("/weather") async def get_weather( db: AsyncSession = Depends(get_db), current_user: Settings = Depends(get_current_session) ): # Check cache now = datetime.now() if _cache.get("expires_at") and now < _cache["expires_at"]: return _cache["data"] # Get city from settings result = await db.execute(select(Settings)) settings_row = result.scalar_one_or_none() city = settings_row.weather_city if settings_row else None if not city: raise HTTPException(status_code=400, detail="No weather city configured") api_key = app_settings.OPENWEATHERMAP_API_KEY if not api_key: raise HTTPException(status_code=500, detail="Weather API key not configured") try: # Current weather current_url = f"https://api.openweathermap.org/data/2.5/weather?q={urllib.parse.quote(city)}&units=metric&appid={api_key}" with urllib.request.urlopen(current_url, timeout=10) as resp: current_data = json.loads(resp.read().decode()) # Forecast for rain probability forecast_url = f"https://api.openweathermap.org/data/2.5/forecast?q={urllib.parse.quote(city)}&units=metric&cnt=8&appid={api_key}" with urllib.request.urlopen(forecast_url, timeout=10) as resp: forecast_data = json.loads(resp.read().decode()) rain_chance = 0 for item in forecast_data.get("list", []): pop = item.get("pop", 0) if pop > rain_chance: rain_chance = pop weather_result = { "temp": round(current_data["main"]["temp"]), "temp_min": round(current_data["main"]["temp_min"]), "temp_max": round(current_data["main"]["temp_max"]), "description": current_data["weather"][0]["description"], "rain_chance": round(rain_chance * 100), "sunrise": current_data["sys"]["sunrise"], "sunset": current_data["sys"]["sunset"], "city": current_data["name"], } # Cache for 1 hour _cache["data"] = weather_result _cache["expires_at"] = now + timedelta(hours=1) return weather_result except urllib.error.URLError as e: raise HTTPException(status_code=502, detail=f"Weather service unavailable: {str(e)}") except (KeyError, json.JSONDecodeError) as e: raise HTTPException(status_code=502, detail=f"Invalid weather data: {str(e)}")