DEV Community

Cover image for Ocean Sentinels - An Offline App for Worldwide Costal Communities
Gowshik S
Gowshik S

Posted on

Ocean Sentinels - An Offline App for Worldwide Costal Communities

GitHub Copilot CLI Challenge Submission

This is a submission for the GitHub Copilot CLI Challenge

What I Built

Ocean Sentinels — A full-stack coastal safety platform (Web + Android) with an offline BLE Bluetooth mesh network for disaster scenarios.

When natural disasters knock out cell towers, coastal communities are left stranded. Ocean Sentinels solves this by turning ordinary Android phones into a Bluetooth mesh network — hazard reports hop phone-to-phone until any device finds connectivity and uploads to the server, alerting rescue teams and authorities instantly.

The Platform

  • Web App — Interactive Mapbox map with real-time incident markers, role-based dashboards for 4 user types (Public, Authority, Rescue Team, Admin), WebSocket live notifications, analytics charts, and responsive design
  • Android App — 21 Jetpack Compose screens built with Material3, offline-first architecture with Room DB caching, Firebase push notifications, GPS location tracking, and the BLE mesh networking layer
  • Backend — FastAPI + PostgreSQL with async operations, 16+ REST endpoints, JWT authentication, role-based access control, and mesh message deduplication

The BLE Mesh Network

This is the core innovation. When there's no internet:

  1. A user submits a hazard report on their phone
  2. The report broadcasts over BLE to nearby phones (~400m range using Coded PHY S8)
  3. Each phone relays it forward using store-carry-forward protocol
  4. When ANY phone in the chain gets internet → the report uploads to the server → authorities are alerted

No special hardware needed. Just phones.

Technical specs:

  • Coded PHY S8 — 8x forward error correction, extends BLE range to ~400m (vs 100m standard)
  • 72-hour time-based message expiry instead of hop-count TTL — because in a disaster, a message chain might be 50+ devices long before reaching internet
  • Triple-layer deduplication — relay path tracking + in-memory LRU cache (10K entries) + database-level dedup
  • SHA-256 deterministic message IDs — same report from same device always generates the same ID
  • Dual PHY fallback — tries Coded PHY first for range, gracefully degrades to 1M PHY for older devices

Tech Stack

Layer Stack
Backend Python 3.11, FastAPI, SQLAlchemy 2.0 (async), PostgreSQL, JWT, WebSocket
Frontend Vanilla JS, Mapbox GL JS, CSS3, role-based navigation
Android Kotlin, Jetpack Compose, Material3, Hilt, Room, Retrofit, Mapbox SDK, Firebase
Mesh BLE 5.0 Coded PHY S8, GATT server/client, SHA-256 dedup, foreground service
Deploy Render (backend), Vercel (frontend)

Demo

Video walkthrough coming soon — will be updated here!

https://vid.gowshik.online

Live Web App: [Ocean Sentinels - Web]
GitHub Repo: https://github.com/Gowshik-S/Ocean-Sentinels

Screenshots

Index Page for Ocean Sentinels

Web Analytics :

Web Analytics :

My Experience with GitHub Copilot CLI

GitHub Copilot CLI was instrumental across every layer of Ocean Sentinels. Here's how it shaped my development:

BLE Mesh Layer — The Hardest Part

Building a Bluetooth mesh network from scratch is complex. Copilot CLI helped me:

  • Design the BleMeshManager that runs a GATT server and BLE scanner simultaneously
  • Implement the triple-layer deduplication strategy (relay path + LRU cache + DB check)
  • Build the DeviceIdentifier system — Android 6+ masks real MAC addresses, so Copilot suggested a SHA-256(deviceId + androidId) fingerprint approach
  • Debug BLE Coded PHY negotiation and fallback logic when devices don't support PHY S8
  • Architect the time-based TTL system — Copilot understood why hop-count TTL fails in disaster scenarios and suggested 72-hour expiry instead

Full-Stack Development at Speed

  • Backend: Generated all FastAPI endpoints, SQLAlchemy async models, Pydantic schemas, and JWT middleware with role-based guards — gh copilot suggest understood the access control patterns I needed
  • Frontend: Role-based navigation manager, Mapbox GL custom markers, WebSocket reconnection handlers — Copilot scaffolded the boilerplate so I focused on user experience
  • Android: 21 Compose screens with Hilt dependency injection, Room database entities, Retrofit API client — it understood my clean architecture layers and generated consistent code across data/domain/presentation

Cross-Layer Intelligence

The most impressive moment: while working on mesh message dedup in the Android BleMeshManager, Copilot correctly suggested that the backend's Incident model also needed a mesh_message_id unique constraint. It understood the end-to-end flow — BLE relay → API upload → database dedup — without me explicitly describing it.

Impact on Development

What would have taken weeks of researching BLE specs, GATT protocol documentation, and Android Bluetooth stack quirks was compressed into days. Copilot CLI didn't just autocomplete — it understood context across files, layers, and even the research paper concepts I was implementing.


