[feat](trx-frontend-http): /meter SSE endpoint for instant signal metering
Adds a dedicated /meter SSE stream that wraps the per-rig meter watch and emits one compact JSON frame per update with no equality gating, so 30 Hz samples reach the browser unthrottled. Registered as a Read-access route. app.js opens a dedicated EventSource on /meter alongside /events, writing directly to the signal bar and value on each frame with no requestAnimationFrame coalescing, starts/stops with connect/disconnect, and reconnects on rig switch. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
@@ -3700,6 +3700,8 @@ function connect() {
|
||||
if (esHeartbeat) {
|
||||
clearInterval(esHeartbeat);
|
||||
}
|
||||
stopMeterStreaming();
|
||||
startMeterStreaming();
|
||||
pollFreshSnapshot();
|
||||
const eventsUrl = lastActiveRigId
|
||||
? `/events?remote=${encodeURIComponent(lastActiveRigId)}`
|
||||
@@ -3778,6 +3780,7 @@ function disconnect() {
|
||||
decodeSource = null;
|
||||
}
|
||||
stopSpectrumStreaming();
|
||||
stopMeterStreaming();
|
||||
// Clear timers
|
||||
if (esHeartbeat) {
|
||||
clearInterval(esHeartbeat);
|
||||
@@ -3900,6 +3903,9 @@ async function switchRigFromSelect(selectEl) {
|
||||
// Reconnect spectrum SSE to the new rig's spectrum channel.
|
||||
stopSpectrumStreaming();
|
||||
startSpectrumStreaming();
|
||||
// Reconnect meter SSE to the new rig's meter channel.
|
||||
stopMeterStreaming();
|
||||
startMeterStreaming();
|
||||
// Reconnect audio to the new rig if audio is active.
|
||||
if (rxActive) {
|
||||
stopRxAudio();
|
||||
@@ -6476,6 +6482,8 @@ const spectrumCenterLeftBtn = document.getElementById("spectrum-center-left-btn"
|
||||
const spectrumCenterRightBtn = document.getElementById("spectrum-center-right-btn");
|
||||
let spectrumSource = null;
|
||||
let spectrumReconnectTimer = null;
|
||||
let meterSource = null;
|
||||
let meterReconnectTimer = null;
|
||||
let spectrumDrawPending = false;
|
||||
let spectrumAxisKey = "";
|
||||
let spectrumDbAxisKey = "";
|
||||
@@ -6996,6 +7004,63 @@ function stopSpectrumStreaming() {
|
||||
clearSpectrumCanvas();
|
||||
}
|
||||
|
||||
// ── /meter (fast signal-strength) streaming ─────────────────────────────────
|
||||
// Dedicated SSE channel pushed at ~30 Hz by trx-server; bypasses /events so
|
||||
// meter frames are never gated by full-RigState diffing. Synchronous DOM
|
||||
// write per frame — no rAF coalescing, per user requirement that it "feel
|
||||
// instant" on the frontend.
|
||||
function scheduleMeterReconnect() {
|
||||
if (meterReconnectTimer !== null) return;
|
||||
meterReconnectTimer = setTimeout(() => {
|
||||
meterReconnectTimer = null;
|
||||
startMeterStreaming();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function applyMeterSample(dbm) {
|
||||
if (typeof dbm !== "number" || !Number.isFinite(dbm)) return;
|
||||
prevRenderData.sigDbm = dbm;
|
||||
const sUnits = dbmToSUnits(dbm);
|
||||
sigLastSUnits = sUnits;
|
||||
sigLastDbm = dbm;
|
||||
const pct = sUnits <= 9 ? Math.max(0, Math.min(100, (sUnits / 9) * 100)) : 100;
|
||||
if (signalBar) signalBar.style.width = `${pct}%`;
|
||||
if (signalValue) signalValue.innerHTML = formatSignal(sUnits);
|
||||
refreshSigStrengthDisplay();
|
||||
}
|
||||
|
||||
function startMeterStreaming() {
|
||||
if (meterSource !== null) return;
|
||||
const url = lastActiveRigId
|
||||
? `/meter?remote=${encodeURIComponent(lastActiveRigId)}`
|
||||
: "/meter";
|
||||
meterSource = new EventSource(url);
|
||||
meterSource.onmessage = (evt) => {
|
||||
try {
|
||||
const { sig } = JSON.parse(evt.data);
|
||||
applyMeterSample(sig);
|
||||
} catch (_) {}
|
||||
};
|
||||
meterSource.onerror = () => {
|
||||
if (meterSource) {
|
||||
meterSource.close();
|
||||
meterSource = null;
|
||||
}
|
||||
scheduleMeterReconnect();
|
||||
};
|
||||
}
|
||||
|
||||
function stopMeterStreaming() {
|
||||
if (meterSource !== null) {
|
||||
meterSource.close();
|
||||
meterSource = null;
|
||||
}
|
||||
if (meterReconnectTimer !== null) {
|
||||
clearTimeout(meterReconnectTimer);
|
||||
meterReconnectTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
// ── Rendering ────────────────────────────────────────────────────────────────
|
||||
function clearSpectrumCanvas() {
|
||||
if (!spectrumCanvas || !spectrumGl || !spectrumGl.ready) return;
|
||||
|
||||
Reference in New Issue
Block a user