Compare commits

...

1 Commits

Author SHA1 Message Date
Smittix 9ec316fbe2 fix(bt-locate): stabilize first-load map and release v2.21.1 2026-02-20 00:49:08 +00:00
5 changed files with 107 additions and 18 deletions
+9
View File
@@ -2,6 +2,15 @@
All notable changes to iNTERCEPT will be documented in this file. All notable changes to iNTERCEPT will be documented in this file.
## [2.21.1] - 2026-02-20
### Fixed
- BT Locate map first-load rendering race that could cause blank/late map initialization
- BT Locate mode switch timing so Leaflet invalidation runs after panel visibility settles
- BT Locate trail restore startup latency by batching historical GPS point rendering
---
## [2.21.0] - 2026-02-20 ## [2.21.0] - 2026-02-20
### Added ### Added
+10 -1
View File
@@ -7,10 +7,19 @@ import os
import sys import sys
# Application version # Application version
VERSION = "2.21.0" VERSION = "2.21.1"
# Changelog - latest release notes (shown on welcome screen) # Changelog - latest release notes (shown on welcome screen)
CHANGELOG = [ CHANGELOG = [
{
"version": "2.21.1",
"date": "February 2026",
"highlights": [
"BT Locate map first-load fix with render stabilization retries during initial mode open",
"BT Locate trail restore optimization for faster startup when historical GPS points exist",
"BT Locate mode-switch map invalidation timing fix to prevent delayed/blank map render",
]
},
{ {
"version": "2.21.0", "version": "2.21.0",
"date": "February 2026", "date": "February 2026",
+1 -1
View File
@@ -1,6 +1,6 @@
[project] [project]
name = "intercept" name = "intercept"
version = "2.21.0" version = "2.21.1"
description = "Signal Intelligence Platform - Pager/433MHz/ADS-B/Satellite/WiFi/Bluetooth" description = "Signal Intelligence Platform - Pager/433MHz/ADS-B/Satellite/WiFi/Bluetooth"
readme = "README.md" readme = "README.md"
requires-python = ">=3.9" requires-python = ">=3.9"
+71 -6
View File
@@ -37,6 +37,7 @@ const BtLocate = (function() {
let smoothingEnabled = true; let smoothingEnabled = true;
let lastRenderedDetectionKey = null; let lastRenderedDetectionKey = null;
let pendingHeatSync = false; let pendingHeatSync = false;
let mapStabilizeTimer = null;
const MAX_HEAT_POINTS = 1200; const MAX_HEAT_POINTS = 1200;
const MAX_TRAIL_POINTS = 1200; const MAX_TRAIL_POINTS = 1200;
@@ -44,6 +45,8 @@ const BtLocate = (function() {
const OUTLIER_HARD_JUMP_METERS = 2000; const OUTLIER_HARD_JUMP_METERS = 2000;
const OUTLIER_SOFT_JUMP_METERS = 450; const OUTLIER_SOFT_JUMP_METERS = 450;
const OUTLIER_MAX_SPEED_MPS = 50; const OUTLIER_MAX_SPEED_MPS = 50;
const MAP_STABILIZE_INTERVAL_MS = 150;
const MAP_STABILIZE_ATTEMPTS = 28;
const OVERLAY_STORAGE_KEYS = { const OVERLAY_STORAGE_KEYS = {
heatmap: 'btLocateHeatmapEnabled', heatmap: 'btLocateHeatmapEnabled',
movement: 'btLocateMovementEnabled', movement: 'btLocateMovementEnabled',
@@ -99,6 +102,7 @@ const BtLocate = (function() {
Settings.createTileLayer().addTo(map); Settings.createTileLayer().addTo(map);
} }
flushPendingHeatSync(); flushPendingHeatSync();
scheduleMapStabilization(10);
}, 150); }, 150);
} }
checkStatus(); checkStatus();
@@ -113,15 +117,23 @@ const BtLocate = (function() {
zoom: 2, zoom: 2,
zoomControl: true, zoomControl: true,
}); });
let tileLayer = null;
// Use tile provider from user settings // Use tile provider from user settings
if (typeof Settings !== 'undefined' && Settings.createTileLayer) { if (typeof Settings !== 'undefined' && Settings.createTileLayer) {
Settings.createTileLayer().addTo(map); tileLayer = Settings.createTileLayer();
tileLayer.addTo(map);
Settings.registerMap(map); Settings.registerMap(map);
} else { } else {
L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', { tileLayer = L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', {
maxZoom: 19, maxZoom: 19,
attribution: '© OSM © CARTO' attribution: '© OSM © CARTO'
}).addTo(map); });
tileLayer.addTo(map);
}
if (tileLayer && typeof tileLayer.on === 'function') {
tileLayer.on('load', () => {
scheduleMapStabilization(8);
});
} }
ensureHeatLayer(); ensureHeatLayer();
syncMovementLayer(); syncMovementLayer();
@@ -133,6 +145,7 @@ const BtLocate = (function() {
safeInvalidateMap(); safeInvalidateMap();
flushPendingHeatSync(); flushPendingHeatSync();
}, 100); }, 100);
scheduleMapStabilization();
} }
// Init RSSI chart canvas // Init RSSI chart canvas
@@ -524,6 +537,8 @@ const BtLocate = (function() {
const lon = Number(point.lon); const lon = Number(point.lon);
if (!isFinite(lat) || !isFinite(lon)) return false; if (!isFinite(lat) || !isFinite(lon)) return false;
if (!shouldAcceptMapPoint(point, lat, lon)) return false; if (!shouldAcceptMapPoint(point, lat, lon)) return false;
const suppressFollow = options.suppressFollow === true;
const bulkLoad = options.bulkLoad === true;
const trailPoint = normalizeTrailPoint(point, lat, lon); const trailPoint = normalizeTrailPoint(point, lat, lon);
const band = (trailPoint.proximity_band || 'FAR').toLowerCase(); const band = (trailPoint.proximity_band || 'FAR').toLowerCase();
@@ -563,13 +578,17 @@ const BtLocate = (function() {
if (heatPoints.length > MAX_HEAT_POINTS) { if (heatPoints.length > MAX_HEAT_POINTS) {
heatPoints.splice(0, heatPoints.length - MAX_HEAT_POINTS); heatPoints.splice(0, heatPoints.length - MAX_HEAT_POINTS);
} }
if (bulkLoad) {
pendingHeatSync = true;
return true;
}
syncHeatLayer(); syncHeatLayer();
if (!isMapRenderable()) { if (!isMapRenderable()) {
safeInvalidateMap(); safeInvalidateMap();
} }
const canFollowMap = isMapRenderable(); const canFollowMap = isMapRenderable();
if (autoFollowEnabled && !options.suppressFollow && canFollowMap) { if (autoFollowEnabled && !suppressFollow && canFollowMap) {
if (!gpsLocked) { if (!gpsLocked) {
gpsLocked = true; gpsLocked = true;
map.setView([lat, lon], Math.max(map.getZoom(), 16)); map.setView([lat, lon], Math.max(map.getZoom(), 16));
@@ -645,8 +664,13 @@ const BtLocate = (function() {
const gpsTrail = Array.isArray(trail.gps_trail) ? trail.gps_trail : []; const gpsTrail = Array.isArray(trail.gps_trail) ? trail.gps_trail : [];
const allTrail = Array.isArray(trail.trail) ? trail.trail : []; const allTrail = Array.isArray(trail.trail) ? trail.trail : [];
const recentGpsTrail = gpsTrail.slice(-MAX_TRAIL_POINTS);
gpsTrail.forEach(p => addMapMarker(p, { suppressFollow: true })); recentGpsTrail.forEach(p => addMapMarker(p, {
suppressFollow: true,
bulkLoad: true,
}));
syncHeatLayer();
if (allTrail.length > 0) { if (allTrail.length > 0) {
rssiHistory = allTrail.map(p => p.rssi).filter(v => typeof v === 'number' && isFinite(v)).slice(-MAX_RSSI_POINTS); rssiHistory = allTrail.map(p => p.rssi).filter(v => typeof v === 'number' && isFinite(v)).slice(-MAX_RSSI_POINTS);
@@ -659,7 +683,7 @@ const BtLocate = (function() {
drawRssiChart(); drawRssiChart();
} }
updateStats(allTrail.length, gpsTrail.length); updateStats(allTrail.length, recentGpsTrail.length);
if (trailPoints.length > 0 && map) { if (trailPoints.length > 0 && map) {
const latestGps = trailPoints[trailPoints.length - 1]; const latestGps = trailPoints[trailPoints.length - 1];
@@ -675,6 +699,7 @@ const BtLocate = (function() {
syncStrongestMarker(); syncStrongestMarker();
updateConfidenceLayer(); updateConfidenceLayer();
updateMovementStats(); updateMovementStats();
scheduleMapStabilization(12);
}) })
.catch(() => {}); .catch(() => {});
} }
@@ -908,6 +933,45 @@ const BtLocate = (function() {
return true; return true;
} }
function stopMapStabilization() {
if (mapStabilizeTimer) {
clearInterval(mapStabilizeTimer);
mapStabilizeTimer = null;
}
}
function scheduleMapStabilization(attempts = MAP_STABILIZE_ATTEMPTS) {
if (!map) return;
stopMapStabilization();
let remaining = Math.max(1, Number(attempts) || MAP_STABILIZE_ATTEMPTS);
const tick = () => {
if (!map) {
stopMapStabilization();
return;
}
if (safeInvalidateMap()) {
flushPendingHeatSync();
syncMovementLayer();
syncStrongestMarker();
updateConfidenceLayer();
if (isMapRenderable()) {
stopMapStabilization();
return;
}
}
remaining -= 1;
if (remaining <= 0) {
stopMapStabilization();
}
};
tick();
if (map && !mapStabilizeTimer && !isMapRenderable()) {
mapStabilizeTimer = setInterval(tick, MAP_STABILIZE_INTERVAL_MS);
}
}
function flushPendingHeatSync() { function flushPendingHeatSync() {
if (!pendingHeatSync) return; if (!pendingHeatSync) return;
syncHeatLayer(); syncHeatLayer();
@@ -1566,6 +1630,7 @@ const BtLocate = (function() {
syncStrongestMarker(); syncStrongestMarker();
updateConfidenceLayer(); updateConfidenceLayer();
} }
scheduleMapStabilization(8);
} }
return { return {
+6
View File
@@ -4242,6 +4242,12 @@
SubGhz.init(); SubGhz.init();
} else if (mode === 'bt_locate') { } else if (mode === 'bt_locate') {
BtLocate.init(); BtLocate.init();
setTimeout(() => {
if (typeof BtLocate !== 'undefined' && BtLocate.invalidateMap) BtLocate.invalidateMap();
}, 100);
setTimeout(() => {
if (typeof BtLocate !== 'undefined' && BtLocate.invalidateMap) BtLocate.invalidateMap();
}, 320);
} else if (mode === 'spaceweather') { } else if (mode === 'spaceweather') {
SpaceWeather.init(); SpaceWeather.init();
} }