Skip to content

Releases: clorth0/aetherscope

v1.0.0 — first stable release

14 Jun 21:35

Choose a tag to compare

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

14 Jun 21:07

Choose a tag to compare

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

14 Jun 20:56

Choose a tag to compare

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

14 Jun 20:33

Choose a tag to compare

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

14 Jun 20:18

Choose a tag to compare

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

14 Jun 19:52

Choose a tag to compare

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

14 Jun 19:28

Choose a tag to compare

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

14 Jun 19:17

Choose a tag to compare

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 geolocation in 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), and AETHERSCOPE_GPS=0 to 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 .iq via core:dataset, so recordings are portable to other
    SDR tools (GNU Radio, inspectrum, IQEngine, the sigmf library). Geotags ride
    in core:geolocation (GeoJSON Point) and are scrubbed by redaction. A SigMF
    download link is on each capture row. Non-breaking: the .iq and 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

14 Jun 18:26

Choose a tag to compare

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-sqlite3 data 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, and escapeHtml on 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

14 Jun 16:53

Choose a tag to compare

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.py find_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.