Как сделать SMS-оповещение о землетрясениях с GeoJSON и SMS API

—

от автора

Привет, Хабр! Слышали о землетрясениях, которые происходят каждый день по всему миру? Как правило, если вы не сейсмолог или не живёте рядом с тектоническим разломом, то вам всё равно. Но информировать людей о реальных катастрофах в их регионе очень важно, покажем пример такой системы оповещения через SMS. 

Сегодня мы построим небольшой центр уведомлений. За основу возьмем GeoJSON Earthquake API для получения данных о землетрясениях, подключим Exolve API, чтобы рассылать SMS, а для хранения данных используем PostgreSQL.

Что используем

  • GeoJSON Earthquake API — предоставляет данные о землетрясениях в формате GeoJSON. Включает координаты, магнитуду, время и другие параметры.

  • Exolve SMS API — позволяет отправлять SMS с динамическими шаблонами.

  • PostgreSQL — база данных для хранения землетрясений и логирования уведомлений.

  • RabbitMQ — очередь сообщений для асинхронной отправки SMS.

  • Python — связываем все компоненты в единую работающую систему.

Как всё будет работать

  1. Получение данных: скрипт запрашивает данные о землетрясениях через GeoJSON API каждые 10 минут.

  2. Фильтрация: геофильтры отбирают только события, которые относятся к нужному региону (например, России).

  3. Обработка событий: новые события записываются в базу данных. Уведомления отправляются в RabbitMQ.

  4. Асинхронная отправка SMS: RabbitMQ обрабатывает очередь, отправляя SMS через Exolve API.

  5. Хранение истории: PostgreSQL сохраняет данные для аналитики.

Подготовка базы данных

Сначала создаём таблицы для хранения данных о землетрясениях и уведомлениях.

CREATE TABLE earthquakes (     id SERIAL PRIMARY KEY,     quake_id TEXT UNIQUE NOT NULL,     magnitude REAL NOT NULL,     place TEXT,     time TIMESTAMP NOT NULL,     longitude REAL NOT NULL,     latitude REAL NOT NULL );  CREATE TABLE notifications (     id SERIAL PRIMARY KEY,     earthquake_id INTEGER REFERENCES earthquakes(id),     phone_number TEXT NOT NULL,     sent_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );

Таблица earthquakes хранит данные о землетрясениях. Поле quake_id уникальное, чтобы одно событие не записывалось дважды.

Таблица notifications логирует каждое отправленное SMS, связывая его с конкретным землетрясением.

Подключим RabbitMQ

RabbitMQ — это очередь сообщений, которая позволяет отправлять уведомления асинхронно. Установим RabbitMQ:

sudo apt install rabbitmq-server sudo systemctl start rabbitmq-server sudo systemctl enable rabbitmq-server

Теперь создадим очередь для уведомлений. Очереди делают обработку сообщений надёжной, даже если часть системы временно недоступна.

Подключимся к базе данных и RabbitMQ:

import psycopg2 import pika  # Подключение к PostgreSQL def get_db_connection():     return psycopg2.connect(         dbname="earthquakes",         user="your_user",         password="your_password",         host="localhost"     )  # Инициализация RabbitMQ def init_rabbitmq():     connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))     channel = connection.channel()     channel.queue_declare(queue='notifications')     return channel

get_db_connection() создаёт подключение к PostgreSQL, а init_rabbitmq() подключается к RabbitMQ и создаёт очередь notifications, если её ещё нет.

Работа с GeoJSON API и фильтрация событий

