Create a Stylish Telegram Weather Bot with Python

Create a Stylish Telegram Weather Bot with Python

In this tutorial, we’ll walk through the process of creating a Telegram bot that delivers beautifully designed weather reports. By the end, you’ll have a bot that can provide weather information for any city, presented in a sleek, modern design.

Prerequisites

Before we begin, make sure you have the following installed:

  • Python 3.7+
  • pip (Python package installer)

You’ll also need to sign up for:

  • A Telegram Bot API token
  • An OpenWeatherMap API key

Setting Up Your Telegram Bot

If you’re new to creating Telegram bots or aren’t familiar with using BotFather, I recommend checking out my previous article: How to Make a Telegram Bot: A Python Guide for Beginners. This guide will walk you through the process of:

  1. Starting a chat with BotFather
  2. Creating a new bot and obtaining your API token
  3. Setting up your bot’s profile

Once you’ve completed these steps and have your Telegram Bot API token, you’re ready to proceed with this tutorial.

Step 1: Setting Up the Environment

First, let’s install the required Python libraries:

pip install telebot requests Jinja2 imgkit

Note: imgkit requires wkhtmltopdf to be installed on your system. Follow the installation instructions for your operating system here.

Step 2: Importing Libraries and Setting Up API Keys

Create a new Python file (e.g., weather_bot.py) and add the following imports and API key setup:

import telebot
import requests
from jinja2 import Template
import imgkit
import io

TELEGRAM_BOT_TOKEN = "YOUR_TELEGRAM_BOT_TOKEN"
WEATHER_API_KEY = "YOUR_OPENWEATHERMAP_API_KEY"

bot = telebot.TeleBot(TELEGRAM_BOT_TOKEN)

Replace YOUR_TELEGRAM_BOT_TOKEN and YOUR_OPENWEATHERMAP_API_KEY with your actual API tokens.

Step 3: Creating the HTML Template

Next, we’ll create an HTML template for our weather card. This will be used to generate the image we’ll send to users. Add the following to your Python file:

html_template = """
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title> Weather</title>
    <style>
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
            background-color: #ffffff;
            margin: 0;
            padding: 10px;
            color: #1e1e1e;
        }
        .weather-card {
            border-radius: 12px;
            padding: 20px;
            width: 300px;
        }
        .location {
            font-size: 20px;
            font-weight: bold;
            color: #3a5998;
            margin-bottom: 12px;
        }
        .temp-icon {
            display: flex;
            align-items: center;
            justify-content: space-between;
            margin-bottom: 12px;
        }
        .temperature {
            font-size: 36px;
            font-weight: bold;
            color: #1d2129;
        }
        .weather-icon img {
            width: 64px;
            height: 64px;
        }
        .description {
            font-size: 14px;
            color: #606770;
            margin-bottom: 18px;
            padding-bottom: 12px;
            border-bottom: 1px solid #e9ebee;
        }
        .details-table {
            width: 100%;
            border-collapse: collapse;
        }
        .details-table td {
            padding: 5px 0;
            font-size: 13px;
            color: #1d2129;
        }
        .detail-label {
            font-size: 12px;
            color: #606770;
        }
        .detail-value {
            font-weight: 500;
            text-align: right;
        }
    </style>
</head>
<body>
    <div class="weather-card">
        <div class="location">, </div>
        <div class="temp-icon">
            <div class="temperature">°C</div>
            <div class="weather-icon">
                <img src="http://openweathermap.org/img/wn/@2x.png" alt="">
            </div>
        </div>
        <div class="description">Feels like °C. </div>
        <table class="details-table">
            <tr>
                <td class="detail-label">Wind</td>
                <td class="detail-value">m/s </td>
            </tr>
            <tr>
                <td class="detail-label">Pressure</td>
                <td class="detail-value"> hPa</td>
            </tr>
            <tr>
                <td class="detail-label">Humidity</td>
                <td class="detail-value">%</td>
            </tr>
            <tr>
                <td class="detail-label">Cloudiness</td>
                <td class="detail-value">%</td>
            </tr>
        </table>
    </div>
</body>
</html>
"""

Step 4: Implementing Helper Functions

Now, let’s add some helper functions to create the weather image and determine wind direction:

def create_weather_image(html_content):
    options = {
        "format": "png",
        "encoding": "UTF-8",
        "width": 290,
        "height": 340,
        "quality": 100,
    }
    return imgkit.from_string(html_content, False, options=options)

def get_wind_direction(degrees):
    directions = ["N", "NE", "E", "SE", "S", "SW", "W", "NW"]
    index = round(degrees / 45) % 8
    return directions[index]

Step 5: Creating Bot Commands

Let’s implement the bot commands:

@bot.message_handler(commands=["start", "help"])
def send_welcome(message):
    bot.reply_to(message, "Welcome! Send me a city name to get the current weather.")

@bot.message_handler(func=lambda message: True)
def get_weather(message):
    city = message.text
    weather_url = f"https://api.openweathermap.org/data/2.5/find?q={city}&appid={WEATHER_API_KEY}&units=metric"

    response = requests.get(weather_url)
    data = response.json()

    if data["cod"] == "200" and data["count"] > 0:
        weather_data = data["list"][0]

        template = Template(html_template)
        html_content = template.render(
            city=weather_data["name"],
            country=weather_data["sys"]["country"],
            temperature=round(weather_data["main"]["temp"]),
            feels_like=round(weather_data["main"]["feels_like"]),
            description=weather_data["weather"][0]["description"].capitalize(),
            wind_speed=round(weather_data["wind"]["speed"], 1),
            wind_direction=get_wind_direction(weather_data["wind"]["deg"]),
            pressure=weather_data["main"]["pressure"],
            humidity=weather_data["main"]["humidity"],
            cloudiness=weather_data["clouds"]["all"],
            icon=weather_data["weather"][0]["icon"],
        )

        image = create_weather_image(html_content)

        # Send the image
        bot.send_photo(message.chat.id, image)
    else:
        bot.reply_to(message, "Sorry, I couldn't find weather information for that city.")

Step 6: Running the Bot

Finally, add this line at the end of your script to start the bot:

bot.polling()

Running Your Weather Bot

To run your bot, simply execute your Python script:

python weather_bot.py

Your bot is now active and ready to provide weather information!

How to Use the Bot

  1. Start a chat with your bot on Telegram.
  2. Send the /start command to get a welcome message.
  3. Send any city name to receive a beautifully designed weather report.

Conclusion

Congratulations! You’ve successfully created a Telegram bot that provides stylish weather reports. This project demonstrates how to combine APIs, web design, and Python programming to create a useful and visually appealing tool. Feel free to expand on this bot by adding features like multi-language support, location-based reports, or weather forecasts. Happy coding!