mirror of
https://github.com/smittix/intercept.git
synced 2026-06-22 03:58:52 -07:00
Add graphical signal meter for APRS decoding
Backend changes (routes/aprs.py): - Remove -q h flag from direwolf to enable audio level output - Add parse_audio_level() to extract levels from direwolf output - Add rate-limiting (max 10 updates/sec, min 2-level change) - Push meter events to SSE queue as type='meter' Frontend changes: - Add signal meter widget to APRS sidebar - Horizontal bar gauge with gradient (green->cyan->yellow->red) - Numeric level display (0-100) - "BURST" indicator for levels >70 - Status text (weak/moderate/strong signal) - "No RF activity" state after 5 seconds of silence - CSS styles in static/css/modes/aprs.css Also added UK region to dropdown (same freq as Europe: 144.800) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
+99
-1
@@ -5949,6 +5949,9 @@
|
||||
let isAprsRunning = false;
|
||||
let aprsPacketCount = 0;
|
||||
let aprsStationCount = 0;
|
||||
let aprsMeterLastUpdate = 0;
|
||||
let aprsMeterCheckInterval = null;
|
||||
const APRS_METER_TIMEOUT = 5000; // 5 seconds for "no signal" state
|
||||
|
||||
function checkAprsTools() {
|
||||
fetch('/aprs/tools')
|
||||
@@ -6052,6 +6055,10 @@
|
||||
updateAprsStatus('listening', data.frequency);
|
||||
document.getElementById('aprsStatusStations').textContent = '0';
|
||||
document.getElementById('aprsStatusPackets').textContent = '0';
|
||||
// Show signal meter
|
||||
document.getElementById('aprsSignalMeter').style.display = 'block';
|
||||
resetAprsMeter();
|
||||
startAprsMeterCheck();
|
||||
startAprsStream();
|
||||
} else {
|
||||
alert('APRS Error: ' + data.message);
|
||||
@@ -6071,10 +6078,13 @@
|
||||
isAprsRunning = false;
|
||||
document.getElementById('startAprsBtn').style.display = 'block';
|
||||
document.getElementById('stopAprsBtn').style.display = 'none';
|
||||
// Hide sidebar status bar
|
||||
// Hide sidebar status bar and signal meter
|
||||
document.getElementById('aprsStatusBar').style.display = 'none';
|
||||
document.getElementById('aprsSignalMeter').style.display = 'none';
|
||||
document.getElementById('aprsMapStatus').textContent = 'STANDBY';
|
||||
document.getElementById('aprsMapStatus').style.color = '';
|
||||
// Stop meter check interval
|
||||
stopAprsMeterCheck();
|
||||
if (aprsEventSource) {
|
||||
aprsEventSource.close();
|
||||
aprsEventSource = null;
|
||||
@@ -6099,6 +6109,9 @@
|
||||
updateAprsStatus('tracking');
|
||||
}
|
||||
processAprsPacket(data);
|
||||
} else if (data.type === 'meter') {
|
||||
// Update signal meter
|
||||
updateAprsMeter(data.level);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -6108,6 +6121,91 @@
|
||||
};
|
||||
}
|
||||
|
||||
// Signal Meter Functions
|
||||
function resetAprsMeter() {
|
||||
aprsMeterLastUpdate = 0;
|
||||
const bar = document.getElementById('aprsMeterBar');
|
||||
const value = document.getElementById('aprsMeterValue');
|
||||
const burst = document.getElementById('aprsMeterBurst');
|
||||
const status = document.getElementById('aprsMeterStatus');
|
||||
if (bar) {
|
||||
bar.style.width = '0%';
|
||||
bar.classList.remove('no-signal');
|
||||
}
|
||||
if (value) value.textContent = '--';
|
||||
if (burst) burst.style.display = 'none';
|
||||
if (status) {
|
||||
status.textContent = 'Waiting for signal...';
|
||||
status.className = 'aprs-meter-status';
|
||||
}
|
||||
}
|
||||
|
||||
function updateAprsMeter(level) {
|
||||
aprsMeterLastUpdate = Date.now();
|
||||
const bar = document.getElementById('aprsMeterBar');
|
||||
const value = document.getElementById('aprsMeterValue');
|
||||
const burst = document.getElementById('aprsMeterBurst');
|
||||
const status = document.getElementById('aprsMeterStatus');
|
||||
|
||||
if (bar) {
|
||||
bar.style.width = level + '%';
|
||||
bar.classList.remove('no-signal');
|
||||
}
|
||||
if (value) value.textContent = level;
|
||||
|
||||
// Show burst indicator for high levels (>70)
|
||||
if (burst) {
|
||||
if (level > 70) {
|
||||
burst.style.display = 'inline';
|
||||
// Remove and re-add to trigger animation
|
||||
burst.style.animation = 'none';
|
||||
burst.offsetHeight; // Trigger reflow
|
||||
burst.style.animation = null;
|
||||
} else {
|
||||
burst.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
// Update status text
|
||||
if (status) {
|
||||
status.className = 'aprs-meter-status active';
|
||||
if (level < 10) {
|
||||
status.textContent = 'Low signal / noise floor';
|
||||
} else if (level < 30) {
|
||||
status.textContent = 'Weak signal detected';
|
||||
} else if (level < 60) {
|
||||
status.textContent = 'Moderate signal';
|
||||
} else {
|
||||
status.textContent = 'Strong signal / packet burst';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function startAprsMeterCheck() {
|
||||
// Check for no-signal state every second
|
||||
aprsMeterCheckInterval = setInterval(function() {
|
||||
if (aprsMeterLastUpdate > 0 && (Date.now() - aprsMeterLastUpdate) > APRS_METER_TIMEOUT) {
|
||||
// No meter updates for 5 seconds - show no-signal state
|
||||
const bar = document.getElementById('aprsMeterBar');
|
||||
const status = document.getElementById('aprsMeterStatus');
|
||||
const burst = document.getElementById('aprsMeterBurst');
|
||||
if (bar) bar.classList.add('no-signal');
|
||||
if (burst) burst.style.display = 'none';
|
||||
if (status) {
|
||||
status.textContent = 'No RF activity / silence';
|
||||
status.className = 'aprs-meter-status no-signal';
|
||||
}
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function stopAprsMeterCheck() {
|
||||
if (aprsMeterCheckInterval) {
|
||||
clearInterval(aprsMeterCheckInterval);
|
||||
aprsMeterCheckInterval = null;
|
||||
}
|
||||
}
|
||||
|
||||
function processAprsPacket(packet) {
|
||||
// Update packet log
|
||||
const logEl = document.getElementById('aprsPacketLog');
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
<select id="aprsRegion">
|
||||
<option value="north_america">North America (144.390)</option>
|
||||
<option value="europe">Europe (144.800)</option>
|
||||
<option value="uk">UK (144.800)</option>
|
||||
<option value="australia">Australia (145.175)</option>
|
||||
<option value="japan">Japan (144.640)</option>
|
||||
</select>
|
||||
@@ -48,4 +49,23 @@
|
||||
<span class="aprs-stat"><span class="aprs-stat-label">PACKETS:</span> <span id="aprsStatusPackets">0</span></span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Signal Meter -->
|
||||
<div id="aprsSignalMeter" class="aprs-signal-meter" style="display: none;">
|
||||
<div class="aprs-meter-header">
|
||||
<span class="aprs-meter-label">SIGNAL</span>
|
||||
<span class="aprs-meter-value" id="aprsMeterValue">--</span>
|
||||
<span class="aprs-meter-burst" id="aprsMeterBurst" style="display: none;">BURST</span>
|
||||
</div>
|
||||
<div class="aprs-meter-bar-container">
|
||||
<div class="aprs-meter-bar" id="aprsMeterBar"></div>
|
||||
<div class="aprs-meter-ticks">
|
||||
<span>0</span>
|
||||
<span>25</span>
|
||||
<span>50</span>
|
||||
<span>75</span>
|
||||
<span>100</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="aprs-meter-status" id="aprsMeterStatus">Waiting for signal...</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user