Files
giglez/scripts/analyze_flipper_signatures.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

157 lines
4.6 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Analyze Flipper Zero signature database
Parses all Flipper Zero .sub files and creates a comprehensive device signature database
"""
import sys
from pathlib import Path
from collections import defaultdict
from typing import Dict, List
# Add project root to path
sys.path.insert(0, str(Path(__file__).parent.parent))
from src.parser.sub_parser import SubFileParser
def analyze_flipper_database(flipper_dir: Path):
"""Analyze all Flipper Zero .sub files"""
print("="*80)
print("FLIPPER ZERO SIGNATURE DATABASE ANALYSIS")
print("="*80)
print()
parser = SubFileParser()
# Find all .sub files
sub_files = list(flipper_dir.glob('**/*.sub'))
print(f"Found {len(sub_files)} Flipper Zero .sub files\n")
# Parse all files
signatures = []
parse_errors = []
for sub_file in sub_files:
try:
metadata = parser.parse(str(sub_file))
# Extract device name from path
device_name = sub_file.stem
signatures.append({
'filename': sub_file.name,
'device_name': device_name,
'path': str(sub_file.relative_to(flipper_dir)),
'frequency': metadata.frequency,
'protocol': metadata.protocol,
'file_format': metadata.file_format,
'modulation': metadata.modulation,
'bit_length': metadata.bit_length,
'has_raw_data': bool(metadata.raw_data),
'raw_samples': len(metadata.raw_data) if metadata.raw_data else 0
})
except Exception as e:
parse_errors.append((sub_file.name, str(e)))
print(f"Successfully parsed: {len(signatures)} files")
print(f"Parse errors: {len(parse_errors)} files\n")
# Analyze by frequency
print("-"*80)
print("FREQUENCY DISTRIBUTION")
print("-"*80)
freq_groups = defaultdict(list)
for sig in signatures:
freq_mhz = sig['frequency'] / 1e6 if sig['frequency'] else 0
freq_groups[freq_mhz].append(sig)
for freq in sorted(freq_groups.keys()):
if freq > 0:
count = len(freq_groups[freq])
print(f"{freq:8.2f} MHz: {count:3d} devices")
# Analyze by protocol
print(f"\n{'-'*80}")
print("PROTOCOL DISTRIBUTION")
print("-"*80)
protocol_groups = defaultdict(list)
for sig in signatures:
proto = sig['protocol'] or 'RAW'
protocol_groups[proto].append(sig)
for proto in sorted(protocol_groups.keys(), key=lambda x: len(protocol_groups[x]), reverse=True)[:15]:
count = len(protocol_groups[proto])
print(f"{proto:30s}: {count:3d} devices")
# Analyze by format
print(f"\n{'-'*80}")
print("FILE FORMAT DISTRIBUTION")
print("-"*80)
format_groups = defaultdict(list)
for sig in signatures:
format_groups[sig['file_format']].append(sig)
for fmt in sorted(format_groups.keys()):
count = len(format_groups[fmt])
print(f"{fmt:10s}: {count:3d} files")
# Show sample devices by frequency band
print(f"\n{'-'*80}")
print("SAMPLE DEVICES BY FREQUENCY BAND")
print("-"*80)
# Group into common RF bands
bands = {
'300-350 MHz (Garage/Gate)': (300, 350),
'400-450 MHz (Key Fobs/Remotes)': (400, 450),
'800-900 MHz (Sensors/Utility)': (800, 900),
'900-930 MHz (ISM Band - US)': (900, 930)
}
for band_name, (min_freq, max_freq) in bands.items():
matching = [s for s in signatures
if min_freq <= (s['frequency']/1e6) <= max_freq]
print(f"\n{band_name}: {len(matching)} devices")
# Show first 10
for sig in matching[:10]:
print(f" - {sig['device_name']:40s} {sig['frequency']/1e6:7.2f} MHz {sig['protocol'] or 'RAW'}")
return signatures, parse_errors
def main():
"""Main entry point"""
flipper_dir = Path(__file__).parent.parent / 'signatures' / 'flipperzero-firmware'
if not flipper_dir.exists():
print(f"❌ Flipper Zero directory not found: {flipper_dir}")
print("Run: git clone https://github.com/flipperdevices/flipperzero-firmware.git")
return 1
signatures, errors = analyze_flipper_database(flipper_dir)
# Summary
print(f"\n{'='*80}")
print("SUMMARY")
print(f"{'='*80}")
print(f"Total signatures: {len(signatures)}")
print(f"Parse errors: {len(errors)}")
print(f"\nThese signatures can now be imported into GigLez database")
print(f"for device matching against wardriving captures.")
print("="*80)
return 0
if __name__ == '__main__':
sys.exit(main())