Как создать Python-приложение, которое предупредит о приближении астероида
Привет, Хабр! В статье я постарался показать, как объединить космос и технологии в одном приложении, которое через API оповестит пользователей по SMS о приближающемся к Земле астероиде. Подробности, как всегда, под катом.
NASA OpenAPI
NASA каждый день собирает более 15 терабайт различных данных! Вся эта информация доступна широкой аудитории бесплатно. С помощью API агентства разработчики могут использовать её для создания приложений.
Вот некоторые из доступных API, которые потенциально полезны для вашего проекта:
камера полихроматической визуализации Земли (EPIC) — полные изображения диска Земли:
отслеживание природных явлений обсерваторией EONET — прототип веб-службы, предоставляющий постоянно обновляемые метаданные природных явлений, такие как изображения штормов, собранные с поверхности Земли;
библиотека изображений и видео NASA — доступ к библиотеке изображений и видео;
звуки (бета-версия) — доступ к космическим звукам через SoundCloud с устранением некоторых шумов;
веб-служба объектов, сближающихся с Землёй (NeoWs) — предоставляет доступ к информации об астероидах, которые держат курс на нашу планету. Этот сервис нам и нужен.
Как подключить NASA API
Механику мы подглядели в этой статье на HackerNoon. И попробовали адаптировать шаги для аудитории Хабра.
Нужно получить доступ к необходимому нам программному интерфейсу. На официальном сайте NASA кликните по ссылке для подачи заявки на получение личного API-ключа. После отправки заявки NASA пришлёт вам ключ по электронной почте.
Экран с формой регистрации API НАСА.
Обратите внимание, что большинство протоколов имеет ограничение API в 1 000 запросов в час. Они подходят для тестов и личного использования, но не для коммерческих целей.
Изучение данных от NASA API
Посмотрим на данные, возвращаемые API, для построения нашего варианта использования.
Запрос (GET):
start_date (ГГГГ-ММ-ДД) — дата начала поиска астероидов
end_date (ГГГГ-ММ-ДД) — дата окончания поиска астероидов
api_key — ключ, который вы получили по электронной почте на предыдущем шаге
Ответ:
Возвращает объект JSON с ценными данными, с которыми нужно работать для получения результата.
{
"links": {
"next": "http://api.nasa.gov/neo/rest/v1/feed?start_date=2023-10-17&end_date=2023-10-17&detailed=false&api_key=8DaCUyeKqnNbupBJvDO42iUMS6tqfLFK4JjM263G",
"prev": "http://api.nasa.gov/neo/rest/v1/feed?start_date=2023-10-15&end_date=2023-10-15&detailed=false&api_key=8DaCUyeKqnNbupBJvDO42iUMS6tqfLFK4JjM263G",
"self": "http://api.nasa.gov/neo/rest/v1/feed?start_date=2023-10-16&end_date=2023-10-16&detailed=false&api_key=8DaCUyeKqnNbupBJvDO42iUMS6tqfLFK4JjM263G"
},
"element_count": 10,
"near_earth_objects": {
"2023-10-16": [
{
"links": {
"self": "http://api.nasa.gov/neo/rest/v1/neo/2337558?api_key=8DaCUyeKqnNbupBJvDO42iUMS6tqfLFK4JjM263G"
},
"id": "2337558",
"neo_reference_id": "2337558",
"name": "337558 (2001 SG262)",
"nasa_jpl_url": "http://ssd.jpl.nasa.gov/sbdb.cgi?sstr=2337558",
"absolute_magnitude_h": 19.33,
"estimated_diameter": {
"kilometers": {
"estimated_diameter_min": 0.3618719966,
"estimated_diameter_max": 0.8091703835
},
"meters": {
"estimated_diameter_min": 361.8719965994,
"estimated_diameter_max": 809.1703835499
},
"miles": {
"estimated_diameter_min": 0.2248567644,
"estimated_diameter_max": 0.5027950104
},
"feet": {
"estimated_diameter_min": 1187.2441213233,
"estimated_diameter_max": 2654.758561166
}
},
"is_potentially_hazardous_asteroid": true,
"close_approach_data": [
{
"close_approach_date": "2023-10-16",
"close_approach_date_full": "2023-Oct-16 16:00",
"epoch_date_close_approach": 1697472000000,
"relative_velocity": {
"kilometers_per_second": "20.8203253059",
"kilometers_per_hour": "74953.171101087",
"miles_per_hour": "46572.9856766726"
},
"miss_distance": {
"astronomical": "0.2519750156",
"lunar": "98.0182810684",
"kilometers": "37694925.626976772",
"miles": "23422540.6669605736"
},
"orbiting_body": "Earth"
}
],
"is_sentry_object": false
},
[...]
Обратите внимание на структуру near_earth_objects с необходимыми деталями:
estimated_diameter — диаметр астероида в метрах, километрах, милях и футах
relative_velocity — относительная скорость объекта
miss_distance — расстояние от орбитального тела
orbiting_body — в большинстве случаев это Земля, но при желании вы можете изучить и другие варианты
Поиск данных ближайшего астероида с помощью Python-приложения
NASA API даёт сведения об объектах, проходящих рядом. Мы найдём ближайший из них, чтобы ежедневно отправлять предупреждение в SMS. Используем для этого Python и библиотеку requests. Если у вас ещё не установлен Python, скачайте его с официального сайта.
Чтобы установить библиотеку requests, введите следующую команду:
$ python -m pip install requests
Создайте новый файл, например alert.py. Импортируйте установленную библиотеку requests, чтобы отправлять запросы в API. Также добавьте объект date из стандартного модуля datetime, чтобы получить сегодняшнюю дату:
import requests
from datetime import date
Получите сегодняшнюю дату с помощью импортированного модуля в формате, нужном для отправки HTTP-запроса в NASA:
# Сегодняшняя дата
todays_date = date.today().strftime("%Y-%m-%d")
Пропишите API-ключ и URL-адрес для подключения к NASA API. Получить бесплатный API-ключ нужно здесь:
nasa_api_key = "NASA_API_KEY"
nasa_url = "https://api.nasa.gov/neo/rest/v1/feed?start_date=" + todays_date +"&end_date="+ todays_date + "&api_key="+nasa_api_key
Отправьте GET-запрос в NASA API и конвертируйте ответ в JSON-формат:
# Отправляем запрос в NASA API и получаем ответ в JSON
nasa_response = requests.get(nasa_url)
json_nasa_response = nasa_response.json()
В полученном от NASA ответе нужно найти ближайший к Земле астероид в массиве near_earth_objects. Напишите функцию для поиска индекса ближайшего астероида в массиве всех близких к Земле астероидов:
# Функция для нахождения индекса ближайшего к Земле астероида в массиве всех близких астероидов
def find_closest_asteroid_index(near_asteroids):
# пустой массив для учёта дальности астероидов от Земли
asteroids = []
# перебираем астероиды в массиве near_earth_objects
for i in range(0, len(near_asteroids)):
# добавляем расстояние до Земли в массив
asteroids.insert(i, near_asteroids[i]['close_approach_data'][0]['miss_distance']['kilometers'])
# находим минимальное расстояние в массиве и возвращаем его индекс
# индекс будет совпадать с индексом ближайшего астероида в near_earth_objects
return asteroids.index(min(asteroids))
Отправка SMS-уведомления с данными о ближайшем астероиде
Далее нужно отправить SMS-уведомление, если NASA API сообщает о том, что вблизи Земли есть астероиды. Проверьте, есть ли массив near_earth_objects в ответе от NASA API. Если есть, получите список всех ближайших астероидов и найдите индекс ближайшего с помощью функции, которую написали ранее:
# Если около Земли есть астероиды
if "near_earth_objects" in json_nasa_response:
# Получаем список близких астероидов
near_asteroids = json_nasa_response['near_earth_objects'][todays_date]
# Индекс ближайшего астероида
closest_asteroid_index = find_closest_asteroid_index(near_asteroids)
Получите данные ближайшего астероида, которые отправим в SMS-уведомлении:
# Получаем данные астероида, которые отправим в SMS-уведомлении
name = near_asteroids[closest_asteroid_index]['name'] #название астероида
how_close = near_asteroids[closest_asteroid_index]['close_approach_data'][0]['miss_distance']['kilometers'] #расстояние от Земли
diameter = near_asteroids[closest_asteroid_index]['estimated_diameter']['meters']['estimated_diameter_max'] #диаметр астероида
Переведите полученные данные в строку и сформируйте текст сообщения:
# Форматируем данные в строку
how_close_str = str(round(float(how_close)))
diameter_str = str(round(diameter))
# Формируем сообщение
alert ="Ближайший астероид сегодня - " + name + ". Он находится в " + how_close_str + " км от Земли. Его диаметр составляет " + diameter_str + " метров."
Теперь можно перейти к отправке SMS-уведомления с помощью Exolve SMS API. Для этого нам понадобятся:
Добавьте в код номер Exolve, URL-адрес, API-ключ и номер получателя:
# Настройки подключения к Exolve
exolve_number = "7999XXXXXXX"
exolve_url = "https://api.exolve.ru/messaging/v1/SendSMS"
recipient_number = "7924XXXXXXX"
exolve_api_key = "EXOLVE_API_KEY"
Сделайте запрос к Exolve API с помощью библиотеки requests, чтобы отправить SMS-уведомление на указанный номер со сформированным ранее текстом сообщения с данными о ближайшем астероиде:
# Отправляем запрос в EXOLVE SMS API и получаем ответ в JSON
exolve_response = requests.post(exolve_url,
headers = {"Authorization": "Bearer " + exolve_api_key},
json = {
"number": exolve_number,
"destination": recipient_number,
"text": alert
})
json_exolve_response = exolve_response.json()
print(json_exolve_response) # message_id или ошибка отправки
Запустите код. Вы должны получить похожее SMS-уведомление:
SMS-уведомление
Резюме
Подытожим, что мы сделали:
Получили ключ API для портала NASA OpenAPI.
Изучили API NeoWs, который даёт доступ к информации об астероидах, направляющихся к Земле.
Нашли ближайший к нашей планете объект из всех тех, что могли пройти поблизости.
Отправили SMS-уведомление, чтобы предупредить себя об этой встрече.
Теперь можно спать спокойно, учитывая, что вы знаете о каждом большом объекте, летящем к Земле.
Исходный код приложения можно найти на GitHub.