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.
Ocean Sentinels is personal to me — coastal communities in India are among the most disaster-prone in the world, and the cruel irony is that when disasters strike hardest, the communication infrastructure goes down first. I built this because I believe no one should be unreachable just because a cell tower fell.
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:
- A user submits a hazard report on their phone
- The report broadcasts over BLE to nearby phones (~400m range using Coded PHY S8)
- Each phone relays it forward using store-carry-forward protocol
- When ANY phone in the chain gets internet → the report uploads to the server → authorities are alerted
No special hardware needed. Just phones.
Cover Video :
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
Live Test In Screen :
Live Demo :
Live Web App: [Ocean Sentinels - Web]
GitHub Repo: https://github.com/Gowshik-S/Ocean-Sentinels
APK Link: [Ocean Sentinels - APK]
APK Link: (Alternate Link) [Ocean Sentinels - APK]
IOS Link: Developed but can't be exported due to some limitations. Refer the github repo for source code.
Test Credentials
| Role | Username/Email | Password |
|---|---|---|
| Citizen | sihcitizen@vi.com | SIH@2025 |
| Rescue | sihrescue@vi.com | Ocean@123 |
| Admin | OceanAdmin1 | admin |
Works on both the Web App and Android APK.
Screenshots
Web Analytics (Public) :
Authority Analytics :
Android - Home Screen (dashboard with action cards):
Android - Report Incident (form with GPS, hazard type)
Android - Mesh Network Screen (BLE peers, relay status)
Android - Map View (Mapbox with markers)
Architecture Diagram (phone-to-phone mesh relay)
My Experience with GitHub Copilot CLI
GitHub Copilot CLI was instrumental across every layer of Ocean Sentinels. Here's how it shaped my development:
GitHub Copilot CLI terminal examples :
Using gh copilot in the Terminal
The challenge is built around GitHub Copilot CLI — and here's where it directly shaped my workflow:
Designing the BLE deduplication strategy:
$ gh copilot suggest "how do I deduplicate BLE mesh messages across 50+ relay hops in Android without using hop count TTL"
Copilot suggested time-based TTL (72hr) + SHA-256 deterministic IDs + LRU in-memory cache — the exact triple-layer system I implemented.
Debugging Coded PHY negotiation failure:
$ gh copilot explain "BluetoothAdapter.listenUsingInsecureL2capChannel returning null on Android 11 with Coded PHY"
It explained the Android 11 BLE stack quirk and suggested the dual-PHY fallback pattern I now use.
Generating FastAPI async SQLAlchemy boilerplate:
$ gh copilot suggest "FastAPI async SQLAlchemy 2.0 endpoint with JWT role-based access control for incident reporting"
Scaffolded the entire endpoint pattern — I reused this template across all 16+ backend routes.
BLE Mesh Layer — The Hardest Part
Building a Bluetooth mesh network from scratch is complex. Copilot CLI helped me:
- Design the
BleMeshManagerthat runs a GATT server and BLE scanner simultaneously - Implement the triple-layer deduplication strategy (relay path + LRU cache + DB check)
- Build the
DeviceIdentifiersystem — Android 6+ masks real MAC addresses, so Copilot suggested aSHA-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 suggestunderstood 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
BLE Mesh Relay Network (Offline Mode)
+------------------+ +------------------+
| Offline Device | ----BLE------> | Relay Peer | ----BLE-----> ...
| | | |
| Creates Report | | Receives Msg |
| Stores in Room | | SHA-256 Dedup |
| Broadcasts via | | Checks 72h |
| BLE GATT Server | | Expiry Window |
+------------------+ +--------+---------+
|
+-----------+-----------+
| |
No Internet Has Internet
| |
v v
+----------------+ +--------------------+
| Continue Relay | | Upload to Backend |
| to Next Peers | | (Server Dedup via |
| (Append to | | mesh_message_id) |
| Relay Path) | | |
+----------------+ +--------------------+
Mesh Specifications:
+------------------------+--------------------------+
| Parameter | Value |
+------------------------+--------------------------+
| Max Connections | 7 simultaneous peers |
| Fragment Size | 469 bytes |
| Max Packet Size | 512 bytes |
| Dedup Cache | 10,000 message IDs (LRU) |
| Message Expiry | 72 hours (time-based) |
| Peer Stale Timeout | 180 seconds |
| Scan Restart Interval | 30 seconds |
| PHY Strategy | Coded PHY (long range), |
| | 1M PHY fallback |
+------------------------+--------------------------+
📡 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: Time Based upto 72Hrs |
│ 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 │
└─────────────────────────────────────────────────────────────────┘
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.
- > 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)