How to Create Your Personal Weather Forecast Bot on Telegram

Have you ever wanted to have your own personal bot that sends you a weather forecast for today and even reminds you to bring an umbrella if it’s rainy? If so, you are in the right place.

After reading this article, you will learn:

  1. How to get weather data from OpenWeather API
  2. How to create a Telegram Bot
  3. How to send a personalized message through Telegram API
  4. How to make the bot remind you to take an umbrella
  5. How to upload your script on an AWS server and make it run every morning

Mental Preparation

Before starting to do things I always start with a little bit of mental preparation by asking these questions:

  1. What’s my final goal?
  2. What resources can I use to achieve it?
  3. What steps should I take in order to achieve the goal using available resources?

These three simple questions will prepare your mind for the upcoming work and ultimately will simplify the workflow. So let’s start answering them!

  1. I want a personal bot that would send me today’s weather forecast every day and remind me to bring my umbrella before going outside if it’s rainy
  2. Firstly, I need a website/API that can tell me the weather forecast. I can either scrape one of the hundreds of weather websites out there which would be unnecessarily complicated or use the OpenWeather API that has a very simple internal structure.

Secondly, I need a communication channel for my bot: e-mail, WhatsApp, Telegram? Well, e-mail is good for professional communication but it would overload my mailbox… WhatsApp? Good to go, but it does not seem to have any public bot API and I would like to avoid using third-party services. On the other hand, Telegram has a very well-documented API, and many people use Telegram bots. So, Telegram is our choice.

Finally, I would like to run my script early in the morning hence I’d need to use a server that runs 24/7 to use cron to schedule the scripts. There are plenty of good options available here: Google Cloud, Heroku, AWS, and others. Since I already use AWS (Amazon Web Service) to run other scripts, I choose this option.

Thus, I will use OpenWeather API for a weather forecast that I will send to my Telegram
every morning using a script scheduled to run on an AWS server.

  1. Now we will go through the steps we need to achieve the goal:

  2. Sign up on the OpenWeather website and obtain the API key

  3. Get to know the Telegram API and find a way to create bots and send messages (we do not need to know every single detail of the API!)

  4. Write the script

  5. Upload the script on the server and schedule it to run every day

With these answers in mind, we can go on with the project.

OpenWeather API Key

First things first, we need to go to the OpenWeather website and sign up. It’s pretty straightforward so I will go directly to how to get your API key with which you access their data.

If you go to this page, you’ll find different API options you can subscribe to but the one we will use in this project is called “Call 5 day / 3 hour forecast data” which provides a 5-day weather forecast with 3-hour intervals. Click on “Subscribe” and you will get your API key. Everything is very simple, and you should not run into any problems.

5 days API

You will be able to access this API key whenever you want so do not worry about losing it.

Investigating OpenWeather API

The next thing we have to do is to study the structure of the API we will work with. In the documentation, we can read that we need two mandatory query parameters:

  1. City name
  2. API key

I will also use an optional “units” parameter set to “metric” to use the metric system of measurement.

It’s a good practice to create a new Python virtual environment for each project and to define the so-called environmental variables inside of it. Our first variable will be the city name and API key. I use conda to manage all my environments but you’re free to also use Python virtualenv. As a short note, I use Linux Ubuntu 20.10.

conda create --prefix ./env requests
conda activate ./env

In the cell above, I created a new environment in the current working directory and installed the package requests that we will use to interact with the APIs. FInally, I activated the environment.

Next, we will set two environmental variables OPENWEATHER_API_KEY and OPEN_WEATHER_CITY that contain the OperWeather API token and the name of the city you want the weather forecast for. In my case, it is Padova in Italy.

conda env config vars set OPENWEATHER_API_KEY=<YOUR_OPENWEATHER_API_KEY>
conda env config vars set OPEN_WEATHER_CITY=Padova

Let’s create our virtual environment and define the environmental variables. If the commands below are cryptic to you, you can read refer to the conda documentation.

Now it’s time to investigate the structure of the JSON that OpenWeather will return. I like separating my scripts into functions for easier management so our first function will return a JSON object for specified queries. Let’s start to code!

But wait! Let’s think of what we want at the end. Our function should return a JSON using the environmental variables we set before. To grab them we will have to use the os module that allows us to interact with the operating system. Bear in mind, that these variables are present only in the environment we’re writing the script in. So the code is:

def get_response():
‘’’Returns a response with the weather forecast for the next 5 days in 3-hour intervals’’’
    api_key = os.getenv("OPENWEATHER_API_KEY")
city = os.getenv("OPEN_WEATHER_CITY")
    base_url = "http://api.openweathermap.org/data/2.5/forecast"
    payload = {"q": city, "appid": api_key, "units": "metric"}

    return rq.get(base_url, params=payload)

The os module has a method getenv that allows passing the environmental variables inside the script. Then we just specify them as the parameters to our GET request (make sure to study the requests package to fully understand the code).

