/** * GigLez RF Protocol Database * JavaScript port of Python protocol_database.py * * Contains timing signatures for 18 known RF protocols * @module protocol-database */ export class ProtocolSignature { constructor({ name, category, manufacturer = null, model = null, frequency = 433920000, frequencyTolerance = 100000, shortPulseUs = 500, longPulseUs = 1000, timingTolerance = 0.2, preamblePattern = null, syncPattern = null, minBits = 24, maxBits = 64, typicalPulseCount = 100, minConfidence = 0.6 }) { this.name = name; this.category = category; this.manufacturer = manufacturer; this.model = model; this.frequency = frequency; this.frequencyTolerance = frequencyTolerance; this.shortPulseUs = shortPulseUs; this.longPulseUs = longPulseUs; this.timingTolerance = timingTolerance; this.preamblePattern = preamblePattern; this.syncPattern = syncPattern; this.minBits = minBits; this.maxBits = maxBits; this.typicalPulseCount = typicalPulseCount; this.minConfidence = minConfidence; } /** * Check if observed timing matches this protocol * @param {number} shortUs - Observed short pulse width (microseconds) * @param {number} longUs - Observed long pulse width (microseconds) * @returns {boolean} */ matchesTiming(shortUs, longUs) { const shortMin = this.shortPulseUs * (1 - this.timingTolerance); const shortMax = this.shortPulseUs * (1 + this.timingTolerance); const longMin = this.longPulseUs * (1 - this.timingTolerance); const longMax = this.longPulseUs * (1 + this.timingTolerance); return (shortMin <= shortUs && shortUs <= shortMax) && (longMin <= longUs && longUs <= longMax); } /** * Check if frequency matches this protocol * @param {number} freq - Observed frequency (Hz) * @returns {boolean} */ matchesFrequency(freq) { return Math.abs(freq - this.frequency) <= this.frequencyTolerance; } } // Weather Sensor Protocols export const WEATHER_SENSORS = [ new ProtocolSignature({ name: 'Oregon Scientific v2.1', category: 'Weather Sensor', manufacturer: 'Oregon Scientific', shortPulseUs: 488, longPulseUs: 976, preamblePattern: '10101010101010101010101010101010', // 32-bit preamble syncPattern: '1000', minBits: 64, maxBits: 128, typicalPulseCount: 200 }), new ProtocolSignature({ name: 'Oregon Scientific v3.0', category: 'Weather Sensor', manufacturer: 'Oregon Scientific', shortPulseUs: 500, longPulseUs: 1000, preamblePattern: '101010101010101010101010101010101010101010101010', // 48-bit preamble syncPattern: '1000', minBits: 64, maxBits: 128, typicalPulseCount: 250 }), new ProtocolSignature({ name: 'Acurite Tower Sensor', category: 'Weather Sensor', manufacturer: 'Acurite', shortPulseUs: 220, longPulseUs: 440, syncPattern: '10', minBits: 56, maxBits: 64, typicalPulseCount: 130 }), new ProtocolSignature({ name: 'Acurite 5n1 Weather Station', category: 'Weather Sensor', manufacturer: 'Acurite', shortPulseUs: 220, longPulseUs: 440, minBits: 64, maxBits: 80, typicalPulseCount: 160 }), new ProtocolSignature({ name: 'LaCrosse TX141TH-Bv2', category: 'Weather Sensor', manufacturer: 'LaCrosse', shortPulseUs: 500, longPulseUs: 1000, preamblePattern: '10101010', // 8-bit preamble minBits: 40, maxBits: 48, typicalPulseCount: 100 }), new ProtocolSignature({ name: 'Nexus Temperature/Humidity', category: 'Weather Sensor', manufacturer: 'Nexus', shortPulseUs: 500, longPulseUs: 1000, preamblePattern: '11111111', // 8-bit preamble minBits: 36, maxBits: 40, typicalPulseCount: 90 }), new ProtocolSignature({ name: 'Ambient Weather F007TH', category: 'Weather Sensor', manufacturer: 'Ambient Weather', shortPulseUs: 500, longPulseUs: 1000, minBits: 64, maxBits: 72, typicalPulseCount: 150 }) ]; // Garage Door Opener Protocols export const GARAGE_DOOR_OPENERS = [ new ProtocolSignature({ name: 'Princeton', category: 'Garage Door Opener', manufacturer: null, shortPulseUs: 400, longPulseUs: 1200, preamblePattern: '1111', // 4-bit preamble syncPattern: '10', minBits: 24, maxBits: 32, typicalPulseCount: 60 }), new ProtocolSignature({ name: 'Chamberlain/LiftMaster', category: 'Garage Door Opener', manufacturer: 'Chamberlain', shortPulseUs: 300, longPulseUs: 900, minBits: 32, maxBits: 40, typicalPulseCount: 80, frequency: 315000000 // 315 MHz }), new ProtocolSignature({ name: 'Linear MegaCode', category: 'Garage Door Opener', manufacturer: 'Linear', shortPulseUs: 250, longPulseUs: 500, minBits: 32, maxBits: 32, typicalPulseCount: 70, frequency: 318000000 // 318 MHz }) ]; // Doorbell Protocols export const DOORBELLS = [ new ProtocolSignature({ name: 'Honeywell Doorbell', category: 'Doorbell', manufacturer: 'Honeywell', shortPulseUs: 175, longPulseUs: 340, minBits: 48, maxBits: 48, typicalPulseCount: 100 }) ]; // TPMS Protocols export const TIRE_PRESSURE = [ new ProtocolSignature({ name: 'Toyota TPMS', category: 'TPMS', manufacturer: 'Toyota', shortPulseUs: 50, longPulseUs: 100, minBits: 64, maxBits: 80, typicalPulseCount: 160, frequency: 315000000 // 315 MHz }), new ProtocolSignature({ name: 'Schrader TPMS', category: 'TPMS', manufacturer: 'Schrader', shortPulseUs: 50, longPulseUs: 100, minBits: 64, maxBits: 80, typicalPulseCount: 160, frequency: 433920000 // 433.92 MHz }) ]; // Security Sensor Protocols export const SECURITY_SENSORS = [ new ProtocolSignature({ name: 'Magellan', category: 'Security Sensor', manufacturer: 'Paradox', shortPulseUs: 250, longPulseUs: 500, minBits: 32, maxBits: 48, typicalPulseCount: 80, frequency: 433920000 }) ]; // Remote Control Protocols export const REMOTE_CONTROLS = [ new ProtocolSignature({ name: 'PT2262', category: 'Remote Control', manufacturer: null, shortPulseUs: 350, longPulseUs: 1050, preamblePattern: '1111', // 4-bit preamble minBits: 24, maxBits: 24, typicalPulseCount: 50 }), new ProtocolSignature({ name: 'PT2260', category: 'Remote Control', manufacturer: null, shortPulseUs: 300, longPulseUs: 900, minBits: 24, maxBits: 24, typicalPulseCount: 50 }), new ProtocolSignature({ name: 'EV1527', category: 'Remote Control', manufacturer: null, shortPulseUs: 300, longPulseUs: 900, minBits: 24, maxBits: 24, typicalPulseCount: 50 }), new ProtocolSignature({ name: 'HCS301', category: 'Remote Control', manufacturer: 'Microchip', shortPulseUs: 400, longPulseUs: 800, minBits: 66, maxBits: 66, typicalPulseCount: 140 }) ]; // Combined protocol list export const ALL_PROTOCOLS = [ ...WEATHER_SENSORS, ...GARAGE_DOOR_OPENERS, ...DOORBELLS, ...TIRE_PRESSURE, ...SECURITY_SENSORS, ...REMOTE_CONTROLS ]; /** * Protocol Database class for querying and indexing protocols */ export class ProtocolDatabase { constructor() { this.protocols = ALL_PROTOCOLS; this._byCategory = {}; this._byFrequency = {}; this._indexProtocols(); } /** * Build indexes for fast lookup * @private */ _indexProtocols() { for (const proto of this.protocols) { // Index by category if (!this._byCategory[proto.category]) { this._byCategory[proto.category] = []; } this._byCategory[proto.category].push(proto); // Index by frequency (rounded to MHz) const freqMHz = Math.round(proto.frequency / 1_000_000); if (!this._byFrequency[freqMHz]) { this._byFrequency[freqMHz] = []; } this._byFrequency[freqMHz].push(proto); } } /** * Find protocols matching timing characteristics * @param {number} shortUs - Short pulse width (microseconds) * @param {number} longUs - Long pulse width (microseconds) * @param {number} [frequency] - Optional frequency filter (Hz) * @returns {ProtocolSignature[]} */ findByTiming(shortUs, longUs, frequency = null) { let candidates = this.protocols; if (frequency) { const freqMHz = Math.round(frequency / 1_000_000); candidates = this._byFrequency[freqMHz] || this.protocols; } const matches = []; for (const proto of candidates) { if (proto.matchesTiming(shortUs, longUs)) { if (!frequency || proto.matchesFrequency(frequency)) { matches.push(proto); } } } return matches; } /** * Find protocols by category * @param {string} category - Category name * @returns {ProtocolSignature[]} */ findByCategory(category) { return this._byCategory[category] || []; } /** * Find protocols by frequency * @param {number} frequency - Frequency in Hz * @returns {ProtocolSignature[]} */ findByFrequency(frequency) { const matches = []; for (const proto of this.protocols) { if (proto.matchesFrequency(frequency)) { matches.push(proto); } } return matches; } /** * Get all protocols * @returns {ProtocolSignature[]} */ getAll() { return this.protocols; } /** * Get database statistics * @returns {Object} */ getStatistics() { return { totalProtocols: this.protocols.length, categories: Object.keys(this._byCategory), byCategory: Object.fromEntries( Object.entries(this._byCategory).map(([cat, protos]) => [cat, protos.length]) ), frequencyBands: [...new Set( this.protocols.map(p => Math.round(p.frequency / 1_000_000)) )].sort((a, b) => a - b) }; } } // Export singleton instance export const protocolDb = new ProtocolDatabase();