Files
giglez/scripts/match_with_flipper_db.py
T
Trilltechnician 48fcb00241 Phase 3 Complete: Web Interface MVP
Major Achievements:
-  Full web interface (1,520+ lines of frontend code)
-  Interactive Leaflet.js map with marker clustering
-  Drag-and-drop upload system with GPS input
-  Search & filter UI with multi-criteria
-  Statistics dashboard with Chart.js
-  Responsive mobile-friendly design

Backend:
-  FastAPI static file serving
-  Simplified server mode (main_simple.py)
-  Improved startup script with port auto-selection
-  PostgreSQL schema ready (requires setup)

Database:
-  SQLite populated with 85 Flipper Zero signatures
-  Device matching system operational
-  Frequency-based search working

Documentation:
-  PHASE_3_COMPLETE.md - Technical summary
-  WEB_INTERFACE_README.md - User guide
-  WEBAPP_STARTUP_GUIDE.md - Troubleshooting
-  POSTGRESQL_SETUP_EXPLANATION.md - DB setup guide
-  DATABASE_POPULATION_SUCCESS.md - Import report
-  DEVICE_IDENTIFICATION_REPORT.md - Matching analysis

Files Created:
- templates/index.html (260 lines)
- static/css/main.css (500 lines)
- static/js/*.js (760 lines total)
- src/api/main_simple.py (simplified server)
- start_web.sh (auto port selection)

Status: Production MVP Ready
Next: Phase 4 - API & Integration

🛰️ Generated with Claude Code
https://claude.com/claude-code

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-12 18:21:11 -08:00

174 lines
5.4 KiB
Python

#!/usr/bin/env python3
"""
Match T-Embed captures against Flipper Zero signature database
Demonstrates device identification using expanded signature knowledge base
"""
import sys
from pathlib import Path
from typing import List, Dict
# Add project root to path
sys.path.insert(0, str(Path(__file__).parent.parent))
from src.parser.sub_parser import SubFileParser
def load_flipper_signatures(flipper_dir: Path) -> List[Dict]:
"""Load all Flipper Zero signatures"""
parser = SubFileParser()
signatures = []
for sub_file in flipper_dir.glob('**/*.sub'):
try:
metadata = parser.parse(str(sub_file))
signatures.append({
'device_name': sub_file.stem,
'filename': sub_file.name,
'frequency': metadata.frequency,
'protocol': metadata.protocol or 'RAW',
'file_format': metadata.file_format,
'bit_length': metadata.bit_length,
'has_raw': bool(metadata.raw_data),
'raw_samples': len(metadata.raw_data) if metadata.raw_data else 0
})
except:
pass
return signatures
def match_by_frequency(target_freq: int, signatures: List[Dict], tolerance_hz: int = 10000) -> List[Dict]:
"""Match by frequency with tolerance"""
matches = []
for sig in signatures:
freq_diff = abs(sig['frequency'] - target_freq)
if freq_diff <= tolerance_hz:
confidence = 1.0 - (freq_diff / tolerance_hz)
confidence = max(0.5, confidence)
matches.append({
'signature': sig,
'confidence': confidence,
'freq_diff_hz': freq_diff,
'match_method': 'frequency'
})
return sorted(matches, key=lambda x: x['confidence'], reverse=True)
def main():
"""Main entry point"""
print("="*80)
print("DEVICE MATCHING: T-Embed vs Flipper Zero Database")
print("="*80)
print()
# Load Flipper signatures
flipper_dir = Path(__file__).parent.parent / 'signatures' / 'flipperzero-firmware'
if not flipper_dir.exists():
print("❌ Flipper Zero database not found")
return 1
print("Loading Flipper Zero signature database...")
signatures = load_flipper_signatures(flipper_dir)
print(f"✅ Loaded {len(signatures)} signatures\n")
# Load T-Embed capture
tembed_dir = Path(__file__).parent.parent / 'signatures' / 't-embed-rf'
parser = SubFileParser()
tembed_file = tembed_dir / 'raw_7.sub'
print(f"Analyzing T-Embed capture: {tembed_file.name}")
print("-"*80)
metadata = parser.parse(str(tembed_file))
print(f"Frequency: {metadata.frequency/1e6:.2f} MHz")
print(f"Protocol: {metadata.protocol or 'RAW (undecoded)'}")
print(f"Format: {metadata.file_format}")
if metadata.raw_data:
print(f"RAW Samples: {len(metadata.raw_data)}")
print(f"\n{'='*80}")
print("MATCHING AGAINST FLIPPER ZERO DATABASE")
print(f"{'='*80}\n")
# Match by frequency (±10 kHz tolerance)
matches = match_by_frequency(metadata.frequency, signatures, tolerance_hz=10000)
if matches:
print(f"Found {len(matches)} potential matches:\n")
for i, match in enumerate(matches[:10], 1):
sig = match['signature']
print(f"{i}. {sig['device_name']}")
print(f" Frequency: {sig['frequency']/1e6:.3f} MHz (diff: {match['freq_diff_hz']/1000:.1f} kHz)")
print(f" Protocol: {sig['protocol']}")
print(f" Format: {sig['file_format']}")
print(f" Confidence: {match['confidence']:.1%}")
print()
# Best match
best = matches[0]
print(f"{'='*80}")
print(f"BEST MATCH: {best['signature']['device_name']}")
print(f"Confidence: {best['confidence']:.1%}")
print(f"Method: Frequency matching ({best['freq_diff_hz']/1000:.1f} kHz difference)")
print(f"{'='*80}")
else:
print("❌ No matches found in Flipper Zero database")
print("\nThis device is at 915 MHz (ISM band)")
print("Flipper Zero database contains mostly 433 MHz devices")
print("\nTo improve matching:")
print("- Import RTL_433 database (has 915 MHz devices)")
print("- Add more T-Embed captures from wardriving")
print("- Import community-contributed 915 MHz signatures")
print(f"\n{'='*80}")
print("DATABASE COVERAGE ANALYSIS")
print(f"{'='*80}\n")
# Analyze frequency coverage
freq_groups = {}
for sig in signatures:
freq_mhz = sig['frequency'] / 1e6
freq_band = f"{int(freq_mhz/100)*100}-{int(freq_mhz/100)*100+100}"
if freq_band not in freq_groups:
freq_groups[freq_band] = 0
freq_groups[freq_band] += 1
print("Frequency Band Coverage:")
for band in sorted(freq_groups.keys()):
print(f" {band} MHz: {freq_groups[band]} devices")
# Check if 915 MHz covered
target_freq = metadata.frequency / 1e6
target_band = f"{int(target_freq/100)*100}-{int(target_freq/100)*100+100}"
print(f"\nTarget device: {target_freq:.2f} MHz ({target_band} MHz band)")
if target_band in freq_groups:
print(f"✅ Coverage: {freq_groups[target_band]} devices in target band")
else:
print(f"❌ No coverage: Target band not in Flipper database")
print("\n" + "="*80)
return 0
if __name__ == '__main__':
sys.exit(main())