The data we need is inside a list of dictionaries called “list” where each dictionary is the forecast. If we run get_response().json()[“list”][0] it will return a forecast dictionary:

{'dt': 1616252400,
 'main': {'temp': 7.74,
  'feels_like': 3,
  'temp_min': 7.74,
  'temp_max': 9.12,
  'pressure': 1018,
  'sea_level': 1018,
  'grnd_level': 1016,
  'humidity': 54,
  'temp_kf': -1.38},
 'weather': [{'id': 500,
   'main': 'Rain',
   'description': 'light rain',
   'icon': '10d'}],
 'clouds': {'all': 70},
 'wind': {'speed': 3.73, 'deg': 71},
 'visibility': 10000,
 'pop': 0.5,
 'rain': {'3h': 0.27},
 'sys': {'pod': 'd'},
 'dt_txt': '2021-03-20 15:00:00'}

Well, the structure is easy and we can extract the data we will need.

Creating the Telegram Bot

The next step is to understand how we can create a telegram bot and interact with it. The setup is so simple that I won’t repeat the things already explained in this tutorial. In the end, the bot will give you the token to access it using Python.

Now we will have to figure out how to interact with the bot. Start a conversation on Telegram Web on your desktop computer then run this command:

rq.get(f"https://api.telegram.org/bot<YOUR_BOT_TOKEN>/getUpdates").json()

