Telegram bot on the cloud

Nikolay Rubanov
Selectel
Published in
6 min readDec 4, 2020

There are plenty of services that give you weather information, but which of them should you trust? When I started cycling a lot, I wanted as accurate information as possible on the weather conditions where I was riding.

My first idea was to assemble a small DIY weather station with sensors and obtain data from it. However, I chose not to ‘reinvent the wheel’. To ensure that I had a source of verified data, I opted to use weather information that is used in civil aviation, namely METAR (Meteorological Aerodrome Report) and TAF (Terminal Aerodrome Forecast). The lives of hundreds of people depend on weather conditions in aviation, so aviation weather forecasts are highly accurate.

This information is broadcast vocally around the clock at every modern airfield in the form of ATIS (Automatic Terminal Information Service) and VOLMET (derived from French: vol means flight and météo means weather). The first one provides information about the actual weather at the airfield, while the second provides a forecast for the next 24–30 hours, not only at the airfield of broadcast but at others, too.

Example of ATIS at Vnukovo Airport

Example of Volmet at Vnukovo Airport

Given that it’s not very convenient to lug around a radio scanner or transceiver set to the right range every time, I wanted to create a bot in Telegram which allows you to get the same forecast at the click of a button. At the very least, it’s not feasible to allocate a separate server for this, in the same way that it’s not feasible to run requests through your home Raspberry.

So I decided to use the Selectel Serverless as a backend. As the number of requests will be negligible, this service will be virtually free (coming in at $0.30 per 100,000 requests, according to my calculations).

Preparing a backend

Creating a function

Open the Cloud Platform view on the my.selectel.ru control panel and create a new project:

Once you have created a project, go to the Functions:

Click the Create function button and give it a name:

After clicking Create function, a view of the created function will appear:

Before you start creating code in Python, you will need to create a bot in Telegram. I am not going to describe how to do this — detailed instructions for this are available in our knowledge base. The main thing here is creating a token for the created bot.

Making a code

As a source of reliable data, I chose the National Oceanic and Atmospheric Administration, or NOAA. This scientific agency updates data on its server in real time in TXT format.

Link to METAR data:

https://tgftp.nws.noaa.gov/data/observations/metar/stations/{код аэропорта по ICAO}.TXT

Pay attention to the register.

In my case, the nearest airport to me is Vnukovo, and its ICAO code is UUWW. Converting it to a generated URL will give the following:

2020/08/10 11:30
UUWW 101130Z 31004MPS 9999 SCT048 24/13 Q1014 R01/000070 NOSIG

The first line is the current GMT forecast. The second line is a summary of the actual weather. Civil aviation pilots will have no problem understanding what this line means, but we need to decrypt it:

[UUWW]: Vnukovo, city of Moscow (Russia, RU);

[101130Z]: 10th day of the month, 11.30 a.m. GMT;

[31004MPS]: wind direction 310 degrees, speed 4 m/sec;

[9999]: visibility at the earth’s surface of 10 km or more;

[SCT048]: scattered clouds at 4,800 feet (~1584m);

[24/13]: temperature 24°C, dew point 13°C;

[Q1014]:pressure (QNH) 1014 hPa (750 mmHg);

[R01/000070]: friction coefficient 01: 0.70;

[NOSIG]: no significant change.

Let’s start writing the software code. First, we need to import the request and pytaf functions:

from urllib import request
import pytaf

Specify the variables and prepare the decoding function:

URL_METAR = "https://tgftp.nws.noaa.gov/data/observations/metar/stations/UUWW.TXT"
URL_TAF = "https://tgftp.nws.noaa.gov/data/forecasts/taf/stations/UUWW.TXT"
def parse_data(code):
code = code.split('\n')[1]
return pytaf.Decoder(pytaf.TAF(code)).decode_taf()

Now let’s move on to TAF.

https://tgftp.nws.noaa.gov/data/forecasts/taf/stations/{код аэропорта по ICAO}.TXT

The register is also important.

As in the previous example, let’s take a look at the forecast at Vnukovo airport:

