Wetter-Chip auf Karte + Bugfix private Routen zählen für km-Stats
- GET /api/weather?lat=&lon= (Open-Meteo, 30-min TTL-Cache) - Zecken-Warnung regelbasiert: März–Okt + Temp > 7°C - Karte: Wetterchip oben rechts nach GPS-Fix - stats.py + achievements.py: is_public-Filter entfernt — private Routen zählen jetzt für eigene km/Achievements - SW by-v320, APP_VER 308
This commit is contained in:
parent
43d33c0fd1
commit
0461f936ce
9 changed files with 185 additions and 13 deletions
|
|
@ -1,13 +1,105 @@
|
|||
"""
|
||||
BAN YARO — Wetter-Zusammenfassung via Open-Meteo
|
||||
Prüft mehrere deutsche Städte und liefert max. Temperatur und Gewitterwarnung.
|
||||
BAN YARO — Wetter via Open-Meteo
|
||||
- get_weather_summary(): Push-Job, prüft 5 deutsche Städte
|
||||
- get_weather_for_location(): API-Endpoint, beliebiger Standort mit TTL-Cache
|
||||
"""
|
||||
|
||||
import time
|
||||
import logging
|
||||
import httpx
|
||||
from datetime import datetime
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# WMO-Wettercodes → (Beschreibung, Phosphor-Icon-Name)
|
||||
_WMO = {
|
||||
0: ('Klar', 'sun'),
|
||||
1: ('Überwiegend klar', 'cloud-sun'),
|
||||
2: ('Teilweise bewölkt', 'cloud-sun'),
|
||||
3: ('Bedeckt', 'cloud'),
|
||||
45: ('Nebel', 'cloud-fog'),
|
||||
48: ('Gefrierender Nebel', 'cloud-fog'),
|
||||
51: ('Leichter Nieselregen', 'cloud-rain'),
|
||||
53: ('Nieselregen', 'cloud-rain'),
|
||||
55: ('Starker Nieselregen', 'cloud-rain'),
|
||||
61: ('Leichter Regen', 'cloud-rain'),
|
||||
63: ('Regen', 'cloud-rain'),
|
||||
65: ('Starker Regen', 'cloud-rain'),
|
||||
71: ('Leichter Schnee', 'snowflake'),
|
||||
73: ('Schnee', 'snowflake'),
|
||||
75: ('Starker Schnee', 'snowflake'),
|
||||
77: ('Schneekörner', 'snowflake'),
|
||||
80: ('Leichte Schauer', 'cloud-rain'),
|
||||
81: ('Schauer', 'cloud-rain'),
|
||||
82: ('Starke Schauer', 'cloud-rain'),
|
||||
85: ('Schneeschauer', 'snowflake'),
|
||||
86: ('Starke Schneeschauer', 'snowflake'),
|
||||
95: ('Gewitter', 'cloud-lightning'),
|
||||
96: ('Gewitter mit Hagel', 'cloud-lightning'),
|
||||
99: ('Schweres Gewitter', 'cloud-lightning'),
|
||||
}
|
||||
|
||||
# TTL-Cache: (round(lat,1), round(lon,1)) → (timestamp, data)
|
||||
_location_cache: dict = {}
|
||||
_CACHE_TTL = 1800 # 30 Minuten
|
||||
|
||||
|
||||
async def get_weather_for_location(lat: float, lon: float) -> dict:
|
||||
"""Holt aktuelles Wetter für einen Standort. 30-min TTL-Cache."""
|
||||
key = (round(lat, 1), round(lon, 1))
|
||||
now = time.time()
|
||||
if key in _location_cache:
|
||||
ts, cached = _location_cache[key]
|
||||
if now - ts < _CACHE_TTL:
|
||||
return cached
|
||||
|
||||
url = (
|
||||
"https://api.open-meteo.com/v1/forecast"
|
||||
f"?latitude={lat}&longitude={lon}"
|
||||
"¤t=temperature_2m,apparent_temperature,weathercode,windspeed_10m,is_day"
|
||||
"&daily=precipitation_probability_max,uv_index_max"
|
||||
"&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()
|
||||
|
||||
cur = raw.get('current', {})
|
||||
daily = raw.get('daily', {})
|
||||
|
||||
temp = cur.get('temperature_2m')
|
||||
feels_like = cur.get('apparent_temperature')
|
||||
wcode = cur.get('weathercode', 0)
|
||||
wind = cur.get('windspeed_10m')
|
||||
is_day = cur.get('is_day', 1)
|
||||
precip = (daily.get('precipitation_probability_max') or [None])[0]
|
||||
uv = (daily.get('uv_index_max') or [None])[0]
|
||||
|
||||
desc, icon = _WMO.get(wcode, ('Unbekannt', 'cloud'))
|
||||
if wcode == 0 and not is_day:
|
||||
icon = 'moon'
|
||||
|
||||
month = datetime.now().month
|
||||
zecken = None
|
||||
if temp is not None and temp > 7.0 and 3 <= month <= 10:
|
||||
zecken = 'hoch' if temp > 20 else ('mittel' if temp > 12 else 'niedrig')
|
||||
|
||||
data = {
|
||||
'temp_c': temp,
|
||||
'feels_like_c': feels_like,
|
||||
'weathercode': wcode,
|
||||
'desc': desc,
|
||||
'icon': icon,
|
||||
'wind_kmh': wind,
|
||||
'precip_prob': precip,
|
||||
'uv_index': uv,
|
||||
'is_day': bool(is_day),
|
||||
'zecken_warnung': zecken,
|
||||
}
|
||||
_location_cache[key] = (now, data)
|
||||
return data
|
||||
|
||||
# Wichtige deutsche Städte als Stichprobe
|
||||
CITIES = [
|
||||
{"name": "Berlin", "lat": 52.52, "lon": 13.41},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue