Compare commits

...

2 Commits

Author SHA1 Message Date
819aaaa1f5 Add Weather Bot for Telegram 2024-07-14 19:20:40 +02:00
d8ca020c98 Update README 2024-07-13 14:20:03 +02:00
6 changed files with 181 additions and 14 deletions

View File

@ -28,6 +28,7 @@ def def_handler(sig, frame):
Función manejadora de señales para salir del programa de manera elegante. Función manejadora de señales para salir del programa de manera elegante.
""" """
logger.info("Saliendo del programa...") logger.info("Saliendo del programa...")
print("\n[!] Saliendo del programa...")
exit(1) exit(1)

View File

@ -0,0 +1,10 @@
FROM python:3.10-alpine
WORKDIR /app
COPY . /app/
RUN pip install -r requirements.txt
CMD ["python", "clima_bot.py"]

View File

@ -0,0 +1,126 @@
import asyncio
import logging
import requests
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import ApplicationBuilder, CommandHandler, MessageHandler, CallbackQueryHandler, CallbackContext
from telegram.ext import filters
import config
# Logging setup
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO)
logger = logging.getLogger(__name__)
TELEGRAM_API_TOKEN = config.BOT_TOKEN
WEATHER_API_KEY = config.WEATHER_API_KEY
BASE_WEATHER_URL = "http://api.openweathermap.org/data/2.5/weather?q={}&appid={}"
FORECAST_URL = "http://api.openweathermap.org/data/2.5/forecast?q={}&appid={}"
city = None
def weather_emoji(description):
"""Devuelve un emoji basado en la descripción del clima."""
description = description.lower()
if "clear" in description:
return "☀️"
elif "cloud" in description:
return "☁️"
elif "rain" in description:
return "🌧️"
elif "thunder" in description:
return "⛈️"
elif "snow" in description:
return "❄️"
elif "mist" in description or "fog" in description:
return "🌫️"
else:
return ""
async def start(update: Update, context: CallbackContext) -> None:
"""Manejador del comando /start. Solicita al usuario la ciudad en la que vive."""
logger.debug(f"Comando /start recibido de {update.message.chat.username}")
await update.message.reply_text("¿En qué ciudad vives?")
async def menu(update: Update, context: CallbackContext) -> None:
"""Manejador de mensajes. Muestra un menú con opciones al usuario después de recibir la ciudad."""
global city
city = update.message.text
logger.debug(f"Ciudad recibida: {city}")
keyboard = [
[InlineKeyboardButton("Clima Actual", callback_data='current_weather')],
[InlineKeyboardButton("Pronóstico del Tiempo", callback_data='forecast')],
]
reply_markup = InlineKeyboardMarkup(keyboard)
await update.message.reply_text('Elige una opción:', reply_markup=reply_markup)
async def button(update: Update, context: CallbackContext) -> None:
"""Manejador de botones. Procesa la opción seleccionada por el usuario."""
query = update.callback_query
await query.answer()
logger.debug(f"Opción seleccionada: {query.data}")
try:
if query.data == 'current_weather':
response = requests.get(BASE_WEATHER_URL.format(city, WEATHER_API_KEY))
response.raise_for_status()
data = response.json()
main = data['main']
weather_data = data['weather'][0]
celsius_temp = main['temp'] - 273.15
emoji = weather_emoji(weather_data['description'])
message = f"Clima actual en {city} {emoji}:\n"
message += f"Temperatura: {celsius_temp:.2f}°C\n"
message += f"Descripción: {weather_data['description'].capitalize()}\n"
message += f"Humedad: {main['humidity']}%\n"
await query.edit_message_text(text=message)
elif query.data == 'forecast':
response = requests.get(FORECAST_URL.format(city, WEATHER_API_KEY))
response.raise_for_status()
data = response.json()
message = f"Pronóstico del tiempo para {city}:\n"
for item in data['list'][:5]:
celsius_temp = item['main']['temp'] - 273.15
emoji = weather_emoji(item['weather'][0]['description'])
message += f"\nFecha: {item['dt_txt']} {emoji}\n"
message += f"Temperatura: {celsius_temp:.2f}°C\n"
message += f"Descripción: {item['weather'][0]['description'].capitalize()}\n"
await query.edit_message_text(text=message)
except requests.RequestException as e:
logger.error(f"Error al obtener datos del clima: {e}")
await query.edit_message_text(
text="No se puede encontrar información meteorológica para esta ciudad. Inténtalo de nuevo.")
except Exception as e:
logger.error(f"Error inesperado: {e}")
await query.edit_message_text(
text="Ocurrió un error inesperado. Inténtalo de nuevo más tarde.")
def error(update: Update, context: CallbackContext):
"""Registra errores causados por actualizaciones."""
logger.warning('La actualización "%s" causó el error "%s"', update, context.error)
def main():
"""Función principal del bot. Configura y ejecuta el bot de Telegram."""
logger.info("Iniciando el bot...")
application = ApplicationBuilder().token(TELEGRAM_API_TOKEN).build()
application.add_handler(CommandHandler("start", start))
application.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, menu))
application.add_handler(CallbackQueryHandler(button))
# Registra todos los errores
application.add_error_handler(error)
logger.info("Bot iniciado y en espera de mensajes...")
application.run_polling()
if __name__ == '__main__':
main()

View File

@ -0,0 +1,17 @@
# config.py
# Este módulo gestiona la configuración y la carga de variables de entorno.
import os
from dotenv import load_dotenv
# Cargar las variables de entorno desde el archivo .env
load_dotenv('.env')
# Obtener el token del bot y el ID del chat de grupo desde las variables de entorno
BOT_TOKEN = os.getenv('BOT_TOKEN')
WEATHER_API_KEY = os.getenv('WEATHER_API_KEY')
# Validar que las variables de entorno estén configuradas
if not BOT_TOKEN or not WEATHER_API_KEY:
raise AssertionError("Por favor, configura las variables de entorno BOT_TOKEN y GROUP_CHAT_ID")

View File

@ -0,0 +1,13 @@
certifi==2024.7.4
cffi==1.16.0
charset-normalizer==3.3.2
cryptography==42.0.8
decorator==5.1.1
idna==3.7
pycparser==2.22
python-decouple==3.8
python-dotenv==1.0.1
python-telegram-bot==21.3
requests==2.32.3
tornado==6.4.1
urllib3~=1.26

View File

@ -1,16 +1,16 @@
# Bots de Telegram # Bots de Telegram
| Nombre | Descripción | Nivel | | Nombre | Descripción | Nivel |
| ----------------------------------------- | ----------------------------------------- | ---------- | | ----------------------------------------- | ------------------------------------------------- | ---------- |
| [Bot id del chat](./01_id_bot/) | Bot que devuelve el id del bot | básico | | [Bot id del chat](./01_id_bot/) | Bot que devuelve el id del bot | básico |
| [Bot mensajes](./02_pruebas_bot/) | Bot que devuelve mensajes básicos. Loggin | intermedio | | [Bot mensajes](./02_pruebas_bot/) | Bot que devuelve mensajes básicos. Loggin | intermedio |
| [Bot de traducción](./03_translator_bot/) | Bot que traduce mensajes a varios idiomas | avanzado | | [Bot de traducción](./03_translator_bot/) | Bot que traduce mensajes a varios idiomas. Loggin | avanzado |
| **Bot de clima** (próximamente) | Bot que devuelve el clima de una ciudad | intermedio | | [Bot de clima](./04_clima_bot/) | Bot que devuelve el clima de una ciudad | avanzado |
| **Bot de noticias** (próximamente) | Bot que devuelve noticias de última hora | intermedio | | **Bot de noticias** (próximamente) | Bot que devuelve noticias de última hora | intermedio |
| **Bot de mareas** (próximamente) | Bot que devuelve información de mareas | avanzado | | **Bot de mareas** (próximamente) | Bot que devuelve información de mareas | avanzado |
| **Bot de juegos** (próximamente) | Bot con juegos de adivinanzas y preguntas | avanzado | | **Bot de juegos** (próximamente) | Bot con juegos de adivinanzas y preguntas | avanzado |
| **Bot de películas** (próximamente) | Bot que devuelve información de películas | avanzado | | **Bot de películas** (próximamente) | Bot que devuelve información de películas | avanzado |
| **Bot de series** (próximamente) | Bot que devuelve información de series | avanzado | | **Bot de series** (próximamente) | Bot que devuelve información de series | avanzado |
| **Bot de libros** (próximamente) | Bot que devuelve información de libros | avanzado | | **Bot de libros** (próximamente) | Bot que devuelve información de libros | avanzado |
| **Bot de recetas** (próximamente) | Bot que devuelve recetas de cocina | avanzado | | **Bot de recetas** (próximamente) | Bot que devuelve recetas de cocina | avanzado |
| **Bot de deportes** (próximamente) | Bot que devuelve información de deportes | avanzado | | **Bot de deportes** (próximamente) | Bot que devuelve información de deportes | avanzado |