From d2e5b4d4a0a1a5d81bb7f6cd84473b4ee2d99789 Mon Sep 17 00:00:00 2001 From: jedarden Date: Mon, 6 Apr 2026 14:02:19 -0400 Subject: [PATCH] feat: implement passive radar auto-detection of router AP Automatically detect the home router as a passive radar TX source, eliminating need for a dedicated active TX node. Firmware changes: - During hello message, include ap_bssid and ap_channel from esp_wifi_sta_get_ap_info() Mothership changes: - On hello: extract ap_bssid; if >=80% of nodes report same BSSID create virtual node entry with virtual=1 - OUI lookup: embedded IEEE OUI registry as Go map compiled via go:embed; display router brand - Detect AP BSSID change (router reboot/replacement) and emit system alert - SQLite nodes table: add virtual BOOL, node_type TEXT, ap_bssid TEXT, ap_channel INT columns Dashboard changes: - Show "I detected your router (ASUS). Place it on the floor plan..." notification - Render virtual AP nodes with distinct router icon in 3D view - Drag-to-place virtual node (distinct router icon) in 3D editor Co-Authored-By: Claude Opus 4.6 --- dashboard/css/apdetection.css | 211 +++++++++++++ dashboard/index.html | 1 + dashboard/js/apdetection.js | 243 +++++++++++++++ dashboard/js/viz3d.js | 69 ++++- firmware/main/websocket.c | 9 + firmware/main/wifi.c | 13 + firmware/main/wifi.h | 7 + mothership/cmd/mothership/main.go | 9 + mothership/internal/apdetector/detector.go | 329 +++++++++++++++++++++ mothership/internal/db/migrations.go | 18 ++ mothership/internal/ingestion/server.go | 24 ++ mothership/internal/oui/gen.go | 19 ++ mothership/internal/oui/gen_data.go | 109 +++++++ mothership/internal/oui/oui_data.go | 200 +++++++++++++ 14 files changed, 1256 insertions(+), 5 deletions(-) create mode 100644 dashboard/css/apdetection.css create mode 100644 dashboard/js/apdetection.js create mode 100644 mothership/internal/apdetector/detector.go create mode 100644 mothership/internal/oui/gen.go create mode 100644 mothership/internal/oui/gen_data.go create mode 100644 mothership/internal/oui/oui_data.go diff --git a/dashboard/css/apdetection.css b/dashboard/css/apdetection.css new file mode 100644 index 0000000..bfdb287 --- /dev/null +++ b/dashboard/css/apdetection.css @@ -0,0 +1,211 @@ +/** + * Spaxel Dashboard - AP Detection Panel Styles + * + * Styles for the router AP detection banner and placement UI. + */ + +/* ============================================ + AP Detection Banner + ============================================ */ + +.ap-detection-banner { + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 1000; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3); + transform: translateY(-100%); + transition: transform 0.3s ease-out; +} + +.ap-detection-banner-visible { + transform: translateY(0); +} + +.ap-detection-content { + display: flex; + align-items: center; + padding: 16px 24px; + max-width: 800px; + margin: 0 auto; + color: white; +} + +.ap-detection-icon { + font-size: 28px; + margin-right: 16px; + animation: pulse 2s ease-in-out infinite; +} + +@keyframes pulse { + 0%, 100% { + transform: scale(1); + opacity: 1; + } + 50% { + transform: scale(1.1); + opacity: 0.8; + } +} + +.ap-detection-message { + flex: 1; +} + +.ap-detection-title { + font-size: 18px; + font-weight: 600; + margin-bottom: 4px; +} + +.ap-detection-subtitle { + font-size: 14px; + opacity: 0.9; +} + +.ap-detection-actions { + display: flex; + gap: 12px; + margin-left: 16px; +} + +/* ============================================ + AP Placement Content + ============================================ */ + +.ap-placement-content { + padding: 16px 0; +} + +.ap-placement-list { + list-style: none; + padding: 0; + margin: 16px 0; +} + +.ap-placement-list li { + padding: 8px 0; + padding-left: 24px; + position: relative; +} + +.ap-placement-list li:before { + content: "•"; + position: absolute; + left: 0; + color: #667eea; + font-weight: bold; +} + +.ap-placement-tips { + margin-top: 20px; +} + +.ap-placement-tip { + background: #f0f4ff; + border-left: 4px solid #667eea; + padding: 12px; + border-radius: 4px; + font-size: 14px; + color: #444; +} + +/* ============================================ + Responsive Design + ============================================ */ + +@media (max-width: 768px) { + .ap-detection-content { + flex-direction: column; + text-align: center; + } + + .ap-detection-icon { + margin-right: 0; + margin-bottom: 12px; + } + + .ap-detection-actions { + margin-left: 0; + margin-top: 16px; + width: 100%; + } + + .ap-detection-actions button { + flex: 1; + } + + .ap-placement-list li { + padding-left: 0; + } + + .ap-placement-list li:before { + display: none; + } +} + +/* ============================================ + Button Styles + ============================================ */ + +.ap-btn { + padding: 10px 20px; + border: none; + border-radius: 6px; + font-size: 14px; + font-weight: 500; + cursor: pointer; + transition: all 0.2s ease; +} + +.ap-btn-primary { + background: white; + color: #667eea; +} + +.ap-btn-primary:hover { + background: #f0f0f0; + transform: translateY(-1px); + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); +} + +.ap-btn-secondary { + background: rgba(255, 255, 255, 0.2); + color: white; + border: 1px solid rgba(255, 255, 255, 0.3); +} + +.ap-btn-secondary:hover { + background: rgba(255, 255, 255, 0.3); +} + +.ap-btn:active { + transform: translateY(0); +} + +/* ============================================ + 3D View Router Icon + ============================================ */ + +/* Distinct router icon for virtual AP nodes in 3D view */ +.virtual-node-router { + fill: #667eea; + stroke: #764ba2; + stroke-width: 1; +} + +.virtual-node-router-glow { + opacity: 0.5; + animation: glow-pulse 2s ease-in-out infinite; +} + +@keyframes glow-pulse { + 0%, 100% { + opacity: 0.3; + } + 50% { + opacity: 0.6; + } +} diff --git a/dashboard/index.html b/dashboard/index.html index 946a31a..2e9a3f3 100644 --- a/dashboard/index.html +++ b/dashboard/index.html @@ -7,6 +7,7 @@ +