GiZano/QuakeGuard

GitHub: GiZano/QuakeGuard

QuakeGuard 是一个将家用电器转化为分布式地震传感器的全栈 IoT 预警系统,实现从边缘振动检测、云端分析到移动端实时告警的完整链路。

Stars: 18 | Forks: 2

# 🌋 QuakeGuard ### 家用地震报警系统 **用于实时地震检测的全栈 IoT 架构** ![Version](https://img.shields.io/badge/Version-1.0.0-red?style=for-the-badge) ![License](https://img.shields.io/badge/License-AGPL--3.0-blue?style=for-the-badge) ![C++](https://img.shields.io/badge/C++-Hardware_Logic-00599C?style=for-the-badge&logo=c%2B%2B&logoColor=white) ![Python](https://img.shields.io/badge/Python-FastAPI-3670A0?style=for-the-badge&logo=python&logoColor=ffdd54) ![React Native](https://img.shields.io/badge/React_Native-Mobile-20232A?style=for-the-badge&logo=react&logoColor=61DAFB) ![PostgreSQL](https://img.shields.io/badge/PostgreSQL-PostGIS-316192?style=for-the-badge&logo=postgresql&logoColor=white) ![Redis](https://img.shields.io/badge/Redis-Message_Broker-DC382D?style=for-the-badge&logo=redis&logoColor=white) ![Docker](https://img.shields.io/badge/Docker-Containerization-2496ED?style=for-the-badge&logo=docker&logoColor=white) ![CI Backend](https://static.pigsec.cn/wp-content/uploads/repos/cas/60/60d45088f57ac8c97e6ad533cdadd8091e00a4ff2fb972e63ba7420983afcec5.svg) ![CI Frontend](https://static.pigsec.cn/wp-content/uploads/repos/cas/f7/f7820b0c1bfcd7b7f1036571f27536a5fefe6db84280c8a53a03e41882a5b681.svg) ![CI IoT](https://static.pigsec.cn/wp-content/uploads/repos/cas/34/34629a399b42290930d40e5b9263c5aedf23ebce44eec8b8e46f9822ddaf85b4.svg) ![QuakeGuard Logo](https://raw.githubusercontent.com/GiZano/QuakeGuard/main/docs/assets/logo/png/github-banner.png)
## 📖 概述 **QuakeGuard** 是一个用于实时检测、分析和报告地震事件的全栈 IoT 架构。该系统将日常家用电器——洗衣机、电视、冰箱——转化为一个分布式地震传感器网络,每个节点都能自主检测和报告地震活动。 智能边缘传感器(ESP32-C3 + ADXL345)使用专业级算法在本地分析振动,并将经过加密签名的数据传输到异步云端 backend。该 backend 旨在处理大规模流量峰值——即广泛地震事件期间典型的**惊群效应(Thundering Herd)**——确保无瓶颈地可靠交付警报。React Native 移动应用通过 WebSocket 接收实时触觉和视觉警报。 ## 🏗️ 系统架构 ``` ESP32-C3 + ADXL345 │ │ MQTT (signed payload) ▼ MQTT Bridge ──► POST /readings/ ──► ECDSA Verification │ ▼ Redis Queue │ ▼ Background Worker │ │ ▼ ▼ PostgreSQL Redis Pub/Sub + PostGIS │ ▼ WebSocket Broadcast │ ▼ React Native Mobile App (Haptic + Visual Alert) ``` 该项目在三个完全独立的层中遵循**微服务**和**事件驱动设计**原则。 ## 📡 IoT 边缘层 (`firmware/`) | 功能 | 详情 | |---------|--------| | 硬件 | ESP32-C3 SuperMini + ADXL345 加速度计 | | 采样率 | 100 Hz | | 检测算法 | STA/LTA(短期 / 长期平均值) | | 信号处理 | 数字高通滤波器(HPF),用于消除重力影响 | | 数据结构 | 静态分配的环形缓冲区(`RingBuffer<100>` STA, `RingBuffer<1000>` LTA) | | 安全性 | 对每个 payload 进行 ECDSA NIST256p 加密签名 | | 传输 | 通过 MQTT 发布到 `quakeguard/telemetry` | | 配置 | 设备首次启动时通过 `POST /devices/register` 自动握手 | | 密钥注入 | 通过 PlatformIO 预脚本在编译时注入 `ENROLLMENT_TOKEN` + `#error` 快速失败 | ## ☁️ Backend (`backend/`) | 功能 | 详情 | |---------|--------| | 框架 | FastAPI (Python 3.11),完全异步 | | 安全性 | API Key 认证,ECDSA 签名验证,防重放(60秒窗口) | | 消息代理 | Redis —— 将数据摄取与处理解耦 | | 限流 | 通过 Redis 对每个 IP 进行 50 req/s 的固定窗口限流 | | 警报引擎 | 类 ML 震级估算(`M = log10(PGA_calib) + b`),阈值 M ≥ 4.5 | | 去重 | 每个区域的 Redis TTL 冷却锁(60秒),防止警报风暴 | | 持久化 | PostgreSQL + PostGIS,带有 `recorded_at` 时间戳 | | 区域分配 | 通过 PostGIS `ST_Contains` 空间查询自动分配,按 `ST_Area` 升序排列 | | 区域播种 | 8 个预填充的全球宏观区域 + “未知区域”回退 | | 可观测性 | `GET /health` —— 并发执行 PostgreSQL + Redis ping | | 密钥 | 启动时如果缺少环境变量会触发快速失败 `RuntimeError` | | MQTT 网桥 | `mqtt_subscriber.py` —— 将 MQTT payload 转发到安全的 HTTP pipeline | ## 📱 Frontend (`mobile/`) | 功能 | 详情 | |---------|--------| | 框架 | React Native (Expo) 与 TypeScript | | 导航 | Expo Router —— 3 标签底部导航器(监控、传感器地图、设置) | | 状态管理 | Zustand 切片(`usePreferencesStore`、`useAlertStore`) | | 服务端状态 | TanStack Query + Axios —— 缓存、后台重新获取、重试 | | 实时 | 具有指数退避重连机制的 WebSocket 上下文 | | 警报传递 | SOS 触觉振动模式 + 通过 `expo-notifications` 推送 OS 通知 | | 警报历史 | 会话内显示最近 10 次关键事件的动态 | | 离线模式 | 开关可静音 WebSocket,停止所有 TanStack Query 轮询 | | 通知 | `notificationsEnabled` 开关控制触觉反馈和推送通知 | | 安全区域 | `react-native-safe-area-context` —— 兼容灵动岛和打孔屏 | ## 🔐 安全模型 在紧急系统中,数据完整性至关重要。每个遥测数据包都经过了端到端的加密保护。 ``` ESP32 signs payload with ECDSA NIST256p (SHA256) ↓ Backend verifies signature against registered public key ↓ Timestamp validated within 60-second window (Anti-Replay) ↓ API Key checked on every request (X-API-Key header) ↓ Payload accepted → Redis Queue ``` **威胁模型覆盖范围:** - ✅ 中间人攻击—— ECDSA 签名验证 - ✅ 欺骗攻击—— 公钥注册 + 签名检查 - ✅ 重放攻击—— 60秒时间戳窗口 - ✅ 暴力破解—— 每个 IP 限制 50 req/s - ✅ 未经授权的访问—— API Key + 注册 token 快速失败 | ## 🚀 快速开始 ### 前置条件 - Docker Desktop & Docker Compose - PlatformIO(VS Code 扩展) - Node.js 18+ & Expo Go(移动端) - 用于 ESP32 + backend 连接的移动热点或共享 WiFi 网络 ### 1. 配置环境变量 ``` cd backend/api cp .env.example .env ``` 编辑 `.env` 并设置所需的密钥: ``` IOT_API_KEY=your_secret_key MOBILE_WS_TOKEN=your_ws_token ENROLLMENT_TOKEN=your_enrollment_token POSTGRES_DB=quakeguard_db POSTGRES_USER=developer POSTGRES_PASSWORD=your_db_password API_PORT=8000 ``` ### 2. 启动 Backend Stack ``` cd backend/api docker compose up --build -d ``` | 端点 | URL | |----------|-----| | API | `http://localhost:8000` | | Swagger UI | `http://localhost:8000/docs` | | 健康检查 | `http://localhost:8000/health` | ### 3. 配置并刷入 IoT 固件 ``` cd firmware/esp32_code cp esp32_config.env.example esp32_config.env # 使用你的网络 IP 和 ENROLLMENT_TOKEN 编辑 esp32_config.env ``` 通过 PlatformIO 刷入。首次启动时,设备将: 1. 打开 WiFi 强制门户(`QuakeGuard-Setup`) 2. 连接到您的网络 3. 自动向 backend 注册并接收 `sensor_id` ### 4. 启动移动应用 ``` cd mobile npm install ``` 使用您机器的本地 IP 更新 `constants/config.ts`: ``` export const API_BASE_URL = "http://YOUR_LOCAL_IP:8000"; ``` 在 mobile 根目录下创建 `.env`: ``` EXPO_PUBLIC_IOT_API_KEY=your_secret_key EXPO_PUBLIC_MOBILE_WS_TOKEN=your_ws_token ``` ``` npx expo start ``` 使用 Expo Go 扫描二维码。确保您的手机与 backend 机器连接在**相同的 WiFi 网络**下。 ## 🧪 压力测试 验证完整 pipeline:摄取 → Redis → worker → PostGIS → WebSocket 警报。 ``` cd backend/api export API_URL="http://localhost:8000" export NUM_SENSORS=150 export CONCURRENCY_LIMIT=50 python -m tests.stress_test ``` **三个阶段:** | 阶段 | 测试内容 | |-------|--------------| | 🔥 阶段 1 —— 消防水带 | 150 个并发传感器,限流器验证 | | ⚔️ 阶段 2 —— 安全性 | 错误签名被阻止 (401),重放攻击被阻止 (403) | | 🔍 阶段 3 —— E2E | 通过轮询 `GET /sensors/{id}/statistics` 验证数据库持久化 | 成功运行将以 `🏆 SYSTEM CERTIFIED` 结束。 ## 🎮 演示模式 直接从 Swagger UI 立即触发模拟地震,而无需运行压力测试: ``` POST /demo/trigger-earthquake ``` 默认 payload(适用于空的 `{}`): ``` { "zone_id": 1, "magnitude": 7.5, "message": "Simulated Critical Event" } ``` 这会直接发布到 Redis 的 `quake_alerts` 频道,完全绕过 IoT pipeline,并在几毫秒内触发移动应用警报 UI。 ## 🗺️ 地理区域 数据库预装了 8 个全球宏观区域。传感器在注册时会通过 PostGIS 空间查询自动分配到正确的区域。 | 区域 | 覆盖范围 | |------|----------| | 意大利 - 北部 | 伦巴第、威尼托、皮埃蒙特 | | 意大利 - 中部 | 托斯卡纳、拉齐奥、翁布里亚 | | 意大利 - 南部及岛屿 | 坎帕尼亚、西西里、撒丁 | | 西欧 | 法国、西班牙、德国、英国 | | 北美 | 美国、加拿大、墨西哥 | | 南美 | 巴西、阿根廷、智利 | | 东亚 | 中国、日本、印度 | | 未知区域 | 未映射坐标的回退区域 | ## 🔄 CI/CD Pipeline | 工作流 | 触发器 | 检查项 | |----------|---------|--------| | `backend-ci.yml` | `backend/**` | Bandit, Safety, 压力测试 | | `frontend-ci.yml` | `mobile/**` | ESLint, npm audit | | `iot-ci.yml` | `firmware/**` | PlatformIO 编译 | | `pr-lint.yml` | 所有 PR | 语义化 PR 标题(`type(scope): message`) | | `devops-ci.yml` | `.github/workflows/**` | Actionlint workflow 验证 | ## 🗂️ 项目结构 ``` QuakeGuard/ ├── backend/ │ └── api/ │ ├── src/ │ │ ├── main.py # FastAPI gateway + REST endpoints │ │ ├── security.py # ECDSA, API Key, Anti-Replay │ │ ├── worker.py # Redis consumer + magnitude + alert engine │ │ ├── mqtt_subscriber.py # MQTT to HTTP bridge │ │ ├── seed.py # Geographic zone seeder │ │ ├── models.py # SQLAlchemy ORM models │ │ ├── schemas.py # Pydantic request/response schemas │ │ └── database.py # DB engine and session factory │ ├── tests/ │ │ └── stress_test.py # Critical E2E stress test suite │ ├── build.ps1 # Automatic container publish │ ├── docker-compose.yml │ ├── Dockerfile │ ├── mosquitto.conf │ ├── requirements.txt # Python requirements for backend development │ └── .env.example ├── mobile/ │ ├── app/ # Expo Router screens │ │ └── (tabs)/ │ │ ├── index.tsx # Monitor / Dashboard │ │ ├── map.tsx # Sensor Network Map │ │ └── settings.tsx # User Preferences │ ├── api/ # Axios client + TanStack Query hooks │ ├── components/ # Shared UI components │ ├── store/ # Zustand state slices │ ├── context/ │ │ └── WebSocketContext.tsx # Real-time alert context │ └── constants/ │ └── config.ts # Centralized configuration └── firmware/ └── esp32_code/ ├── src/ │ ├── main.cpp # FreeRTOS tasks, STA/LTA, MQTT, provisioning │ └── RingBuffer.h # Statically allocated circular buffer ├── test/ # Test scripts to insert into the ESP32 ├── key_generator/ │ └── key_gen.py # ECDSA key generator for backend testing ├── esp32_config.env.example ├── extra_script.py # ENV variables injector └── platformio.ini ``` ## 🔮 路线图 | 版本 | 重点 | |---------|-------| | **v1.0** | ✅ 当前版本 —— 完整的 E2E pipeline,移动应用,CI/CD | | **v1.1** | 文档 wiki,Alembic 迁移,云端 MQTT broker | | **v2.0** | AI 驱动的地震智能助手(Ollama + 自然语言查询) | ## 📄 许可证 该项目基于 **GNU Affero General Public License v3.0 (AGPL-3.0)** 授权。 详情请参阅 [LICENSE](LICENSE) 文件。
**由 [GiZano](https://giovanni-zanotti.is-a.dev) 和 [riccardo0731](https://riccardo0731.github.io) 开发**
*开源 —— AGPL-3.0 许可证*

标签:AV绕过, FastAPI, PostgreSQL, React Native, Redis, 地震监测, 嵌入式硬件, 搜索引擎查询, 测试用例, 物联网, 请求拦截, 逆向工具