Files
giglez/static/js/decoder/index.js
T
Trilltechnician 01b06fadc6 Phase 3: JavaScript pattern decoder implementation
Completed JavaScript port of pattern_decoder.py with full client-side
RF signal analysis capability for Sub-GHz devices.

## New Files Created (8 files, ~2,100 lines):

### Core Decoder Modules:
- static/js/decoder/protocol-database.js (410 lines)
  * 18 RF protocol signatures (Weather, Garage, TPMS, Doorbells, Security, Remotes)
  * ProtocolSignature class with timing/frequency matching
  * ProtocolDatabase with indexed queries
  * Categories: Weather Sensors (7), Garage Doors (3), TPMS (2), etc.

- static/js/decoder/pulse-analyzer.js (238 lines)
  * K-means clustering for SHORT/LONG pulse detection
  * identifyPulseWidths() using k-means
  * decodeToBits() for PWM encoding (SHORT=0, LONG=1)
  * analyzePulseTrain() for comprehensive timing analysis
  * validatePulseData() quality checks
  * estimateSNR() signal quality estimation

- static/js/decoder/fingerprint.js (312 lines)
  * PulseFingerprint class for statistical characteristics
  * extractFingerprint() - mean, std, duty cycle, pulse/gap ratio
  * calculateSimilarity() - 0-1 similarity score with weights
  * compareToProtocol() - protocol library matching
  * classifySignal() - heuristic device type classification
  * generateReport() - debugging output

- static/js/decoder/pattern-decoder.js (457 lines)
  * DeviceMatch class (standardized result format)
  * PatternDecoder main decoder class
  * Multi-strategy decoding:
    - Strategy 1: Timing pattern analysis (K-means + protocol DB)
    - Strategy 2: Statistical fingerprint matching
    - Strategy 3: Heuristic classification (fallback)
  * Match deduplication and ranking
  * Statistics tracking (success rate, avg confidence)

- static/js/decoder/index.js (226 lines)
  * ES6 module exports for all decoder components
  * parseSubFile() - Flipper Zero .sub parser
  * quickDecode() - convenience API
  * decodeFromURL() - fetch and decode remote files
  * decodeFromFile() - browser File API support
  * getVersion() - version and feature info

### Demo & Testing:
- static/decoder-demo.html (374 lines)
  * Beautiful drag-and-drop UI for .sub file upload
  * Real-time client-side decoding (no server needed!)
  * Interactive results with confidence badges
  * Signal quality visualization
  * Debug console output
  * Mobile-responsive design

- static/js/decoder/test.js (120 lines)
  * Node.js test suite for decoder
  * Tests all 4 strategies (timing, fingerprint, protocol DB, heuristics)
  * Validates parsing, analysis, and matching
  * Example output shows 7 matches @ 43.3% confidence

- package.json
  * Enable ES6 modules ("type": "module")
  * NPM script: "test:decoder"

## Test Results:
 JavaScript decoder successfully tested with Node.js
 Found 7 device matches on test .sub file (43.3% best confidence)
 All modules working: protocol DB (18 protocols), pulse analysis, fingerprinting, decoding
 Browser demo ready at /static/decoder-demo.html

## Features:
- 🔬 K-means pulse width clustering
- 📊 Statistical fingerprinting
- 📚 Protocol library matching (18 protocols)
- 🎯 Multi-strategy matching
- 📱 Client-side decoding (privacy-focused)
- 🌐 Browser and Node.js compatible
-  Single-transmission decoding (no repetitions needed)

## Next Steps:
- Integrate decoder into main upload UI
- Test with T-Embed and Flipper datasets
- Optimize for larger .sub files
- Add more protocol signatures

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-14 23:08:53 -08:00

227 lines
6.4 KiB
JavaScript