2020/08/10 12:21
TAF UUWW 101050Z 1012/1112 28003G10MPS 9999 SCT030 TX25/1012Z TN15/1103Z
TEMPO 1012/1020 -TSRA BKN020CB
BECMG 1020/1021 FEW007 BKN016
TEMPO 1021/1106 -SHRA BKN020CB PROB40
TEMPO 1021/1106 -TSRA BKN020CB
BECMG 1101/1103 34006G13MPS

Pay particular attention to the TEMPO and BECMG lines. TEMPO means that the actual weather will change periodically during the specified period. BECMG means that the weather will change gradually in the given time frame.

That is, the line:

TEMPO 1012/1020 -TSRA BKN020CB

can be decrypted as follows:

[1012/1020]: between 12.00 and 20.00 (GMT);

[-TSRA]: thunderstorm (TS = thunderstorm) with rain (RA = rain) of low intensity (minus sign);

[BKN020CB]: significant (BKN = broken), cumulonimbus clouds (CB = cumulonimbus) at 2,000 feet (610 metres) above sea level.

There are quite a lot of terms denoting weather activity, and it’s quite difficult to remember them. The code for the TAF request is written out in a similar way.

Inputting the code into the cloud

Use the Telegram bot template from our cloud-telegram-bot repository to save yourself time. There are pre-prepared requirements.txt and setup.py with the correct directory structure.

Since we access the pytaf module in the code, that version should be immediately added to requirements.txt.

pytaf~=1.2.1

Go to editing bot/tele_bot.py. Remove anything that isn’t needed and finish writing out our code.

import os
from urllib import request
import telebot
import pytaf

TOKEN = os.environ.get('TOKEN')
URL_METAR = "https://tgftp.nws.noaa.gov/data/observations/metar/stations/UUWW.TXT"
URL_TAF = "https://tgftp.nws.noaa.gov/data/forecasts/taf/stations/UUWW.TXT"

bot = telebot.TeleBot(token=TOKEN, threaded=False)
keyboard = telebot.types.ReplyKeyboardMarkup(resize_keyboard=True)
keyboard.row('/start', '/get_metar', '/get_taf')

def start(message):
msg = "Привет. Это бот для получения авиационного прогноза погоды " \
"с серверов NOAA. Бот настроен на аэропорт Внуково (UUWW)."
bot.send_message(message.chat.id, msg, reply_markup=keyboard)

def parse_data(code):
code = code.split('\n')[1]
return pytaf.Decoder(pytaf.TAF(code)).decode_taf()

def get_metar(message):
# Fetch info from server.
code = request.urlopen(URL_METAR).read().decode('utf-8')
# Send formatted answer.
bot.send_message(message.chat.id, parse_data(code), reply_markup=keyboard)

def get_taf(message):
# Fetch info from server.
code = request.urlopen(URL_TAF).read().decode('utf-8')
# Send formatted answer.
bot.send_message(message.chat.id, parse_data(code), reply_markup=keyboard)

def route_command(command, message):
"""
Commands router.
"""
if command == '/start':
return start(message)
elif command == '/get_metar':
return get_metar(message)
elif command == '/get_taf':
return get_taf(message)

def main(**kwargs):
"""
Serverless environment entry point.
"""
print(f'Received: "{kwargs}"')
message = telebot.types.Update.de_json(kwargs)
message = message.message or message.edited_message
if message and message.text and message.text[0] == '/':
print(f'Echo on "{message.text}"')
route_command(message.text.lower(), message)

⦁ Pack the entire directory in the ZIP archive and go to the created function in the control panel.

⦁ Click Edit and download the archive with the code.

⦁ Fill in the relative path in the tele_bot file (you cannot specify the .py extension) and endpoint function (in the example given, this is main).

⦁ In the Environment Variables section, write out the TOKEN variable and assign it a token of the desired telegram bot.

⦁ Click Save and expand, then go to the Triggers section.

⦁ Set the HTTP request switch to make the request public.

We have a URL that allows you to publicly name the function. All that’s left is to set up a webhook. Find our bot @BotFather in Telegram and register your bot with:

/setwebhook <you bot token> <public URL of your function>

The result

If everything is done correctly, your bot will start working immediately and display an up-to-date summary of the aviation weather directly in the messenger.

Of course, the code can be fine-tuned, but even as it is, it’s sufficient to provide you with a highly accurate weather forecast from a trusted source.

You can find the full version of the code in our repository on GitHub.

--

--