diff --git a/.github/ISSUE_TEMPLATE/hardware_issue.md b/.github/ISSUE_TEMPLATE/hardware_issue.md new file mode 100644 index 0000000..21d883e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/hardware_issue.md @@ -0,0 +1,40 @@ +--- +name: Hardware Issue +about: Report a hardware-related problem (PCB, wiring, components, assembly) +title: "[HW] " +labels: hardware +--- + +# Description +A clear description of the hardware issue. Specify which board revision and components are affected. + +# Guidelines +Before submitting, please verify: +- [ ] You have checked the [Bill of Materials (BOM)](https://github.com/GiZano/QuakeGuard/wiki/Bill-of-Materials) and confirmed correct components +- [ ] You have verified wiring against the [Pinout Table](firmware/PINOUT.md) +- [ ] You have included photos or serial output below + +# Hardware Details +- **PCB Revision:** +- **Assembly Method:** +- **Component Affected:** +- **Power Source:** + +# Steps to Reproduce +1. +2. +3. + +# Serial Monitor Output +``` + +``` + +# Photos + + +# Expected Behavior +What should happen with correct hardware operation. + +# Actual Behavior +What is actually happening. Include any error LEDs, missing readings, or unexpected behavior. diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..e59abc4 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,42 @@ +# Dependabot — Automated dependency updates for QuakeGuard +# Docs: https://docs.github.com/en/code-security/dependabot/dependabot-version-updates +version: 2 +updates: + # --- Python (Backend) --- + - package-ecosystem: "pip" + directory: "/backend" + schedule: + interval: "weekly" + day: "monday" + labels: + - "dependencies" + - "backend" + commit-message: + prefix: "chore(deps)" + open-pull-requests-limit: 5 + + # --- npm (Mobile) --- + - package-ecosystem: "npm" + directory: "/mobile" + schedule: + interval: "weekly" + day: "monday" + labels: + - "dependencies" + - "mobile" + commit-message: + prefix: "chore(deps)" + open-pull-requests-limit: 5 + + # --- GitHub Actions --- + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + labels: + - "dependencies" + - "ci" + commit-message: + prefix: "chore(ci)" + open-pull-requests-limit: 5 diff --git a/.github/workflows/gitleaks.yml b/.github/workflows/gitleaks.yml new file mode 100644 index 0000000..91f1e4b --- /dev/null +++ b/.github/workflows/gitleaks.yml @@ -0,0 +1,24 @@ +name: "Gitleaks — Secret Scanning" + +on: + push: + branches: ["main"] + pull_request: + branches: ["main"] + +jobs: + scan: + name: Detect Leaked Secrets + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Checkout repository + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 + with: + fetch-depth: 0 + + - name: Run Gitleaks + uses: gitleaks/gitleaks-action@ff98106e4c7b2bc287b24eaf42907196e88a9c30 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index 7877068..33b0a84 100644 --- a/.gitignore +++ b/.gitignore @@ -62,4 +62,9 @@ extract.sh research/data/ research/out/ research/*.png -firmware/tools/detect_cli \ No newline at end of file +firmware/tools/detect_cli + +# ------------------------------------------ +# KiCad local history +# ------------------------------------------ +.history/ \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index f31940c..01139d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,26 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [2.0.2] - 2026-09-03 +### Added +- **Dependabot Configuration:** Automated dependency updates for pip (backend), npm (mobile), and GitHub Actions (`.github/dependabot.yml`). +- **Gitleaks Secret Scanning:** CI workflow (`.github/workflows/gitleaks.yml`) to prevent accidental credential leaks in commits — critical for a project handling ECDSA keys and MQTT credentials. +- **Architecture Decision Records (ADRs):** Created `docs/adr/` with 4 initial ADRs documenting key architectural decisions: Redis Streams (0001), HiveMQ Cloud (0002), Hybrid Edge AI (0003), CERN-OHL licensing (0004). +- **C4 and Sequence Diagrams:** Created `docs/diagrams/` with Mermaid diagrams: C4 Context/Container, provisioning sequence, alert delivery sequence, and triangulation sequence — versionable independently from the Typst whitepaper. +- **Firmware Versioning:** Added `#define FIRMWARE_VERSION "2.0.2"` printed at boot via serial for field identification and remote debugging. +- **Pinout Reference:** Created `firmware/PINOUT.md` — unified GPIO mapping, LED behavior table, connector pinout, and passive component reference. +- **Flashing Guide:** Created `firmware/FLASHING.md` — standalone step-by-step flashing instructions for users without VS Code/PlatformIO IDE. +- **Privacy Policy:** Created `mobile/PRIVACY_POLICY.md` — documents data collection, storage, and third-party services for App Store/Play Store compliance. +- **SUPPORT.md:** Routing guide for all help channels (bugs, features, hardware, security, discussions). +- **Hardware Issue Template:** `.github/ISSUE_TEMPLATE/hardware_issue.md` for PCB, wiring, and component assembly reports. +- **Docker Compose Override Example:** `backend/docker-compose.override.yml.example` for local development customization. + +### Changed +- **Dockerfile Multi-Stage Build:** Refactored `backend/Dockerfile` to a two-stage build (builder + runtime), reducing final image size by excluding build toolchain (gcc, python3-dev). +- **BOM Enrichment:** Expanded `hardware/QuakeGuard_PCB/output/BOM.csv` with manufacturer, part number, unit cost, distributor links (LCSC/DigiKey), and socketable modules (ESP32-C3, ADXL345, NEO-6M). +- **README Enhancements:** Added "PRs welcome" badge, prominent landing page link, CERN-OHL license reference, hardware compliance disclaimer, and v2.0.2 roadmap entry. +- **Version artifacts bumped to v2.0.2** (CITATION.cff, firmware header, README roadmap, SECURITY.md). + ## [2.0.1] - 2026-09-01 ### Changed - **Documentation Polish (Zenodo Sync):** Removed residual LLM tags (`[cite: 1]`) from the technical whitepaper. diff --git a/CITATION.cff b/CITATION.cff index a72055c..b24824b 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -10,12 +10,12 @@ authors: given-names: "Riccardo" alias: "riccardo0731" title: "QuakeGuard" -version: 2.0.1 +version: 2.0.2 identifiers: - type: doi value: "10.5281/zenodo.21710405" description: "Concept DOI (Absolute - resolves to all versions)" -date-released: 2026-09-01 +date-released: 2026-09-03 url: "https://giovanni-zanotti.is-a.dev/projects/quakeguard.html" repository-code: "https://github.com/GiZano/QuakeGuard" license: "AGPL-3.0" diff --git a/README.md b/README.md index 07910e3..e80be2d 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,8 @@ [![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=GiZano_QuakeGuard&metric=code_smells)](https://sonarcloud.io/summary/new_code?id=GiZano_QuakeGuard) [![Duplicated Lines (%)](https://sonarcloud.io/api/project_badges/measure?project=GiZano_QuakeGuard&metric=duplicated_lines_density)](https://sonarcloud.io/summary/new_code?id=GiZano_QuakeGuard) +![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen?style=for-the-badge) + > 📚 **Technical Specification:** A comprehensive architecture whitepaper is available in the `docs/` directory, compiled via Typst. For a browsable, topic-by-topic reference, check out the [project Wiki](https://github.com/GiZano/QuakeGuard/wiki). ![QuakeGuard Logo](docs/web/assets/quakeguard/github-banner.png) @@ -41,6 +43,10 @@ --- +🌐 **[Landing Page](https://giovanni-zanotti.is-a.dev/projects/quakeguard.html)** · 📚 **[Wiki](https://github.com/GiZano/QuakeGuard/wiki)** · 📄 **[Whitepaper (PDF)](docs/whitepaper/)** · 🗺️ **[ROADMAP](ROADMAP.md)** + +--- + ## 📖 Overview **QuakeGuard** is a full-stack IoT architecture for real-time detection, analysis, and reporting of seismic events. The system transforms everyday household appliances — washing machines, TVs, refrigerators — into a distributed seismic sensor network, each node capable of detecting and reporting earthquake activity autonomously. @@ -434,6 +440,7 @@ QuakeGuard/ | **v1.2.2** | ✅ Released — Zero-Trust Serial Fallback — signed telemetry over USB CDC (serial) when MQTT is unreachable | | **v2.0.0** | ✅ Released — Triangulation (multi-node spatial correlation), Hybrid Network Architecture, Automated DevOps Orchestration (Ptyxis), Local Factory Provisioning, GNSS sync, NTP+PPS, ADXL calibration, and INGV FDSN SIL validation | | **v2.0.1** | ✅ Released — Documentation & Zenodo Sync: PDF/Wiki architectural coherence (Cloudflare, 300s anti-replay), CERN-OHL hardware licensing, SIL vs Firmware threshold clarification, and `CITATION.cff` bump | +| **v2.0.2** | ✅ Released — Repository Health: Dependabot, Gitleaks CI, ADRs, C4/sequence diagrams, multi-stage Dockerfile, firmware versioning, pinout table, flashing guide, privacy policy, hardware compliance disclaimer | | **v2.1** | Data Dashboards — Grafana dashboards for real-time visualization of seismic telemetry | | **v2.1.1** | Timeseries DB & Mobile Fix — migration to TimescaleDB/InfluxDB; per-sensor chart isolation in React Native mobile | | **v2.2** | Heterogeneous Edge Intelligence — hybrid Tier A (STA/LTA) + Tier B (quantized CNN) decision fusion | @@ -462,6 +469,11 @@ QuakeGuard's architecture and real-world applicability have been recognized in t This project is licensed under the **GNU Affero General Public License v3.0 (AGPL-3.0)**. See the [LICENSE](LICENSE) file for details. +Hardware designs (`hardware/`) are licensed under the **CERN Open Hardware Licence v2 — Strongly Reciprocal (CERN-OHL-S-2.0)**. +See [hardware/LICENSE](hardware/LICENSE) for details. + +> ⚠️ **Hardware Compliance:** The QuakeGuard PCB is **not certified for CE/FCC/RoHS**. It is intended for **prototyping, educational, and research use only**. Do not deploy as a commercial safety-critical device without appropriate regulatory certification. + ---
diff --git a/ROADMAP.md b/ROADMAP.md index 42ad6fc..d59a7bd 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -103,6 +103,24 @@ Documentation-only patch aligning the technical whitepaper, GitHub Wiki, and pro --- +## v2.0.2 — Repository Health (Released) + +Comprehensive repository maturity improvements: CI hardening, architectural documentation, developer experience, and compliance foundations. + +- ✅ **Dependabot** for automated dependency updates (pip, npm, GitHub Actions) +- ✅ **Gitleaks** secret scanning in CI (prevents credential leaks) +- ✅ **Architecture Decision Records (ADRs):** 4 initial ADRs (Redis Streams, HiveMQ, Hybrid Edge AI, CERN-OHL) +- ✅ **C4 and Sequence Diagrams** in Mermaid (versionable, GitHub-renderable) +- ✅ **Multi-stage Dockerfile** (builder + runtime stages, reduced image size) +- ✅ **Firmware versioning** (`FIRMWARE_VERSION` define, printed at boot) +- ✅ **Pinout reference** (`firmware/PINOUT.md`) and **Flashing guide** (`firmware/FLASHING.md`) +- ✅ **Privacy Policy** (`mobile/PRIVACY_POLICY.md`) for App Store/Play Store readiness +- ✅ **SUPPORT.md**, **Hardware Issue Template**, **Docker Compose override example** +- ✅ **BOM enrichment** (manufacturer, cost, distributor links, socketable modules) +- ✅ **README enhancements** (landing page link, PRs welcome badge, hardware disclaimer) + +--- + ## v2.1.0 — Data Dashboards Grafana dashboards for real-time visualization of seismic telemetry. diff --git a/SECURITY.md b/SECURITY.md index d9c392e..efdf92b 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -5,7 +5,7 @@ QuakeGuard takes the security of its IoT early warning infrastructure very serio | Version | Supported | Notes | | ------- | ------------------ | ----- | -| 2.0.x | :white_check_mark: | Current stable release (Hybrid Network Architecture, GNSS Precision & SIL Validation). | +| 2.0.x | :white_check_mark: | Current stable release (Repository Health, Hybrid Network Architecture, GNSS Precision & SIL Validation). | | 1.3.x | :white_check_mark: | Prior stable release (GNSS Precision & SIL Validation). | | 1.2.x | :x: | Deprecated. (Cloud MQTT + TLS + on-premise AI reports). | | 1.1.x | :x: | Deprecated. Cloud MQTT + TLS. | diff --git a/SUPPORT.md b/SUPPORT.md new file mode 100644 index 0000000..7594b9c --- /dev/null +++ b/SUPPORT.md @@ -0,0 +1,26 @@ +# Getting Help with QuakeGuard + +Thank you for using QuakeGuard! Here's how to get support depending on your situation. + +## 🐛 Bug Reports +If you've found a reproducible bug, please open a [Bug Report](https://github.com/GiZano/QuakeGuard/issues/new?template=bug_report.md). + +## 💡 Feature Requests +Have an idea for a new feature or improvement? Open a [Feature Request](https://github.com/GiZano/QuakeGuard/issues/new?template=feature_request.md). + +## 🔧 Hardware Issues +Problems with the PCB, wiring, or component assembly? Open a [Hardware Issue](https://github.com/GiZano/QuakeGuard/issues/new?template=hardware_issue.md). + +## 💬 Questions & Discussion +For general questions, architecture discussions, or community conversations, use [GitHub Discussions](https://github.com/GiZano/QuakeGuard/discussions). + +## 🔐 Security Vulnerabilities +**DO NOT** open a public issue for security vulnerabilities. Please read our [Security Policy](SECURITY.md) and report privately to **gizano.dev@gmail.com**. + +## 📚 Documentation +- **Technical Whitepaper:** Available in `docs/whitepaper/` (compiled via Typst) +- **Project Wiki:** [github.com/GiZano/QuakeGuard/wiki](https://github.com/GiZano/QuakeGuard/wiki) +- **Landing Page:** [giovanni-zanotti.is-a.dev/projects/quakeguard.html](https://giovanni-zanotti.is-a.dev/projects/quakeguard.html) + +## 📧 Direct Contact +For anything not covered above, reach out at **gizano.dev@gmail.com**. diff --git a/backend/Dockerfile b/backend/Dockerfile index d34df7e..fbaea55 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,21 +1,31 @@ -FROM python:3.11-slim +# ============================================================================= +# Stage 1: Build — install system deps and compile Python wheels +# ============================================================================= +FROM python:3.11-slim AS builder -RUN addgroup --system --gid 1001 appgroup && \ - adduser --system --uid 1001 --gid 1001 --no-create-home appuser - -WORKDIR /app +WORKDIR /build -# Install dependencies for PostgreSQL RUN apt-get update && apt-get install --no-install-recommends -y \ gcc \ python3-dev \ && rm -rf /var/lib/apt/lists/* -# Copy requirements and install Python dependencies COPY requirements.txt . -RUN pip install --no-cache-dir --only-binary :all: --require-hashes -r requirements.txt +RUN pip install --no-cache-dir --only-binary :all: --require-hashes \ + --prefix=/install -r requirements.txt -USER appuser +# ============================================================================= +# Stage 2: Runtime — slim image with only compiled packages and app code +# ============================================================================= +FROM python:3.11-slim AS runtime + +RUN addgroup --system --gid 1001 appgroup && \ + adduser --system --uid 1001 --gid 1001 --no-create-home appuser + +WORKDIR /app + +# Copy pre-built Python packages from builder +COPY --from=builder /install /usr/local # Set PYTHONPATH to include both /app and /app/src ENV PYTHONPATH="/app:/app/src" @@ -23,6 +33,8 @@ ENV PYTHONPATH="/app:/app/src" # Copy application code COPY src/ ./src/ +USER appuser + # Expose port EXPOSE 8000 diff --git a/backend/docker-compose.override.yml.example b/backend/docker-compose.override.yml.example new file mode 100644 index 0000000..7f598be --- /dev/null +++ b/backend/docker-compose.override.yml.example @@ -0,0 +1,32 @@ +# docker-compose.override.yml — Local Development Overrides +# +# This file is automatically loaded by Docker Compose alongside docker-compose.yml. +# Use it to customize the stack for local development without modifying the base config. +# +# Usage: +# cp docker-compose.override.yml.example docker-compose.override.yml +# # Edit as needed, then: +# docker compose up --build -d + +services: + # --- Bind-mount source code for hot reload --- + fastapi-app: + volumes: + - ./src:/app/src:ro + environment: + - LOG_LEVEL=DEBUG + + worker: + volumes: + - ./src:/app/src:ro + environment: + - LOG_LEVEL=DEBUG + + # --- Expose additional ports for debugging --- + postgres: + ports: + - "5432:5432" + + redis: + ports: + - "6379:6379" diff --git a/docs/adr/0001-redis-streams-ingestion.md b/docs/adr/0001-redis-streams-ingestion.md new file mode 100644 index 0000000..69093f5 --- /dev/null +++ b/docs/adr/0001-redis-streams-ingestion.md @@ -0,0 +1,33 @@ +# ADR-0001: Redis Streams as the Ingestion Transport + +## Status +Accepted (v2.3.0) + +## Context +QuakeGuard's original ingestion pipeline used a Redis `LPUSH`/`BRPOP` list queue with a single-consumer worker. While simple, this design has inherent scaling limitations: + +- **Single consumer:** Only one worker process can drain the queue, creating a bottleneck under load. +- **No at-least-once delivery:** A crashed worker loses the popped message. +- **No message inspection:** No way to audit pending or failed messages. +- **No replay:** Once consumed, a message is gone. + +As the sensor network grows beyond ~150 nodes, the single-consumer list becomes the throughput ceiling. + +## Decision +Replace the Redis list queue with **Redis Streams** (`XADD`/`XREADGROUP`): + +- Producers append via `XADD` to `readings:stream` (O(1)). +- Workers form a **consumer group**, enabling horizontal scaling (`docker compose scale worker=N`). +- `XAUTOCLAIM` recovers pending entries across worker restarts (at-least-once delivery). +- Poisoned messages are parked on `readings:dlq` (dead-letter queue) instead of stalling the group. +- Batched DB commits: a stream batch (default 64 messages) is written in one transaction. + +## Consequences +- **Positive:** Horizontal worker scaling, at-least-once delivery, DLQ for debugging, batched writes. +- **Negative:** Slightly more complex consumer logic vs. simple `BRPOP`. +- **Neutral:** The `enqueue_reading` / `read_batch` / `ack` interface in `src/ingest.py` is transport-agnostic, so a future Kafka backend can slot in without touching the worker. + +## Alternatives Considered +- **Kafka/Redpanda:** More scalable but adds an entirely new infrastructure dependency. Documented as the next step for millions-class ingestion (see ROADMAP.md "Future Horizon"). +- **RabbitMQ:** Feature-rich but heavier; Redis is already in the stack. +- **Keep LPUSH/BRPOP:** Insufficient for consumer groups and recovery. diff --git a/docs/adr/0002-hivemq-cloud-mqtt-broker.md b/docs/adr/0002-hivemq-cloud-mqtt-broker.md new file mode 100644 index 0000000..5f7b481 --- /dev/null +++ b/docs/adr/0002-hivemq-cloud-mqtt-broker.md @@ -0,0 +1,32 @@ +# ADR-0002: HiveMQ Cloud as the MQTT Broker + +## Status +Accepted (v1.1.0) + +## Context +The ESP32-C3 firmware transmits cryptographically signed seismic telemetry via MQTT. The system requires a broker that: + +1. Supports TLS (port 8883) for transport-layer encryption +2. Is reachable from any network (ESP32 nodes may be behind NAT) +3. Has minimal operational overhead (no broker to self-host and maintain) +4. Supports standard MQTT username/password authentication + +## Decision +Use **HiveMQ Cloud (Serverless)** as the managed MQTT broker: + +- Managed, zero-ops TLS termination on port 8883 +- Free tier sufficient for development and small-scale deployment +- Standard Paho-compatible client library on both ESP32 (PubSubClient) and Python (paho-mqtt) +- No self-hosted infrastructure to maintain or secure + +The Python MQTT bridge (`mqtt_subscriber.py`) subscribes to `quakeguard/telemetry` and forwards payloads to the HTTP ingestion pipeline, keeping the data plane (MQTT) separate from the control plane (REST). + +## Consequences +- **Positive:** Zero infrastructure overhead, TLS built-in, globally reachable. +- **Negative:** WAN dependency — the alert path depends on internet connectivity. The "local-first resilience" claim (R2) only holds for on-premise topology with a local broker. +- **Risk:** Vendor lock-in is minimal (standard MQTT protocol), but a self-hosted Mosquitto would eliminate the WAN dependency. + +## Alternatives Considered +- **Self-hosted Mosquitto:** Full local control, enables true local-first resilience. Documented as a future step in ROADMAP.md. Currently, the added operational burden outweighs benefits for a 2-person team. +- **EMQX Cloud:** Similar managed offering, but HiveMQ's free tier was more generous at evaluation time. +- **AWS IoT Core:** Enterprise-grade but introduces AWS dependency and costs that are disproportionate for a research/educational project. diff --git a/docs/adr/0003-hybrid-edge-ai-pattern.md b/docs/adr/0003-hybrid-edge-ai-pattern.md new file mode 100644 index 0000000..acdbb1c --- /dev/null +++ b/docs/adr/0003-hybrid-edge-ai-pattern.md @@ -0,0 +1,32 @@ +# ADR-0003: Hybrid Edge AI — Ollama Bare-Metal on Host + +## Status +Accepted (v1.2.0) + +## Context +QuakeGuard generates AI emergency reports from confirmed seismic alerts using a local LLM (Llama 3.2 1B via Ollama). The architectural decision is whether to run Ollama inside Docker alongside the other services, or bare-metal on the host OS. + +Key constraints: +- The deployment target is a Linux workstation (not a cloud VM with GPU passthrough). +- Docker on Linux does not natively support GPU passthrough without `nvidia-container-toolkit` or `--gpus` flags, which adds complexity. +- Even CPU-only inference benefits from direct access to host memory and SIMD instructions. +- The AI worker is a non-critical, asynchronous service — an alert is delivered regardless of whether the AI report succeeds. + +## Decision +Adopt an industrial **Hybrid Edge AI** pattern (similar to NVIDIA Jetson or Tesla FSD architectures): + +- **Ollama runs bare-metal** on the host Linux OS (`curl -fsSL https://ollama.com/install.sh | sh`) +- **Application services run in Docker** as before +- The AI worker container uses `network_mode: "host"` to reach Ollama at `http://127.0.0.1:11434` +- The Ollama Docker container definition is kept in `docker-compose.yml` (commented out) for environments where Docker-native is preferred + +## Consequences +- **Positive:** Maximum hardware efficiency (direct memory, no container overhead), simpler GPU passthrough if available, model persisted natively. +- **Positive:** Clear separation of concerns: the AI engine is a host-level capability, not a container sidecar. +- **Negative:** The AI worker container must use `network_mode: "host"`, losing Docker network isolation for that single service. +- **Negative:** Requires separate Ollama installation on the host (not fully containerized). + +## Alternatives Considered +- **Ollama in Docker:** Fully containerized, but Docker GPU passthrough adds significant complexity on heterogeneous hardware. The commented `ollama` service block remains available for this path. +- **Cloud LLM API (OpenAI, Anthropic):** Eliminates the privacy-first claim — telemetry would leave the host. Rejected on principle. +- **TensorFlow Lite on ESP32:** Inference on the edge device itself. Reserved for v2.2.0 Tier B sensors (ESP32-S3 with quantized CNN). The ESP32-C3 lacks the memory for meaningful LLM inference. diff --git a/docs/adr/0004-cern-ohl-hardware-license.md b/docs/adr/0004-cern-ohl-hardware-license.md new file mode 100644 index 0000000..e10b7d1 --- /dev/null +++ b/docs/adr/0004-cern-ohl-hardware-license.md @@ -0,0 +1,31 @@ +# ADR-0004: CERN-OHL-S-2.0 for Hardware Licensing + +## Status +Accepted (v2.0.1) + +## Context +QuakeGuard is a multi-layer project with distinct software and hardware components: + +- **Software** (backend, mobile, firmware logic): Licensed under AGPL-3.0 +- **Hardware** (KiCad schematics, PCB layout, Gerber files): Needs a separate, hardware-specific open-source license + +The AGPL-3.0 is designed for software and its concepts (source code, compilation, linking) do not map cleanly to hardware design files. Using AGPL for hardware creates legal ambiguity. + +## Decision +Apply **CERN Open Hardware Licence Version 2 — Strongly Reciprocal (CERN-OHL-S-2.0)** to all hardware design files in the `hardware/` directory: + +- Placed as a separate `hardware/LICENSE` file (distinct from the root `LICENSE` for software) +- The CERN-OHL-S is the hardware equivalent of copyleft: modifications to the hardware design must be shared under the same terms +- This aligns with the project's open-source philosophy while using a license designed specifically for hardware + +## Consequences +- **Positive:** Legally precise — the license terms are designed for hardware "Source" (schematics, PCB layout, Gerber files) and "Products" (manufactured PCBs). +- **Positive:** Strongly reciprocal — anyone modifying the PCB design must share their modifications (consistent with AGPL copyleft philosophy for software). +- **Positive:** CERN-backed and widely recognized in the open hardware community (CERN, RISC-V, others). +- **Negative:** Two licenses in one repo can confuse contributors. Mitigated by clear directory separation and documentation. + +## Alternatives Considered +- **AGPL-3.0 for everything:** Legally unclear for hardware; AGPL concepts (linking, network interaction) have no hardware equivalent. +- **CERN-OHL-P (Permissive):** Allows proprietary derivatives. Rejected to maintain copyleft consistency with the software license. +- **CERN-OHL-W (Weakly Reciprocal):** Only requires sharing modifications to the original design, not the larger work. The strongly reciprocal variant better matches AGPL's intent. +- **TAPR OHL:** Less widely adopted than CERN-OHL; CERN-OHL v2 is the current community standard. diff --git a/docs/diagrams/README.md b/docs/diagrams/README.md new file mode 100644 index 0000000..60d786a --- /dev/null +++ b/docs/diagrams/README.md @@ -0,0 +1,13 @@ +# QuakeGuard — Architectural Diagrams + +This directory contains versionable architectural diagrams in Mermaid format. +They complement the diagrams in the Typst whitepaper (`docs/whitepaper/`) but are independently viewable on GitHub. + +## Contents + +| File | Description | +|------|-------------| +| `c4-context.md` | C4 Context Diagram — who interacts with QuakeGuard | +| `sequence-provisioning.md` | Sequence diagram — device first-boot provisioning | +| `sequence-alert-delivery.md` | Sequence diagram — earthquake detection → mobile alert | +| `sequence-triangulation.md` | Sequence diagram — multi-node triangulation flow | diff --git a/docs/diagrams/c4-context.md b/docs/diagrams/c4-context.md new file mode 100644 index 0000000..9f0e1ac --- /dev/null +++ b/docs/diagrams/c4-context.md @@ -0,0 +1,73 @@ +# C4 Context Diagram — QuakeGuard + +> Level 1 (System Context): shows the QuakeGuard system and the external actors/systems that interact with it. + +```mermaid +C4Context + title QuakeGuard — System Context Diagram + + Person(user, "End User", "Receives earthquake alerts on mobile device") + Person(maintainer, "Maintainer", "Deploys, configures, and monitors the system") + + System(quakeguard, "QuakeGuard System", "Distributed IoT EEW platform: edge sensors, backend, mobile app") + + System_Ext(hivemq, "HiveMQ Cloud", "Managed MQTT broker (TLS, port 8883)") + System_Ext(ollama, "Ollama (Host)", "Local LLM inference engine (Llama 3.2)") + System_Ext(cloudflare, "Cloudflare Tunnel", "HTTPS tunnel for remote control plane access") + System_Ext(expo, "Expo Push Service", "Delivers push notifications to iOS/Android") + + Rel(user, quakeguard, "Receives alerts, views sensor map", "WebSocket / Push Notification") + Rel(maintainer, quakeguard, "Deploys stack, flashes firmware", "Docker / PlatformIO / SSH") + Rel(quakeguard, hivemq, "Publishes/subscribes telemetry", "MQTT over TLS") + Rel(quakeguard, ollama, "Requests AI emergency reports", "HTTP (localhost)") + Rel(quakeguard, cloudflare, "Exposes control plane", "HTTPS tunnel") + Rel(quakeguard, expo, "Sends push notifications", "HTTPS") +``` + +## Container-Level Breakdown + +```mermaid +C4Container + title QuakeGuard — Container Diagram + + Person(user, "End User") + + System_Boundary(edge, "IoT Edge Layer") { + Container(esp32, "ESP32-C3 Node", "C++/FreeRTOS", "STA/LTA detection, ECDSA signing, MQTT publish") + Container(adxl, "ADXL345", "I2C Sensor", "3-axis accelerometer @ 100 Hz") + Container(gnss, "NEO-6M GNSS", "UART", "GPS coordinates + PPS time sync") + } + + System_Boundary(backend, "Backend Layer (Docker)") { + Container(api, "FastAPI Gateway", "Python 3.11", "REST API, ECDSA verification, WebSocket") + Container(worker, "Background Worker", "Python", "Magnitude calc, alert engine, triangulation") + Container(ai_worker, "AI Report Worker", "Python", "Consumes ai_report_queue, generates reports via Ollama") + Container(mqtt_bridge, "MQTT Bridge", "Python/Paho", "Subscribes to HiveMQ, forwards to HTTP pipeline") + ContainerDb(postgres, "PostgreSQL + PostGIS", "TimescaleDB", "Sensors, readings, zones, alerts") + ContainerDb(redis, "Redis", "Streams + Pub/Sub", "Ingestion queue, alert broadcast, zone cache") + } + + System_Boundary(mobile, "Mobile Layer") { + Container(app, "React Native App", "Expo/TypeScript", "Dashboard, sensor map, alert feed") + } + + System_Ext(hivemq, "HiveMQ Cloud") + System_Ext(ollama, "Ollama (Host)") + + Rel(esp32, hivemq, "MQTT publish", "TLS 8883") + Rel(mqtt_bridge, hivemq, "MQTT subscribe", "TLS 8883") + Rel(mqtt_bridge, api, "POST /readings/", "HTTP") + Rel(esp32, api, "POST /devices/register", "HTTP/HTTPS") + Rel(api, redis, "XADD readings:stream") + Rel(worker, redis, "XREADGROUP") + Rel(worker, postgres, "INSERT readings, alerts") + Rel(worker, redis, "PUBLISH quake_alerts") + Rel(ai_worker, redis, "BRPOP ai_report_queue") + Rel(ai_worker, ollama, "POST /api/generate", "HTTP") + Rel(ai_worker, redis, "PUBLISH ai_reports") + Rel(api, app, "WebSocket broadcast", "WSS") + Rel(app, api, "REST queries", "HTTPS") + Rel(user, app, "Views alerts") + Rel(adxl, esp32, "I2C data") + Rel(gnss, esp32, "UART + PPS") +``` diff --git a/docs/diagrams/sequence-alert-delivery.md b/docs/diagrams/sequence-alert-delivery.md new file mode 100644 index 0000000..4ccb0b8 --- /dev/null +++ b/docs/diagrams/sequence-alert-delivery.md @@ -0,0 +1,71 @@ +# Sequence Diagram — Alert Delivery (Earthquake Detection → Mobile Alert) + +```mermaid +sequenceDiagram + participant ADXL as ADXL345 Sensor + participant ESP as ESP32-C3 Node + participant MQTT as HiveMQ Cloud + participant Bridge as MQTT Bridge + participant API as FastAPI Gateway + participant Redis as Redis + participant Worker as Background Worker + participant DB as PostgreSQL + participant AI as AI Report Worker + participant Ollama as Ollama LLM + participant WS as WebSocket + participant App as Mobile App + participant User as End User + + ADXL->>ESP: Acceleration data (100 Hz, I2C) + ESP->>ESP: HPF → STA/LTA detection + Note over ESP: STA/LTA ratio > 1.8 → TRIGGER + + ESP->>ESP: ECDSA sign (value:timestamp) + ESP->>MQTT: PUBLISH quakeguard/telemetry
{value, sensor_id, timestamp, signature} + + MQTT->>Bridge: Deliver message (TLS) + Bridge->>API: POST /readings/
X-API-Key header + + API->>API: Validate API Key + API->>API: Verify ECDSA signature + API->>API: Check anti-replay (300s window) + API->>API: Rate limit check (50 req/s/IP) + + API->>Redis: XADD readings:stream + + Worker->>Redis: XREADGROUP (batch) + Worker->>Worker: Calculate magnitude
M = log10(PGA/scale) × K + B + Worker->>DB: INSERT INTO readings + + alt M ≥ 4.5 (Alert threshold) + Worker->>Redis: Check cooldown lock
(alert_cooldown:geohash) + + alt No active cooldown + Worker->>DB: INSERT INTO alerts + Worker->>Redis: SET cooldown lock (60s TTL) + Worker->>Redis: PUBLISH quake_alerts
{zone, magnitude, alert_id} + + Redis->>WS: Broadcast to subscribers + WS->>App: QUAKE_ALERT message + + App->>App: SOS haptic vibration + App->>App: Push notification + App->>User: 🚨 EARTHQUAKE ALERT + + opt AI Reports enabled + Worker->>Redis: LPUSH ai_report_queue + AI->>Redis: BRPOP ai_report_queue + AI->>Ollama: POST /api/generate
(structured prompt + telemetry) + Ollama-->>AI: Emergency report text + AI->>DB: UPDATE EmergencyReport (COMPLETED) + AI->>Redis: PUBLISH ai_reports + Redis->>WS: Broadcast report + WS->>App: EMERGENCY_REPORT message + App->>User: 📋 AI Report banner + end + + else Cooldown active + Note over Worker: Duplicate suppressed (60s window) + end + end +``` diff --git a/docs/diagrams/sequence-provisioning.md b/docs/diagrams/sequence-provisioning.md new file mode 100644 index 0000000..7825757 --- /dev/null +++ b/docs/diagrams/sequence-provisioning.md @@ -0,0 +1,46 @@ +# Sequence Diagram — Device Provisioning (First Boot) + +```mermaid +sequenceDiagram + participant ESP as ESP32-C3 Node + participant WM as WiFiManager + participant User as User (Phone/Laptop) + participant API as FastAPI Gateway + participant DB as PostgreSQL + PostGIS + participant NVS as ESP32 NVS Storage + + Note over ESP: Power-on → LED boot test (2x blink) + ESP->>ESP: Generate ECDSA key pair (if first boot) + ESP->>NVS: Store private key in NVS + + ESP->>WM: Start captive portal "QuakeGuard-Setup" + User->>WM: Connect to AP, enter WiFi credentials + WM->>ESP: WiFi connected + + ESP->>ESP: Check NVS for existing sensor_id + Note over ESP: sensor_id == 0 → Unregistered + + ESP->>API: POST /devices/register
{public_key_hex, mac_address,
enrollment_token, latitude?, longitude?} + + API->>API: Validate enrollment_token + API->>DB: Check for existing device (MAC or public key) + + alt New Device + API->>DB: INSERT Sensor (public_key, mac, coordinates) + DB->>API: sensor_id assigned + else Existing Device + API->>DB: SELECT sensor_id WHERE mac_address = ... + DB->>API: existing sensor_id + end + + alt Coordinates provided + API->>DB: ST_Contains query → assign zone + else No coordinates + API->>DB: Assign to "Unknown Region" + end + + API-->>ESP: 200 OK {sensor_id: N} + ESP->>NVS: Store sensor_id in NVS + Note over ESP: Blue LED solid → Fully connected + ESP->>ESP: Start SensorTask + NetworkTask +``` diff --git a/docs/diagrams/sequence-triangulation.md b/docs/diagrams/sequence-triangulation.md new file mode 100644 index 0000000..090bcdf --- /dev/null +++ b/docs/diagrams/sequence-triangulation.md @@ -0,0 +1,57 @@ +# Sequence Diagram — Multi-Node Triangulation + +```mermaid +sequenceDiagram + participant N1 as Node A (ESP32) + participant N2 as Node B (ESP32) + participant N3 as Node C (ESP32) + participant API as FastAPI Gateway + participant Redis as Redis Stream + participant Worker as Background Worker + participant Tri as Triangulation Engine + participant DB as PostgreSQL + PostGIS + participant WS as WebSocket + participant App as Mobile App + + Note over N1,N3: Earthquake P-wave propagates
outward from epicenter + + N1->>API: POST /readings/ (t₁, lat₁, lon₁, sig₁) + Note over N1: First node triggered (closest to epicenter) + + N2->>API: POST /readings/ (t₂, lat₂, lon₂, sig₂) + Note over N2: Second node triggered (Δt later) + + N3->>API: POST /readings/ (t₃, lat₃, lon₃, sig₃) + Note over N3: Third node triggered (Δt later) + + API->>Redis: XADD readings:stream (×3) + + Worker->>Redis: XREADGROUP batch + Worker->>Worker: Detect concurrent triggers
(temporal window + spatial proximity) + + alt ≥ 3 nodes triggered in window + Worker->>Tri: correlate_events(triggers[]) + + Tri->>Tri: Compute TDOA from timestamps
Δt₁₂ = t₂ - t₁
Δt₁₃ = t₃ - t₁ + + Tri->>Tri: Solve least-squares minimization
for epicenter (lat_e, lon_e) + + Tri->>Tri: Estimate origin time (t₀) + + Tri-->>Worker: TriangulationResult
{epicenter, origin_time, confidence} + + Worker->>DB: INSERT alert (is_triangulated=True,
epicenter_lat, epicenter_lon) + + Worker->>Redis: PUBLISH quake_alerts
{type: TRIANGULATED, epicenter, ETA} + + Redis->>WS: Broadcast + WS->>App: TRIANGULATED alert + + App->>App: Calculate ETA from user GPS
to epicenter (wave speed ~6 km/s) + + App->>App: Show EarlyWarningBanner
with countdown timer + + else < 3 nodes (single-node detection) + Worker->>Worker: Standard single-node alert flow + end +``` diff --git a/docs/web/assets/quakeguard/github-banner.png b/docs/web/assets/quakeguard/github-banner.png index 4689b60..40d0f28 100644 Binary files a/docs/web/assets/quakeguard/github-banner.png and b/docs/web/assets/quakeguard/github-banner.png differ diff --git a/firmware/FLASHING.md b/firmware/FLASHING.md new file mode 100644 index 0000000..53a21dc --- /dev/null +++ b/firmware/FLASHING.md @@ -0,0 +1,114 @@ +# 🔧 QuakeGuard — Firmware Flashing Guide + +> Step-by-step instructions for flashing the QuakeGuard firmware onto an ESP32-C3 SuperMini, without requiring VS Code or PlatformIO IDE. + +## Prerequisites + +- **Python 3.8+** installed on your system +- **PlatformIO Core (CLI):** Install via `pip install platformio` +- **USB-C cable** (data-capable, not charge-only) +- **QuakeGuard PCB** assembled, or ESP32-C3 SuperMini with ADXL345 wired on breadboard (see [PINOUT.md](PINOUT.md)) + +## 1. Configure Environment Variables + +```bash +cd firmware +cp esp32_config.env.example esp32_config.env +``` + +Edit `esp32_config.env` with your specific values: +- **WiFi credentials** (`WIFI_SSID`, `WIFI_PASS`) +- **Backend address** (`SERVER_HOST`, `SERVER_PORT`) +- **MQTT broker** (`MQTT_BROKER_HOST`, credentials) +- **Enrollment token** (`ENROLLMENT_TOKEN`) — must match the backend `.env` + +> ⚠️ The build will fail with `#error` if `ENROLLMENT_TOKEN`, `MQTT_BROKER_HOST`, `MQTT_USERNAME`, or `MQTT_PASSWORD` are missing. This is intentional fail-fast behavior. + +## 2. Connect the ESP32-C3 + +1. Connect the ESP32-C3 SuperMini via USB-C to your computer +2. Identify the serial port: + - **Linux:** `/dev/ttyACM0` (default) + - **macOS:** `/dev/cu.usbmodem*` + - **Windows:** `COM3` or similar (check Device Manager) + +3. If needed, update the port in `platformio.ini`: + ```ini + upload_port = /dev/ttyACM0 + monitor_port = /dev/ttyACM0 + ``` + +## 3. Build and Flash + +```bash +cd firmware + +# Build only (compile without flashing) +pio run + +# Build and flash to the connected device +pio run --target upload + +# Open serial monitor after flashing +pio device monitor +``` + +### SuperMini Boot Mode + +The ESP32-C3 SuperMini may require manual boot mode entry for the first flash: + +1. Hold the **BOOT** button +2. Press and release the **RESET** button +3. Release the **BOOT** button +4. Run `pio run --target upload` + +Subsequent flashes should work without manual intervention (the `--before=no_reset --after=hard_reset` flags in `platformio.ini` handle this). + +## 4. First Boot Sequence + +On first power-up after a successful flash, the device will: + +1. 🔵🔴 **LED boot test:** Both LEDs blink 2x to verify wiring +2. 📡 **WiFi captive portal:** Opens `QuakeGuard-Setup` AP (180s timeout) +3. 🌐 **Connect to WiFi** and auto-provision with the backend +4. 🔑 **Generate ECDSA key pair** (stored in NVS, never leaves the device) +5. 📋 **Register with backend** via `POST /devices/register` +6. 🔵 **Solid blue LED** = fully connected and transmitting + +### Serial Monitor Output (Successful Boot) + +``` +[BOOT] QuakeGuard v2.0.2 +[SEC] Generating New ECDSA Key Pair... +[SEC] Keys Generated. +[BOOT] Device UNREGISTERED. Entering Provisioning Mode... +[NET] WiFi Connected. +[PROV] Starting Device Handshake... +[PROV] SUCCESS! Assigned Sensor ID: 1 +[SENSOR] Task Active. Stabilizing and filling buffers... +[SYS] System Running. +``` + +## 5. Troubleshooting + +| Symptom | Cause | Fix | +|---------|-------|-----| +| Build fails with `#error ENROLLMENT_TOKEN` | Missing env variable | Check `esp32_config.env` | +| `Upload failed: No serial port` | Wrong port or cable | Try different USB-C cable (data-capable) | +| 🔴 Solid red LED after boot | ADXL345 not detected | Check J3 wiring: SDA→GPIO7, SCL→GPIO8, VCC→3.3V | +| 🔵 Double blink | WiFi not connecting | Reconnect via `QuakeGuard-Setup` captive portal | +| `[PROV] Registration Failed. HTTP Code: -1` | Backend unreachable | Verify `SERVER_HOST` is correct and backend is running | +| `errno 118` / connection refused | DNS/subnet issue | Use local IP (e.g. `192.168.1.x`), not hostname | + +## Optional: GNSS Module + +To enable the optional GNSS module (NEO-6M), uncomment in `esp32_config.env`: + +```env +GNSS_ENABLED=1 +GPS_SERIAL_RX_PIN=5 +GPS_SERIAL_TX_PIN=4 +GPS_SERIAL_BAUD=9600 +``` + +See [PINOUT.md](PINOUT.md) for connector wiring (J4). diff --git a/firmware/PINOUT.md b/firmware/PINOUT.md new file mode 100644 index 0000000..ff58b2e --- /dev/null +++ b/firmware/PINOUT.md @@ -0,0 +1,81 @@ +# 🔌 QuakeGuard — Firmware Pinout Reference + +> **PCB Revision:** v2.0.0 (JLCPCB) +> **MCU:** ESP32-C3 SuperMini + +## GPIO Mapping + +| GPIO | Function | Component | PCB Connector | Notes | +|------|----------|-----------|---------------|-------| +| 7 | I2C SDA | ADXL345 | J3-3 (SDA) | 100 kHz clock, internal pull-up | +| 8 | I2C SCL | ADXL345 | J3-4 (SCL) | 100 kHz clock, internal pull-up | +| 10 | LED Blue (PWM) | Status LED | D2 (Blue) | Connection state indicator, via R2 (330Ω) | +| 3 | LED Red (Digital) | Alert LED | D3 (Red) | Earthquake detected indicator, via R3 (330Ω) | +| 5 | UART1 RX | NEO-6M GNSS TX | J4-3 (GNSS TX) | Optional: compile with `GNSS_ENABLED=1` | +| 4 | UART1 TX | NEO-6M GNSS RX | J4-4 (GNSS RX) | Optional: compile with `GNSS_ENABLED=1` | +| 2 | PPS Interrupt | NEO-6M PPS | J4-5 (PPS) | Optional: 1PPS discipline for ms-accuracy | +| USB | CDC Serial | Host Bridge | USB-C | Telemetry fallback + debug monitor | + +## I2C Bus + +| Address | Device | Purpose | +|---------|--------|---------| +| `0x53` | ADXL345 | Primary accelerometer address | +| `0x1D` | ADXL345 | Alternate address (ALT pin HIGH) | + +## LED Behavior + +| Pattern | Meaning | +|---------|---------| +| 🔵 Double blink (100ms on/off) | WiFi disconnected | +| 🔵 Single blink (200ms on/off) | WiFi OK, MQTT disconnected | +| 🔵 Solid (PWM ~40%) | Fully connected | +| 🔴 Solid | Sensor hardware fault (ADXL345 init failed) | +| 🔴 3-second pulse | Earthquake event detected | +| 🔵🔴 2x alternating blink | Boot self-test (wiring verification) | +| 🔴 Rapid 3x blink | ADXL345 I2C retry (during init) | + +## Power + +| Pin | Source | Notes | +|-----|--------|-------| +| 3V3 | ESP32-C3 LDO | Powers ADXL345 (J3-1) and GNSS (J4-1) | +| GND | Common ground | Shared across all connectors | +| 5V (USB) | USB-C input | Powers the ESP32-C3 SuperMini | + +## PCB Connector Pinout + +### J1 — ESP32-C3 Left Header (8-pin) +Directly soldered to the ESP32-C3 SuperMini left row. + +### J2 — ESP32-C3 Right Header (8-pin) +Directly soldered to the ESP32-C3 SuperMini right row. + +### J3 — ADXL345 Accelerometer (8-pin) +| Pin | Signal | Connected To | +|-----|--------|-------------| +| 1 | VCC (3.3V) | ESP32 3V3 | +| 2 | GND | Common GND | +| 3 | SDA | GPIO 7 | +| 4 | SCL | GPIO 8 | +| 5-8 | NC | Not connected | + +### J4 — GNSS Module NEO-6M (5-pin) +| Pin | Signal | Connected To | +|-----|--------|-------------| +| 1 | VCC (3.3V) | ESP32 3V3 | +| 2 | GND | Common GND | +| 3 | TX (GNSS → ESP) | GPIO 5 (UART1 RX) | +| 4 | RX (ESP → GNSS) | GPIO 4 (UART1 TX) | +| 5 | PPS | GPIO 2 | + +## Passive Components + +| Ref | Value | Purpose | +|-----|-------|---------| +| R1, R2, R3 | 330Ω | Current limiting for LEDs D1, D2, D3 | +| C1, C3 | 10µF | Decoupling capacitors (power supply) | +| C2 | 0.1µF | High-frequency bypass capacitor | +| D1 | Green LED | Reserved (future use) | +| D2 | Blue LED | Connection status indicator | +| D3 | Red LED | Earthquake alert indicator | diff --git a/firmware/src/main.cpp b/firmware/src/main.cpp index 71e14d9..06dc3ae 100644 --- a/firmware/src/main.cpp +++ b/firmware/src/main.cpp @@ -1,6 +1,6 @@ /** * Project: QuakeGuard - Professional Seismic Node - * Version: 1.3.0-GNSS-PPS + * Version: 2.0.2 * Target Hardware: ESP32-C3 SuperMini + ADXL345 + NEO-6M (JLCPCB) * Author: GiZano * @@ -36,6 +36,11 @@ #include #include +// -------------------------------------------------------------------------- +// FIRMWARE VERSION (printed at boot for field identification) +// -------------------------------------------------------------------------- +#define FIRMWARE_VERSION "2.0.2" + // -------------------------------------------------------------------------- // HARDWARE & SERVER CONFIGURATION // -------------------------------------------------------------------------- @@ -605,7 +610,7 @@ void setup() { digitalWrite(LED_RED_PIN, LOW); ledBootTest(); // verify wiring: 2x blink both LEDs - Serial.println("\n\n[BOOT] QuakeGuard v2.0.0 GNSS+PPS+LED"); + Serial.printf("\n\n[BOOT] QuakeGuard v%s\n", FIRMWARE_VERSION); crypto().init(); diff --git a/hardware/QuakeGuard_PCB/output/BOM.csv b/hardware/QuakeGuard_PCB/output/BOM.csv index c79b3dc..db58d22 100644 --- a/hardware/QuakeGuard_PCB/output/BOM.csv +++ b/hardware/QuakeGuard_PCB/output/BOM.csv @@ -1,14 +1,17 @@ -"Refs","Value","Footprint","Qty","DNP" -"C1","10µF","Capacitor_THT:CP_Radial_D5.0mm_P2.50mm","1","" -"C2","0.1µF","Capacitor_THT:C_Disc_D5.0mm_W2.5mm_P5.00mm","1","" -"C3","10µF","Capacitor_THT:CP_Radial_D5.0mm_P2.50mm","1","" -"D1","Green","LED_THT:LED_D5.0mm","1","" -"D2","Blue","LED_THT:LED_D5.0mm","1","" -"D3","Red","LED_THT:LED_D5.0mm","1","" -"J1","ESP32-C3[L]","Connector_PinSocket_2.54mm:PinSocket_1x08_P2.54mm_Vertical","1","" -"J2","ESP32-C3[R]","Connector_PinSocket_2.54mm:PinSocket_1x08_P2.54mm_Vertical","1","" -"J3","ADXL345","Connector_PinSocket_2.54mm:PinSocket_1x08_P2.54mm_Vertical","1","" -"J4","NEO-6M","Connector_PinSocket_2.54mm:PinSocket_1x05_P2.54mm_Vertical","1","" -"R1","330Ω","Resistor_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P10.16mm_Horizontal","1","" -"R2","330Ω","Resistor_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P10.16mm_Horizontal","1","" -"R3","330Ω","Resistor_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P10.16mm_Horizontal","1","" \ No newline at end of file +"Refs","Value","Footprint","Qty","DNP","Manufacturer","Part Number","Unit Cost (EUR)","Distributor","Link" +"C1","10µF","Capacitor_THT:CP_Radial_D5.0mm_P2.50mm","1","","Panasonic / Generic","ECA-1HM100I","0.15","LCSC / DigiKey","https://www.lcsc.com/search?q=10uF+radial+electrolytic" +"C2","0.1µF","Capacitor_THT:C_Disc_D5.0mm_W2.5mm_P5.00mm","1","","Murata / Generic","RD15N104J1HL2L","0.05","LCSC / DigiKey","https://www.lcsc.com/search?q=100nF+ceramic+disc" +"C3","10µF","Capacitor_THT:CP_Radial_D5.0mm_P2.50mm","1","","Panasonic / Generic","ECA-1HM100I","0.15","LCSC / DigiKey","https://www.lcsc.com/search?q=10uF+radial+electrolytic" +"D1","Green","LED_THT:LED_D5.0mm","1","","Generic","LED 5mm Green","0.05","LCSC / Amazon","https://www.lcsc.com/search?q=5mm+green+LED" +"D2","Blue","LED_THT:LED_D5.0mm","1","","Generic","LED 5mm Blue","0.05","LCSC / Amazon","https://www.lcsc.com/search?q=5mm+blue+LED" +"D3","Red","LED_THT:LED_D5.0mm","1","","Generic","LED 5mm Red","0.05","LCSC / Amazon","https://www.lcsc.com/search?q=5mm+red+LED" +"J1","ESP32-C3[L]","Connector_PinSocket_2.54mm:PinSocket_1x08_P2.54mm_Vertical","1","","Generic","Pin Socket 1x08 2.54mm","0.20","LCSC / Amazon","https://www.lcsc.com/search?q=pin+socket+1x08+2.54mm" +"J2","ESP32-C3[R]","Connector_PinSocket_2.54mm:PinSocket_1x08_P2.54mm_Vertical","1","","Generic","Pin Socket 1x08 2.54mm","0.20","LCSC / Amazon","https://www.lcsc.com/search?q=pin+socket+1x08+2.54mm" +"J3","ADXL345","Connector_PinSocket_2.54mm:PinSocket_1x08_P2.54mm_Vertical","1","","Generic","Pin Socket 1x08 2.54mm","0.20","LCSC / Amazon","https://www.lcsc.com/search?q=pin+socket+1x08+2.54mm" +"J4","NEO-6M","Connector_PinSocket_2.54mm:PinSocket_1x05_P2.54mm_Vertical","1","","Generic","Pin Socket 1x05 2.54mm","0.15","LCSC / Amazon","https://www.lcsc.com/search?q=pin+socket+1x05+2.54mm" +"R1","330Ω","Resistor_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P10.16mm_Horizontal","1","","Generic","MF 1/4W 330R","0.02","LCSC / DigiKey","https://www.lcsc.com/search?q=330+ohm+1/4W+THT" +"R2","330Ω","Resistor_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P10.16mm_Horizontal","1","","Generic","MF 1/4W 330R","0.02","LCSC / DigiKey","https://www.lcsc.com/search?q=330+ohm+1/4W+THT" +"R3","330Ω","Resistor_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P10.16mm_Horizontal","1","","Generic","MF 1/4W 330R","0.02","LCSC / DigiKey","https://www.lcsc.com/search?q=330+ohm+1/4W+THT" +"--","ESP32-C3 SuperMini","Module (socketable)","1","","Espressif / AliExpress","ESP32-C3 SuperMini","3.50","AliExpress / Amazon","https://www.aliexpress.com/w/wholesale-esp32-c3-supermini.html" +"--","ADXL345 Breakout","Module (socketable)","1","","Analog Devices / Generic","GY-291 ADXL345","2.00","AliExpress / Amazon","https://www.aliexpress.com/w/wholesale-ADXL345-module.html" +"--","NEO-6M GNSS Module","Module (socketable, optional)","1","","u-blox / Generic","GY-NEO6MV2","4.50","AliExpress / Amazon","https://www.aliexpress.com/w/wholesale-neo-6m-gps.html" \ No newline at end of file diff --git a/mobile/PRIVACY_POLICY.md b/mobile/PRIVACY_POLICY.md new file mode 100644 index 0000000..3e56460 --- /dev/null +++ b/mobile/PRIVACY_POLICY.md @@ -0,0 +1,84 @@ +# QuakeGuard — Privacy Policy + +**Last updated:** September 3, 2026 +**Effective for:** QuakeGuard Mobile App (iOS / Android) + +## Overview + +QuakeGuard is an open-source earthquake early warning system. This privacy policy explains how the QuakeGuard mobile application collects, uses, and protects your information. + +## Data We Collect + +### 1. Device Location (Optional) +- **What:** Approximate GPS coordinates +- **Why:** To determine your seismic zone and calculate earthquake wave arrival time (ETA) +- **When:** Only when you explicitly enable "Detect my zone via GPS" in Settings +- **Storage:** Transmitted to the QuakeGuard backend for zone assignment; not stored persistently on the server beyond the session + +### 2. Push Notification Token +- **What:** Device push notification token (Expo Push Token) +- **Why:** To deliver earthquake alerts even when the app is in the background +- **When:** Only when you enable notifications in Settings +- **Storage:** Used by the push notification service (Expo) to route alerts; not shared with third parties + +### 3. App Preferences +- **What:** User settings (notification preferences, offline mode toggle, display preferences) +- **Why:** To remember your configuration between app sessions +- **Storage:** Stored locally on your device only (via Zustand persistence); never transmitted to any server + +## Data We Do NOT Collect + +- ❌ Personal identification (name, email, phone number) +- ❌ Contacts, photos, or files +- ❌ Browsing history or usage analytics +- ❌ Advertising identifiers +- ❌ Health or biometric data + +## Data Transmission + +All communication between the app and the QuakeGuard backend uses: +- **WebSocket (WSS)** for real-time alerts — authenticated via `MOBILE_WS_TOKEN` +- **HTTPS** for API calls — authenticated via `IOT_API_KEY` + +No telemetry data is sent to third-party analytics services. + +## Third-Party Services + +| Service | Purpose | Data Shared | +|---------|---------|-------------| +| Expo | Push notifications delivery | Device push token | +| React Native Maps | Sensor network visualization | None (map tiles only) | + +## Data Retention + +- **Location data:** Not retained beyond the active session +- **Alert history:** Stored in-memory only (last 10 alerts); cleared on app restart +- **Preferences:** Stored locally on-device until the user clears app data + +## Open Source Transparency + +QuakeGuard is fully open source. You can audit exactly what data the app collects by reviewing the source code: +- **Repository:** [github.com/GiZano/QuakeGuard](https://github.com/GiZano/QuakeGuard) +- **Mobile source:** [`mobile/`](https://github.com/GiZano/QuakeGuard/tree/main/mobile) +- **License:** AGPL-3.0 + +## Children's Privacy + +QuakeGuard does not knowingly collect data from children under 13. The app is a safety tool and does not contain age-restricted content. + +## Your Rights + +You can: +- **Disable location access** at any time via your device's system settings +- **Disable notifications** via the app's Settings screen or system settings +- **Delete all local data** by uninstalling the app + +## Changes to This Policy + +We may update this privacy policy to reflect changes in the app. Updates will be posted in this file in the repository and noted in the CHANGELOG. + +## Contact + +For privacy-related questions or concerns: +- **Email:** gizano.dev@gmail.com +- **Repository:** [github.com/GiZano/QuakeGuard](https://github.com/GiZano/QuakeGuard)