fix(wavelog): push live tuned frequency, not just band center

The CAT push only fired on band select (band center). Fine-tuning inside
OpenWebRX did not update Wavelog. Hook the per-operator live-state updates
(/v1/openwebrx/plugin/live-state) so the actual tuned frequency/mode is
pushed, trailing-debounced (WAVELOG_MIN_INTERVAL_MS, default 3000 ms) so
tuning does not flood the Wavelog API. Band-select push kept as immediate
feedback on band change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
ARCG Admin (Claude)
2026-10-22 21:16:17 +02:00
parent 4ced7418cd
commit 061045999b
3 changed files with 75 additions and 10 deletions

View File

@@ -44,6 +44,7 @@ const config = {
actionRateLimit: Number(process.env.ACTION_RATE_LIMIT || 30),
openWebRxPttLiveFreqToleranceHz: Number(process.env.OPENWEBRX_PTT_LIVE_FREQ_TOLERANCE_HZ || 50),
openWebRxLiveStateTtlMs: Number(process.env.OPENWEBRX_LIVE_STATE_TTL_MS || 10000),
wavelogMinIntervalMs: Number(process.env.WAVELOG_MIN_INTERVAL_MS || 3000),
openWebRxPttBlockedBandConfigIdsRaw: String(process.env.OPENWEBRX_PTT_BLOCKED_BAND_CONFIG_IDS || "27,6,24"),
openWebRxTxPollMs: Number(process.env.OPENWEBRX_TX_POLL_MS || 3000),
txAudioEnabled: String(process.env.TX_AUDIO_ENABLED || "true").trim().toLowerCase(),
@@ -196,6 +197,7 @@ const runtime = {
lastEnsureSdrAtMs: 0
},
openWebRxLiveStateByUserId: {},
wavelogCatByUserId: {},
rotor: {
azimuth: null,
rawAzimuth: null,
@@ -3717,9 +3719,9 @@ async function handleOpenWebRxBandSelect(res, user, body) {
}
}
// Push current frequency/mode to the active operator's Wavelog logbook (CAT API).
// Best-effort: never throws into the band-select flow.
async function maybePublishWavelogCat(user, bandResult) {
// Push a frequency/mode to the active operator's Wavelog logbook (CAT API).
// Best-effort: never throws into the caller's flow.
async function sendWavelogCat(user, frequencyHz, mode) {
try {
if (!user || !user.wavelogApiKey) {
return;
@@ -3730,13 +3732,13 @@ async function maybePublishWavelogCat(user, bandResult) {
if (!runtime.pluginState.providers["logging.cat.publish"]) {
return;
}
const frequencyHz = Number(bandResult && bandResult.centerFreqHz);
if (!Number.isFinite(frequencyHz) || frequencyHz <= 0) {
const freq = Number(frequencyHz);
if (!Number.isFinite(freq) || freq <= 0) {
return;
}
const outcome = await executeCapability("logging.cat.publish", "publish", {
frequencyHz,
mode: bandResult && bandResult.startMod ? bandResult.startMod : null,
frequencyHz: freq,
mode: mode || null,
apiKey: user.wavelogApiKey
}, { user, skipTxSafety: true });
if (!outcome || outcome.ok !== true) {
@@ -3753,6 +3755,62 @@ async function maybePublishWavelogCat(user, bandResult) {
}
}
// Band select: push the band center immediately (best-effort).
async function maybePublishWavelogCat(user, bandResult) {
await sendWavelogCat(user, bandResult && bandResult.centerFreqHz, bandResult && bandResult.startMod ? bandResult.startMod : null);
}
// Live tuning in OpenWebRX: push the actual tuned frequency/mode, throttled so
// fine-tuning doesn't flood the Wavelog API. Trailing-edge: the latest value is
// always sent once the throttle window elapses.
function scheduleWavelogCatLive(user, frequencyHz, mode) {
try {
if (!user || !user.wavelogApiKey || !runtime.pluginState.enabled["rms.wavelog.cat"]) {
return;
}
const freq = Number(frequencyHz);
if (!Number.isFinite(freq) || freq <= 0) {
return;
}
const key = String(user.id || "");
if (!key) {
return;
}
const minIntervalMs = Number.isFinite(config.wavelogMinIntervalMs) ? Math.max(500, config.wavelogMinIntervalMs) : 3000;
const rec = runtime.wavelogCatByUserId[key] || { lastFreq: null, lastMode: null, lastPushMs: 0, timer: null };
runtime.wavelogCatByUserId[key] = rec;
rec.pendingFreq = freq;
rec.pendingMode = mode || null;
rec.pendingUser = user;
if (rec.lastFreq === freq && rec.lastMode === (mode || null)) {
return;
}
const fire = () => {
rec.timer = null;
rec.lastFreq = rec.pendingFreq;
rec.lastMode = rec.pendingMode;
rec.lastPushMs = Date.now();
sendWavelogCat(rec.pendingUser, rec.pendingFreq, rec.pendingMode);
};
const elapsed = Date.now() - (rec.lastPushMs || 0);
if (!rec.timer && elapsed >= minIntervalMs) {
fire();
} else if (!rec.timer) {
rec.timer = setTimeout(fire, Math.max(250, minIntervalMs - elapsed));
if (rec.timer && typeof rec.timer.unref === "function") {
rec.timer.unref();
}
}
// If a timer is already pending, pendingFreq/Mode were updated above so the
// trailing push sends the latest tuned frequency.
} catch (error) {
console.warn("wavelog.cat live schedule error", {
userId: user && user.id,
error: String(error && error.message ? error.message : error)
});
}
}
async function handleOpenWebRxTxEnable(res, user) {
if (!runtime.station.isInUse || runtime.station.activeByUserId !== user.id) {
return sendError(res, 403, "openwebrx.not_owner", "OpenWebRX TX nur fuer aktiven Stationsbenutzer");
@@ -5033,6 +5091,7 @@ async function handleOpenWebRxPluginLiveState(req, res, url, body) {
updatedAtMs: Date.now(),
source: "plugin"
});
scheduleWavelogCatLive(user, parsed.frequencyHz, parsed.mode);
return sendJson(res, 200, {
ok: true,
liveState: {