NavGuard is an offline emergency communication system designed for areas without cellular network or internet connectivity. It enables long-range communication using LoRa radio technology, combines GPS/NavIC positioning, and provides offline mapping capabilities for rescue operations and emergency response.
NavGuard creates a mesh communication network for emergency situations using:
- LoRa (Long Range) Radio: 10-15km direct range, mesh relay capability
- Bluetooth: Local connectivity between Android app and hardware device
- GPS/NavIC: Satellite positioning for location tracking
- Offline Maps: Pre-loaded map files for navigation without internet
- Mountain rescue operations
- Disaster relief communications
- Remote area expeditions
- Search and rescue missions
- Military and defense applications
- Areas with destroyed telecommunications infrastructure
- Technology: Kotlin, Jetpack Compose, Material Design 3
- Features:
- Bluetooth connectivity with LoRa devices
- Real-time GPS location tracking (NavIC/GPS)
- Chat interface with message status (Sending → Sent → Delivered → Read)
- Live location sharing with continuous updates
- Offline map viewer with Mapsforge library
- Message persistence and chat history
- Signal strength monitoring (RSSI/SNR)
- Precision finding mode for signal tracking
- Microcontroller: ESP32 (dual-core, Bluetooth + WiFi)
- LoRa Module: RYLR998 (Reyax) operating at 868MHz
- GPS Module: NavIC/GPS compatible module (UART1)
- Interface:
- Bluetooth Serial (115200 baud)
- Hardware button (GPIO27) for live location control
- Flash button (GPIO0) for signal sending
- Buzzer (GPIO26) for audio alerts
- Blue LED (GPIO2) for visual feedback
Message Format: TYPE|CONTENT|LAT|LON|MESSAGE_ID|STATUS
- TYPE: REGULAR, EMERGENCY, SOS, RELAY
- CONTENT: Message text or "LOC" for live updates
- LAT/LON: Geographic coordinates (0.0 if unavailable)
- MESSAGE_ID: 6-character unique identifier (base36)
- STATUS: 0=Sending, 1=Sent, 2=Delivered, 3=Read
Acknowledgment Format: ACK|MESSAGE_ID|STATUS_CODE
Signal Format: SIGNAL|SOS from X|RSSI|SNR
Control Format: CTRL|LOC_STOP (stops live location)
- Regular Messages: Text communication with delivery confirmation
- Emergency Messages: Priority messages with GPS location
- SOS Alerts: Critical emergency signals with automatic location
- Message Status Tracking: Real-time delivery and read receipts
- Message Persistence: Chat history saved per device
- Continuous Transmission: GPS coordinates sent every 2 seconds
- Two Modes:
- App-initiated: Share from Android app
- Hardware-initiated: Long-press button (3s) on ESP32 device
- NavIC/GPS Support: High-accuracy positioning with Indian satellite system
- Visual Indicators: Animated status banner and map markers
- Stop Controls: Double-press button or tap "Stop" in app
- Direction Finding: Send periodic signals for rescue location
- Signal Strength: Real-time RSSI (Received Signal Strength Indicator)
- Signal Quality: SNR (Signal-to-Noise Ratio) monitoring
- Precision Finding Mode: Dedicated screen for signal tracking and triangulation
- Map Format: Mapsforge .map files
- Map Sources:
- Bundled world.map (low detail, global coverage)
- Downloadable regional maps via in-app browser
- Features:
- Real-time location marker (updates every second)
- Dual marker support (your location + sender's location)
- Distance calculation between markers
- Smooth zoom and pan (levels 5-20)
- Map scale bar and zoom controls
- Map Downloads: Integrated download manager for OpenAndroMaps
- Message Relay: Automatic forwarding through intermediate devices
- Extended Range: Coverage beyond direct line-of-sight
- Hop Count Tracking: Monitor relay chain length
- Relay Path Recording: Track message routing (future feature)
- Auto-connection: Automatically connects to paired devices
- Device Discovery: Scan and pair new Bluetooth devices
- Connection Status: Real-time indicator (green = connected)
- Multiple Device Support: Chat history per paired device
- Background Service: Maintains connection when app is backgrounded
| Component | Specification | Purpose |
|---|---|---|
| ESP32 | Dual-core, 240MHz, 520KB RAM | Main controller |
| RYLR998 | LoRa transceiver, 868MHz, 115200 baud | Long-range radio |
| GPS Module | NavIC/GPS compatible, UART 115200 | Positioning |
| Buzzer | Active 5V | Audio alerts |
| LED | Built-in blue LED (GPIO2) | Visual feedback |
| Button | Momentary push button | User controls |
| Power Supply | 3.3V-5V, 500mA+ | Device power |
ESP32 Pin Assignments:
├── UART2 (LoRa - RYLR998)
│ ├── GPIO16 (RX) ← LoRa TX
│ └── GPIO17 (TX) → LoRa RX
├── UART1 (GPS/NavIC)
│ ├── GPIO21 (RX) ← GPS TX (Blue)
│ └── GPIO22 (TX) → GPS RX (Green)
├── GPIO27 → Button (Pull-up, Active-low)
├── GPIO0 → Flash Button (Pull-up, Active-low)
├── GPIO26 → Buzzer Signal
└── GPIO2 → Blue LED
AT+ADDRESS=2 // Device address (1 or 2)
AT+NETWORKID=5 // Network ID (match all devices)
AT+IPR=115200 // UART baud rate
AT+BAND=868000000 // Frequency: 868MHz (Europe)- 433MHz: Asia/Africa
- 915MHz: Americas/Australia
- 868MHz: Europe (default)
- Android Studio: 2023.1.1 (Hedgehog) or newer
- Android SDK: API 21 (minimum) to API 34 (target)
- Kotlin: 1.9.20
- Gradle: 8.1.4
- JDK: 8 or higher
// UI Framework
Jetpack Compose 2024.02.00
Material Design 3
Navigation Compose 2.7.6
// Bluetooth & Location
Core KTX 1.12.0
Lifecycle Runtime KTX 2.7.0
// Offline Maps
Mapsforge 0.25.0 (core, map, map-reader, themes)
AndroidSVG 1.4
Jsoup 1.16.1 (map downloads)
// Data Persistence
Gson 2.10.1<!-- Bluetooth (Classic) -->
android.permission.BLUETOOTH (API ≤32)
android.permission.BLUETOOTH_ADMIN (API ≤30)
android.permission.BLUETOOTH_CONNECT (API ≥31)
android.permission.BLUETOOTH_SCAN (API ≥31)
<!-- Location (GPS) -->
android.permission.ACCESS_FINE_LOCATION
android.permission.ACCESS_COARSE_LOCATION
<!-- Services -->
android.permission.FOREGROUND_SERVICE
android.permission.FOREGROUND_SERVICE_LOCATION
android.permission.FOREGROUND_SERVICE_REMOTE_MESSAGING
android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE
<!-- Other -->
android.permission.VIBRATE
android.permission.POST_NOTIFICATIONS
android.permission.INTERNET (map downloads only)- Install Android Studio
- Clone or download this repository
- Ensure Android SDK API levels 21-34 are installed
# Navigate to project directory
cd NavGuard
# Sync Gradle (automatic in Android Studio)
# Or via command line:
./gradlew --refresh-dependencies
# Build debug APK
./gradlew assembleDebug
# Build release APK (requires signing key)
./gradlew assembleRelease- Debug:
app/build/outputs/apk/debug/app-debug.apk - Release:
app/build/outputs/apk/release/app-release.apk
# Via ADB
adb install app/build/outputs/apk/debug/app-debug.apk
# Or use Android Studio "Run" button
# Or transfer APK to device and install manually- Install Arduino IDE 2.0+
- Add ESP32 board support:
- File → Preferences → Additional Board Manager URLs
- Add:
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
- Install ESP32 board package (Tools → Board → Boards Manager)
- Install libraries:
- TinyGPS++ (for GPS parsing)
- HardwareSerial (built-in)
- Open
navguard/navguard.inoin Arduino IDE - Configure device address:
String myAddress = "2"; // Change to "1" or "2" String targetAddress = "1"; // Opposite of myAddress
- Select board: "ESP32 Dev Module"
- Select port: Your ESP32's USB port
- Click "Upload"
- Device A: Set
myAddress = "1",targetAddress = "2" - Device B: Set
myAddress = "2",targetAddress = "1" - Multiple devices can form mesh network (relay capability)
-
Power on ESP32 device
- Blue LED should blink during startup
- Buzzer confirms initialization
-
Enable Bluetooth on Android phone
- Settings → Bluetooth → On
-
Launch NavGuard app
- Grant all requested permissions
- Bluetooth, Location, Notifications
-
Pair Device
- Tap "SCAN" to discover devices
- Select "LoRa_Node_X" from available devices
- Tap to pair (may require pairing confirmation)
-
Connect
- After pairing, tap device to connect
- Status bar shows "Connected to device" (green icon)
- Type message in text field
- Tap send button (▶)
- Message shows status: ⏳ Sending → ✔ Sent → ✔✔ Delivered
- Compose message describing emergency
- Long-press send button
- App automatically attaches GPS coordinates
- Message type shown as "🚨 EMERGENCY"
- Press and hold hardware button for 3+ seconds
- Buzzer gives long beep
- Device sends "SOS from [ADDRESS]" every second
- Press flash button to stop
- Connect to device
- Tap location icon (📍) in message input area
- Icon turns green, status banner shows "Live location sharing"
- GPS coordinates sent every 2 seconds
- Tap "Stop" in banner or press icon again to stop
- Press and hold button for 3+ seconds
- Long beep confirms activation
- NavIC/GPS coordinates sent every 2 seconds as "LOC|lat|lon"
- Double-press button to stop
- Automatically activates when peer starts sharing
- Status banner shows "Live location receiving"
- Coordinates update in real-time
- Tap "Map" to view on offline map
- Two markers: Red (your location), Blue (sender's location)
-
Open Map
- Tap map icon (🗺️) in top bar
- Or tap "Map" button in live location banner
-
Initial Map
- Bundled world.map loads (low detail)
- Your location shown with red pin marker
- Auto-centers on your GPS position
-
Download Detailed Maps
- Tap download icon (⬇️) in map screen
- Opens web browser to OpenAndroMaps
- Download .map file for your region
- Return to app
-
Load Downloaded Map
- Tap folder icon (📁) in map screen
- Select downloaded map from list
- Map reloads with high detail
- Position markers remain
-
Map Controls
- Pinch to zoom (levels 5-20)
- Pan by dragging
- Tap location icon (📍) to re-center on your position
- Scale bar shows distance
-
Sender: Press flash button on ESP32
- Sends "SOS from [ADDRESS]" signal every second
- Continues until flash button pressed again
-
Receiver: Tap "Track" in signal banner
- Opens Precision Finding screen
- Shows real-time RSSI and SNR values
- Move to maximize signal strength
- Guides you toward sender
| Action | Duration | Function |
|---|---|---|
| Long Press | 3+ seconds | Start live location (NavIC/GPS) |
| Double Press | < 500ms between taps | Stop live location |
| Flash Button | Single press | Toggle signal sending (SOS) |
Feedback Indicators:
- Long beep: Live location started
- Two short beeps: Live location stopped
- Mini tick: Location/signal sent successfully
- Three beeps: Incoming message (no Bluetooth connected)
- LED blink: Message received
User Input → Android App → Bluetooth Serial → ESP32
→ LoRa Module → Radio Transmission → Remote Device
Radio Reception → LoRa Module → ESP32 → Parse +RCV
→ Bluetooth Serial → Android App → Display + ACK
- Sender transmits message with status=0 (Sending)
- Sender updates to status=1 (Sent) after transmission
- Receiver sends ACK with status=2 (Delivered)
- Sender updates message status to Delivered
- User views message, sender receives ACK with status=3 (Read)
- Android App Mode: Foreground service (LocationService) sends every 2s
- Hardware Mode: ESP32 reads NavIC/GPS, formats "LOC|lat|lon", transmits via LoRa
- Receiver: Parses LOC message, displays in status banner, updates map marker
- Efficiency: Compact format reduces radio airtime (critical for LoRa)
- NavIC: Indian Regional Navigation Satellite System (7 satellites)
- Compatibility: Dual GPS/NavIC modules supported
- Accuracy: Typically 3-5 meters in open sky
- Update Rate: 1-10Hz depending on module
- Latching Time: 30-120 seconds for first fix
- Range: 10-15km line-of-sight, 2-5km urban
- Data Rate: 300bps - 50kbps (configurable)
- Power: ~100mW transmit, ~10mA receive
- Modulation: Chirp Spread Spectrum (CSS)
- Advantages: Long range, low power, penetrates obstacles
- Limitations: Low data rate, duty cycle restrictions (EU: 1% for 868MHz)
- Format: Mapsforge .map (binary vector maps)
- Sources:
- OpenAndroMaps - Detailed regional maps
- Mapsforge Downloads - Official repository
- Features: Multi-language, elevation contours, hiking trails
- Size: 50MB-500MB per country, ~2GB for world.map (low detail)
- Rendering: On-device vector rendering (smooth zoom, small file size)
NavGuard/
├── app/
│ ├── src/main/
│ │ ├── AndroidManifest.xml # App permissions & components
│ │ ├── assets/world.map # Bundled world map (low detail)
│ │ ├── java/com/navguard/app/
│ │ │ ├── MainActivity.kt # Main entry point, navigation
│ │ │ ├── EmergencyMessage.kt # Message data model & logic
│ │ │ ├── LocationManager.kt # GPS location handling
│ │ │ ├── LocationService.kt # Background location service
│ │ │ ├── SerialService.kt # Bluetooth serial communication
│ │ │ ├── SerialSocket.kt # Bluetooth socket wrapper
│ │ │ ├── SerialListener.kt # Serial event callbacks
│ │ │ ├── SerialBus.kt # App-wide message event bus
│ │ │ ├── PersistenceManager.kt # Chat & settings storage
│ │ │ ├── MapDownloadActivity.kt # In-app map browser
│ │ │ ├── BluetoothUtil.kt # Bluetooth helpers
│ │ │ ├── TextUtil.kt # Text formatting utilities
│ │ │ ├── Constants.kt # App constants
│ │ │ └── ui/
│ │ │ ├── screens/
│ │ │ │ ├── DevicesScreen.kt # Device list & pairing
│ │ │ │ ├── EmergencyTerminalScreen.kt # Chat interface
│ │ │ │ ├── OfflineMapScreen.kt # Map viewer
│ │ │ │ └── PrecisionFindingScreen.kt # Signal tracking
│ │ │ ├── components/
│ │ │ │ └── StatusBar.kt # Reusable status bar
│ │ │ └── theme/
│ │ │ ├── Color.kt # Color palette
│ │ │ ├── Theme.kt # Material theme
│ │ │ └── Type.kt # Typography
│ │ └── res/
│ │ ├── drawable/ # Icons & images
│ │ ├── mipmap/ # App launcher icons
│ │ ├── values/
│ │ │ ├── strings.xml # Text resources
│ │ │ ├── colors.xml # Color definitions
│ │ │ ├── styles.xml # UI styles
│ │ │ └── arrays.xml # String arrays
│ │ └── ...
│ └── build.gradle # App dependencies & config
├── navguard/
│ └── navguard.ino # Arduino ESP32 firmware
├── gradle/ # Gradle wrapper files
├── build.gradle # Project-level build config
├── settings.gradle # Project settings
├── gradlew / gradlew.bat # Gradle wrapper scripts
├── LICENSE.txt # MIT License
└── README.md # This file
- Check: Bluetooth enabled on phone
- Check: Device paired (appears in "Paired Devices" list)
- Try: Unpair and re-pair device
- Try: Restart Bluetooth: Settings → Bluetooth → Toggle off/on
- Check: Device not connected to another phone
- Check: Location permission granted (Fine Location)
- Check: Location services enabled: Settings → Location → On
- Try: Go outdoors for clear sky view
- Wait: First GPS fix can take 30-120 seconds
- Check: GPS icon in status bar (should show coordinates)
- Check: Bluetooth icon green (connected)
- Check: Device within LoRa range (10-15km line-of-sight)
- Check: Message not too long (LoRa payload limit ~240 bytes)
- Try: Restart app and reconnect
- Try: Clear app data: Settings → Apps → NavGuard → Storage → Clear Data
- Try: Reinstall app
- Check: Android version (minimum API 21 / Android 5.0)
- Check: Logcat for error messages
- Check: Storage permission granted
- Check: Map file has .map extension
- Check: Map file not corrupted (re-download)
- Try: Use bundled world.map (folder icon → select world.map)
- Check: Power supply adequate (5V, 500mA+)
- Check: USB cable data capable (not charge-only)
- Try: Press RESET button on ESP32
- Check: Blue LED blinks on startup
- Check: Serial monitor shows initialization messages
- Check: RYLR998 wired correctly (RX/TX not swapped)
- Check: LoRa antenna connected (module can be damaged without antenna)
- Check: Device address configured (AT+ADDRESS)
- Check: Network ID matches (AT+NETWORKID=5)
- Try: Test with AT commands via Serial Monitor
- Check: GPS module powered (LED blinking)
- Check: GPS antenna has clear sky view (no metal/concrete above)
- Wait: NavIC cold start can take 5-10 minutes
- Check: GPS TX/RX wires not swapped (TX→RX, RX→TX)
- Try: Different location (away from buildings)
- Check: Buzzer wiring (GPIO26 → Buzzer+, GND → Buzzer-)
- Check: Active buzzer used (not passive piezo)
- Try: Swap buzzer polarity
- Check: GPIO26 not shorted to ground
- Check: LoRa frequency correct for region (868MHz EU, 915MHz US)
- Check: Antenna properly connected (SMA connector tight)
- Try: Elevate devices (higher = better range)
- Check: Line-of-sight path (obstacles reduce range)
- Check: Other LoRa devices causing interference
- Normal: LoRa duty cycle limits (1% for 868MHz in EU)
- Check: Too many devices transmitting simultaneously
- Try: Reduce live location frequency (increase interval in code)
- Check: UART baud rate matches (115200)
- Check: LoRa network ID matches all devices
- Check: Message format correct (TYPE|CONTENT|LAT|LON|ID|STATUS)
- Try: Power cycle both devices
Edit navguard.ino:
// Change frequency band (match your region)
sendAT("AT+BAND=868000000"); // 868MHz (EU)
// sendAT("AT+BAND=915000000"); // 915MHz (US/AU)
// sendAT("AT+BAND=433000000"); // 433MHz (Asia)
// Adjust transmit power (5-20dBm)
sendAT("AT+POWER=20"); // Maximum power
// Change spreading factor (5-11, higher=longer range, slower)
sendAT("AT+PARAMETER=12,7,1,7"); // BW=125kHz, SF=7, CR=1, Preamble=7Edit navguard.ino:
const unsigned long liveIntervalMs = 2000; // Default: 2 seconds
// Increase to 5000 for 5-second intervals (reduces radio usage)Edit LocationService.kt:
private const val LOCATION_UPDATE_INTERVAL = 5000L // 5 seconds- Flash firmware to additional ESP32 units
- Set unique address for each:
myAddress = "3","4", etc. - Set
targetAddressto recipient (or broadcast address in future) - All devices on same
NETWORKIDcan communicate - Messages automatically relay through intermediate devices
Edit EmergencyMessage.kt:
enum class MessageType {
REGULAR,
EMERGENCY,
SOS,
RELAY,
// Add custom types:
WEATHER,
STATUS,
PHOTO // Future: image transmission support
}Currently, relay capability exists but requires manual configuration. To enable automatic mesh relay:
- Modify
navguard.inoto track received message IDs - Check if message already seen (avoid loops)
- Re-transmit message with incremented hop count
- Add relay path to message format
- Automatic mesh routing algorithm
- End-to-end encryption (AES-128)
- Group messaging (broadcast to multiple devices)
- Voice message recording and playback
- Image compression and transmission
- Battery level monitoring
- Solar charging integration
- Web-based configuration interface
- Desktop companion app (Windows/Linux/Mac)
- Integration with emergency services (API)
- LoRa duty cycle restrictions in regulated bands
- No end-to-end encryption (messages visible to relays)
- Single-hop relay only (no multi-hop routing)
- Limited message size (~240 bytes)
- No message queue (one message at a time)
- No image/file transfer capability
Contributions are welcome! Please follow these guidelines:
- Fork the repository
- Create a feature branch (
git checkout -b feature/YourFeature) - Commit your changes (
git commit -m 'Add YourFeature') - Push to the branch (
git push origin feature/YourFeature) - Open a Pull Request
- Kotlin: Follow official Kotlin style guide
- Arduino: Use consistent indentation (2 spaces)
- Comments: Document complex logic and hardware interactions
- Testing: Test on physical hardware before submitting
This project is based on SimpleBluetoothTerminal by Kai Morich:
- Repository: kai-morich/SimpleBluetoothTerminal
- License: MIT
- Jetpack Compose - Modern Android UI framework
- Mapsforge - Offline map rendering
- TinyGPS++ - GPS parsing library
- RYLR998 - LoRa transceiver module
- OpenAndroMaps - Offline map data
- Material Design - UI design system
- NavIC: Indian Regional Navigation Satellite System by ISRO
- Bharat Pi: NavIC shield for ESP32 by Bharat Pi
This project is licensed under the MIT License. See LICENSE.txt for full details.
MIT License
Copyright (c) 2019 Kai Morich (original SimpleBluetoothTerminal)
Copyright (c) 2025 NavGuard Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
- GitHub Issues: Report bugs and feature requests on GitHub
- Logs: Include Android logcat output when reporting crashes
- Hardware: Specify ESP32 model and component versions
This software is provided for educational and emergency preparedness purposes. Users are responsible for:
- Complying with local radio transmission regulations
- Obtaining necessary licenses for LoRa operation
- Ensuring proper usage in emergency situations
- Not relying solely on this system for life-safety applications
Radio Regulations: LoRa operates in ISM (Industrial, Scientific, Medical) bands. Check your country's regulations:
- Europe: 868MHz (ETSI EN300.220, 1% duty cycle)
- USA: 915MHz (FCC Part 15, unlicensed)
- Asia: 433MHz (varies by country, license may be required)
Emergency Use: This system should complement, not replace, professional emergency communication systems. Always contact official emergency services (911, 112, etc.) when possible.
Version: 1.0 Last Updated: January 2025 Status: Active Development
Made with ❤️ for emergency preparedness and rescue operations.