1. Descripción del Proyecto

OpenWeatherMap es una plataforma que proporciona datos meteorológicos globales a través de una API, permitiendo el acceso a información como temperatura, humedad, velocidad del viento, precipitación y previsiones a corto y largo plazo. Utiliza datos de estaciones meteorológicas, satélites y modelos meteorológicos. Su API es ampliamente usada en aplicaciones y proyectos para obtener actualizaciones en tiempo real, históricos de clima, alertas meteorológicas y pronósticos detallados para cualquier ubicación en el mundo.

Este sistema consulta la API de OpenWeatherMap para obtener datos climáticos de diferentes ubicaciones y:

  1. Verifica condiciones específicas (temperatura, velocidad del viento, condiciones de lluvia o nieve) y crea alertas cuando las condiciones coinciden con los criterios definidos.
  2. Guarda los datos del clima y las alertas en un archivo CSV, creando un registro diario que puede analizarse posteriormente.

Requisitos del Proyecto

  1. Cuenta en OpenWeatherMap con una API key que puedes obtener en este enlace de forma gratuita: https://home.openweathermap.org/users/sign_up (puede tardar un rato en activarse, por eso proporciono los datos de una cuenta creada de antemano, usuario: “iker.l@fptxurdinaga.com”, contraseña: “r00t*pwd”, clave API: “35efb00415742337258dd1ba28238572”).
  2. Módulos Python: requests, json, csv, datetime.

2. Pasos del Proyecto

2.1. Configurar OpenWeatherMap

Regístrate en OpenWeatherMap (no es necesario sino quieres, puedes usar la clave API que te proporciono arriba)

2.2. Obtener Datos Básicos

Asegúrate de importar las librerías necesarias:

  • requests: para realizar la solicitud HTTP a la API.

La clave API_KEY y la BASE_URL http://api.openweathermap.org/data/2.5/weather se deben definir como constantes globales para poder reutilizarlas en sucesivas funciones.

Primero debes desarrollar una función obtener_clima que consulte el clima actual de una ciudad específica recibida como parámetro (sino se especifica en la llamada por defecto usaremos “Alonsotegi”).

Dentro de la función configura un diccionario llamado parametros que incluirá:

  • q: el nombre de la ciudad (es el argumento ciudad que recibe la función).
  • appid: tu API_KEY para la autenticación.
  • units: establece ‘metric’ para que la temperatura se muestre en grados Celsius.
  • lang: establece ‘es’ para obtener descripciones en español.

Puedes consultar la documentación de OpenWeatherMap para formar la URL de la llamada:

Realiza una solicitud HTTP GET a la API usando requests.get, enviando como parámetros el diccionario parametros.

Verifica errores HTTP (Ejemplos: URL mal formada o si el servicio Web está caido) para gestionar la excepción con raise_for_status()

Ejemplo de ejecución si definimos mal BASE_URL:

Retorno de la función:

  • Comprobación de éxito: Si el código de estado de la respuesta es 200, convierte el JSON en un diccionario de Python y retorna este diccionario.
  • Si la solicitud falla, imprime un mensaje de error junto con el código de estado y retorna None.

Código 01.py

#!/usr/bin/python3 

import requests

API_KEY = '35efb00415742337258dd1ba28238572'  # Reemplaza 'tu_api_key' con tu clave de OpenWeatherMap
BASE_URL = 'http://api.openweathermap.org/data/2.5/weather'