You can also write this URL in your browser. Look for {‘chat’: {‘id’: -xxxxxxxxxx… where xxxxxxxxx is the ID of the chat with your bot.

You may encounter some problems at this step (like the request returning {"ok":true,"result":[]}). Check this topic on StackOverflow, the second answer should help you (also try to send the message to your bot again).

At this step, let’s set the BOT_API_KEY (token) and CHAT_ID as environmental variables:

conda env config vars set BOT_API_KEY=<YOUR_BOT_TOKEN>
conda env config vars set CHAT_ID=<YOUR_CHAT_ID>

We need to send a forecast message to the chat with the bot but how to do it? A quick Google search can help us find out that the parameter /sendMessage with two queries (text and chat_id) can help us achieve this goal.

Let’s then write a function that will get a message as input and send it to the chat with our bot.

def send_message(message):
‘’’Sends ‘message’ to the chat with a specified ID’’’
    bot_key = os.getenv("BOT_API_KEY")
    chat_id = os.getenv("CHAT_ID")
    url =  "https://api.telegram.org/bot" + bot_key
    rq.get(url + "/sendMessage", params={"chat_id": chat_id, "text": message})

Now we have all the pieces we need to write the main function that will connect the two functions we wrote!

The Final Function

Our last function will be called main() that will take the data from the OpenWeather API, pass it to the send_message() function (with a custom message), and send it to us! Additionally, this function will add a message that reminds us to bring an umbrella if today’s rainy.

You can learn more about why I called this function main() from this great article.

So, the function is:

def main():
    forecast = get_response().json()["list"][0:7] # Forecast for the next 18 hours
    message = f"Morning Artur,\n\nToday's forecast is:\n"
    for weather in forecast:
            time_dt = dt.strptime(weather["dt_txt"], "%Y-%m-%d %H:%M:%S")
            message += (f"\nTime: {time_dt.strftime('%H:%M')}\n" \
                f"Weather: {weather['weather'][0]['description']}\n" \
                f"Temperature: {int(round(weather['main']['temp'], 0))}°C\n"
                f"Feels like: {int(round(weather['main']['feels_like'], 0))}°C\n"
                f"Wind  speed: {int(round(weather['wind']['speed'], 0)) * 3.6} Km/h\n") # Convert m/sec to km/h
    send_message(message)

Let’s go through it step by step:

  1. The first variable forecast will return the weather forecast from 6:00 to midnight if I run the script at 5:30 am

  2. The variable message initializes the text I want to receive every morning

  3. Next, we loop through the weather forecast where we:

  4. Convert the data string “dt_txt” into a datetime object

  5. Extract the time and 4 weather parameters and append them to the message. Note the symbol \n that creates a new line after each parameter

  6. We also convert the wind speed from m/sec to km/h (in Italy, we usually measure the wind speed in km/h)

  7. Finally, we pass the message to the function send_message()

That’s it! Just 10 lines of code of the main function that connects each piece of the script. The final step is to write

if __name__ == "__main__":
    main()

Why? Here is a good explanation.

The entire script is just 42 lines of code (it is the Answer to the Ultimate Question of Life, the Universe, and Everything).

Script Automation

Okay, we’ve got the script, we tested it and it works fine! But we want this bot to send us a message every morning just before we wake up. You do not want to run this manually because it will kill all the effort we’ve put in. The answer is automation: we will schedule the script to run every day at 5:30 am so we have a weather forecast from 6:00 till midnight.

One of the ways to achieve it is to use cron available on Linux. cron is a small service that allows you to schedule different tasks. The use is very simple, and you can read more about it in the article I referenced above.

I have a Linux machine but it’s not on 24/7 so I had to find another solution. One of them is to buy a Raspberry Pi, a very cheap micro-computer where you can install a Linux distribution and keep it running. The second solution is to use the 12-month free tier of Amazon Web Services that provides you a small machine with just 1 GB of RAM and 8 GB of the hard disk. It is more than enough to run small scripts like ours.

Let’s break the process in steps:

Register on AWS, add your credit card and sign in to the console. Now, you will have to click on “Launch a virtual machine” and select “Ubuntu Server ” 64-bit (x86).

On the next page, select the “t2.micro” instance and click on the “Review and Launch” blue button.

Review your instance and launch it!

You will be prompted to create a key pair that you will use to access your machine. Name it and save the .pem file in a secure place.

Now, your machine will be created. You can see it on the “Instances” page.

The next step is to connect to the server. Select your instance and click “Connect”. The page will explain to you how to connect to the server using an SSH client. They assume that you’re using Linux (that many developers use). Locate your .pem file and run this command (to give you read permissions):

chmod 400 <name>.pem
ssh -i "<name>.pem" ubuntu@<name_of_your_machine>

You should connect to your Ubuntu server where you can run usual Linux commands.

For easy management, you can move the .pem file to the ~/.ssh/ directory.

I connect to my server almost every day so it is not very practical to run the above command every time I want to connect. To simplify this process I wrote a small script that will connect me to the server by running “aws” in the terminal.

The user-defined scripts are usually located in the /usr/local/bin directory on Linux systems. Head there and create a new file called “aws” (without an extension). You may want to run the editor of your choice with the superuser permissions (using sudo). In my case, I used nano so the command was sudo nano aws. Inside the file write these two lines changing them accordingly:

#!/bin/bash
ssh -i "~/.ssh/<name>.pem" ubuntu@<name_of_your_machine>

Then save the file and make it executable by running in the terminal:

chmod +x aws

That’s it, now you can just run “aws” in your terminal and this will connect your to the AWS server. If the above commands are a bit cryptic make sure to learn a bit of Linux, it will help you in your Data Science journey.

At this point, you have to upload your script to the server. This can be done using the command scp or secure copy that will move the specified files to the AWS instance.

scp -i "<name>.pem" script.py <name_of_your_machine>:~/bots/telegram/

As before, provide the location of the .pem file and the name of your machine. The “script.py” file is the Python program you want to move; make sure you specify the exact location if you don’t run the command from the script’s directory. The “~/bots/telegram/” part is where you want the script to be uploaded on the server.

If you frequently upload different files you can try to write a script to help you do this: it may be a bit more challenging because you have to specify two arguments: the file(s) you want to upload and the place you want to upload them to.

Finally, we will have to write a small bash script that will be run with cron. I’m using a conda environment so it’s a bit challenging. Setup the environment and create a file with these commands:

#!/bin/bash
source /home/ubuntu/miniconda3/bin/activate
conda activate /home/ubuntu/bots/telegram/env
python /home/ubuntu/bots/telegram/weather_bot.py
conda deactivate
  1. The first row is called shebang (you’ve already seen it in the previous scripts). It tells the program which shell to use to run the file. In this case, we use bash.
  2. The second row makes sure that the current shell “understands” that you want to use conda
  3. The third row activates the environment
  4. The fourth row runs the script
  5. The fifth row deactivate the conda environment

I called the file run and made it executable by running:

chmod +x run

If you now run bash run, our script will send you a message. Bear in mind that the shebang is not necessary, if you remove this row, nothing will change. You have to add it if you want to run the script from every location on your computer. Have a look at this discussion on StackOverflow for more details.

cron

The last thing we need to do is to schedule it using cron. The syntax of the cron is very easy and you can read more about it in this article. The interesting challenge that I encountered is that on the AWS server if you modify the crontab file with the usual command sudo crontab -e, it will be modified in the /tmp directory so the action won’t be permanent.

You will have to modify the crontab file in the /etc directory. To do this, run this command:

sudo nano /etc/crontab

This will open the crontab file. Then I added this line to run my script every day at 5:30 am (make sure the server has the right time in your timezone).

30 5    * * *   root    /bin/bash /home/ubuntu/bots/telegram/run >> /home/ubuntu/bot-logs/telegram.log 2>&1

The last part of the above command (>> /home/ubuntu/bot-logs/telegram.log 2>&1) will append the output and errors of the script to a log file. It is very important because if the script fails it will be very helpful to know the reason to debug it.

Wrapping Up

Creating your own personal Telegram bot is a great way to learn more about Python and Linux and it’s very satisfying to create something that you and other people may use on daily basics.

After reading this article, you should know:

  • How to interact with OpenWeather API
  • How to create Telegram bots and send messages to you phone using Telegram API
  • How to set environmental variables
  • Use APIs to send a personalized weather forecast to your phone
  • Setup and AWS server
  • Upload the script on the server and schedule it

Now use your imagination and add more functionality to your script! For example, my idea is to add the info about daily vaccine administrations in Italy.

You can check the script on my GitHub.

Happy coding!

5 Likes