#!/usr/bin/env python3 """ Import Flipper Zero signatures into SQLite database Uses SQLite for immediate testing without PostgreSQL setup """ import sys import sqlite3 from pathlib import Path from datetime import datetime # Add project root to path sys.path.insert(0, str(Path(__file__).parent.parent)) from src.parser.sub_parser import SubFileParser def create_sqlite_schema(conn): """Create SQLite schema""" cursor = conn.cursor() # Devices table cursor.execute(''' CREATE TABLE IF NOT EXISTS devices ( id INTEGER PRIMARY KEY AUTOINCREMENT, device_name TEXT, manufacturer TEXT, model TEXT, device_type TEXT, typical_frequency INTEGER, protocol TEXT, description TEXT, first_seen TIMESTAMP DEFAULT CURRENT_TIMESTAMP, is_verified BOOLEAN DEFAULT 0, source TEXT ) ''') # Signatures table cursor.execute(''' CREATE TABLE IF NOT EXISTS signatures ( id INTEGER PRIMARY KEY AUTOINCREMENT, device_id INTEGER REFERENCES devices(id), protocol TEXT, frequency INTEGER, modulation TEXT, bit_pattern BLOB, bit_mask BLOB, timing_min INTEGER, timing_max INTEGER, raw_pattern TEXT, confidence_threshold REAL DEFAULT 0.7, source TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ''') # Indexes cursor.execute('CREATE INDEX IF NOT EXISTS idx_sig_freq ON signatures(frequency)') cursor.execute('CREATE INDEX IF NOT EXISTS idx_sig_device ON signatures(device_id)') conn.commit() def import_flipper_signature(conn, sub_file: Path, parser: SubFileParser): """Import a single Flipper Zero .sub file""" try: metadata = parser.parse(str(sub_file)) # Skip if frequency is 0 if metadata.frequency == 0: return None cursor = conn.cursor() # Determine device type from frequency freq_mhz = metadata.frequency / 1e6 if 300 <= freq_mhz <= 350: device_type = 'garage_door' elif 400 <= freq_mhz <= 450: device_type = 'remote_control' elif 800 <= freq_mhz <= 900: device_type = 'sensor' else: device_type = 'unknown' # Create device record cursor.execute(''' INSERT INTO devices (device_name, manufacturer, model, device_type, typical_frequency, protocol, description, source) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ''', ( sub_file.stem, 'Unknown', sub_file.stem, device_type, metadata.frequency, metadata.protocol or 'RAW', f'Imported from Flipper Zero: {sub_file.name}', 'flipper_zero' )) device_id = cursor.lastrowid # Extract timing info timing_min, timing_max = None, None raw_pattern = None if metadata.raw_data and len(metadata.raw_data) > 0: abs_timings = [abs(t) for t in metadata.raw_data] timing_min = min(abs_timings) timing_max = max(abs_timings) raw_pattern = ','.join(map(str, metadata.raw_data[:100])) # First 100 samples # Create signature record cursor.execute(''' INSERT INTO signatures (device_id, protocol, frequency, modulation, timing_min, timing_max, raw_pattern, source) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ''', ( device_id, metadata.protocol or 'RAW', metadata.frequency, metadata.modulation, timing_min, timing_max, raw_pattern, 'flipper_zero' )) conn.commit() return { 'device_id': device_id, 'device_name': sub_file.stem, 'frequency': metadata.frequency, 'protocol': metadata.protocol } except Exception as e: return None def main(): """Main entry point""" print("="*80) print("FLIPPER ZERO → SQLite IMPORT") print("="*80) print() # Create/connect to SQLite database db_path = Path(__file__).parent.parent / 'giglez.db' print(f"Database: {db_path}") conn = sqlite3.connect(str(db_path)) print("✅ Connected to SQLite database\n") # Create schema print("Creating schema...") create_sqlite_schema(conn) print("✅ Schema ready\n") # Find Flipper signatures flipper_dir = Path(__file__).parent.parent / 'signatures' / 'flipperzero-firmware' if not flipper_dir.exists(): print(f"❌ Flipper directory not found: {flipper_dir}") return 1 sub_files = list(flipper_dir.glob('**/*.sub')) print(f"Found {len(sub_files)} Flipper Zero .sub files\n") # Import all signatures parser = SubFileParser() imported = [] skipped = 0 print("Importing signatures...") for i, sub_file in enumerate(sub_files, 1): if i % 10 == 0: print(f" Processed {i}/{len(sub_files)}...") result = import_flipper_signature(conn, sub_file, parser) if result: imported.append(result) else: skipped += 1 print(f"✅ Import complete\n") # Summary print("="*80) print("IMPORT SUMMARY") print("="*80) print(f"Total files: {len(sub_files)}") print(f"Imported: {len(imported)}") print(f"Skipped: {skipped}") # Query database cursor = conn.cursor() print(f"\nDATABASE CONTENTS") print("-"*80) cursor.execute("SELECT COUNT(*) FROM devices") device_count = cursor.fetchone()[0] print(f"Devices: {device_count}") cursor.execute("SELECT COUNT(*) FROM signatures") sig_count = cursor.fetchone()[0] print(f"Signatures: {sig_count}") # Frequency distribution print(f"\nFREQUENCY DISTRIBUTION") print("-"*80) cursor.execute(''' SELECT frequency, COUNT(*) as count FROM signatures GROUP BY frequency ORDER BY count DESC ''') for freq, count in cursor.fetchall(): print(f"{freq/1e6:8.2f} MHz: {count:3d} devices") conn.close() print(f"\n{'='*80}") print("✅ Database ready at:", db_path) print("="*80) return 0 if __name__ == '__main__': sys.exit(main())