Add alerts/recording, WiFi/TSCM updates, optimize waterfall

This commit is contained in:
Smittix
2026-02-07 18:29:58 +00:00
parent 4bbc00b765
commit 86e4ba7e29
42 changed files with 2514 additions and 485 deletions
+61 -6
View File
@@ -806,7 +806,8 @@
<div class="bt-detail-services" id="btDetailServices" style="display: none;">
<span class="bt-detail-services-list" id="btDetailServicesList"></span>
</div>
<button class="bt-detail-btn" onclick="BluetoothMode.copyAddress()">Copy</button>
<button class="bt-detail-btn" id="btDetailWatchBtn" onclick="BluetoothMode.toggleWatchlist()">Watchlist</button>
<button class="bt-detail-btn" id="btDetailCopyBtn" onclick="BluetoothMode.copyAddress()">Copy</button>
</div>
</div>
</div>
@@ -6058,11 +6059,44 @@
: 'Monitor mode: <span style="color: var(--accent-red);">Inactive</span>';
}
function getWifiChannelPresetList(preset) {
switch (preset) {
case '2.4-common':
return '1,6,11';
case '2.4-all':
return '1,2,3,4,5,6,7,8,9,10,11,12,13';
case '5-low':
return '36,40,44,48';
case '5-mid':
return '52,56,60,64';
case '5-high':
return '149,153,157,161,165';
default:
return '';
}
}
function buildWifiChannelConfig() {
const preset = document.getElementById('wifiChannelPreset')?.value || '';
const listInput = document.getElementById('wifiChannelList')?.value || '';
const singleInput = document.getElementById('wifiChannel')?.value || '';
const listValue = listInput.trim();
const presetValue = getWifiChannelPresetList(preset);
const channels = listValue || presetValue || '';
const channel = channels ? null : (singleInput.trim() ? parseInt(singleInput.trim()) : null);
return {
channels: channels || null,
channel: Number.isFinite(channel) ? channel : null,
};
}
// Start WiFi scan - auto-enables monitor mode if needed
async function startWifiScan() {
console.log('startWifiScan called');
const band = document.getElementById('wifiBand').value;
const channel = document.getElementById('wifiChannel').value;
const channelConfig = buildWifiChannelConfig();
// Auto-enable monitor mode if not already enabled
if (!monitorInterface) {
@@ -6124,7 +6158,8 @@
body: JSON.stringify({
interface: monitorInterface,
band: band,
channel: channel || null
channel: channelConfig.channel,
channels: channelConfig.channels,
})
});
const scanData = await scanResp.json();
@@ -6821,7 +6856,7 @@
if (data.handshake_found) {
// Handshake captured!
statusSpan.textContent = '✓ HANDSHAKE CAPTURED!';
statusSpan.textContent = '✓ VALID HANDSHAKE CAPTURED!';
statusSpan.style.color = 'var(--accent-green)';
handshakeCount++;
document.getElementById('handshakeCount').textContent = handshakeCount;
@@ -6854,7 +6889,11 @@
activeCapture.capturedFile = data.file;
} else if (data.file_exists) {
const sizeKB = (data.file_size / 1024).toFixed(1);
statusSpan.textContent = 'Capturing... (' + sizeKB + ' KB, ' + elapsedStr + ')';
let extra = '';
if (data.handshake_checked && data.handshake_valid === false) {
extra = data.handshake_reason ? ' • ' + data.handshake_reason : ' • No valid handshake yet';
}
statusSpan.textContent = 'Capturing... (' + sizeKB + ' KB, ' + elapsedStr + ')' + extra;
statusSpan.style.color = 'var(--accent-orange)';
} else if (data.status === 'stopped') {
statusSpan.textContent = 'Capture stopped';
@@ -10905,6 +10944,13 @@
if (client.score >= 3) {
addHighInterestDevice(client, 'wifi');
}
if (isRecordingBaseline) {
fetch('/tscm/feed/wifi', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(client)
}).catch(e => console.error('Baseline feed error:', e));
}
}
}
@@ -12331,6 +12377,11 @@
const id = item.bssid || item.mac || '';
return `${escapeHtml(name)} ${id ? `<span class="device-detail-id">${escapeHtml(id)}</span>` : ''}`;
}
if (protocol === 'wifi_clients') {
const name = item.vendor || 'WiFi Client';
const id = item.mac || item.address || '';
return `${escapeHtml(name)} ${id ? `<span class="device-detail-id">${escapeHtml(id)}</span>` : ''}`;
}
if (protocol === 'bluetooth') {
const name = item.name || 'Unknown';
const id = item.mac || item.address || '';
@@ -12357,6 +12408,7 @@
const sections = [
{ key: 'wifi', label: 'WiFi' },
{ key: 'wifi_clients', label: 'WiFi Clients' },
{ key: 'bluetooth', label: 'Bluetooth' },
{ key: 'rf', label: 'RF' },
];
@@ -12759,7 +12811,7 @@
if (data.status === 'success') {
document.getElementById('tscmBaselineStatus').textContent =
`Baseline saved: ${data.wifi_count} WiFi, ${data.bt_count} BT, ${data.rf_count} RF`;
`Baseline saved: ${data.wifi_count} WiFi, ${data.wifi_client_count || 0} Clients, ${data.bt_count} BT, ${data.rf_count} RF`;
document.getElementById('tscmBaselineStatus').style.color = '#00ff88';
loadTscmBaselines();
} else {
@@ -14574,6 +14626,9 @@
<script src="{{ url_for('static', filename='js/core/updater.js') }}"></script>
<!-- Settings Manager -->
<script src="{{ url_for('static', filename='js/core/settings-manager.js') }}"></script>
<!-- Alerts + Recording -->
<script src="{{ url_for('static', filename='js/core/alerts.js') }}"></script>
<script src="{{ url_for('static', filename='js/core/recordings.js') }}"></script>
</body>
</html>
+16 -1
View File
@@ -69,7 +69,22 @@
</select>
</div>
<div class="form-group">
<label>Channel (empty = hop)</label>
<label>Channel Preset</label>
<select id="wifiChannelPreset">
<option value="">Auto hop (all)</option>
<option value="2.4-common">2.4 GHz Common (1,6,11)</option>
<option value="2.4-all">2.4 GHz All (1-13)</option>
<option value="5-low">5 GHz Low (36-48)</option>
<option value="5-mid">5 GHz Mid/DFS (52-64)</option>
<option value="5-high">5 GHz High (149-165)</option>
</select>
</div>
<div class="form-group">
<label>Channel List (overrides preset)</label>
<input type="text" id="wifiChannelList" placeholder="e.g., 1,6,11 or 36,40,44,48">
</div>
<div class="form-group">
<label>Channel (single)</label>
<input type="text" id="wifiChannel" placeholder="e.g., 6 or 36">
</div>
</div>
+79
View File
@@ -15,6 +15,8 @@
<button class="settings-tab" data-tab="display" onclick="switchSettingsTab('display')">Display</button>
<button class="settings-tab" data-tab="updates" onclick="switchSettingsTab('updates')">Updates</button>
<button class="settings-tab" data-tab="tools" onclick="switchSettingsTab('tools')">Tools</button>
<button class="settings-tab" data-tab="alerts" onclick="switchSettingsTab('alerts')">Alerts</button>
<button class="settings-tab" data-tab="recording" onclick="switchSettingsTab('recording')">Recording</button>
<button class="settings-tab" data-tab="about" onclick="switchSettingsTab('about')">About</button>
</div>
@@ -280,6 +282,83 @@
</div>
</div>
<!-- Alerts Section -->
<div id="settings-alerts" class="settings-section">
<div class="settings-group">
<div class="settings-group-title">Alert Feed <span id="alertsFeedCount" style="color: var(--text-dim); font-weight: 500;"></span></div>
<div id="alertsFeedList" class="settings-feed">
<div class="settings-feed-empty">No alerts yet</div>
</div>
</div>
<div class="settings-group">
<div class="settings-group-title">Quick Rules</div>
<div style="display: flex; gap: 10px; flex-wrap: wrap;">
<button class="check-assets-btn" onclick="AlertCenter.enableTrackerAlerts()">Enable Tracker Alerts</button>
<button class="check-assets-btn" onclick="AlertCenter.disableTrackerAlerts()">Disable Tracker Alerts</button>
</div>
<div class="settings-info" style="margin-top: 10px;">
Use Bluetooth device details to add specific device watchlist alerts.
</div>
</div>
</div>
<!-- Recording Section -->
<div id="settings-recording" class="settings-section">
<div class="settings-group">
<div class="settings-group-title">Start Recording</div>
<div class="settings-row" style="border-bottom: none; padding-top: 0;">
<div class="settings-label">
<span class="settings-label-text">Mode</span>
<span class="settings-label-desc">Record live events for a mode</span>
</div>
<select id="recordingModeSelect" class="settings-select" style="width: 200px;">
<option value="pager">Pager</option>
<option value="sensor">433 Sensors</option>
<option value="wifi">WiFi</option>
<option value="bluetooth">Bluetooth</option>
<option value="adsb">ADS-B</option>
<option value="ais">AIS</option>
<option value="dsc">DSC</option>
<option value="acars">ACARS</option>
<option value="aprs">APRS</option>
<option value="rtlamr">RTLAMR</option>
<option value="dmr">DMR</option>
<option value="tscm">TSCM</option>
<option value="sstv">SSTV</option>
<option value="sstv_general">SSTV General</option>
<option value="listening_scanner">Listening Post</option>
<option value="waterfall">Waterfall</option>
</select>
</div>
<div class="settings-row" style="border-bottom: none;">
<div class="settings-label">
<span class="settings-label-text">Label</span>
<span class="settings-label-desc">Optional note for the session</span>
</div>
<input type="text" id="recordingLabelInput" class="settings-input" placeholder="Morning sweep" style="width: 200px;">
</div>
<div style="display: flex; gap: 10px; margin-top: 10px;">
<button class="check-assets-btn" onclick="RecordingUI.start()">Start</button>
<button class="check-assets-btn" onclick="RecordingUI.stop()">Stop</button>
</div>
</div>
<div class="settings-group">
<div class="settings-group-title">Active Sessions</div>
<div id="recordingActiveList" class="settings-feed">
<div class="settings-feed-empty">No active recordings</div>
</div>
</div>
<div class="settings-group">
<div class="settings-group-title">Recent Recordings</div>
<div id="recordingList" class="settings-feed">
<div class="settings-feed-empty">No recordings yet</div>
</div>
</div>
</div>
<!-- About Section -->
<div id="settings-about" class="settings-section">
<div class="settings-group">