Files
smart-mirror/raspi/Weather.py

118 lines
3.4 KiB
Python
Raw Normal View History

2026-05-02 20:57:18 +02:00
"""
Weather.py
Fetches hourly weather from Open-Meteo (free, no API key).
Runs in a background thread and caches the last result.
"""
import threading
import time
import urllib.request
import json
from datetime import datetime
_lock = threading.Lock()
_cache = {}
_cfg = {}
WMO_CODES = {
0: ("Klar", "☀️"),
1: ("Überwiegend klar", "🌤️"),
2: ("Teilweise bewölkt", ""),
3: ("Bedeckt", "☁️"),
45: ("Nebel", "🌫️"),
48: ("Reifnebel", "🌫️"),
51: ("Leichter Nieselregen","🌦️"),
53: ("Nieselregen", "🌦️"),
55: ("Dichter Nieselregen", "🌦️"),
61: ("Leichter Regen", "🌧️"),
63: ("Regen", "🌧️"),
65: ("Starker Regen", "🌧️"),
71: ("Leichter Schnee", "🌨️"),
73: ("Schnee", "🌨️"),
75: ("Starker Schnee", "❄️"),
80: ("Regenschauer", "🌦️"),
81: ("Regenschauer", "🌦️"),
82: ("Starke Schauer", "⛈️"),
95: ("Gewitter", "⛈️"),
96: ("Gewitter mit Hagel", "⛈️"),
99: ("Heftiges Gewitter", "⛈️"),
}
def init(location_cfg: dict) -> None:
global _cfg
_cfg = location_cfg
def get_weather() -> dict:
with _lock:
return dict(_cache)
def start_fetcher() -> threading.Thread:
t = threading.Thread(target=_fetch_loop, daemon=True, name="weather-fetch")
t.start()
return t
def _fetch_loop() -> None:
interval = _cfg.get("weather_refresh_s", 600)
while True:
try:
_do_fetch()
except Exception as exc:
print(f"[Weather] fetch error: {exc}")
time.sleep(interval)
def _do_fetch() -> None:
lat = _cfg["latitude"]
lon = _cfg["longitude"]
url = (
f"https://api.open-meteo.com/v1/forecast"
f"?latitude={lat}&longitude={lon}"
f"&hourly=precipitation_probability"
f"&current=temperature_2m,relative_humidity_2m,"
f"apparent_temperature,weather_code,wind_speed_10m"
f"&wind_speed_unit=kmh"
f"&timezone=Europe%2FBerlin"
f"&forecast_days=1"
)
with urllib.request.urlopen(url, timeout=10) as resp:
raw = json.loads(resp.read())
cur = raw.get("current", {})
hrly = raw.get("hourly", {})
# Pick precipitation probability for current hour
now_h = datetime.now().hour
prec_prob = 0
times = hrly.get("time", [])
precs = hrly.get("precipitation_probability", [])
for i, t in enumerate(times):
if f"T{now_h:02d}:" in t and i < len(precs):
prec_prob = precs[i]
break
code = cur.get("weather_code", 0)
desc, icon = WMO_CODES.get(code, ("Unbekannt", ""))
result = {
"location": _cfg.get("name", ""),
"temp": cur.get("temperature_2m"),
"feels_like": cur.get("apparent_temperature"),
"humidity": cur.get("relative_humidity_2m"),
"wind_kmh": cur.get("wind_speed_10m"),
"weather_code": code,
"description": desc,
"icon": icon,
"rain_prob": prec_prob,
"fetched_at": datetime.now().isoformat(timespec="seconds"),
}
with _lock:
_cache.update(result)
print(f"[Weather] {desc} {cur.get('temperature_2m')}°C, Regen {prec_prob}%")