4237c4bdb8
## Phase 1: Code Cleanup (~1,859 lines removed) **Deleted Redundant Matchers:** - ❌ strategies_orm.py (356 lines) - Old ORM-based strategies - ❌ simple_matcher.py (351 lines) - Replaced by strategies.py - ❌ rtl433_matcher.py (352 lines) - Replaced by strategies.py **Archived Old Scripts:** - Moved 11 one-time analysis/import scripts to scripts/archive/ - Scripts: analyze_flipper_signatures, analyze_tembed_files, identify_tembed_devices, import_flipper_sqlite, import_tembed_signatures, match_tembed_with_db, match_with_flipper_db, rematch_captures, test_gps_extraction, test_tembed_matching, test_wardriving_import **Consolidated API:** - Renamed main.py → main_orm_legacy.py (archived old ORM-based API) - main_simple.py is now the primary production API ## Phase 2: Pattern Decoder Integration ✅ **CRITICAL FIX: Pattern decoder now integrated into production API!** **Changes:** 1. Updated main_simple.py to use unified SignatureMatcher 2. Added 6 strategies to matcher pipeline: - ExactMatcher (protocol + frequency) - FrequencyMatcher (frequency-based) - BitPatternMatcher (data patterns) - TimingMatcher (timing-based) - RTL433DecoderStrategy (RTL_433 decoder) - PatternBasedStrategy (NEW! Pattern decoder for short captures) 3. Created MockDB class for simplified mode (no real database) 4. Replaced old get_matcher() with get_matcher_engine() 5. Updated upload handler to use MatchResult format 6. All matches now include confidence scores and match methods **Result:** - Pattern decoder is NOW ACTIVE in production 🎉 - Unified matching pipeline with 6 strategies - Cleaner codebase (-1,859 lines) - Single source of truth for matching logic 🎉 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
154 lines
4.5 KiB
Python
Executable File
154 lines
4.5 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Test T-Embed signature matching
|
|
|
|
This script:
|
|
1. Imports T-Embed signatures into database (if not already imported)
|
|
2. Tests matching engine against the same files
|
|
3. Shows matching accuracy and confidence scores
|
|
"""
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
# Add project root to path
|
|
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
|
|
from src.parser.sub_parser import SubFileParser
|
|
from src.matcher.strategies_orm import (
|
|
FrequencyMatcherORM,
|
|
TimingMatcherORM,
|
|
RAWPatternMatcherORM,
|
|
ExactMatcherORM
|
|
)
|
|
from src.database.connection import get_session
|
|
|
|
|
|
def test_matching():
|
|
"""Test signature matching with T-Embed files"""
|
|
|
|
print("="*70)
|
|
print("T-Embed Signature Matching Test")
|
|
print("="*70)
|
|
print()
|
|
|
|
# Get database session
|
|
session = get_session()
|
|
|
|
# Initialize parser and matchers
|
|
parser = SubFileParser()
|
|
|
|
matchers = [
|
|
('Exact', ExactMatcherORM(session)),
|
|
('Frequency', FrequencyMatcherORM(session, tolerance_hz=10000)),
|
|
('Timing', TimingMatcherORM(session)),
|
|
('RAW Pattern', RAWPatternMatcherORM(session, min_samples=10))
|
|
]
|
|
|
|
# Find T-Embed files
|
|
tembed_dir = Path(__file__).parent.parent / 'signatures' / 't-embed-rf'
|
|
sub_files = sorted(tembed_dir.glob('*.sub'))
|
|
|
|
print(f"Found {len(sub_files)} .sub files\n")
|
|
|
|
total_files = 0
|
|
total_matches = 0
|
|
|
|
# Test each file
|
|
for sub_file in sub_files:
|
|
print("-"*70)
|
|
print(f"File: {sub_file.name}")
|
|
|
|
# Parse file
|
|
try:
|
|
metadata = parser.parse(str(sub_file))
|
|
except Exception as e:
|
|
print(f" ❌ Parse error: {e}\n")
|
|
continue
|
|
|
|
# Skip empty files
|
|
if metadata.frequency == 0 or (metadata.file_format == 'RAW' and not metadata.raw_data):
|
|
print(f" ⏭️ Skipped: Empty capture\n")
|
|
continue
|
|
|
|
total_files += 1
|
|
|
|
# Show signal info
|
|
print(f"\nSignal Info:")
|
|
print(f" Frequency: {metadata.frequency/1e6:.2f} MHz")
|
|
print(f" Protocol: {metadata.protocol or 'RAW'}")
|
|
print(f" Format: {metadata.file_format}")
|
|
|
|
if metadata.raw_data:
|
|
abs_timings = [abs(t) for t in metadata.raw_data]
|
|
print(f" RAW Samples: {len(metadata.raw_data)}")
|
|
print(f" Timing Range: {min(abs_timings)}-{max(abs_timings)} μs")
|
|
print(f" Avg Timing: {sum(abs_timings)/len(abs_timings):.1f} μs")
|
|
|
|
# Try each matcher
|
|
print(f"\nMatching Results:")
|
|
|
|
file_matched = False
|
|
|
|
for matcher_name, matcher in matchers:
|
|
try:
|
|
matches = matcher.match(metadata)
|
|
|
|
if matches:
|
|
file_matched = True
|
|
print(f"\n {matcher_name} Matcher: {len(matches)} match(es)")
|
|
|
|
# Show top 3 matches
|
|
for i, match in enumerate(matches[:3], 1):
|
|
print(f" {i}. {match.device_name}")
|
|
print(f" Manufacturer: {match.manufacturer}")
|
|
print(f" Confidence: {match.confidence:.2%}")
|
|
print(f" Method: {match.match_method}")
|
|
|
|
# Show match details
|
|
if match.match_details:
|
|
for key, value in match.match_details.items():
|
|
if key != 'signature_id':
|
|
print(f" {key}: {value}")
|
|
|
|
except Exception as e:
|
|
print(f" ❌ {matcher_name} error: {e}")
|
|
|
|
if file_matched:
|
|
total_matches += 1
|
|
print(f"\n ✅ File matched successfully!")
|
|
else:
|
|
print(f"\n ⚠️ No matches found")
|
|
|
|
print()
|
|
|
|
# Summary
|
|
print("="*70)
|
|
print("MATCHING SUMMARY")
|
|
print("="*70)
|
|
print(f"Files tested: {total_files}")
|
|
print(f"Files matched: {total_matches}")
|
|
|
|
if total_files > 0:
|
|
match_rate = (total_matches / total_files) * 100
|
|
print(f"Match rate: {match_rate:.1f}%")
|
|
|
|
if match_rate == 100:
|
|
print("\n✅ Perfect! All files matched to signatures")
|
|
elif match_rate >= 75:
|
|
print(f"\n✅ Good! Most files matched")
|
|
elif match_rate >= 50:
|
|
print(f"\n⚠️ Moderate: Some files unmatched")
|
|
else:
|
|
print(f"\n❌ Low match rate - may need more signatures or tuning")
|
|
else:
|
|
print("\n⚠️ No valid files to test")
|
|
|
|
print("="*70)
|
|
|
|
session.close()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
test_matching()
|