# SubGHz Wigle-Like Wardriving System **Complete GPS+RF Capture and Export System** ## Overview This system creates a Wigle-like wardriving platform for sub-GHz RF signals, pairing GPS coordinates with Bruce T-Embed RF captures in a standardized format similar to Wigle WiFi wardriving. **Architecture:** ``` ┌──────────────────────────────────────────────────────────┐ │ GPS Sources (termux-location) │ └─────────────────┬────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────┐ │ Bruce T-Embed RF Captures (.sub files) │ │ - Frequency, Protocol, Preset │ │ - RAW data, Key data │ └─────────────────┬────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────┐ │ SubGHz Wardriving Database (~/logs/subghz_wardriving.db) │ │ ├─ wardriving_sessions │ │ ├─ gps_track (GPS breadcrumbs) │ │ └─ subghz_signals (RF+GPS pairs) │ └─────────────────┬────────────────────────────────────────┘ │ ▼ ┌──────────────────────────────────────────────────────────┐ │ Export Formats │ │ ├─ JSON (detailed) │ │ ├─ CSV (standard wardriving) │ │ ├─ Wigle CSV (standardized for sharing) │ │ └─ SQLite (database backup) │ └──────────────────────────────────────────────────────────┘ ``` ## Quick Start ### 1. Capture GPS + Associate with RF File ```bash # Capture current GPS and pair with Bruce .sub file python3 ~/python/subghz_wardriving/quick_capture.py \ ~/projects/device-integration/bruce/data/captures/raw10.sub # With custom session name python3 ~/python/subghz_wardriving/quick_capture.py \ raw10.sub downtown_survey ``` **Latest GPS:** - **Coordinates:** 34.07362505, -118.35955673 - **Accuracy:** 24.5m - **Timestamp:** 2026-01-13T11:17:51-08:00 - **Provider:** GPS ### 2. Export to Wigle Format ```bash # Export all data to Wigle CSV gps wigle-export # Export specific session gps wigle-export --session downtown_survey # Direct export python3 -c " from subghz_wardriving.exporter import SubGHzExporter, ExportConfig exporter = SubGHzExporter() config = ExportConfig(format='wigle', compress=False) result = exporter.export_session(config) print(f'Exported to: {result[\"output_file\"]}') " ``` **Output Location:** `~/exports/subghz_wardriving/` ## Database Schema ### Table: `subghz_signals` Stores RF captures paired with GPS coordinates: | Column | Type | Description | |--------|------|-------------| | `id` | INTEGER | Primary key | | `session_id` | TEXT | Wardriving session ID | | `capture_id` | TEXT | Unique capture identifier | | `timestamp` | TEXT | ISO 8601 timestamp | | `bruce_filename` | TEXT | Original .sub filename | | `bruce_file_path` | TEXT | Full path to .sub file | | `file_size_bytes` | INTEGER | File size | | `frequency_hz` | INTEGER | RF frequency in Hz | | `protocol` | TEXT | Protocol (RAW, Princeton, etc.) | | `gps_latitude` | REAL | Latitude (decimal degrees) | | `gps_longitude` | REAL | Longitude (decimal degrees) | | `gps_accuracy_meters` | REAL | GPS accuracy | | `interpolated` | BOOLEAN | GPS interpolated? | | `interpolation_confidence` | REAL | Confidence score (0-1) | | `time_gap_seconds` | REAL | Time since last capture | | `distance_traveled_meters` | REAL | Distance from last capture | | `estimated_speed_mps` | REAL | Speed in m/s | | `file_hash_md5` | TEXT | MD5 hash of file | | `notes` | TEXT | Additional notes | ### Table: `gps_track` GPS breadcrumb trail: | Column | Type | Description | |--------|------|-------------| | `id` | INTEGER | Primary key | | `session_id` | TEXT | Session identifier | | `timestamp` | TEXT | ISO 8601 timestamp | | `latitude` | REAL | Latitude | | `longitude` | REAL | Longitude | | `altitude` | REAL | Altitude (meters) | | `accuracy` | REAL | Horizontal accuracy (meters) | | `speed` | REAL | Speed (m/s) | | `provider` | TEXT | GPS provider (gps/network/passive) | ### Table: `wardriving_sessions` Session metadata: | Column | Type | Description | |--------|------|-------------| | `session_id` | TEXT | Primary key | | `start_time` | TEXT | Session start time | | `end_time` | TEXT | Session end time | | `total_signals` | INTEGER | Number of signals captured | | `total_distance_km` | REAL | Total distance traveled | | `device_info` | TEXT | Device information | | `notes` | TEXT | Session notes | ## Wigle CSV Format ### Header Format ```csv WigleWifi-1.4,appRelease=SubGHz-Wardrive-1.0,model=BruceT-Embed,release=Android,device=Phone,display=SubGHzWardrive,board=termux,brand=custom SignalHash,Frequency(MHz),Protocol,RSSI(dBm),Latitude,Longitude,Altitude,Accuracy,FirstSeen,LastSeen,CaptureCount,Interpolated,Confidence,BruceFile,SessionID ``` ### Columns | Column | Description | |--------|-------------| | `SignalHash` | SHA256 hash of frequency+protocol (16 chars) | | `Frequency(MHz)` | Frequency in MHz (e.g., 433.92) | | `Protocol` | Protocol name (RAW, Princeton, etc.) | | `RSSI(dBm)` | Signal strength (not available from .sub files) | | `Latitude` | Decimal degrees | | `Longitude` | Decimal degrees | | `Altitude` | Meters above sea level | | `Accuracy` | GPS accuracy in meters | | `FirstSeen` | ISO 8601 timestamp of first capture | | `LastSeen` | ISO 8601 timestamp of last capture | | `CaptureCount` | Number of times signal was seen | | `Interpolated` | true/false - was GPS interpolated? | | `Confidence` | Interpolation confidence (0-1) | | `BruceFile` | Original .sub filename | | `SessionID` | Wardriving session ID | ### Signal Aggregation Signals are grouped by hash (frequency + protocol), similar to how Wigle groups WiFi by BSSID. Multiple captures of the same signal show: - First and last seen timestamps - Total capture count - Location from first capture ## Usage Examples ### Example 1: Quick Capture ```bash # Capture GPS now with Bruce file python3 ~/python/subghz_wardriving/quick_capture.py raw10.sub ``` **Output:** ``` 📡 SubGHz GPS Capture ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Bruce File: raw10.sub Session: quick_20260113_112045 🛰️ Getting GPS location... ✓ GPS Location: 34.073625, -118.359557 Accuracy: 24.5m 📻 Parsing RF file... ✓ Frequency: 433920000 Hz (433.920 MHz) Protocol: RAW Preset: FCC_433 💾 Storing to database... ✓ Stored signal: quick_20260113_112045_raw10_1736789645 ✅ Capture paired successfully! Database: ~/logs/subghz_wardriving.db ``` ### Example 2: Export Session ```bash # Export to Wigle CSV gps wigle-export --session downtown_survey ``` **Output File:** `~/exports/subghz_wardriving/downtown_survey_20260113_112130_wigle.csv` **Content:** ```csv WigleWifi-1.4,appRelease=SubGHz-Wardrive-1.0,model=BruceT-Embed,release=Android,device=Phone,display=SubGHzWardrive,board=termux,brand=custom SignalHash,Frequency(MHz),Protocol,RSSI(dBm),Latitude,Longitude,Altitude,Accuracy,FirstSeen,LastSeen,CaptureCount,Interpolated,Confidence,BruceFile,SessionID 8a3f2d1c4e5b6a7f,433.920,RAW,,34.073625,-118.359557,,24.5,2026-01-13T19:17:51Z,2026-01-13T19:17:51Z,1,false,1.0,raw10.sub,downtown_survey ``` ### Example 3: Wardriving Session ```bash # Start GPS logging gps on --session wardrive_session1 --interval 158.4 # Bruce captures RF signals to /BruceRF/*.sub files # (Manually on Bruce device) # After session, run batch import for subfile in ~/projects/device-integration/bruce/data/captures/*.sub; do python3 ~/python/subghz_wardriving/quick_capture.py "$subfile" wardrive_session1 done # Stop GPS logging gps off # Export to Wigle format gps wigle-export --session wardrive_session1 ``` ## File Locations | Component | Path | |-----------|------| | **Database** | `~/logs/subghz_wardriving.db` | | **GPS Quick Log** | `~/logs/gps_quick.jsonl` | | **GPS Correlations** | `~/logs/gps_correlations.db` (legacy) | | **Exports** | `~/exports/subghz_wardriving/` | | **Bruce Captures** | `~/projects/device-integration/bruce/data/captures/` | | **Quick Capture Script** | `~/python/subghz_wardriving/quick_capture.py` | | **Exporter Module** | `~/python/subghz_wardriving/exporter.py` | | **Database Module** | `~/python/subghz_wardriving/database.py` | ## Integration with Existing GPS Infrastructure This system integrates with your existing GPS wardriving infrastructure: ### Existing Systems 1. **`gps` command** - CLI tool for GPS operations 2. **`gps_service.py`** - Background GPS logging (158.4s interval) 3. **`smart_gps_detector.py`** - Auto-detection and file renaming 4. **`realtime_gps_attribution.py`** - Real-time GPS attribution ### New Additions 1. **`quick_capture.py`** - Quick GPS+RF pairing 2. **Wigle export format** - Added to `exporter.py` 3. **`gps wigle-export`** - New command in `gps` script 4. **Standardized database** - Uses existing `subghz_wardriving.db` ## Advanced Features ### GPS Interpolation When RF captures occur between GPS readings, the system interpolates GPS coordinates based on: - Time gap between captures - Distance traveled - Estimated speed - Interpolation confidence score ### Session Management ```python from subghz_wardriving.database import SubGHzWardrivingDB db = SubGHzWardrivingDB() # Create session db.create_session("my_session", device_info="Bruce T-Embed", notes="Downtown survey") # End session (calculates statistics) db.end_session("my_session") # Get summary summary = db.get_session_summary("my_session") print(f"Signals: {summary['session']['total_signals']}") print(f"Distance: {summary['session']['total_distance_km']} km") ``` ### Filtering Exports ```python from subghz_wardriving.exporter import SubGHzExporter, ExportConfig exporter = SubGHzExporter() # Export only 433 MHz signals config = ExportConfig( format='wigle', frequency_filter=(433_000_000, 434_000_000), # 433-434 MHz confidence_threshold=0.8, # High confidence only protocol_filter='RAW' ) result = exporter.export_session(config) ``` ## Comparison to WiFi Wigle | Feature | WiFi Wigle | SubGHz Wigle | |---------|------------|--------------| | **Signal ID** | BSSID (MAC address) | SignalHash (freq+protocol) | | **Signal Name** | SSID | Protocol name | | **Frequency** | WiFi channels (2.4/5 GHz) | SubGHz (300-928 MHz) | | **Strength** | RSSI (dBm) | Not available from .sub | | **Device** | WiFi adapter | Bruce T-Embed CC1101 | | **Format** | CSV | CSV (Wigle-compatible) | | **Location** | GPS | GPS | | **Aggregation** | By BSSID | By SignalHash | ## Future Enhancements 1. **RSSI Integration** - If Bruce firmware provides signal strength 2. **Real-time Export** - Live streaming to Wigle format 3. **Map Visualization** - Plot signals on map 4. **Protocol Decoding** - Decode known protocols (garage doors, car keys, etc.) 5. **Community Database** - Share SubGHz signal maps 6. **Cross-device Correlation** - Combine with Pineapple WiFi wardriving ## Troubleshooting ### No GPS Fix ```bash # Check GPS status gps status # Try network provider termux-location -p network # Use test coordinates # Edit gps script to add test coordinate option ``` ### Database Locked ```bash # Check for running processes ps aux | grep python | grep subghz # Close database connections pkill -f subghz_wardriving ``` ### Export Fails ```bash # Check database exists ls -lh ~/logs/subghz_wardriving.db # Check export directory mkdir -p ~/exports/subghz_wardriving # Test export directly python3 -m subghz_wardriving.exporter ``` ## Resources - **Bruce Firmware:** https://github.com/pr3y/Bruce - **Flipper SubGHz Format:** https://docs.flipperzero.one/sub-ghz - **Wigle.net:** https://wigle.net/ - **CC1101 Datasheet:** https://www.ti.com/product/CC1101 --- **Created:** 2026-01-13 **System Version:** 1.0 **Database:** ~/logs/subghz_wardriving.db **Latest GPS:** 34.07362505, -118.35955673 (24.5m accuracy)