def obtener_clima(ciudad="Alonsotegi"):
    """
    Consulta el clima de una ciudad específica y maneja errores de conexión y HTTP.
    
    Parámetros:
        ciudad (str): Nombre de la ciudad a consultar.
    
    Retorna:
        dict: Datos meteorológicos en caso de éxito.
        None: Si ocurre un error en la conexión o la solicitud.
    """
    parametros = {
        'q': ciudad,
        'appid': API_KEY,
        'units': 'metric',  # Resultados en grados Celsius
        'lang': 'es'        # Descripciones en español
    }
    
    try:
        response = requests.get(BASE_URL, params=parametros)
        response.raise_for_status()  # Verifica errores HTTP
        
        return response.json()  # Retorna los datos JSON si la solicitud es exitosa

    except requests.exceptions.RequestException as e:
        # Captura errores de conexión o URL mal formada
        print("Error en la conexión o URL:", e)
        return None
    
    except requests.exceptions.HTTPError as err:
        # Captura errores HTTP específicos (404, 500, etc.)
        print("Error HTTP:", err)
        return None

# Ejemplo de uso
#print(obtener_clima("Bilbao"))
print(obtener_clima())

2.3. Definir Reglas para las Alertas

El objetivo de este apartado es que implementes una función llamada verificar_alertas que reciba datos climáticos y genere alertas sobre condiciones meteorológicas extremas, como calor extremo, viento fuerte o lluvia.

Al final del ejercicio, tendrás una función que evalúa varios factores en los datos climáticos y devuelve una lista con las alertas adecuadas en función de los valores detectados.

Definición de la función verificar_alertas: La función debe recibir un parámetro llamado data, que será una secuencia de datos con información del clima (obtenidos de la llamada a obtener_clima).

Dentro de la función, inicializa una lista vacía llamada alertas, que almacenará los mensajes de alerta si se cumplen ciertas condiciones climáticas.

  • Alerta de calor extremo: Si la temperatura supera los 35°C, agrega “⚠️ Alerta de calor extremo” a la lista de alertas.
  • Alerta de viento fuerte: Si la velocidad del viento es superior a 20 m/s, agrega “⚠️ Alerta de viento fuerte” a la lista de alertas.
  • Alerta de lluvia: Si la clave ‘rain’ está presente, agrega “☔ Alerta de lluvia” a la lista de alertas.

Al finalizar la verificación, retorna la lista alertas con los mensajes generados.

Código: 02.py

def verificar_alertas(data):
    """
    Verifica condiciones meteorológicas extremas en los datos climáticos y genera alertas adecuadas.
    
    Parámetros:
        data (dict): Un diccionario con datos meteorológicos, típicamente obtenido de la API de OpenWeatherMap. 
                     Debe incluir al menos las claves 'main' con la subclave 'temp' para la temperatura, 
                     'wind' con la subclave 'speed' para la velocidad del viento, y opcionalmente 'rain' para lluvia.
    
    Retorna:
        list: Una lista de strings con las alertas correspondientes a condiciones climáticas extremas:
              - "⚠️ Alerta de calor extremo" si la temperatura supera los 35°C.
              - "⚠️ Alerta de viento fuerte" si la velocidad del viento supera los 20 m/s.
              - "☔ Alerta de lluvia" si se detecta la clave 'rain' en los datos meteorológicos.

    Ejemplo:
        data = {
            "main": {"temp": 37},
            "wind": {"speed": 15},
            "rain": {"1h": 1.0}
        }
        alertas = verificar_alertas(data)
        # alertas debería ser: ["⚠️ Alerta de calor extremo", "☔ Alerta de lluvia"]
    """
    
    alertas = []  # Lista para almacenar alertas
    
    # Verifica si la temperatura supera los 35°C
    if data['main']['temp'] > 35:
        alertas.append("⚠️ Alerta de calor extremo")
    
    # Verifica si la velocidad del viento supera los 20 m/s
    if data['wind']['speed'] > 20:
        alertas.append("⚠️ Alerta de viento fuerte")
    
    # Verifica si hay datos de lluvia
    if 'rain' in data:
        alertas.append("☔ Alerta de lluvia")
    
    return alertas

2.3.1. Ejemplos de Uso

Ejemplo 1: Temperatura y lluvia

# Datos de ejemplo con temperatura alta y lluvia
data = {
    "main": {"temp": 36},
    "wind": {"speed": 10},
    "rain": {"1h": 1.5}
}
alertas = verificar_alertas(data)
print(alertas)
# Salida esperada: ["⚠️ Alerta de calor extremo", "☔ Alerta de lluvia"]

