Fix geocoding for "City,Country" format (e.g. Rab,Croatia)

Split location on comma, search for city name, then filter results
by country name/code to find the correct match.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Sam 2026-03-02 17:48:45 +01:00
parent d3305a243c
commit ac63370876

View file

@ -71,17 +71,28 @@ _geocode_cache: Dict[str, Dict[str, Any]] = {}
async def _geocode(location: str) -> Optional[Dict[str, Any]]: async def _geocode(location: str) -> Optional[Dict[str, Any]]:
"""Resolve a city name to lat/lon using Open-Meteo Geocoding API. """Resolve a city name to lat/lon using Open-Meteo Geocoding API.
Supports "City,Country" format (e.g. "Rab,Croatia") the country part
is used to filter results when multiple matches exist.
Returns dict with keys: latitude, longitude, name, timezone Returns dict with keys: latitude, longitude, name, timezone
""" """
cache_key = location.lower().strip() cache_key = location.lower().strip()
if cache_key in _geocode_cache: if cache_key in _geocode_cache:
return _geocode_cache[cache_key] return _geocode_cache[cache_key]
# Split "City,Country" into search name + country filter
city_name = location
country_hint = ""
if "," in location:
parts = [p.strip() for p in location.split(",", 1)]
city_name = parts[0]
country_hint = parts[1].lower() if len(parts) > 1 else ""
try: try:
async with httpx.AsyncClient(timeout=10) as client: async with httpx.AsyncClient(timeout=10) as client:
resp = await client.get( resp = await client.get(
"https://geocoding-api.open-meteo.com/v1/search", "https://geocoding-api.open-meteo.com/v1/search",
params={"name": location, "count": 1, "language": "de"}, params={"name": city_name, "count": 10, "language": "de"},
) )
resp.raise_for_status() resp.raise_for_status()
data = resp.json() data = resp.json()
@ -94,15 +105,29 @@ async def _geocode(location: str) -> Optional[Dict[str, Any]]:
logger.warning("[WEATHER] Geocoding: no results for '%s'", location) logger.warning("[WEATHER] Geocoding: no results for '%s'", location)
return None return None
# If country hint provided, try to find a matching result
best = results[0]
if country_hint:
for r in results:
country = (r.get("country", "") or "").lower()
country_code = (r.get("country_code", "") or "").lower()
if country_hint in country or country_hint == country_code:
best = r
break
else:
logger.warning("[WEATHER] Country '%s' not found in results for '%s', using first match",
country_hint, city_name)
geo = { geo = {
"latitude": results[0]["latitude"], "latitude": best["latitude"],
"longitude": results[0]["longitude"], "longitude": best["longitude"],
"name": results[0].get("name", location), "name": best.get("name", location),
"timezone": results[0].get("timezone", "Europe/Berlin"), "timezone": best.get("timezone", "Europe/Berlin"),
} }
_geocode_cache[cache_key] = geo _geocode_cache[cache_key] = geo
logger.info("[WEATHER] Geocoded '%s'%s (%.2f, %.2f)", logger.info("[WEATHER] Geocoded '%s'%s (%s, %.2f, %.2f)",
location, geo["name"], geo["latitude"], geo["longitude"]) location, geo["name"], best.get("country", "?"),
geo["latitude"], geo["longitude"])
return geo return geo