It generated the NetworkModule, DatabaseModule, and AppModule with proper @Provides and @Singleton annotations — all correctly wired.

📡 BLE Mesh Network — Where Copilot Truly Shined

The mesh layer was the most complex part. I had the IEEE BitChat paper as reference, but translating academic protocols into Android BLE code is a different beast.

┌─────────────────────────────────────────────────────────────────────────┐
│                           DEVICE ROLES                                   │
└─────────────────────────────────────────────────────────────────────────┘

┌──────────────┐         ┌──────────────┐         ┌──────────────┐
│   GATEWAY    │         │    RELAY     │         │   NORMAL     │
│    DEVICE    │         │    NODE      │         │    NODE      │
├──────────────┤         ├──────────────┤         ├──────────────┤
│ ✅ Internet  │         │ ❌ No Internet│         │ ❌ No Internet│
│              │         │              │         │              │
│ 🔄 Relay     │◄───────►│ 🔄 Forward   │◄───────►│ 📤 Send      │
│ 📤 Upload    │         │ 📥 Receive   │         │ 📥 Receive   │
│ 📥 Download  │         │ 🔄 Re-broadcast    │    📤 Broadcast│
└──────────────┘         └──────────────┘         └──────────────┘

  * Any device can become Gateway if it gets internet
Enter fullscreen mode Exit fullscreen mode

📡 BLE Mesh Protocol Stack

┌─────────────────────────────────────────────────────────────────┐
│                     MESH APPLICATION LAYER                       │
├─────────────────────────────────────────────────────────────────┤
│  ┌────────────┐  ┌────────────┐  ┌────────────┐  ┌────────────┐│
│  │  Incident  │  │   Status   │  │   Sync     │  │   Ack      ││
│  │  Report    │  │  Update    │  │  Request   │  │  Message   ││
│  └─────┬──────┘  └─────┬──────┘  └─────┬──────┘  └─────┬──────┘│
└────────┼───────────────┼───────────────┼───────────────┼────────┘
         │               │               │               │
         ▼               ▼               ▼               ▼
┌─────────────────────────────────────────────────────────────────┐
│                     MESH TRANSPORT LAYER                         │
├─────────────────────────────────────────────────────────────────┤
│  Serialization: Protocol Buffers → Byte Array                    │
│  Fragmentation: 469 bytes per fragment (512-byte BLE limit)     │
│  Reassembly: Sequence numbers + CRC verification                 │
│  Encryption: ChaCha20-Poly1305 (via libsodium)                   │
└─────────────────────────────────────────────────────────────────┘
         │
         ▼
┌─────────────────────────────────────────────────────────────────┐
│                     MESH NETWORK LAYER                           │
├─────────────────────────────────────────────────────────────────┤
│  TTL Management: Decrement on each hop (max 8 hops)              │
│  Deduplication: SHA-256 message IDs, 10K cache                  │
│  Flood Control: Randomized delays to prevent collisions          │
│  Peer Discovery: mDNS/Zeroconf for local service discovery       │
└─────────────────────────────────────────────────────────────────┘
         │
         ▼
┌─────────────────────────────────────────────────────────────────┐
│                     BLE PHYSICAL LAYER                           │
├─────────────────────────────────────────────────────────────────┤
│  ┌──────────────────┐    ┌──────────────────┐               │
│  │   CODED PHY S=8   │    │    STANDARD PHY   │               │
│  │    (Primary)      │    │    (Fallback)     │               │
│  ├──────────────────┤    ├──────────────────┤               │
│  │ • Long range      │    │ • Standard range  │               │
│  │ • ~400m outdoors  │    │ • ~100m outdoors  │               │
│  │ • 125 kbps speed  │    │ • 1 Mbps speed    │               │
│  │ • High FEC        │    │ • Lower latency   │               │
│  └──────────────────┘    └──────────────────┘               │
│                                                                  │
│  Timeslot: Each node scans 30ms, then advertises 100ms         │
└─────────────────────────────────────────────────────────────────┘
Enter fullscreen mode Exit fullscreen mode

GATT Server + Scanner Setup:
I used Copilot in VS Code to help write BleMeshManager.kt — it understood that I needed a BLE GATT server advertising a custom service UUID while simultaneously scanning for other devices. When I typed the GATT server callback scaffold, Copilot auto-completed the entire onConnectionStateChange, onCharacteristicReadRequest, and onCharacteristicWriteRequest handlers with proper response codes.

Device Identification Problem:
-> Android 6+ randomizes MAC addresses, so I couldn't use them to identify devices.
-> I described the problem in a comment:
// Need a persistent unique device identifier since Android 6+ masks real MAC addresses

Built for coastal communities worldwide. When the network goes down, the mesh goes up.

Built within 2 weeks. Impossible without Github CLI !

Top comments (0)