Ejemplo 2: Viento fuerte

# Datos de ejemplo con viento fuerte
data = {
    "main": {"temp": 22},
    "wind": {"speed": 25},
}
alertas = verificar_alertas(data)
print(alertas)
# Salida esperada: ["⚠️ Alerta de viento fuerte"]

Ejemplo 3

# Ejemplo de uso
#print(verificar_alertas(obtener_clima("Bilbao")))
print(verificar_alertas(obtener_clima()))

2.4. Guardar Datos y Alertas en un Archivo CSV

Guarda los datos obtenidos y cualquier alerta generada en un archivo CSV para facilitar el análisis y almacenamiento de registros históricos.

  • Definición de la función guardar_datos: Crea una función llamada guardar_datos que acepte tres parámetros: data: un diccionario con información climática, típicamente obtenido de una API como OpenWeatherMap. alertas: una lista de alertas generadas por la función verificar_alertas. archivo: una cadena de texto opcional que especifica el nombre del archivo CSV en el que se guardarán los datos. Su valor por defecto será ‘registro_clima.csv’
  • Encabezados del Archivo CSV: Define una lista llamada campos que contenga los encabezados para el archivo CSV. Los encabezados deben ser:
    • ‘ciudad’, ‘temp’, ‘humedad’, ‘viento’, ‘descripcion’, ‘fecha’, ‘alertas’.
  • Creación del Archivo CSV:
    • Utiliza la declaración try para intentar abrir el archivo en modo ‘x’ (creación). Si el archivo no existe, se debe crear y escribir la primera fila con los encabezados.
    • Maneja la excepción FileExistsError para evitar errores si el archivo ya existe.
  • Escritura de Datos en el Archivo CSV: Abre el archivo en modo ‘a’ (append) para agregar datos. Crea un escritor CSV y escribe una nueva fila con la siguiente información:
    • Nombre de la ciudad (data['name']).
    • Temperatura (data['main']['temp']).
    • Humedad (data['main']['humidity']).
    • Velocidad del viento (data['wind']['speed']).
    • Descripción del clima (data['weather'][0]['description']).
    • Fecha y hora actuales (utiliza datetime.now()).
    • Una cadena con las alertas unidas por punto y coma ('; '.join(alertas)).

Código: 03.py

def guardar_datos(data, alertas, archivo='registro_clima.csv'):
    """
    Guarda los datos climáticos y las alertas en un archivo CSV.

    La función `guardar_datos` almacena información sobre el clima de una ciudad y cualquier alerta 
    relacionada en un archivo CSV. Si el archivo no existe, se crea automáticamente con los encabezados 
    necesarios.

    Parámetros:
        data (dict): Un diccionario con información climática, generalmente obtenido de una API como OpenWeatherMap. 
                     Este diccionario debe contener al menos:
                        - 'name' (str): Nombre de la ciudad.
                        - 'main': Un subdiccionario con:
                            - 'temp' (float): Temperatura en grados Celsius.
                            - 'humidity' (int): Humedad en porcentaje.
                        - 'wind': Un subdiccionario con:
                            - 'speed' (float): Velocidad del viento en m/s.
                        - 'weather': Una lista de subdiccionarios con:
                            - 'description' (str): Descripción breve de las condiciones climáticas.
        alertas (list): Lista de alertas de condiciones climáticas, generada por la función `verificar_alertas`. 
                        Cada alerta es una cadena que describe un posible riesgo climático.
        archivo (str): Nombre del archivo CSV donde se guardarán los datos. Por defecto es 'registro_clima.csv'.

    Comportamiento:
        - Si el archivo no existe, la función crea un nuevo archivo CSV con los encabezados: 
          'ciudad', 'temp', 'humedad', 'viento', 'descripcion', 'fecha', 'alertas'.
        - Si el archivo ya existe, la función solo añade la nueva fila de datos sin duplicar los encabezados.
        - La fecha y hora actuales se registran con cada entrada, y las alertas se unen en una sola cadena, 
          separadas por '; '.

    Ejemplo de uso:
        data = {
            "name": "Bilbao",
            "main": {"temp": 28.5, "humidity": 65},
            "wind": {"speed": 15},
            "weather": [{"description": "cielo parcialmente nublado"}]
        }
        alertas = ["⚠️ Alerta de calor extremo"]

        guardar_datos(data, alertas, 'registro_clima.csv')
    """
    
    # Encabezados para el archivo CSV
    campos = ['ciudad', 'temp', 'humedad', 'viento', 'descripcion', 'fecha', 'alertas']
    
    # Crear archivo con encabezado si aún no existe
    try:
        with open(archivo, mode='x', newline='') as file:
            writer = csv.writer(file)
            writer.writerow(campos)
    except FileExistsError:
        pass
    
    # Agregar los datos y alertas en una nueva fila del archivo
    with open(archivo, mode='a', newline='') as file:
        writer = csv.writer(file)
        writer.writerow([
            data['name'],
            data['main']['temp'],
            data['main']['humidity'],
            data['wind']['speed'],
            data['weather'][0]['description'],
            datetime.now(),              # Fecha y hora actuales
            '; '.join(alertas)           # Unir las alertas en una cadena de texto
        ])

