From e03ba3f5ed98b2a3c7a315b96765afc5549e1f9d Mon Sep 17 00:00:00 2001 From: Smittix Date: Sun, 8 Feb 2026 21:22:23 +0000 Subject: [PATCH] Fix heatmap: add type coercion, LAC matching, debug logging, and user feedback The heatmap silently failed when: CID types mismatched (string vs number), LAC wasn't checked (wrong tower matched), or no data existed yet (button showed ON with no layer). Now coerces CID/LAC to Number for comparison, validates coordinates with parseFloat, logs match diagnostics to console, and only shows ON when the layer is actually rendered. Co-Authored-By: Claude Opus 4.6 --- templates/gsm_spy_dashboard.html | 58 ++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 14 deletions(-) diff --git a/templates/gsm_spy_dashboard.html b/templates/gsm_spy_dashboard.html index a96e72c..82e0689 100644 --- a/templates/gsm_spy_dashboard.html +++ b/templates/gsm_spy_dashboard.html @@ -3161,12 +3161,14 @@ if (heatmapVisible) { removeHeatmap(); } else { - await updateHeatmap(); - heatmapVisible = true; - const btn = document.getElementById('heatmapToggle'); - btn.textContent = 'Heatmap: ON'; - btn.style.borderColor = 'var(--accent-cyan)'; - btn.style.color = 'var(--accent-cyan)'; + const success = await updateHeatmap(); + if (success) { + heatmapVisible = true; + const btn = document.getElementById('heatmapToggle'); + btn.textContent = 'Heatmap: ON'; + btn.style.borderColor = 'var(--accent-cyan)'; + btn.style.color = 'var(--accent-cyan)'; + } } } @@ -3175,26 +3177,52 @@ const response = await fetch('/gsm_spy/crowd_density?hours=1'); const data = await response.json(); - if (!data || data.length === 0) return; + console.log('[GSM SPY] Heatmap: crowd_density returned', Array.isArray(data) ? data.length + ' items' : data); + + if (!Array.isArray(data) || data.length === 0) { + if (!heatmapVisible) { + console.warn('[GSM SPY] Heatmap: no crowd density data. Start monitoring to collect device pings.'); + } + return false; + } const points = []; let maxIntensity = 1; + let matched = 0; + let unmatched = 0; data.forEach(item => { - // Match CID to tower coordinates - const cid = item.cid; + const itemCid = Number(item.cid); + const itemLac = Number(item.lac); + let found = false; + for (const key in towers) { const t = towers[key]; - if (t.cid === cid && t.lat && t.lon) { - const intensity = item.unique_devices || 1; - if (intensity > maxIntensity) maxIntensity = intensity; - points.push([t.lat, t.lon, intensity]); + if (Number(t.cid) === itemCid && Number(t.lac) === itemLac) { + if (t.lat && t.lon && !isNaN(parseFloat(t.lat)) && !isNaN(parseFloat(t.lon))) { + const intensity = item.unique_devices || 1; + if (intensity > maxIntensity) maxIntensity = intensity; + points.push([parseFloat(t.lat), parseFloat(t.lon), intensity]); + found = true; + } else { + console.log(`[GSM SPY] Heatmap: tower CID ${itemCid} LAC ${itemLac} has no coordinates yet`); + } break; } } + + if (found) matched++; + else unmatched++; }); - if (points.length === 0) return; + console.log(`[GSM SPY] Heatmap: ${matched} matched, ${unmatched} unmatched, ${points.length} points with coords`); + + if (points.length === 0) { + if (!heatmapVisible) { + console.warn('[GSM SPY] Heatmap: density data exists but no towers have coordinates. Wait for geocoding.'); + } + return false; + } // Remove existing layer before adding new one if (heatmapLayer && gsmMap.hasLayer(heatmapLayer)) { @@ -3210,8 +3238,10 @@ }).addTo(gsmMap); heatmapLastRefresh = Date.now(); + return true; } catch (error) { console.error('[GSM SPY] Heatmap update error:', error); + return false; } }