126 lines
3.9 KiB
Python
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}" |