Ejemplo archivo registro_clima.csv:

ciudad,temp,humedad,viento,descripcion,fecha,alertas
Madrid,18.65,54,3.6,cielo claro,2024-10-28 17:07:23.731780,

2.5. Integrar en una Función Principal

Finalmente, combina todo en una función principal para automatizar la consulta de datos, verificación de alertas y almacenamiento de información.

Desarrolla la función sistema_alerta, que reciba el nombre de una ciudad como parámetro. La función debe obtener los datos climáticos de la ciudad utilizando obtener_clima, verificar posibles alertas con verificar_alertas y almacenar la información y alertas en un archivo CSV usando guardar_datos. Además, debe imprimir un mensaje indicando el número de alertas encontradas y, si las hay, mostrarlas en la consola.

Ejemplo de Uso:

sistema_alerta("Bilbao")

Código: 04.py

def sistema_alerta(ciudad):
    """
    Función para gestionar el sistema de alertas climáticas para una ciudad específica.

    Esta función obtiene los datos del clima para la ciudad proporcionada, verifica si hay alertas
    meteorológicas y guarda la información junto con las alertas en un archivo CSV. También imprime
    en la consola un mensaje confirmando la cantidad de alertas encontradas y, si hay alertas, las muestra.

    Parámetros:
        ciudad (str): El nombre de la ciudad para la cual se desean obtener los datos climáticos.

    Comportamiento:
        - Llama a la función `obtener_clima` para obtener los datos climáticos de la ciudad.
        - Si se obtienen datos válidos, llama a la función `verificar_alertas` para determinar
          si hay alertas basadas en los datos climáticos.
        - Llama a la función `guardar_datos` para almacenar los datos y las alertas en un archivo CSV.
        - Imprime un mensaje indicando que los datos han sido guardados y el número de alertas.
        - Si hay alertas, imprime las alertas encontradas.

    Ejemplo de uso:
        sistema_alerta("Bilbao")
    """
    data = obtener_clima(ciudad)  # Obtener datos del clima para la ciudad especificada
    if data:  # Verificar que se obtuvieron datos válidos
        alertas = verificar_alertas(data)  # Obtener alertas basadas en los datos climáticos
        guardar_datos(data, alertas)  # Guardar los datos y alertas en el archivo CSV
        print(f"Datos guardados para {ciudad} con {len(alertas)} alerta(s)")  # Mensaje de confirmación
        if alertas:  # Si hay alertas, imprimirlas
            print("Alertas:", alertas)

3. Referencias