Feature: Trauer-Feature, Futter-Verträglichkeit, Multi-Hund-Fixes, Wetter-Ort (Sprint 47)
- dog-profile.js: Verstorben-Button, Gedenkseite, KI-Abschiedstext - database.py: futter_eintraege/reaktionen, route_dogs, exercise_progress.dog_id - routes/ernaehrung.py: Futter-Verträglichkeit mit 20 Reaktionstypen + Analyse - routes/routen.py: route_dogs Many-to-Many, Routen editierbar - routes/training.py: exercise_progress per dog_id - routes/ki.py: /ki/abschied Trauer-KI - weather.py: Nominatim Ortsname parallel geladen - ui.js: dogChip/bindDogChip, visualViewport-Modal - api.js: gedenken, gedenkseite, futter-Methoden, route_dogs - worlds.js: Ortsname im Wetter-Chip - uebungen.js: _progressLoaded-Flag, dog-spezifischer Fortschritt - trainingsplaene.js: dog_id Unterstützung - diary.js/health.js: P-Badge Cleanup - map.js: Wetter-Ort-Anzeige entfernt - wetter.js: Ort in Wetter-Detail
This commit is contained in:
parent
1ce802c8dc
commit
bda61a0e40
16 changed files with 713 additions and 181 deletions
|
|
@ -4,6 +4,7 @@ BAN YARO — Wetter via Open-Meteo
|
|||
- get_weather_for_location(): API-Endpoint, beliebiger Standort mit TTL-Cache
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import time
|
||||
import logging
|
||||
import httpx
|
||||
|
|
@ -62,9 +63,28 @@ async def get_weather_for_location(lat: float, lon: float) -> dict:
|
|||
"&timezone=Europe%2FBerlin&forecast_days=1"
|
||||
)
|
||||
async with httpx.AsyncClient(timeout=8.0) as client:
|
||||
resp = await client.get(url)
|
||||
resp.raise_for_status()
|
||||
raw = resp.json()
|
||||
resp, geo_resp = await asyncio.gather(
|
||||
client.get(url),
|
||||
client.get(
|
||||
f"https://nominatim.openstreetmap.org/reverse?lat={lat}&lon={lon}&format=json&zoom=10",
|
||||
headers={"User-Agent": "BanYaro/1.0 support@banyaro.app"}
|
||||
),
|
||||
return_exceptions=True,
|
||||
)
|
||||
resp.raise_for_status()
|
||||
raw = resp.json()
|
||||
|
||||
# Ortsname aus Reverse-Geocoding
|
||||
location_name = None
|
||||
try:
|
||||
if not isinstance(geo_resp, Exception) and geo_resp.status_code == 200:
|
||||
geo = geo_resp.json()
|
||||
addr = geo.get("address", {})
|
||||
location_name = (addr.get("city") or addr.get("town") or
|
||||
addr.get("village") or addr.get("municipality") or
|
||||
addr.get("county") or geo.get("name"))
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
cur = raw.get('current', {})
|
||||
daily = raw.get('daily', {})
|
||||
|
|
@ -130,9 +150,10 @@ async def get_weather_for_location(lat: float, lon: float) -> dict:
|
|||
'precip_prob': precip,
|
||||
'uv_index': uv,
|
||||
'is_day': bool(is_day),
|
||||
'zecken_warnung': zecken,
|
||||
'next_rain_time': next_rain_time,
|
||||
'zecken_warnung': zecken,
|
||||
'next_rain_time': next_rain_time,
|
||||
'rain_warning_time': rain_warning_time,
|
||||
'location_name': location_name,
|
||||
}
|
||||
_location_cache[key] = (now, data)
|
||||
return data
|
||||
|
|
@ -272,9 +293,23 @@ async def get_forecast(lat: float, lon: float) -> dict:
|
|||
async with httpx.AsyncClient(timeout=10.0) as client:
|
||||
forecast_task = client.get(forecast_url)
|
||||
pollen_task = client.get(pollen_url)
|
||||
forecast_resp, pollen_resp = await asyncio.gather(
|
||||
forecast_task, pollen_task, return_exceptions=True
|
||||
geo_task = client.get(
|
||||
f"https://nominatim.openstreetmap.org/reverse?lat={lat}&lon={lon}&format=json&zoom=10",
|
||||
headers={"User-Agent": "BanYaro/1.0 support@banyaro.app"}
|
||||
)
|
||||
forecast_resp, pollen_resp, geo_resp_fc = await asyncio.gather(
|
||||
forecast_task, pollen_task, geo_task, return_exceptions=True
|
||||
)
|
||||
|
||||
location_name_fc = None
|
||||
try:
|
||||
if not isinstance(geo_resp_fc, Exception) and geo_resp_fc.status_code == 200:
|
||||
addr = geo_resp_fc.json().get("address", {})
|
||||
location_name_fc = (addr.get("city") or addr.get("town") or
|
||||
addr.get("village") or addr.get("municipality") or
|
||||
addr.get("county"))
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# --- Forecast (required) ---
|
||||
if isinstance(forecast_resp, Exception):
|
||||
|
|
@ -421,7 +456,7 @@ async def get_forecast(lat: float, lon: float) -> dict:
|
|||
'hourly': _hourly_by_day.get(date_str, []),
|
||||
})
|
||||
|
||||
result = {'timezone': timezone, 'days': days}
|
||||
result = {'timezone': timezone, 'days': days, 'location_name': location_name_fc}
|
||||
_forecast_cache[key] = (now, result)
|
||||
_log_forecast(round(lat, 1), round(lon, 1), days)
|
||||
return result
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue