from __future__ import annotations import asyncio import logging from typing import Any import httpx from app.cache import cache_get, cache_set from app.config import CACHE_TTL_GEOCODE, DWD_WMS_URL from app.http_client import get_client logger = logging.getLogger(__name__) WFS_URL = f"{DWD_WMS_URL.rsplit('/wms', 1)[0]}/ows" # Landkreise reicht fuer warnapp_landkreise/json/warnings.json WFS_LAYERS = ("dwd:Warngebiete_Kreise",) async def _wfs_intersects(layer: str, lat: float, lon: float) -> list[dict[str, Any]]: params = { "service": "WFS", "version": "2.0.0", "request": "GetFeature", "typeName": layer, "outputFormat": "application/json", "count": 5, "CQL_FILTER": f"INTERSECTS(SHAPE,POINT({lat} {lon}))", } client = get_client() response = await client.get(WFS_URL, params=params, timeout=8.0) response.raise_for_status() payload = response.json() results = [] for feature in payload.get("features", []): props = feature.get("properties") or {} cell_id = props.get("WARNCELLID") if cell_id is None: continue results.append( { "warncell_id": str(cell_id), "name": props.get("NAME"), "short_name": props.get("KURZNAME"), "layer": layer.split(":")[-1], "state": props.get("BL"), } ) return results def _related_cell_ids(cell_id: str) -> set[str]: ids = {cell_id} if len(cell_id) >= 9: core = cell_id[1:] ids.add(f"1{core}") ids.add(f"9{core}") if cell_id.startswith("9"): ids.add(f"1{cell_id[1:]}") elif cell_id.startswith("1"): ids.add(f"9{cell_id[1:]}") return ids async def resolve_warncells(lat: float, lon: float) -> dict[str, Any]: cache_key = f"warncell:{lat:.4f}:{lon:.4f}" cached = await cache_get(cache_key) if cached: return cached layer_results = await asyncio.gather( *[_wfs_intersects(layer, lat, lon) for layer in WFS_LAYERS], return_exceptions=True, ) areas: list[dict[str, Any]] = [] for layer, result in zip(WFS_LAYERS, layer_results): if isinstance(result, Exception): logger.warning("WFS warncell lookup failed for %s: %s", layer, result) continue areas.extend(result) cell_ids: set[str] = set() for area in areas: cell_ids.update(_related_cell_ids(area["warncell_id"])) payload = { "lat": lat, "lon": lon, "areas": areas, "cell_ids": sorted(cell_ids), } await cache_set(cache_key, payload, CACHE_TTL_GEOCODE) return payload