proyecto-global-psp/logica/T2/getWeather.py

126 lines
3.9 KiB
Python

# Módulo: logica/T2/getWeather.py
import requests
import json
# --- CONFIGURACIÓN DE APIs ---
# 1. API para Geocodificación por IP (Ubicación)
IP_API_URL = "http://ip-api.com/json/"
# 2. API de Clima (Open-Meteo, gratuita y no requiere clave para datos básicos)
CLIMA_API_URL = "https://api.open-meteo.com/v1/forecast"
def _obtener_ubicacion_por_ip():
"""
Obtiene la latitud, longitud y ciudad de la ubicación del usuario
basándose en su dirección IP pública.
"""
try:
# Petición a la API de IP
response = requests.get(IP_API_URL, timeout=5)
response.raise_for_status() # Lanza un error para códigos de estado HTTP 4xx/5xx
data = response.json()
if data.get("status") == "success":
lat = data.get("lat")
lon = data.get("lon")
ciudad = data.get("city", "Ubicación Desconocida")
print(f"🌎 [IP-API] Ubicación obtenida: {ciudad} ({lat}, {lon})")
return lat, lon, ciudad
else:
print(f"❌ [IP-API] Fallo al obtener la IP. Estado: {data.get('status')}")
return None, None, None
except requests.exceptions.RequestException as e:
print(f"❌ [IP-API] Error de conexión o timeout: {e}")
return None, None, None
def _obtener_clima_por_coordenadas(lat, lon):
"""
Obtiene la temperatura y el código de estado del tiempo usando Lat/Lon.
Utiliza Open-Meteo.
"""
if lat is None or lon is None:
return None, None # No hay coordenadas válidas
params = {
"latitude": lat,
"longitude": lon,
"current_weather": "true",
"temperature_unit": "celsius",
"timezone": "auto"
}
try:
response = requests.get(CLIMA_API_URL, params=params, timeout=5)
response.raise_for_status()
data = response.json()
# Extracción de datos
clima_actual = data.get("current_weather", {})
temp = clima_actual.get("temperature")
wmo_code = clima_actual.get("weathercode")
print(f"🌡️ [Open-Meteo] Datos obtenidos: Temp={temp}°C, WMO={wmo_code}")
return temp, wmo_code
except requests.exceptions.RequestException as e:
print(f"❌ [Open-Meteo] Error de conexión al API de clima: {e}")
return None, None
except Exception as e:
print(f"❌ [Open-Meteo] Error al procesar los datos del clima: {e}")
return None, None
def _decodificar_wmo(wmo_code):
"""
Convierte el código WMO de Open-Meteo a una descripción amigable con emojis.
"""
if wmo_code is None:
return "Desconocido ❓"
code = int(wmo_code)
# 0: Cielo despejado, 1-3: Parcialmente nublado, 45-48: Niebla
if code <= 3:
return "Soleado/Parcialmente Nublado 🌤️"
# 51-67: Llovizna y Lluvia
elif 51 <= code <= 67:
return "Lluvia 🌧️"
# 71-75: Nieve
elif 71 <= code <= 75:
return "Nieve ❄️"
# 80-82: Chubascos (Duchas)
elif 80 <= code <= 82:
return "Chubascos 🌦️"
# 95, 96, 99: Tormenta
elif code >= 95:
return "Tormenta ⛈️"
# Por defecto, Nublado o Niebla
else:
return "Nublado ☁️"
def obtener_datos_clima():
"""
Función principal: obtiene la ubicación por IP y luego el clima para esa ubicación.
Devuelve la temperatura en grados Celsius y el estado del tiempo.
"""
# 1. Obtener ubicación
lat, lon, ciudad = _obtener_ubicacion_por_ip()
if lat is None or lon is None:
return "No disponible (Fallo en Ubicación)"
# 2. Obtener clima
temperatura, wmo_code = _obtener_clima_por_coordenadas(lat, lon)
if temperatura is None or wmo_code is None:
return f"Clima no disponible en {ciudad}"
# 3. Decodificar y formatear
estado_tiempo = _decodificar_wmo(wmo_code)
return f"{temperatura}°C ({estado_tiempo}) en {ciudad}"