Сервисов, предоставляющих информацию о погоде, достаточно много, вот только какому из них верить? Когда я стал часто ездить на велосипеде, мне захотелось обладать наиболее точной информацией о погодных условиях в том месте, где я катаюсь.
Первой мыслью было собрать небольшую DIY погодную станцию с датчиками и получать данные с нее. Но я не стал «изобретать велосипед» и в качестве источника проверенных данных выбрал погодную информацию, которая используется в гражданской авиации, а именно METAR (METeorological Aerodrome Report) и TAF (TAF — Terminal Aerodrome Forecast). В авиации от погоды зависят жизни сотен людей, поэтому прогнозы максимально точны.
Эта информация в круглосуточном режиме транслируется голосом на каждом современном аэродроме в виде ATIS (Automatic Terminal Information Service) и VOLMET (от франц. vol — полет и météo — погода). Первый предоставляет информацию о фактической погоде на аэродроме, а второй — прогноз на ближайшие 24-30 часов, причем не только на аэродроме трансляции, но и на других.
Пример работы ATIS аэропорта Внуково:
Пример работы VOLMET аэропорта Внуково
Каждый раз таскать с собой радиосканнер или трансивер на соответствующий диапазон неудобно, и мне захотелось создать бота в Telegram, который по нажатию кнопки позволяет получить такой же прогноз. Выделять под это отдельный сервер как минимум нецелесообразно, равно как и гонять запросы на домашнюю Raspberry.
Поэтому в качестве бэкэнда я решил использовать сервис
Подготовка бэкэнда
Создание функции
В панели управления
После того как проект создан, переходим в раздел Функции:
Нажимаем кнопку Создать функцию и задаем ей нужное имя:
После нажатия Создать функцию у нас появится представление созданной функции:
Перед тем, как приступить к созданию кода на Python, потребуется создать бота в Telegram. Расписывать, как это делается, я не буду — детальная инструкция есть
Готовим код
В качестве источника надежных данных я выбрал Национальное управление океанических и атмосферных исследований США (англ. National Oceanic and Atmospheric Administration, NOAA). Это научное агентство в реальном времени обновляет данные на своем сервере в формате TXT.
Ссылка для получения данных METAR (обратите внимание на регистр):
https://tgftp.nws.noaa.gov/data/observations/metar/stations/<код аэропорта по ICAO>.TXT
В моем случае ближайшим аэропортом является Внуково, его код по ICAO — UUWW. Переход на сформированный URL выдаст следующее:
2020/08/10 11:30
UUWW 101130Z 31004MPS 9999 SCT048 24/13 Q1014 R01/000070 NOSIG
Первая строка — время актуальности прогноза по Гринвичу. Вторая строка — сводка о фактической погоде. Пилоты гражданской авиации без проблем поймут, что означает эта строка, однако нам нужна расшифровка:
- [UUWW] — Внуково, город Москва (Россия — RU);
- [101130Z] — 10-й день месяца, 11 часов 30 минут по Гринвичу;
- [31004MPS] — направление ветра 310 градусов, скорость 4 м/с;
- [9999] — горизонтальная видимость 10 км и более;
- [SCT048] — рассеянные/разбросанные облака на высоте 4800 футов (~1584м);
- [24/13] — температура 24°C, точка росы 13°C;
- [Q1014] — давление (QNH) 1014 гектопаскалей (750 мм рт. ст.);
- [R01/000070] — коэффициент сцепления на полосе 01 — 0,70;
- [NOSIG] — без существенных изменений.
Приступаем к написанию программного кода. Для начала потребуется импортировать функции request и pytaf:
from urllib import request
import pytaf
Указать переменные и подготовить функцию декодирования:
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()
Перейдем к TAF (регистр также важен).
https://tgftp.nws.noaa.gov/data/forecasts/taf/stations/<код аэропорта по ICAO>.TXT
Как и в предыдущем примере, посмотрим прогноз в аэропорту Внуково:
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
Особенно обратим внимание на строки TEMPO и BECMG. TEMPO означает то, что фактическая погода в указанный промежуток будет периодически меняться. BECMG — погода постепенно изменится в указанный промежуток времени.
То есть строка:
TEMPO 1012/1020 -TSRA BKN020CB
Будет означать:
- [1012/1020] — в промежуток с 12 до 20 часов (по Гринвичу);
- [-TSRA] — гроза (TS = thunderstorm) с дождем (RA = rain) небольшой интенсивности (знак минус);
- [BKN020CB] — значительная (BKN = broken), кучево-дождевая (CB = cumulonimbus) облачность на высоте 2000 футов (610 метров) над уровнем моря.
Терминов, означающих погодные явления, достаточно много, и запомнить их сложновато. Код для запроса TAF пишется аналогичным образом.
Заливаем код в облако
Чтобы не тратить зря время, возьмем шаблон телеграм-бота из нашего репозитория
Поскольку в коде мы будем обращаться к модулю pytaf, то его версию следует сразу добавить в requirements.txt
pytaf~=1.2.1
- Переходим к редактированию bot/tele_bot.py. Убираем все лишнее и дописываем наш код.
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)
- Упаковываем всю директорию в ZIP-архив и переходим в панель управления к созданной функции.
- Нажимаем Редактировать и загружаем архив с кодом.
- Заполняем относительный путь в файлу tele_bot (расширение .py можно не указывать) и эндпойнт-функцию (в приведенном примере это main).
- В разделе Переменные окружения пишем переменную TOKEN и присваиваем ей токен нужного телеграм-бота.
- Нажимаем Сохранить и развернуть, после чего переходим в раздел Триггеры.
- Ставим переключатель HTTP-запрос, чтобы сделать запрос публичным.
У нас появился URL для публичного вызова функции. Осталось лишь
/setwebhook <you bot token> <public URL of your function>
Результат
Если все сделано правильно, то ваш бот сразу начнет работать и отображать актуальную сводку авиационной погоды прямо в мессенджере.
Разумеется, код можно дорабатывать, однако даже в текущем состоянии его достаточно, чтобы узнать самую точную погоду и прогноз из проверенного источника.
Полную версию кода вы найдете в нашем
Источник: habr.com