"""Weather source routes: CRUD + test endpoint.""" from fastapi import APIRouter, Depends, HTTPException from wled_controller.api.auth import AuthRequired from wled_controller.api.dependencies import ( fire_entity_event, get_weather_manager, get_weather_source_store, ) from wled_controller.api.schemas.weather_sources import ( WeatherSourceCreate, WeatherSourceListResponse, WeatherSourceResponse, WeatherSourceUpdate, WeatherTestResponse, ) from wled_controller.core.weather.weather_manager import WeatherManager from wled_controller.core.weather.weather_provider import WMO_CONDITION_NAMES from wled_controller.storage.base_store import EntityNotFoundError from wled_controller.storage.weather_source import WeatherSource from wled_controller.storage.weather_source_store import WeatherSourceStore from wled_controller.utils import get_logger logger = get_logger(__name__) router = APIRouter() def _to_response(source: WeatherSource) -> WeatherSourceResponse: d = source.to_dict() return WeatherSourceResponse( id=d["id"], name=d["name"], provider=d["provider"], provider_config=d.get("provider_config", {}), latitude=d["latitude"], longitude=d["longitude"], update_interval=d["update_interval"], description=d.get("description"), tags=d.get("tags", []), created_at=source.created_at, updated_at=source.updated_at, ) @router.get("/api/v1/weather-sources", response_model=WeatherSourceListResponse, tags=["Weather Sources"]) async def list_weather_sources( _auth: AuthRequired, store: WeatherSourceStore = Depends(get_weather_source_store), ): sources = store.get_all_sources() return WeatherSourceListResponse( sources=[_to_response(s) for s in sources], count=len(sources), ) @router.post("/api/v1/weather-sources", response_model=WeatherSourceResponse, status_code=201, tags=["Weather Sources"]) async def create_weather_source( data: WeatherSourceCreate, _auth: AuthRequired, store: WeatherSourceStore = Depends(get_weather_source_store), ): try: source = store.create_source( name=data.name, provider=data.provider, provider_config=data.provider_config, latitude=data.latitude, longitude=data.longitude, update_interval=data.update_interval, description=data.description, tags=data.tags, ) except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) fire_entity_event("weather_source", "created", source.id) return _to_response(source) @router.get("/api/v1/weather-sources/{source_id}", response_model=WeatherSourceResponse, tags=["Weather Sources"]) async def get_weather_source( source_id: str, _auth: AuthRequired, store: WeatherSourceStore = Depends(get_weather_source_store), ): try: return _to_response(store.get_source(source_id)) except EntityNotFoundError: raise HTTPException(status_code=404, detail=f"Weather source {source_id} not found") @router.put("/api/v1/weather-sources/{source_id}", response_model=WeatherSourceResponse, tags=["Weather Sources"]) async def update_weather_source( source_id: str, data: WeatherSourceUpdate, _auth: AuthRequired, store: WeatherSourceStore = Depends(get_weather_source_store), manager: WeatherManager = Depends(get_weather_manager), ): try: source = store.update_source( source_id, name=data.name, provider=data.provider, provider_config=data.provider_config, latitude=data.latitude, longitude=data.longitude, update_interval=data.update_interval, description=data.description, tags=data.tags, ) except EntityNotFoundError: raise HTTPException(status_code=404, detail=f"Weather source {source_id} not found") except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) manager.update_source(source_id) fire_entity_event("weather_source", "updated", source.id) return _to_response(source) @router.delete("/api/v1/weather-sources/{source_id}", status_code=204, tags=["Weather Sources"]) async def delete_weather_source( source_id: str, _auth: AuthRequired, store: WeatherSourceStore = Depends(get_weather_source_store), ): try: store.delete_source(source_id) except EntityNotFoundError: raise HTTPException(status_code=404, detail=f"Weather source {source_id} not found") fire_entity_event("weather_source", "deleted", source_id) @router.post("/api/v1/weather-sources/{source_id}/test", response_model=WeatherTestResponse, tags=["Weather Sources"]) async def test_weather_source( source_id: str, _auth: AuthRequired, store: WeatherSourceStore = Depends(get_weather_source_store), manager: WeatherManager = Depends(get_weather_manager), ): """Force-fetch current weather and return the result.""" try: store.get_source(source_id) # validate exists except EntityNotFoundError: raise HTTPException(status_code=404, detail=f"Weather source {source_id} not found") data = manager.fetch_now(source_id) condition = WMO_CONDITION_NAMES.get(data.code, f"Unknown ({data.code})") return WeatherTestResponse( code=data.code, condition=condition, temperature=data.temperature, wind_speed=data.wind_speed, cloud_cover=data.cloud_cover, )