diff --git a/templates/adsb_dashboard.html b/templates/adsb_dashboard.html
index 397c4a3..be7234a 100644
--- a/templates/adsb_dashboard.html
+++ b/templates/adsb_dashboard.html
@@ -628,33 +628,6 @@
const defaultLon = window.INTERCEPT_DEFAULT_LON || -0.1278;
return { lat: defaultLat, lon: defaultLon };
})();
- const ADSB_FETCH_TIMEOUT_MS = 8000;
- function scheduleAuxDashboardInit(fn, delay = 1200) {
- const run = () => setTimeout(fn, delay);
- if (typeof window.requestIdleCallback === 'function') {
- window.requestIdleCallback(run, { timeout: delay + 1200 });
- } else {
- run();
- }
- }
- async function fetchJsonWithTimeout(url, options = {}, timeoutMs = ADSB_FETCH_TIMEOUT_MS) {
- const controller = new AbortController();
- const timeout = setTimeout(() => controller.abort(), timeoutMs);
- try {
- const response = await fetch(url, {
- credentials: 'same-origin',
- ...options,
- signal: controller.signal,
- });
- const contentType = response.headers.get('Content-Type') || '';
- if (!contentType.includes('application/json')) {
- throw new Error(`Unexpected response from ${url}`);
- }
- return await response.json();
- } finally {
- clearTimeout(timeout);
- }
- }
let rangeRingsLayer = null;
let observerMarker = null;
@@ -1612,7 +1585,8 @@ ACARS: ${r.statistics.acarsMessages} messages`;
// ============================================
async function autoConnectGps() {
try {
- const data = await fetchJsonWithTimeout('/gps/auto-connect', { method: 'POST' });
+ const response = await fetch('/gps/auto-connect', { method: 'POST' });
+ const data = await response.json();
if (data.status === 'connected') {
gpsConnected = true;
@@ -1763,14 +1737,15 @@ ACARS: ${r.statistics.acarsMessages} messages`;
updateClock();
setInterval(updateClock, 1000);
setInterval(cleanupOldAircraft, 10000);
+ checkAdsbTools();
+ checkAircraftDatabase();
+ checkDvbDriverConflict();
+
+ // Auto-connect to gpsd if available
+ autoConnectGps();
// Sync tracking state if ADS-B already running
syncTrackingStatus();
-
- scheduleAuxDashboardInit(() => checkAdsbTools(), 500);
- scheduleAuxDashboardInit(() => checkAircraftDatabase(), 800);
- scheduleAuxDashboardInit(() => checkDvbDriverConflict(), 1100);
- scheduleAuxDashboardInit(() => autoConnectGps(), 1400);
});
// Track which device is being used for ADS-B tracking
@@ -1778,7 +1753,8 @@ ACARS: ${r.statistics.acarsMessages} messages`;
function initDeviceSelectors() {
// Populate both ADS-B and airband device selectors
- fetchJsonWithTimeout('/devices')
+ fetch('/devices')
+ .then(r => r.json())
.then(devices => {
const adsbSelect = document.getElementById('adsbDeviceSelect');
const airbandSelect = document.getElementById('airbandDeviceSelect');
@@ -2429,7 +2405,18 @@ sudo make install
}
try {
- const data = await fetchJsonWithTimeout('/adsb/session');
+ const response = await fetch('/adsb/session');
+ if (!response.ok) {
+ // No session info - only auto-start if enabled
+ if (window.INTERCEPT_ADSB_AUTO_START) {
+ console.log('[ADS-B] No session found, attempting auto-start...');
+ await tryAutoStartLocal();
+ } else {
+ console.log('[ADS-B] No session found; auto-start disabled');
+ }
+ return;
+ }
+ const data = await response.json();
if (data.tracking_active) {
// Session is running - auto-connect to stream
@@ -2492,7 +2479,10 @@ sudo make install
// Try to auto-start local ADS-B tracking if SDR is available
try {
// Check if any SDR devices are available
- const devices = await fetchJsonWithTimeout('/devices');
+ const devResponse = await fetch('/devices');
+ if (!devResponse.ok) return;
+
+ const devices = await devResponse.json();
if (!devices || devices.length === 0) {
console.log('[ADS-B] No SDR devices found - cannot auto-start');
return;
@@ -3852,9 +3842,7 @@ sudo make install
}
// Initialize airband on page load
- document.addEventListener('DOMContentLoaded', () => {
- scheduleAuxDashboardInit(initAirband, 1200);
- });
+ document.addEventListener('DOMContentLoaded', initAirband);
// ============================================
// ACARS Functions
@@ -3888,35 +3876,38 @@ sudo make install
// Initialize ACARS sidebar state and frequency checkboxes
document.addEventListener('DOMContentLoaded', () => {
- scheduleAuxDashboardInit(() => {
- const sidebar = document.getElementById('acarsSidebar');
- if (sidebar && acarsSidebarCollapsed) {
- sidebar.classList.add('collapsed');
- }
- updateAcarsFreqCheckboxes();
+ const sidebar = document.getElementById('acarsSidebar');
+ if (sidebar && acarsSidebarCollapsed) {
+ sidebar.classList.add('collapsed');
+ }
+ updateAcarsFreqCheckboxes();
- fetchJsonWithTimeout('/acars/status')
- .then(data => {
- if (data.running) {
- isAcarsRunning = true;
- acarsMessageCount = data.message_count || 0;
- document.getElementById('acarsCount').textContent = acarsMessageCount;
- document.getElementById('acarsToggleBtn').textContent = '■ STOP ACARS';
- document.getElementById('acarsToggleBtn').classList.add('active');
- document.getElementById('acarsPanelIndicator').classList.add('active');
- startAcarsStream(false);
- fetchJsonWithTimeout('/acars/messages?limit=50')
- .then(msgs => {
- if (!msgs || !msgs.length) return;
- for (let i = msgs.length - 1; i >= 0; i--) {
- addAcarsMessage(msgs[i]);
- }
- })
- .catch(() => {});
- }
- })
- .catch(() => {});
- }, 1600);
+ // Check if ACARS is already running (e.g. after page reload)
+ fetch('/acars/status')
+ .then(r => r.json())
+ .then(data => {
+ if (data.running) {
+ isAcarsRunning = true;
+ acarsMessageCount = data.message_count || 0;
+ document.getElementById('acarsCount').textContent = acarsMessageCount;
+ document.getElementById('acarsToggleBtn').textContent = '■ STOP ACARS';
+ document.getElementById('acarsToggleBtn').classList.add('active');
+ document.getElementById('acarsPanelIndicator').classList.add('active');
+ startAcarsStream(false);
+ // Reload message history from backend
+ fetch('/acars/messages?limit=50')
+ .then(r => r.json())
+ .then(msgs => {
+ if (!msgs || !msgs.length) return;
+ // Add oldest first so newest ends up on top
+ for (let i = msgs.length - 1; i >= 0; i--) {
+ addAcarsMessage(msgs[i]);
+ }
+ })
+ .catch(() => {});
+ }
+ })
+ .catch(() => {});
});
function updateAcarsFreqCheckboxes() {
@@ -4306,28 +4297,26 @@ sudo make install
// Populate ACARS device selector
document.addEventListener('DOMContentLoaded', () => {
- scheduleAuxDashboardInit(() => {
- fetchJsonWithTimeout('/devices')
- .then(devices => {
- const select = document.getElementById('acarsDeviceSelect');
- select.innerHTML = '';
- if (devices.length === 0) {
- select.innerHTML = '';
- } else {
- devices.forEach((d, i) => {
- const opt = document.createElement('option');
- const sdrType = d.sdr_type || 'rtlsdr';
- const idx = d.index !== undefined ? d.index : i;
- opt.value = `${sdrType}:${idx}`;
- opt.dataset.sdrType = sdrType;
- opt.dataset.index = idx;
- opt.textContent = `SDR ${idx}: ${d.name || d.type || 'SDR'}`;
- select.appendChild(opt);
- });
- }
- })
- .catch(() => {});
- }, 1800);
+ fetch('/devices')
+ .then(r => r.json())
+ .then(devices => {
+ const select = document.getElementById('acarsDeviceSelect');
+ select.innerHTML = '';
+ if (devices.length === 0) {
+ select.innerHTML = '';
+ } else {
+ devices.forEach((d, i) => {
+ const opt = document.createElement('option');
+ const sdrType = d.sdr_type || 'rtlsdr';
+ const idx = d.index !== undefined ? d.index : i;
+ opt.value = `${sdrType}:${idx}`;
+ opt.dataset.sdrType = sdrType;
+ opt.dataset.index = idx;
+ opt.textContent = `SDR ${idx}: ${d.name || d.type || 'SDR'}`;
+ select.appendChild(opt);
+ });
+ }
+ });
});
// ============================================
@@ -4368,13 +4357,11 @@ sudo make install
}
document.addEventListener('DOMContentLoaded', () => {
- scheduleAuxDashboardInit(() => {
- const sidebar = document.getElementById('vdl2Sidebar');
- if (sidebar && vdl2SidebarCollapsed) {
- sidebar.classList.add('collapsed');
- }
- updateVdl2FreqCheckboxes();
- }, 1800);
+ const sidebar = document.getElementById('vdl2Sidebar');
+ if (sidebar && vdl2SidebarCollapsed) {
+ sidebar.classList.add('collapsed');
+ }
+ updateVdl2FreqCheckboxes();
});
function updateVdl2FreqCheckboxes() {
@@ -4859,50 +4846,52 @@ sudo make install
// Populate VDL2 device selector and check running status
document.addEventListener('DOMContentLoaded', () => {
- scheduleAuxDashboardInit(() => {
- fetchJsonWithTimeout('/devices')
- .then(devices => {
- const select = document.getElementById('vdl2DeviceSelect');
- select.innerHTML = '';
- if (devices.length === 0) {
- select.innerHTML = '';
- } else {
- devices.forEach((d, i) => {
- const opt = document.createElement('option');
- const sdrType = d.sdr_type || 'rtlsdr';
- const idx = d.index !== undefined ? d.index : i;
- opt.value = `${sdrType}:${idx}`;
- opt.dataset.sdrType = sdrType;
- opt.dataset.index = idx;
- opt.textContent = `SDR ${idx}: ${d.name || d.type || 'SDR'}`;
- select.appendChild(opt);
- });
- }
- })
- .catch(() => {});
+ fetch('/devices')
+ .then(r => r.json())
+ .then(devices => {
+ const select = document.getElementById('vdl2DeviceSelect');
+ select.innerHTML = '';
+ if (devices.length === 0) {
+ select.innerHTML = '';
+ } else {
+ devices.forEach((d, i) => {
+ const opt = document.createElement('option');
+ const sdrType = d.sdr_type || 'rtlsdr';
+ const idx = d.index !== undefined ? d.index : i;
+ opt.value = `${sdrType}:${idx}`;
+ opt.dataset.sdrType = sdrType;
+ opt.dataset.index = idx;
+ opt.textContent = `SDR ${idx}: ${d.name || d.type || 'SDR'}`;
+ select.appendChild(opt);
+ });
+ }
+ });
- fetchJsonWithTimeout('/vdl2/status')
- .then(data => {
- if (data.running) {
- isVdl2Running = true;
- vdl2MessageCount = data.message_count || 0;
- document.getElementById('vdl2Count').textContent = vdl2MessageCount;
- document.getElementById('vdl2ToggleBtn').innerHTML = '■ STOP VDL2';
- document.getElementById('vdl2ToggleBtn').classList.add('active');
- document.getElementById('vdl2PanelIndicator').classList.add('active');
- startVdl2Stream(false);
- fetchJsonWithTimeout('/vdl2/messages?limit=50')
- .then(msgs => {
- if (!msgs || !msgs.length) return;
- for (let i = msgs.length - 1; i >= 0; i--) {
- addVdl2Message(msgs[i]);
- }
- })
- .catch(() => {});
- }
- })
- .catch(() => {});
- }, 2000);
+ // Check if VDL2 is already running (e.g. after page reload)
+ fetch('/vdl2/status')
+ .then(r => r.json())
+ .then(data => {
+ if (data.running) {
+ isVdl2Running = true;
+ vdl2MessageCount = data.message_count || 0;
+ document.getElementById('vdl2Count').textContent = vdl2MessageCount;
+ document.getElementById('vdl2ToggleBtn').innerHTML = '■ STOP VDL2';
+ document.getElementById('vdl2ToggleBtn').classList.add('active');
+ document.getElementById('vdl2PanelIndicator').classList.add('active');
+ startVdl2Stream(false);
+ // Reload message history from backend
+ fetch('/vdl2/messages?limit=50')
+ .then(r => r.json())
+ .then(msgs => {
+ if (!msgs || !msgs.length) return;
+ for (let i = msgs.length - 1; i >= 0; i--) {
+ addVdl2Message(msgs[i]);
+ }
+ })
+ .catch(() => {});
+ }
+ })
+ .catch(() => {});
});
// ============================================
diff --git a/templates/satellite_dashboard.html b/templates/satellite_dashboard.html
index 7ccdb2e..31d008c 100644
--- a/templates/satellite_dashboard.html
+++ b/templates/satellite_dashboard.html
@@ -603,7 +603,6 @@
let _telemetryPollTimer = null;
let _passRequestId = 0;
const DASHBOARD_FETCH_TIMEOUT_MS = 10000;
- const DASHBOARD_AUX_INIT_DELAY_MS = 1200;
const BUILTIN_TX_FALLBACK = {
25544: [
{ description: 'APRS digipeater', downlink_low: 145.825, downlink_high: 145.825, uplink_low: null, uplink_high: null, mode: 'FM AX.25', baud: 1200, status: 'active', type: 'beacon', service: 'Packet' },
@@ -625,34 +624,6 @@
const satColors = ['#00ffff', '#9370DB', '#ff00ff', '#00ff00', '#ff6600', '#ffff00', '#ff69b4', '#7b68ee'];
- async function fetchJsonWithTimeout(url, options = {}, timeoutMs = DASHBOARD_FETCH_TIMEOUT_MS) {
- const controller = new AbortController();
- const timeout = setTimeout(() => controller.abort(), timeoutMs);
- try {
- const response = await fetch(url, {
- credentials: 'same-origin',
- ...options,
- signal: controller.signal,
- });
- const contentType = response.headers.get('Content-Type') || '';
- if (!contentType.includes('application/json')) {
- throw new Error(`Unexpected response from ${url}`);
- }
- return await response.json();
- } finally {
- clearTimeout(timeout);
- }
- }
-
- function scheduleAuxInit(fn, delay = DASHBOARD_AUX_INIT_DELAY_MS) {
- const run = () => setTimeout(fn, delay);
- if (typeof window.requestIdleCallback === 'function') {
- window.requestIdleCallback(run, { timeout: delay + 1000 });
- } else {
- run();
- }
- }
-
function loadDashboardSatellites() {
const btn = document.getElementById('satRefreshBtn');
if (btn) {
@@ -660,7 +631,8 @@
void btn.offsetWidth; // force reflow to restart animation
btn.classList.add('spinning');
}
- fetchJsonWithTimeout('/satellite/tracked?enabled=true')
+ fetch('/satellite/tracked?enabled=true', { credentials: 'same-origin' })
+ .then(r => r.json())
.then(data => {
const prevSelected = selectedSatellite;
const newSats = {
@@ -954,20 +926,18 @@
startSSETracking();
}
startTelemetryPolling();
+ loadAgents();
loadTransmitters(selectedSatellite);
fetchCurrentTelemetry();
if (!usedShared) {
getLocation();
}
- scheduleAuxInit(() => {
- loadAgents();
- if (window.gsInit) window.gsInit();
- });
});
async function loadAgents() {
try {
- const data = await fetchJsonWithTimeout('/controller/agents');
+ const response = await fetch('/controller/agents');
+ const data = await response.json();
if (data.status === 'success' && data.agents) {
agents = data.agents;
populateLocationSelector();
@@ -1848,14 +1818,14 @@
gsLoadRecordings();
gsConnectSSE();
}
- window.gsInit = gsInit;
// -----------------------------------------------------------------------
// Scheduler status
// -----------------------------------------------------------------------
function gsLoadStatus() {
- fetchJsonWithTimeout('/ground_station/scheduler/status')
+ fetch('/ground_station/scheduler/status')
+ .then(r => r.json())
.then(data => { _gsEnabled = data.enabled; _applyStatus(data); })
.catch(() => {});
}
@@ -1895,7 +1865,8 @@
// -----------------------------------------------------------------------
function gsLoadProfiles() {
- fetchJsonWithTimeout('/ground_station/profiles')
+ fetch('/ground_station/profiles')
+ .then(r => r.json())
.then(profiles => _renderProfiles(profiles))
.catch(() => { _renderProfiles([]); });
}
@@ -2369,7 +2340,12 @@
return String(s).replace(/&/g,'&').replace(//g,'>');
}
- // Init is scheduled by the main dashboard boot once the primary UI is live.
+ // Init after DOM is ready
+ if (document.readyState === 'loading') {
+ document.addEventListener('DOMContentLoaded', gsInit);
+ } else {
+ gsInit();
+ }
})();