feat: Integrate frequency-based device identification system

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.
This commit is contained in:
2026-01-14 10:51:46 -08:00
parent 5fbe60c76c
commit b083890e96
8 changed files with 872 additions and 16 deletions
+203
View File
@@ -543,6 +543,209 @@ footer p {
margin-bottom: 0.5rem;
}
/* Modal Styles */
.modal {
display: none;
position: fixed;
z-index: 2000;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.6);
backdrop-filter: blur(4px);
}
.modal.active {
display: flex;
align-items: center;
justify-content: center;
}
.modal-content {
background: white;
border-radius: 0.5rem;
box-shadow: var(--shadow-lg);
max-width: 800px;
width: 90%;
max-height: 90vh;
overflow-y: auto;
position: relative;
animation: modalSlideIn 0.3s ease-out;
}
@keyframes modalSlideIn {
from {
opacity: 0;
transform: translateY(-50px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.modal-header {
padding: 1.5rem;
border-bottom: 1px solid var(--border-color);
display: flex;
justify-content: space-between;
align-items: start;
}
.modal-header h2 {
margin: 0;
font-size: 1.5rem;
}
.modal-close {
background: none;
border: none;
font-size: 1.5rem;
cursor: pointer;
color: var(--text-secondary);
padding: 0;
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 0.25rem;
transition: all 0.2s;
}
.modal-close:hover {
background: var(--light-bg);
color: var(--text-primary);
}
.modal-body {
padding: 1.5rem;
}
.detail-section {
margin-bottom: 2rem;
}
.detail-section:last-child {
margin-bottom: 0;
}
.detail-section h3 {
font-size: 1.125rem;
margin-bottom: 1rem;
color: var(--text-primary);
border-bottom: 2px solid var(--primary-color);
padding-bottom: 0.5rem;
}
.detail-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
}
.detail-item {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.detail-label {
font-size: 0.875rem;
color: var(--text-secondary);
font-weight: 500;
}
.detail-value {
font-size: 1rem;
color: var(--text-primary);
font-weight: 400;
}
.detail-value.highlight {
color: var(--primary-color);
font-weight: 600;
}
.confidence-bar {
height: 8px;
background: var(--light-bg);
border-radius: 4px;
overflow: hidden;
margin-top: 0.5rem;
}
.confidence-fill {
height: 100%;
background: var(--success-color);
transition: width 0.3s ease;
}
.confidence-fill.medium {
background: var(--warning-color);
}
.confidence-fill.low {
background: var(--danger-color);
}
.matched-devices-list {
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.matched-device-item {
padding: 1rem;
background: var(--light-bg);
border-radius: 0.375rem;
border-left: 4px solid var(--primary-color);
}
.matched-device-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 0.5rem;
}
.matched-device-name {
font-weight: 600;
color: var(--text-primary);
}
.matched-device-confidence {
background: var(--primary-color);
color: white;
padding: 0.25rem 0.5rem;
border-radius: 0.25rem;
font-size: 0.875rem;
}
.matched-device-category {
display: inline-block;
background: white;
padding: 0.25rem 0.5rem;
border-radius: 0.25rem;
font-size: 0.875rem;
color: var(--text-secondary);
margin-bottom: 0.5rem;
}
.matched-device-description {
font-size: 0.875rem;
color: var(--text-secondary);
margin-top: 0.5rem;
}
.matched-device-method {
font-size: 0.75rem;
color: var(--text-secondary);
margin-top: 0.5rem;
font-style: italic;
}
/* Responsive */
@media (max-width: 768px) {
header .container {