aethersdr / aethersdr/AetherSDR
RepeaterBook API integration — map-based repeater browse + load-to-slice/memory
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 221
- Forks
- 117
- Avg merge
- 2d 7h
- Merged PRs (30d)
- 299
Description
Context
Our RepeaterBook API access application was approved (distributed/per-user-token model). This issue tracks planning + implementation of RepeaterBook directory lookups in AetherSDR — populate the active slice and/or Memory channels with output frequency, offset/duplex, and CTCSS/DCS tone from the RepeaterBook directory.
Locked design constraints (from the approved application — non-negotiable)
These were promised to RepeaterBook and must match the implementation:
- Per-user API tokens, NOT a shared embedded secret. AetherSDR is GPLv3/distributed — an embedded token would be extractable and is explicitly disclaimed. Each operator enters their own RepeaterBook API key.
- Tokens stored via QtKeychain (Secret Service/Keyring on Linux, Keychain on macOS, Credential Manager on Windows) — never plaintext config. Reuse the existing pattern in
src/gui/MqttSettingsDialog.cpp(HAVE_KEYCHAIN,load/savePasswordFromKeychain). - User-initiated, on-demand lookups only — no background polling or bulk scraping. Results cached locally; honor published rate limits.
- User-Agent:
AetherSDR/<version> (https://github.com/aethersdr/AetherSDR; kk7gwy@aethersdr.com)— version is CalVer (YY.M.patch), changes every release.
v1 scope (decided)
- Primary surface: map-based browse. Plot repeaters on the existing Qt map engine (
src/gui/map/, from #3565 — the PSK Reporter map's engine); click a marker to load it. - Coverage: worldwide from the start — support both the North America and rest-of-world endpoints.
- Result lands in BOTH: load into the active slice/VFO (tune now) and allow save to a Memory channel (persist).
- QTH source for 'near me': GPS (reuse the APRS-beacon position source) + manual Maidenhead/lat-lon + current map center.
Key finding — the radio plumbing already exists ✅
Loading a repeater is already a solved path:
src/core/MemoryRecallPolicy.cppalready emits the FlexLib slice commandsrepeater_offset_dir,fm_repeater_offset_freq,fm_tone_mode,fm_tone_value.- The Memory record already carries
repeaterOffset,toneMode,toneValue(MemoryCsvCompat,MemoryRecallPolicy).
➡️ A RepeaterBook result maps onto the existing Memory record, and the existing recall path applies offset/tone to the slice. Both "load to slice" and "save to memory" reuse this — no new radio-control code needed. The new work is auth + API client + field mapping + map UI.
Open questions / verify before building
- Confirm the exact endpoints + query params available under our approved access, and the auth header format for the per-user token. (Assumption: classic
export.php/exportROW.phpJSON.) - Proximity model. The classic export API is keyed by region (state/county/city), not a lat-lon radius. So "near me" is likely: fetch by admin region, then client-side distance filter/sort around the QTH and center the map there. Confirm whether any radius/bbox query is available; if not, design around region-fetch + client filter.
- Documented rate limits — pin the exact numbers; size the cache TTL + throttle to them.
- Field mapping — RepeaterBook fields → Memory record (freq, offset sign/magnitude, tone mode CTCSS/DCS + value, callsign, location, mode/FM-only). Enumerate and handle missing/odd values.
- DCS vs CTCSS coverage — confirm the slice/tone path handles DCS (digital) codes, not just CTCSS.
Proposed implementation phases
- Phase 0 — API recon (this issue's first PR): confirm endpoints/params/auth/rate-limits against our approved access; document in
docs/. (Principle VIII.) - Phase 1 — Token settings: RepeaterBook settings dialog/section; per-user key entry; QtKeychain store (copy MqttSettingsDialog pattern); nested-JSON config per Principle V for non-secret prefs (endpoint region defaults, cache TTL).
- Phase 2 — API client + cache:
RepeaterBookClient(QNetworkAccessManager), correct User-Agent, JSON parse → result model, on-disk cache keyed by query, throttle to rate limits. - Phase 3 — Field mapping → Memory record: RepeaterBook result → existing Memory struct; unit-test the mapping (offset sign, tone mode/value, DCS).
- Phase 4 — Map browse UI: region fetch → markers on the
src/gui/map/engine; QTH from GPS/manual/map-center; client-side proximity filter; marker click → load active slice + 'Save to Memory' action.
Out of scope for v1
- Writing/contributing data back to RepeaterBook.
- Background auto-refresh / full offline directory mirror (on-demand + local cache only).
- Non-map bulk-import wizard and freq/callsign search dialogs (roadmap follow-ups; the client + mapping built here enable them).
Constitution touchpoints
- Principle V — non-secret prefs as one nested-JSON config object.
- Secrets — API token in OS keychain, never in config (per approved design).
- Principle XI — demonstrate the load path end-to-end (mapping unit tests + a real lookup → slice tune).
- Cross-platform — QtKeychain + QNetworkAccessManager are portable; verify on Linux/macOS/Windows.
cc the core team for design input before Phase 1. Related: #3565 (map engine), Memory subsystem.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Begin with Phase 0 and inspect src/gui/MqttSettingsDialog.cpp for the existing QtKeychain pattern, then review src/gui/map/ and src/core/MemoryRecallPolicy.cpp. The first PR should document the approved endpoints, query parameters, authentication format, rate limits, and field mapping in docs/ before the later implementation phases proceed.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- api, authentication, desktop
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 32/100