GiZano/QuakeGuard
GitHub: GiZano/QuakeGuard
QuakeGuard 是一个将家用电器转化为分布式地震传感器的全栈 IoT 预警系统,实现从边缘振动检测、云端分析到移动端实时告警的完整链路。
Stars: 18 | Forks: 2
# 🌋 QuakeGuard
### 家用地震报警系统
**用于实时地震检测的全栈 IoT 架构**












## 📖 概述
**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 许可证*
*开源 —— AGPL-3.0 许可证*
标签:AV绕过, FastAPI, PostgreSQL, React Native, Redis, 地震监测, 嵌入式硬件, 搜索引擎查询, 测试用例, 物联网, 请求拦截, 逆向工具