b083890e96
Integrated comprehensive device attribution system into GigLez:
1. Simple Device Matcher (src/matcher/simple_matcher.py):
- Frequency-based device categorization (315/433/868/915 MHz)
- Protocol-specific identification (Princeton, EV1527, Oregon Scientific, etc.)
- Modulation + frequency matching (OOK/FSK/ASK)
- Confidence scoring (0.4-0.95 range)
- 50+ device types covered
2. API Integration (src/api/main_simple.py):
- Device matching in upload pipeline
- Added device fields: device_name, device_category, match_confidence, match_method, device_description
- Top 5 alternative matches stored per capture
- New endpoint: GET /api/v1/captures/{id} for detail view
3. Frontend Implementation:
- Detail modal with comprehensive device information
- Device identification section with confidence bars
- Alternative matches display
- Signal, location, and metadata sections
- Keyboard (ESC) and click-outside modal closing
4. UI Enhancements (static/css/main.css):
- Modal overlay with backdrop blur
- Animated modal slide-in
- Confidence visualization (green/yellow/red bars)
- Responsive detail grid layout
- Device match cards with categories
5. JavaScript Integration:
- detail-modal.js: Comprehensive detail view renderer
- Updated map.js and search.js to use detail modal
- Removed placeholder functions
6. Utilities:
- scripts/rematch_captures.py: Re-run matcher on existing data
- Successfully re-matched 20 existing captures
Device Categories Supported:
- Consumer RF (remotes, sensors)
- Automotive (key fobs, TPMS)
- Home Automation (garage/gate openers, blinds)
- Sensors (weather stations, temperature)
- Security (door/window sensors, alarms)
- IoT (smart meters, LoRa devices)
- Industrial (SCADA, telemetry, RFID)
Match Methods:
- Protocol matching (highest confidence: 0.7-0.95)
- Frequency matching (0.4-0.7)
- Modulation + frequency matching (0.5-0.7)
Frontend now displays:
- Device name and category on map markers
- Confidence percentage
- Detailed device information modal
- Alternative device matches
- Match method explanation
All existing captures successfully identified with 60-70% confidence.
92 lines
3.2 KiB
JavaScript
92 lines
3.2 KiB
JavaScript
// GigLez - Search Functionality
|
|
|
|
async function searchCaptures() {
|
|
const query = document.getElementById('search-query').value;
|
|
const frequency = document.getElementById('search-frequency').value;
|
|
const protocol = document.getElementById('search-protocol').value;
|
|
const dateStart = document.getElementById('search-date-start').value;
|
|
const dateEnd = document.getElementById('search-date-end').value;
|
|
const lat = document.getElementById('search-lat').value;
|
|
const lon = document.getElementById('search-lon').value;
|
|
const radius = document.getElementById('search-radius').value;
|
|
|
|
// Build query parameters
|
|
const params = new URLSearchParams();
|
|
|
|
if (query) params.append('q', query);
|
|
if (frequency) params.append('frequency', parseFloat(frequency) * 1e6);
|
|
if (protocol) params.append('protocol', protocol);
|
|
if (dateStart) params.append('date_start', dateStart);
|
|
if (dateEnd) params.append('date_end', dateEnd);
|
|
|
|
// Geographic search
|
|
if (lat && lon && radius) {
|
|
params.append('latitude', lat);
|
|
params.append('longitude', lon);
|
|
params.append('radius_km', radius);
|
|
}
|
|
|
|
try {
|
|
const response = await fetch(`/api/v1/query/captures?${params.toString()}`);
|
|
|
|
if (!response.ok) {
|
|
throw new Error('Search failed');
|
|
}
|
|
|
|
const data = await response.json();
|
|
displaySearchResults(data.captures || []);
|
|
|
|
} catch (error) {
|
|
console.error('Search error:', error);
|
|
alert(`Search failed: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
function displaySearchResults(captures) {
|
|
const resultsDiv = document.getElementById('search-results');
|
|
const resultsList = document.getElementById('results-list');
|
|
|
|
resultsDiv.style.display = 'block';
|
|
|
|
if (captures.length === 0) {
|
|
resultsList.innerHTML = '<p>No results found. Try adjusting your search criteria.</p>';
|
|
return;
|
|
}
|
|
|
|
resultsList.innerHTML = captures.map(capture => createResultCard(capture)).join('');
|
|
}
|
|
|
|
function createResultCard(capture) {
|
|
const freqMHz = (capture.frequency / 1e6).toFixed(2);
|
|
const date = new Date(capture.timestamp || Date.now()).toLocaleString();
|
|
|
|
const deviceName = capture.device_name || 'Unknown Device';
|
|
const protocol = capture.protocol || 'RAW';
|
|
const confidence = capture.match_confidence
|
|
? `${(capture.match_confidence * 100).toFixed(0)}%`
|
|
: 'N/A';
|
|
|
|
return `
|
|
<div class="result-card" onclick="viewCaptureDetails(${capture.id})">
|
|
<div class="result-header">
|
|
<div class="result-title">${deviceName}</div>
|
|
<div class="result-frequency">${freqMHz} MHz</div>
|
|
</div>
|
|
<div class="result-details">
|
|
<div>
|
|
<strong>Protocol:</strong> ${protocol}
|
|
</div>
|
|
<div>
|
|
<strong>Confidence:</strong> ${confidence}
|
|
</div>
|
|
<div>
|
|
<strong>Captured:</strong> ${date}
|
|
</div>
|
|
<div>
|
|
<strong>Location:</strong> ${capture.latitude.toFixed(4)}, ${capture.longitude.toFixed(4)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|