Привет, Хабр! Слышали о землетрясениях, которые происходят каждый день по всему миру? Как правило, если вы не сейсмолог или не живёте рядом с тектоническим разломом, то вам всё равно. Но информировать людей о реальных катастрофах в их регионе очень важно, покажем пример такой системы оповещения через 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: стильные рюкзаки, лонгсливы и мощные беспроводные зарядки. Победители прошлых розыгрышей и правила.

Комментарии (0)