/**
* GigLez Pattern Decoder - Main Entry Point
* JavaScript RF Signal Decoder for Sub-GHz Devices
*
* Export all decoder modules for browser and Node.js usage
*
* @module giglez-decoder
* @version 1.0.0
*/
// ============================================================================
// Protocol Database
// ============================================================================
export {
ProtocolSignature,
ProtocolDatabase,
WEATHER_SENSORS,
GARAGE_DOOR_OPENERS,
DOORBELLS,
TIRE_PRESSURE,
SECURITY_SENSORS,
REMOTE_CONTROLS,
ALL_PROTOCOLS,
protocolDb
} from './protocol-database.js';
// ============================================================================
// Pulse Analysis
// ============================================================================
export {
kMeans,
identifyPulseWidths,
decodeToBits,
analyzePulseTrain,
validatePulseData,
estimateSNR
} from './pulse-analyzer.js';
// ============================================================================
// Statistical Fingerprinting
// ============================================================================
export {
PulseFingerprint,
extractFingerprint,
calculateSimilarity,
compareToProtocol,
classifySignal,
generateReport
} from './fingerprint.js';
// ============================================================================
// Pattern Decoder (Main)
// ============================================================================
export {
DeviceMatch,
PatternDecoder,
decode
} from './pattern-decoder.js';
// ============================================================================
// Convenience API
// ============================================================================
/**
* Quick decode function - analyze .sub file and return device matches
*
* @param {Object} metadata - Parsed .sub file metadata
* @param {number} metadata.frequency - Frequency in Hz
* @param {string} metadata.preset - Modulation preset
* @param {string} metadata.protocol - Protocol name
* @param {number[]} metadata.raw_data - Pulse timing array
* @param {Object} options - Decoder options
* @param {number} options.minConfidence - Minimum confidence threshold (default: 0.4)
* @param {number} options.maxResults - Maximum results to return (default: 10)
* @param {boolean} options.debug - Enable debug logging (default: false)
* @returns {Promise<Array>} Array of DeviceMatch objects
*
* @example
* import { quickDecode } from './decoder/index.js';
*
* const metadata = {
* frequency: 433920000,
* preset: 'FuriHalSubGhzPresetOok270Async',
* protocol: 'RAW',
* raw_data: [2980, -240, 520, -980, 520, -980, ...]
* };
*
* const matches = await quickDecode(metadata, { debug: true });
* console.log(matches[0].toString());
*/
export async function quickDecode(metadata, options = {}) {
const { PatternDecoder } = await import('./pattern-decoder.js');
const decoder = new PatternDecoder(options);
return decoder.decode(metadata);
}
/**
* Parse Flipper Zero .sub file format
*
* @param {string} content - Raw .sub file content
* @returns {Object} Parsed metadata
*
* @example
* const content = await fetch('capture.sub').then(r => r.text());
* const metadata = parseSubFile(content);
* const matches = await quickDecode(metadata);
*/
export function parseSubFile(content) {
const lines = content.split('\n');
const metadata = {
filetype: null,
version: null,
frequency: null,
preset: null,
protocol: null,
bit: null,
key: null,
te: null,
raw_data: []
};
for (const line of lines) {
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith('#')) continue;
if (trimmed.includes(':')) {
const [key, value] = trimmed.split(':', 2).map(s => s.trim());
switch (key) {
case 'Filetype':
metadata.filetype = value;
break;
case 'Version':
metadata.version = parseInt(value);
break;
case 'Frequency':
metadata.frequency = parseInt(value);
break;
case 'Preset':
metadata.preset = value;
break;
case 'Protocol':
metadata.protocol = value;
break;
case 'Bit':
metadata.bit = parseInt(value);
break;
case 'Key':
metadata.key = value;
break;
case 'TE':
metadata.te = parseInt(value);
break;
case 'RAW_Data':
// Parse pulse timing array
const pulses = value.split(/\s+/)
.map(s => parseInt(s))
.filter(n => !isNaN(n));
metadata.raw_data.push(...pulses);
break;
}
}
}
return metadata;
}
/**
* Decode .sub file from URL
*
* @param {string} url - URL to .sub file
* @param {Object} options - Decoder options
* @returns {Promise<Array>} Device matches
*
* @example
* const matches = await decodeFromURL('https://example.com/capture.sub');
* console.log(`Found ${matches.length} potential devices`);
*/
export async function decodeFromURL(url, options = {}) {
const response = await fetch(url);
const content = await response.text();
const metadata = parseSubFile(content);
return quickDecode(metadata, options);
}
/**
* Decode .sub file from File object (browser)
*
* @param {File} file - File object from file input
* @param {Object} options - Decoder options
* @returns {Promise<Array>} Device matches
*
* @example
* document.getElementById('fileInput').addEventListener('change', async (e) => {
* const file = e.target.files[0];
* const matches = await decodeFromFile(file, { debug: true });
* console.log(matches);
* });
*/
export async function decodeFromFile(file, options = {}) {
const content = await file.text();
const metadata = parseSubFile(content);
return quickDecode(metadata, options);
}
/**
* Get decoder version information
* @returns {Object} Version info
*/
export async function getVersion() {
const { ALL_PROTOCOLS } = await import('./protocol-database.js');
return {
version: '1.0.0',
name: 'GigLez Pattern Decoder',
description: 'JavaScript RF Signal Decoder for Sub-GHz Devices',
protocols: ALL_PROTOCOLS.length,
features: [
'K-means pulse width clustering',
'Statistical fingerprinting',
'Protocol library matching',
'18 built-in protocols',
'Single-transmission decoding',
'Browser and Node.js compatible'
]
};
}