Releases: clorth0/aetherscope
v1.0.0 — first stable release
Aetherscope 1.0: a self-hosted browser UI for a HackRF One, now stable.
This caps a full SDR instrument + situational-awareness tool. Highlights since the 0.x line:
- Spectrum analyzer (FFT + waterfall, max-hold/avg, peak table, zoom, marks, calibration).
- Radio: FM / NBFM / AM in the browser, one-click snap-to-peak tuning, a scanner, WAV recording of what you hear, and saved bookmarks.
- Captures you can use: record IQ, then replay as a spectrogram, listen with an offset tuner, or decode with rtl_433. Each capture gets a SigMF sidecar.
- Optional GPS geotagging (opt-in, default off) with per-capture redaction and precision coarsening; a live receiver marker on the map.
- ADS-B enrichment: US registration (N-number), country, range rings around your receiver, and live stats.
- Persistent device inventory aggregating ADS-B + ISM contacts (first/last seen, count, location).
- Configurable port (AETHERSCOPE_PORT); same-origin websockets; strict CSP with vendored deps (works offline).
1.0 readiness pass
Before tagging, a security + quality review (three adversarial passes + semgrep) hardened the release:
- Websocket origin check fixed to enforce same-origin by default.
- RF-derived strings escaped in the Decode/scan/ADS-B renderers; non-numeric RF fields no longer crash the map.
- Capture-label and other input bounds; capture-start failures no longer wedge the app.
- Lock/race fixes (audio-record connect read + start TOCTOU); SigMF and DSP correctness tweaks.
- Semgrep clean (0 findings); 15 test suites green.
Still localhost-only by design with no built-in auth; put TLS + auth in front to expose it.
v0.11.0 — Configurable port
Small config release.
- The HTTP listen port is now configurable via AETHERSCOPE_PORT (default 8765). Invalid or out-of-range values fall back to the default.
- The restart-script health check honors the port; configuration docs updated (also documents the previously-undocumented DATA_DIR / GPS / GPSD env vars).
- The frontend uses same-origin sockets, so nothing client-side changes.
Run on a custom port: AETHERSCOPE_PORT=9000 uv run aetherscope
v0.10.0 — Wireless device inventory
Phase C part 2 (situational awareness).
Wireless device inventory
- A persistent "what is around me" catalog in the data layer (store v2 migration): ADS-B aircraft (by ICAO hex) and rtl_433 ISM devices (by model + id).
- Each contact records first/last seen, sighting count, info (registration/country/altitude or sensor channel/battery), and the receiver location.
- Populated from live ADS-B and from Decode (live and decode-from-file), with throttled writes/broadcasts so a busy feed does not hammer SQLite.
- New Inventory tab: a searchable, sortable table with a Clear action.
- Verified live: 7 aircraft populated with correct N-numbers and accumulating counts.
Completes Phase C alongside v0.9.0 (ADS-B enrichment). The spectrum-occupancy survey was deferred. Everything from v0.9.0 carries forward.
v0.9.0 — ADS-B enrichment
Phase C part 1 (situational awareness).
ADS-B enrichment
- US registration (N-number) derived from the ICAO hex with no database (the FAA algorithm; verified against real aircraft).
- Country from ICAO 24-bit allocation blocks.
- Range rings (50/100/150 nm) drawn around the receiver position (the ADS-B Lat/Lon fields or your GPS fix).
- Per-aircraft range + bearing and registration/country in the map popup (RF-derived text now escaped).
- Stats line gains message rate (msg/s) and max range (farthest aircraft).
New test suite test_adsb_enrich (14 suites total). Everything from v0.8.0 carries forward.
v0.8.0 — Listen / decode from a saved IQ capture
Phase B part 2 of "close the loop". Saved IQ captures become usable, not just viewable.
Listen to a capture
- A Listen button on IQ capture rows demodulates the recorded .iq to audio and streams it (real time) over the existing AudioWorklet path.
- A demod selector and an offset slider (+/- half the sample rate) tune to any signal within the captured band; retuning is live and does not drop audio.
- DSP: mix the offset to baseband, resample to the demod rate, reuse the proven radio demod chain. Clock-based pacing keeps it real time.
Decode a capture
- A Decode button runs rtl_433 over the saved capture: resample to 1 MSps, convert cs8 to cu8 (rtl_433 reads cu8/cs16/cf32, not cs8), then rtl_433 -r; events stream into the existing Decode panel.
- Chunked conversion bounds memory; the temp file is cleaned up.
- Note: the decode pipeline is verified end-to-end mechanically, but a live ISM decode was not demonstrated during testing (nothing transmitting at 433/915). To try it: capture a few seconds while a known 433 MHz device transmits, then Decode.
Both are device-free, mutually-exclusive jobs. New test suites test_iq_playback and test_decode_file (13 suites total). Everything from v0.7.0 carries forward.
v0.7.0 — WAV audio recording
Phase B part 1 of "close the loop".
WAV audio recording
- A Record toggle in the Radio controls writes the live demodulated audio to a WAV file (stdlib wave, no new dependency).
- Recordings live in the captures dir with a geotagged JSON sidecar (opt-in GPS, precision coarsening, and per-capture redaction all apply). SigMF is intentionally excluded (it describes complex IQ, not audio).
- The capture list shows recordings with an "audio" badge, a native Play button, and demod/duration; the spectrogram Replay and SigMF link remain IQ-only.
- Recording auto-finalizes on radio Stop, mode switch, or a radio death, so the WAV is always closed cleanly.
New test suite test_audio_record. 11 suites green. Next: listen/decode from a saved IQ capture.
v0.6.1 — gpsd reconnect fix + ADS-B Use GPS
Patch release.
Fix
- gpsd client reader thread could die on a disable-during-active-read race (recv on a closed/None socket raised an uncaught AttributeError), so re-enabling GPS never reconnected. The reader now holds a local socket reference and catches any error, so it can never die and reconnects cleanly. Regression test added.
Feature
- ADS-B receiver gains a "Use GPS location" button that fills Your Lat/Lon from the current GPS fix (full precision, local-only for map centering and range), or warns when there is no fix.
v0.6.0 — GPS geotagging + SigMF export
Aetherscope v0.6.0 adds optional GPS geotagging and SigMF capture export.
GPS geotagging (opt-in, default off)
- New raw-socket gpsd client (
backend/gps.py, no new dependency): connects only
while enabled, parses TPV/SKY, keeps a thread-safe last-known position, and
never logs latitude/longitude. - A header GPS pill leads with fix quality ("GPS 3D, 7 sat") and keeps
coordinates masked behind the tooltip; clicking it toggles geotagging. - A live Receiver (GPS) marker tracks your position on the ADS-B map.
- Captures are stamped with a
geolocationin their sidecar when GPS is enabled
and holding a fresh fix; geotagging never blocks or fails a capture. - Privacy controls: per-capture Remove location redaction, a Geotag
precision setting (full / ~100 m / ~1 km) that coarsens only the stored
artifact (the live map stays exact), andAETHERSCOPE_GPS=0to hard-disable. - Capture timestamps stay on the system clock (the puck has no PPS); GPS supplies
position only.
SigMF export
- Each capture also writes a companion
<base>.sigmf-meta(SigMF 1.0.0)
referencing the.iqviacore:dataset, so recordings are portable to other
SDR tools (GNU Radio, inspectrum, IQEngine, thesigmflibrary). Geotags ride
incore:geolocation(GeoJSON Point) and are scrubbed by redaction. A SigMF
download link is on each capture row. Non-breaking: the.iqand UI sidecar
are unchanged.
10 test suites (new: test_gps, test_sigmf), CI green. Everything from v0.5.0
carries forward. Install and run are unchanged; geotagging requires a local gpsd
and is off until you enable it.
Env: AETHERSCOPE_GPSD_HOST / AETHERSCOPE_GPSD_PORT (default 127.0.0.1:2947),
AETHERSCOPE_GPS=0 to disable.
v0.5.0 — Data foundation: bookmarks, settings, capture annotations
Aetherscope v0.5.0 adds a persistent data layer: bookmarks, settings, and capture annotations.
Bookmarks
- A managed Bookmarks list in the Radio pane replaces the old hardcoded preset
chips. Tune, edit, delete, tag-filter, and add the current frequency. - The previous presets are seeded once into the bookmark library on first run and
are fully editable thereafter. - Save a sweep mark straight to a bookmark from the marks list.
Settings that survive restarts
- Your last mode, frequency, demod, and volume are restored on reload.
Capture annotations
- Captures can be labelled, noted, and tagged; missing files are flagged. Replays
record a last-played time. The capture-time JSON sidecar remains the source of
truth for capture parameters.
Under the hood
- New
backend/store.py: a stdlib-sqlite3data layer (no new dependency) at
AETHERSCOPE_DATA_DIR(default~/.local/share/aetherscope/, 0600, outside the
repo). Thread-safe (one connection, WAL, a lock) and fully parameterized. - Security: parameterized SQL throughout, server-side validation/bounds on
bookmark and capture fields, a settings key allowlist, andescapeHtmlon every
rendered field. Handlers are defensive against malformed payloads. - 8 test suites (the store alone has 16 tests), CI green.
Everything from v0.4.0 carries forward (snap-to-peak auto-tuner, ADS-B colored
trails, docs site, SA tools, NBFM + scanner, IQ replay, telemetry, vendored deps +
CSP, Linux Docker). Install and run are unchanged; see the README.
This is the first of a multi-phase roadmap. Next: close-the-loop recording (WAV
audio + decode-from-IQ + SigMF), then situational-awareness and security-RX
features (AIS, ADS-B enrichment, spectrum-occupancy survey, device inventory).
v0.4.0 — Snap-to-peak auto-tuner
Aetherscope v0.4.0 adds a one-click snap-to-peak auto-tuner for radio listening.
Snap-to-peak auto-tuner
- New "Snap to signal" button in the Radio controls fine-centers the receiver on
the strongest carrier near your tuned frequency. - Pure DSP (
backend/tuning.pyfind_peak_offset): DC/LO-spike removal,
fftshifted periodogram, strongest bin within a guarded window, gated by a
min-SNR-above-median floor so a dead band leaves the tuning untouched. - Search is intentionally narrow (FM 50 kHz, AM/NFM 15 kHz): it fine-centers the
station you are on rather than seeking nearby ones. Live FM testing showed a
wide window can lock onto a neighboring station's modulation skirt between
channels, so the window stays well inside the channel spacing. - The now-playing frequency readout now shows kHz precision so a small snap is
visible. - Five hardware-free TDD tests (
tests/test_tuning.py); 7 suites / 30 tests
total, CI green.
Fixes
- Device pill: the manual "click to re-probe" no longer probes a device that a
running job owns, which had been false-flipping the pill to "No HackRF". It now
re-broadcasts the current status while busy and only probes when idle.
Everything from v0.3.0 carries forward (ADS-B colored aircraft + fading trails,
docs site, SA tools, NBFM + scanner, IQ replay, telemetry/diagnostics, vendored
deps + CSP, CI, Linux Docker, calibration). Install and run are unchanged; see
the README.
Seek up/down (band browsing) is the documented next extension; see
docs/superpowers/specs/2026-06-14-auto-tuner-snap-to-peak-design.md.