feat: Integrate frequency-based device identification system

Integrated comprehensive device attribution system into GigLez:

1. Simple Device Matcher (src/matcher/simple_matcher.py):
   - Frequency-based device categorization (315/433/868/915 MHz)
   - Protocol-specific identification (Princeton, EV1527, Oregon Scientific, etc.)
   - Modulation + frequency matching (OOK/FSK/ASK)
   - Confidence scoring (0.4-0.95 range)
   - 50+ device types covered

2. API Integration (src/api/main_simple.py):
   - Device matching in upload pipeline
   - Added device fields: device_name, device_category, match_confidence, match_method, device_description
   - Top 5 alternative matches stored per capture
   - New endpoint: GET /api/v1/captures/{id} for detail view

3. Frontend Implementation:
   - Detail modal with comprehensive device information
   - Device identification section with confidence bars
   - Alternative matches display
   - Signal, location, and metadata sections
   - Keyboard (ESC) and click-outside modal closing

4. UI Enhancements (static/css/main.css):
   - Modal overlay with backdrop blur
   - Animated modal slide-in
   - Confidence visualization (green/yellow/red bars)
   - Responsive detail grid layout
   - Device match cards with categories

5. JavaScript Integration:
   - detail-modal.js: Comprehensive detail view renderer
   - Updated map.js and search.js to use detail modal
   - Removed placeholder functions

6. Utilities:
   - scripts/rematch_captures.py: Re-run matcher on existing data
   - Successfully re-matched 20 existing captures

Device Categories Supported:
- Consumer RF (remotes, sensors)
- Automotive (key fobs, TPMS)
- Home Automation (garage/gate openers, blinds)
- Sensors (weather stations, temperature)
- Security (door/window sensors, alarms)
- IoT (smart meters, LoRa devices)
- Industrial (SCADA, telemetry, RFID)

Match Methods:
- Protocol matching (highest confidence: 0.7-0.95)
- Frequency matching (0.4-0.7)
- Modulation + frequency matching (0.5-0.7)

Frontend now displays:
- Device name and category on map markers
- Confidence percentage
- Detailed device information modal
- Alternative device matches
- Match method explanation

All existing captures successfully identified with 60-70% confidence.
This commit is contained in:
2026-01-14 10:51:46 -08:00
parent 5fbe60c76c
commit b083890e96
8 changed files with 872 additions and 16 deletions
+87
View File
@@ -0,0 +1,87 @@
#!/usr/bin/env python3
"""
Re-match existing captures with device matcher
Runs the device matcher on all existing captures in the database
"""
import sys
import json
from pathlib import Path
# Add project root to path
sys.path.insert(0, str(Path(__file__).parent.parent))
from src.matcher.simple_matcher import get_matcher
def rematch_captures(storage_file):
"""Re-run device matching on existing captures"""
if not Path(storage_file).exists():
print(f"❌ Storage file not found: {storage_file}")
return 1
# Load existing captures
with open(storage_file, 'r') as f:
data = json.load(f)
captures = data.get('captures', [])
if not captures:
print("️ No captures to process")
return 0
print(f"🔄 Re-matching {len(captures)} captures...")
matcher = get_matcher()
updated_count = 0
for i, capture in enumerate(captures, 1):
frequency = capture.get('frequency', 0)
protocol = capture.get('protocol', 'RAW')
preset = capture.get('preset', 'Unknown')
# Skip if already has device data
if capture.get('device_name'):
continue
# Perform matching
matches = matcher.match(frequency, protocol, preset)
best_match = matches[0] if matches else None
if best_match:
# Update capture with device data
capture['device_name'] = best_match.device_name
capture['device_category'] = best_match.device_category
capture['match_confidence'] = best_match.confidence
capture['match_method'] = best_match.match_method
capture['device_description'] = best_match.description
capture['matched_devices'] = [
{
"device_name": m.device_name,
"category": m.device_category,
"confidence": m.confidence,
"method": m.match_method,
"description": m.description
}
for m in matches[:5]
]
updated_count += 1
print(f" [{i}/{len(captures)}] {capture['filename']}: {best_match.device_name} ({best_match.confidence:.0%})")
else:
print(f" [{i}/{len(captures)}] {capture['filename']}: No match found")
# Save updated data
with open(storage_file, 'w') as f:
json.dump(data, f, indent=2)
print(f"\n✅ Updated {updated_count}/{len(captures)} captures with device information")
return 0
if __name__ == '__main__':
STORAGE_FILE = Path(__file__).parent.parent / "data" / "captures_simple.json"
sys.exit(rematch_captures(STORAGE_FILE))