[locations] Add weather fetching to birds and moods
This commit is contained in:
@ -1,6 +1,9 @@
|
||||
import logging
|
||||
import xml.etree.ElementTree as ET
|
||||
from typing import Optional
|
||||
from urllib.parse import urlencode
|
||||
|
||||
import requests
|
||||
from django.utils import timezone
|
||||
from scrobbles.models import Scrobble
|
||||
|
||||
@ -196,3 +199,76 @@ def detect_movement(
|
||||
return result
|
||||
|
||||
return result
|
||||
|
||||
|
||||
NWS_URL = "https://forecast.weather.gov/MapClick.php"
|
||||
|
||||
|
||||
def fetch_current_weather(lat: float, lon: float) -> Optional[dict]:
|
||||
"""Fetch current weather from NWS DWML feed for the given lat/lon.
|
||||
|
||||
Returns dict with 'temp' and 'description' keys, or None on failure.
|
||||
"""
|
||||
params = {
|
||||
"lat": lat,
|
||||
"lon": lon,
|
||||
"unit": 0,
|
||||
"lg": "english",
|
||||
"FcstType": "dwml",
|
||||
}
|
||||
url = f"{NWS_URL}?{urlencode(params)}"
|
||||
|
||||
try:
|
||||
resp = requests.get(url, timeout=10)
|
||||
resp.raise_for_status()
|
||||
except requests.RequestException as e:
|
||||
logger.warning("Failed to fetch NWS weather data: %s", e)
|
||||
return None
|
||||
|
||||
try:
|
||||
root = ET.fromstring(resp.content)
|
||||
except ET.ParseError as e:
|
||||
logger.warning("Failed to parse NWS XML: %s", e)
|
||||
return None
|
||||
|
||||
# Find current observations data block
|
||||
data_blocks = root.findall("data")
|
||||
obs_block = None
|
||||
for block in data_blocks:
|
||||
if block.get("type") == "current observations":
|
||||
obs_block = block
|
||||
break
|
||||
|
||||
if obs_block is None:
|
||||
logger.warning("No current observations block in NWS response")
|
||||
return None
|
||||
|
||||
params_el = obs_block.find("parameters")
|
||||
if params_el is None:
|
||||
return None
|
||||
|
||||
# Temperature (apparent / feels-like)
|
||||
temp = None
|
||||
for temp_el in params_el.findall("temperature"):
|
||||
if temp_el.get("type") == "apparent":
|
||||
val_el = temp_el.find("value")
|
||||
if val_el is not None and val_el.text:
|
||||
try:
|
||||
temp = int(round(float(val_el.text)))
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
break
|
||||
|
||||
# Weather description
|
||||
description = None
|
||||
weather_el = params_el.find("weather")
|
||||
if weather_el is not None:
|
||||
cond_el = weather_el.find("weather-conditions")
|
||||
if cond_el is not None:
|
||||
description = cond_el.get("weather-summary")
|
||||
|
||||
if temp is None and description is None:
|
||||
logger.warning("No weather data found in NWS response")
|
||||
return None
|
||||
|
||||
return {"temp": temp, "description": description}
|
||||
|
||||
Reference in New Issue
Block a user