Merge pull request 'fix(wavelog): push live tuned frequency, not just band center' (#2) from fix/wavelog-cat-live-frequency into main
Reviewed-on: #2
This commit was merged in pull request #2.
This commit is contained in:
@@ -93,3 +93,5 @@ WAVELOG_BASE_URL=
|
|||||||
WAVELOG_RADIO_NAME=RMS Remote
|
WAVELOG_RADIO_NAME=RMS Remote
|
||||||
# HTTP timeout for the Wavelog API call (ms).
|
# HTTP timeout for the Wavelog API call (ms).
|
||||||
WAVELOG_TIMEOUT_MS=8000
|
WAVELOG_TIMEOUT_MS=8000
|
||||||
|
# Min interval between live-tuning pushes per operator (ms, trailing-debounced).
|
||||||
|
WAVELOG_MIN_INTERVAL_MS=3000
|
||||||
|
|||||||
@@ -9,9 +9,13 @@
|
|||||||
- `baseUrl` / `WAVELOG_BASE_URL` – URL der Wavelog-Instanz (ohne Slash am Ende). Leer = deaktiviert.
|
- `baseUrl` / `WAVELOG_BASE_URL` – URL der Wavelog-Instanz (ohne Slash am Ende). Leer = deaktiviert.
|
||||||
- `radioName` / `WAVELOG_RADIO_NAME` – Anzeigename in Wavelog (Default `RMS Remote`).
|
- `radioName` / `WAVELOG_RADIO_NAME` – Anzeigename in Wavelog (Default `RMS Remote`).
|
||||||
- `timeoutMs` / `WAVELOG_TIMEOUT_MS` – HTTP-Timeout (Default 8000).
|
- `timeoutMs` / `WAVELOG_TIMEOUT_MS` – HTTP-Timeout (Default 8000).
|
||||||
- Ausloeser: Der Core ruft die Capability beim Bandwechsel (`/v1/openwebrx/bands/select`) auf und
|
- Ausloeser:
|
||||||
uebergibt `centerFreqHz` + `startMod` sowie den Wavelog-Key des aktiven Operators. Best-effort:
|
- **Bandwechsel** (`/v1/openwebrx/bands/select`): sofortiger Push der Band-Mittenfrequenz
|
||||||
Fehler brechen den Bandwechsel nie ab.
|
(`centerFreqHz` + `startMod`).
|
||||||
|
- **Live-Tuning in OpenWebRX** (`/v1/openwebrx/plugin/live-state`): Push der tatsaechlich getunten
|
||||||
|
Frequenz/Mode des aktiven Operators, **gedrosselt** (Trailing-Debounce, `WAVELOG_MIN_INTERVAL_MS`,
|
||||||
|
Default 3000 ms) damit Feintunen die API nicht flutet.
|
||||||
|
- Beides best-effort: Fehler brechen den jeweiligen Flow nie ab.
|
||||||
- Key-Ablage: pro Benutzer in `users.json` (`wavelogApiKey`), setzbar via `PUT /v1/me/wavelog-key`
|
- Key-Ablage: pro Benutzer in `users.json` (`wavelogApiKey`), setzbar via `PUT /v1/me/wavelog-key`
|
||||||
und sichtbar im OpenWebRX-Panel. **Kein** Key im Repo – der Key ist Laufzeit-/Benutzerdatum.
|
und sichtbar im OpenWebRX-Panel. **Kein** Key im Repo – der Key ist Laufzeit-/Benutzerdatum.
|
||||||
- Mode-Mapping: `usb|lsb|ssb → SSB`, `cw|cwr → CW`, `fm|nfm|wfm → FM`, `am|sam → AM`, sonst Rohwert
|
- Mode-Mapping: `usb|lsb|ssb → SSB`, `cw|cwr → CW`, `fm|nfm|wfm → FM`, `am|sam → AM`, sonst Rohwert
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ const config = {
|
|||||||
actionRateLimit: Number(process.env.ACTION_RATE_LIMIT || 30),
|
actionRateLimit: Number(process.env.ACTION_RATE_LIMIT || 30),
|
||||||
openWebRxPttLiveFreqToleranceHz: Number(process.env.OPENWEBRX_PTT_LIVE_FREQ_TOLERANCE_HZ || 50),
|
openWebRxPttLiveFreqToleranceHz: Number(process.env.OPENWEBRX_PTT_LIVE_FREQ_TOLERANCE_HZ || 50),
|
||||||
openWebRxLiveStateTtlMs: Number(process.env.OPENWEBRX_LIVE_STATE_TTL_MS || 10000),
|
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"),
|
openWebRxPttBlockedBandConfigIdsRaw: String(process.env.OPENWEBRX_PTT_BLOCKED_BAND_CONFIG_IDS || "27,6,24"),
|
||||||
openWebRxTxPollMs: Number(process.env.OPENWEBRX_TX_POLL_MS || 3000),
|
openWebRxTxPollMs: Number(process.env.OPENWEBRX_TX_POLL_MS || 3000),
|
||||||
txAudioEnabled: String(process.env.TX_AUDIO_ENABLED || "true").trim().toLowerCase(),
|
txAudioEnabled: String(process.env.TX_AUDIO_ENABLED || "true").trim().toLowerCase(),
|
||||||
@@ -196,6 +197,7 @@ const runtime = {
|
|||||||
lastEnsureSdrAtMs: 0
|
lastEnsureSdrAtMs: 0
|
||||||
},
|
},
|
||||||
openWebRxLiveStateByUserId: {},
|
openWebRxLiveStateByUserId: {},
|
||||||
|
wavelogCatByUserId: {},
|
||||||
rotor: {
|
rotor: {
|
||||||
azimuth: null,
|
azimuth: null,
|
||||||
rawAzimuth: 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).
|
// Push a frequency/mode to the active operator's Wavelog logbook (CAT API).
|
||||||
// Best-effort: never throws into the band-select flow.
|
// Best-effort: never throws into the caller's flow.
|
||||||
async function maybePublishWavelogCat(user, bandResult) {
|
async function sendWavelogCat(user, frequencyHz, mode) {
|
||||||
try {
|
try {
|
||||||
if (!user || !user.wavelogApiKey) {
|
if (!user || !user.wavelogApiKey) {
|
||||||
return;
|
return;
|
||||||
@@ -3730,13 +3732,13 @@ async function maybePublishWavelogCat(user, bandResult) {
|
|||||||
if (!runtime.pluginState.providers["logging.cat.publish"]) {
|
if (!runtime.pluginState.providers["logging.cat.publish"]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const frequencyHz = Number(bandResult && bandResult.centerFreqHz);
|
const freq = Number(frequencyHz);
|
||||||
if (!Number.isFinite(frequencyHz) || frequencyHz <= 0) {
|
if (!Number.isFinite(freq) || freq <= 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const outcome = await executeCapability("logging.cat.publish", "publish", {
|
const outcome = await executeCapability("logging.cat.publish", "publish", {
|
||||||
frequencyHz,
|
frequencyHz: freq,
|
||||||
mode: bandResult && bandResult.startMod ? bandResult.startMod : null,
|
mode: mode || null,
|
||||||
apiKey: user.wavelogApiKey
|
apiKey: user.wavelogApiKey
|
||||||
}, { user, skipTxSafety: true });
|
}, { user, skipTxSafety: true });
|
||||||
if (!outcome || outcome.ok !== 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) {
|
async function handleOpenWebRxTxEnable(res, user) {
|
||||||
if (!runtime.station.isInUse || runtime.station.activeByUserId !== user.id) {
|
if (!runtime.station.isInUse || runtime.station.activeByUserId !== user.id) {
|
||||||
return sendError(res, 403, "openwebrx.not_owner", "OpenWebRX TX nur fuer aktiven Stationsbenutzer");
|
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(),
|
updatedAtMs: Date.now(),
|
||||||
source: "plugin"
|
source: "plugin"
|
||||||
});
|
});
|
||||||
|
scheduleWavelogCatLive(user, parsed.frequencyHz, parsed.mode);
|
||||||
return sendJson(res, 200, {
|
return sendJson(res, 200, {
|
||||||
ok: true,
|
ok: true,
|
||||||
liveState: {
|
liveState: {
|
||||||
|
|||||||
Reference in New Issue
Block a user