Fix dashboard startup regressions and mode utilities

This commit is contained in:
James Smith
2026-03-19 10:37:21 +00:00
parent 5f34d20287
commit 18b442eb21
15 changed files with 283 additions and 96 deletions

View File

@@ -17,9 +17,10 @@ const CheatSheets = (function () {
sstv: { title: 'ISS SSTV', icon: '🖼️', hardware: 'RTL-SDR + 145MHz antenna', description: 'Receives ISS SSTV images via slowrx.', whatToExpect: 'Color images during ISS SSTV events (PD180 mode).', tips: ['ISS SSTV: 145.800 MHz', 'Check ARISS for active event dates', 'ISS must be overhead — check pass times'] },
weathersat: { title: 'Weather Satellites', icon: '🌤️', hardware: 'RTL-SDR + 137MHz turnstile/QFH antenna', description: 'Decodes NOAA APT and Meteor LRPT weather imagery via SatDump.', whatToExpect: 'Infrared/visible cloud imagery.', tips: ['NOAA 15/18/19: 137.1137.9 MHz APT', 'Meteor M2-3: 137.9 MHz LRPT', 'Use circular polarized antenna (QFH or turnstile)'] },
sstv_general:{ title: 'HF SSTV', icon: '📷', hardware: 'RTL-SDR + HF upconverter', description: 'Receives HF SSTV transmissions.', whatToExpect: 'Amateur radio images on 14.230 MHz (USB mode).', tips: ['14.230 MHz USB is primary HF SSTV frequency', 'Scottie 1 and Martin 1 most common', 'Best during daylight hours'] },
gps: { title: 'GPS Receiver', icon: '🗺️', hardware: 'USB GPS receiver (NMEA)', description: 'Streams GPS position and feeds location to other modes.', whatToExpect: 'Lat/lon, altitude, speed, heading, satellite count.', tips: ['BT Locate uses GPS for trail logging', 'Set observer location for satellite prediction', 'Verify a 3D fix before relying on altitude'] },
spaceweather:{ title: 'Space Weather', icon: '☀️', hardware: 'None (NOAA/SpaceWeatherLive data)', description: 'Monitors solar activity and geomagnetic storm indices.', whatToExpect: 'Kp index, solar flux, X-ray flare alerts, CME tracking.', tips: ['High Kp (≥5) = geomagnetic storm', 'X-class flares cause HF radio blackouts', 'Check before HF or satellite operations'] },
tscm: { title: 'TSCM Counter-Surveillance', icon: '🔍', hardware: 'WiFi + Bluetooth adapters', description: 'Technical Surveillance Countermeasures — detects hidden devices.', whatToExpect: 'RF baseline comparison, rogue device alerts, tracker detection.', tips: ['Take baseline in a known-clean environment', 'New strong signals = potential bug', 'Correlate WiFi + Bluetooth observations'] },
gps: { title: 'GPS Receiver', icon: '🗺️', hardware: 'USB GPS receiver (NMEA)', description: 'Streams GPS position and feeds location to other modes.', whatToExpect: 'Lat/lon, altitude, speed, heading, satellite count.', tips: ['BT Locate uses GPS for trail logging', 'Set observer location for satellite prediction', 'Verify a 3D fix before relying on altitude'] },
spaceweather:{ title: 'Space Weather', icon: '☀️', hardware: 'None (NOAA/SpaceWeatherLive data)', description: 'Monitors solar activity and geomagnetic storm indices.', whatToExpect: 'Kp index, solar flux, X-ray flare alerts, CME tracking.', tips: ['High Kp (≥5) = geomagnetic storm', 'X-class flares cause HF radio blackouts', 'Check before HF or satellite operations'] },
controller_monitor: { title: 'Controller Monitor', icon: '🖧', hardware: 'Optional remote agents', description: 'Aggregated controller view across connected agents and local sources.', whatToExpect: 'Combined device activity, logs, and agent health in one place.', tips: ['Use it to compare what each agent is seeing', 'Check agent status before remote starts', 'Open Manage to add or troubleshoot agents'] },
tscm: { title: 'TSCM Counter-Surveillance', icon: '🔍', hardware: 'WiFi + Bluetooth adapters', description: 'Technical Surveillance Countermeasures — detects hidden devices.', whatToExpect: 'RF baseline comparison, rogue device alerts, tracker detection.', tips: ['Take baseline in a known-clean environment', 'New strong signals = potential bug', 'Correlate WiFi + Bluetooth observations'] },
spystations: { title: 'Spy Stations', icon: '🕵️', hardware: 'RTL-SDR + HF antenna', description: 'Database of known number stations, military, and diplomatic HF signals.', whatToExpect: 'Scheduled broadcasts, frequency database, tune-to links.', tips: ['Numbers stations often broadcast on the hour', 'Use Spectrum Waterfall to tune directly', 'STANAG and HF mil signals are common'] },
websdr: { title: 'WebSDR', icon: '🌐', hardware: 'None (uses remote SDR servers)', description: 'Access remote WebSDR receivers worldwide for HF shortwave listening.', whatToExpect: 'Live audio from global HF receivers, waterfall display.', tips: ['websdr.org lists available servers', 'Good for HF when local antenna is lacking', 'Use in-app player for seamless experience'] },
subghz: { title: 'SubGHz Transceiver', icon: '📡', hardware: 'HackRF One', description: 'Transmit and receive sub-GHz RF signals for IoT and industrial protocols.', whatToExpect: 'Raw signal capture, replay, and protocol analysis.', tips: ['Only use on licensed frequencies', 'Capture mode records raw IQ for replay', 'Common: garage doors, keyfobs, 315/433/868/915 MHz'] },

View File

@@ -16,8 +16,13 @@ const SpaceWeather = (function () {
let _xrayChart = null;
// Current image selections
let _solarImageKey = 'sdo_193';
let _drapFreq = 'drap_global';
let _solarImageKey = 'sdo_193';
let _drapFreq = 'drap_global';
const SOLAR_IMAGE_FALLBACKS = {
sdo_193: 'https://sdo.gsfc.nasa.gov/assets/img/latest/latest_512_0193.jpg',
sdo_304: 'https://sdo.gsfc.nasa.gov/assets/img/latest/latest_512_0304.jpg',
sdo_magnetogram: 'https://sdo.gsfc.nasa.gov/assets/img/latest/latest_512_HMIBC.jpg',
};
/** Stable cache-bust key that rotates every 5 minutes (matches backend max-age). */
function _cacheBust() {
@@ -48,33 +53,35 @@ const SpaceWeather = (function () {
_fetchData();
}
function selectSolarImage(key) {
_solarImageKey = key;
_updateSolarImageTabs();
const frame = document.getElementById('swSolarImageFrame');
if (frame) {
frame.innerHTML = '<div class="sw-loading">Loading</div>';
const img = new Image();
img.onload = function () { frame.innerHTML = ''; frame.appendChild(img); };
img.onerror = function () { frame.innerHTML = '<div class="sw-empty">Failed to load image</div>'; };
img.src = '/space-weather/image/' + key + '?' + _cacheBust();
img.alt = key;
}
}
function selectSolarImage(key) {
_solarImageKey = key;
_updateSolarImageTabs();
const frame = document.getElementById('swSolarImageFrame');
if (frame) {
frame.innerHTML = '<div class="sw-loading">Loading</div>';
_loadImageWithFallback(
frame,
['/space-weather/image/' + key + '?' + _cacheBust(), _directImageUrlForKey(key)],
key,
'<div class="sw-empty">NASA SDO image is temporarily unavailable</div>'
);
}
}
function selectDrapFreq(key) {
_drapFreq = key;
_updateDrapTabs();
const frame = document.getElementById('swDrapImageFrame');
if (frame) {
frame.innerHTML = '<div class="sw-loading">Loading</div>';
const img = new Image();
img.onload = function () { frame.innerHTML = ''; frame.appendChild(img); };
img.onerror = function () { frame.innerHTML = '<div class="sw-empty">Failed to load image</div>'; };
img.src = '/space-weather/image/' + key + '?' + _cacheBust();
img.alt = key;
}
}
function selectDrapFreq(key) {
_drapFreq = key;
_updateDrapTabs();
const frame = document.getElementById('swDrapImageFrame');
if (frame) {
frame.innerHTML = '<div class="sw-loading">Loading</div>';
_loadImageWithFallback(
frame,
['/space-weather/image/' + key + '?' + _cacheBust()],
key,
'<div class="sw-empty">Failed to load image</div>'
);
}
}
function toggleAutoRefresh() {
const cb = document.getElementById('swAutoRefresh');
@@ -94,9 +101,41 @@ const SpaceWeather = (function () {
}
}
function _stopAutoRefresh() {
if (_pollTimer) { clearInterval(_pollTimer); _pollTimer = null; }
}
function _stopAutoRefresh() {
if (_pollTimer) { clearInterval(_pollTimer); _pollTimer = null; }
}
function _directImageUrlForKey(key) {
const base = SOLAR_IMAGE_FALLBACKS[key];
if (!base) return null;
return base + '?' + _cacheBust();
}
function _loadImageWithFallback(frame, urls, alt, failureHtml) {
const candidates = (urls || []).filter(Boolean);
if (!frame || candidates.length === 0) {
if (frame) frame.innerHTML = failureHtml;
return;
}
let index = 0;
const img = new Image();
img.alt = alt;
img.referrerPolicy = 'no-referrer';
img.onload = function () {
frame.innerHTML = '';
frame.appendChild(img);
};
img.onerror = function () {
index += 1;
if (index < candidates.length) {
img.src = candidates[index];
return;
}
frame.innerHTML = failureHtml;
};
img.src = candidates[index];
}
function _fetchData() {
fetch('/space-weather/data')