import tkinter as tk import threading import requests import time class WeatherWidget: def __init__(self, parent, api_key): """ Inicializa el widget del clima con detalles adicionales. Args: parent (tk.Frame): Frame en el que se colocará el widget. api_key (str): Clave de la API de OpenWeatherMap. """ self.parent = parent self.api_key = api_key # Crear un Frame para contener los datos self.frame = tk.Frame(self.parent, bg="white", bd=2, relief="groove") self.frame.pack(padx=10, pady=10, fill="x", anchor="n") # Encabezado del clima self.header_label = tk.Label(self.frame, text="Weather in ...", font=("Helvetica", 14, "bold"), bg="white") self.header_label.pack(pady=5) # Temperatura principal self.temp_label = tk.Label(self.frame, text="--°C", font=("Helvetica", 28, "bold"), bg="white") self.temp_label.pack() # Detalles adicionales self.details_label = tk.Label(self.frame, text="", font=("Helvetica", 12), bg="white", justify="left") self.details_label.pack(pady=5) # Iniciar el hilo para actualizar el clima self.start_weather_updates() def get_location(self): """ Obtiene la ubicación actual (latitud y longitud) usando ip-api. """ try: response = requests.get("http://ip-api.com/json/") response.raise_for_status() data = response.json() return data["lat"], data["lon"], data["city"] except Exception as e: return None, None, f"Error al obtener ubicación: {e}" def get_weather(self, lat, lon): """ Obtiene el clima actual usando OpenWeatherMap. Args: lat (float): Latitud de la ubicación. lon (float): Longitud de la ubicación. """ try: weather_url = f"http://api.openweathermap.org/data/2.5/weather?lat={lat}&lon={lon}&appid={self.api_key}&units=metric" response = requests.get(weather_url) response.raise_for_status() data = response.json() # Información principal city = data["name"] temp = data["main"]["temp"] real_feel = data["main"]["feels_like"] wind_speed = data["wind"]["speed"] wind_gusts = data["wind"].get("gust", "N/A") weather = data["weather"][0]["description"].capitalize() # Obtener calidad del aire (Air Quality) air_quality = self.get_air_quality(lat, lon) # Formatear detalles adicionales details = ( f"RealFeel: {real_feel}°\n" f"Wind: {wind_speed} km/h\n" f"Wind Gusts: {wind_gusts} km/h\n" f"Air Quality: {air_quality}" ) return city, temp, details except Exception as e: return None, None, f"Error al obtener el clima: {e}" def get_air_quality(self, lat, lon): """ Obtiene la calidad del aire usando OpenWeatherMap. Args: lat (float): Latitud. lon (float): Longitud. """ try: aqi_url = f"http://api.openweathermap.org/data/2.5/air_pollution?lat={lat}&lon={lon}&appid={self.api_key}" response = requests.get(aqi_url) response.raise_for_status() data = response.json() aqi = data["list"][0]["main"]["aqi"] # Mapear AQI a descripciones aqi_mapping = {1: "Good", 2: "Fair", 3: "Moderate", 4: "Poor", 5: "Very Poor"} return aqi_mapping.get(aqi, "Unknown") except Exception as e: return f"Error: {e}" def update_weather(self): """ Actualiza la información del clima periódicamente. """ while True: lat, lon, location_info = self.get_location() if lat and lon: city, temp, details = self.get_weather(lat, lon) self.header_label.config(text=f"Weather in {city}") self.temp_label.config(text=f"{temp}°C") self.details_label.config(text=details) else: self.header_label.config(text=location_info) # Error de ubicación time.sleep(60) # Actualizar cada 60 segundos def start_weather_updates(self): """ Inicia el hilo para actualizar el clima. """ weather_thread = threading.Thread(target=self.update_weather, daemon=True) weather_thread.start()