import requests from datetime import datetime from shapely.geometry import Point, Polygon  GEOJSON_API_URL = "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_day.geojson"  # Координаты границ региона (пример для России) RUSSIA_BOUNDS = Polygon([     (19.0, 41.0), (19.0, 82.0), (169.0, 82.0), (169.0, 41.0), (19.0, 41.0) ])  def is_in_region(longitude, latitude):     point = Point(longitude, latitude)     return RUSSIA_BOUNDS.contains(point)  def fetch_earthquake_data():     response = requests.get(GEOJSON_API_URL)     if response.status_code != 200:         print(f"Ошибка API: {response.status_code}")         return []      data = response.json()     earthquakes = []     for feature in data["features"]:         props = feature["properties"]         coords = feature["geometry"]["coordinates"]          if props["mag"] >= 4.5 and is_in_region(coords[0], coords[1]):             earthquakes.append({                 "id": feature["id"],                 "magnitude": props["mag"],                 "place": props["place"],                 "time": datetime.fromtimestamp(props["time"] / 1000),                 "longitude": coords[0],                 "latitude": coords[1]             })      return earthquakes

fetch_earthquake_data() запрашивает данные с GeoJSON API и возвращает список землетрясений, которые соответствуют нашим фильтрам. is_in_region() проверяет, находится ли событие в пределах России.

Сохраним данные и отправим уведомления в RabbitMQ

def save_earthquake(conn, quake):     with conn.cursor() as cursor:         cursor.execute("""             INSERT INTO earthquakes (quake_id, magnitude, place, time, longitude, latitude)             VALUES (%s, %s, %s, %s, %s, %s)             ON CONFLICT (quake_id) DO NOTHING         """, (quake['id'], quake['magnitude'], quake['place'], quake['time'], quake['longitude'], quake['latitude']))     conn.commit()  def send_to_queue(channel, earthquake):     message = {         "place": earthquake["place"],         "magnitude": earthquake["magnitude"],         "time": earthquake["time"].strftime("%Y-%m-%d %H:%M:%S")     }     channel.basic_publish(exchange='', routing_key='notifications', body=json.dumps(message))     print(f"Сообщение отправлено в очередь: {message}")

save_earthquake() записывает событие в базу данных и send_to_queue() отправляет данные о землетрясении в очередь RabbitMQ для дальнейшей обработки.

Обработчик уведомлений

import requests import json  EXOLVE_API_URL = "https://api.exolve.ru/messaging/v1/SendSMS" EXOLVE_API_KEY = "Bearer your_api_key_here"  def process_notifications(ch, method, properties, body):     data = json.loads(body)     message = (         f"⚠ Землетрясение!\n"         f"Местоположение: {data['place']}\n"         f"Магнитуда: {data['magnitude']}\n"         f"Время: {data['time']}\n"         f"Рекомендация: Оставайтесь в безопасности."     )      payload = {         "number": "AlfaName",         "destination": "79991112233",         "text": message     }     headers = {         "Authorization": EXOLVE_API_KEY,         "Content-Type": "application/json"     }      response = requests.post(EXOLVE_API_URL, json=payload, headers=headers)     if response.status_code == 200:         print("SMS успешно отправлено")     else:         print(f"Ошибка SMS: {response.status_code}")

process_notifications() забирает данные из очереди и отправляет SMS через Exolve API.

Виды сообщений

  • Предупреждение: «⚠ Землетрясение! Магнитуда 5.4. Оставайтесь в безопасности!»

  • Рекомендация: «Следуйте к безопасной зоне. Проверьте перекрытие газа и воды.»

  • Статус: «Все системы работают. Угрозы нет.»

Заключение

Создали систему, которая:

  1. Обрабатывает данные о землетрясениях.

  2. Фильтрует события по географическим границам.

  3. Отправляет уведомления с помощью RabbitMQ и Exolve API.

  4. Хранит все данные в PostgreSQL.

Знайте, статья носит исключительно ознакомительный характер и не может использоваться как основа для построения системы раннего оповещения или критической инфраструктуры. Для реальных задач, связанных с чрезвычайными ситуациями, рекомендуется обращаться к специализированным службам и сертифицированным решениям.


Подписывайтесь на наш Хаб, следите за новыми гайдами и получайте приз

Каждый понедельник мы случайным образом выбираем победителей среди новых подписчиков нашего Хабр-канала и дарим крутые призы от МТС Exolve: стильные рюкзаки, лонгсливы и мощные беспроводные зарядки. Победители прошлых розыгрышей и правила.


ссылка на оригинал статьи https://habr.com/ru/articles/875216/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *