When dump1090 lacks native --enable-biast support, the system now falls
back to rtl_biast (RTL-SDR Blog drivers) to enable bias-t power before
starting dump1090. The Blog V4's built-in LNA requires bias-t to
receive ADS-B signals.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix SSE fanout thread AttributeError when source queue is None during
interpreter shutdown by snapshotting to local variable with null guard
- Fix branded "i" logo rendering oversized on first page load (FOUC) by
adding inline width/height to SVG elements across 10 templates
- Bump version to 2.26.0 in config.py, pyproject.toml, and CHANGELOG.md
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ensureModeScript() used document.body.appendChild() to load lazy mode
scripts, but the preload for ?mode= query params runs in <head> before
<body> exists, causing all deep-linked modes to silently fail.
Also fix cross-mode handoffs (BT→BT Locate, WiFi→WiFi Locate,
Spy Stations→Waterfall) that assumed target module was already loaded.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Parse hackrf_info stderr (newer firmware) and handle non-zero exit codes
- Fix gain_max from 62 to 102 (combined LNA 40 + VGA 62)
- Apply resolved readsb binary path for all SDR types, not just RTL-SDR
- Add HackRF/SoapySDR-specific error messages in ADS-B startup
- Add HackRF waterfall support via rx_sdr IQ capture + FFT
- Add 17 tests for HackRF detection and command builder
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Several modes didn't pass sdr_type to claim_sdr_device(), defaulting to
'rtlsdr' and triggering an rtl_test USB probe that fails for HackRF with
a confusing "check that the RTL-SDR is connected" message.
- Add sdr_type to frontend start requests for rtlamr, weather-sat, sstv-general
- Read sdr_type in backend routes and pass to claim/release_sdr_device()
- Add early guard returning clear "not yet supported" error for non-RTL-SDR
hardware in modes that are hardcoded to RTL-SDR tools
- Make probe_rtlsdr_device error message device-type-agnostic
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When the /devices fetch hasn't completed or fails, parseInt on an empty
select returns NaN which JSON-serializes to null. The backend then calls
int(None) and raises TypeError. Fix both layers: frontend falls back to
0 on NaN, backend uses `or` defaults so null values don't bypass the
fallback.
Also adds a short TTL cache to detect_all_devices() so multiple
concurrent callers on the same page load don't each spawn blocking
subprocess probes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Stock rtl-sdr packages don't support the -T bias-tee flag (only
RTL-SDR Blog builds do). Passing -T to stock rtl_sdr causes an
immediate exit, breaking meteor scatter and waterfall modes.
Now probes the tool's --help output before adding -T, with a regex
that avoids false-matching "DVB-T" in the description text.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously all HackRF devices were hardcoded as "HackRF One" regardless
of actual hardware variant. Now parses the Board ID line from hackrf_info
to correctly identify HackRF Pro, HackRF One, and other variants.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
rtl_test opens the USB device during probing. After killing the
process, the kernel may not release the USB interface immediately.
dump1090 then fails with usb_claim_interface error -6. Add a 0.5s
delay after probe cleanup to allow the kernel to fully release the
device before the actual decoder opens it.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
rtl_test -t often exits non-zero after finding a device (e.g.
"No E4000 tuner found, aborting" with R820T tuners). The return
code fallback was firing even when the "Found N device(s)" success
message had already been matched. Track device_found separately
and only use return code as fallback when no success was seen.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The success check ('Found' in line and 'device' in line) matched
"No supported devices found" since both keywords appear. Add a
pre-check for negative device messages, a return code fallback,
and a clearer error message.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move adsb_active_device/sdr_type assignment to immediately after
claim_sdr_device so stop_adsb() can always release the device, even
during startup. Sync sdr_type_str after SDRType fallback to prevent
claim/release key mismatch. Clear active device on all error paths.
Replace blind 3s sleep for dump1090 readiness with port-polling loop
(100ms intervals, 3s max). Replace subprocess.run() in rtl_test probe
with Popen + select-based early termination on success/error detection.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The -D flag is only available in newer rtl_fm builds. Docker and distro
packages use the older -E direct / -E direct2 flags instead, which are
universally supported.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Enable direct sampling (-D 2) for RTL-SDR at HF frequencies below 24 MHz
so rtl_fm can actually receive CW signals. Add startup health check to
detect immediate rtl_fm failures. Push stopped status event from decoder
thread on EOF so the frontend auto-resets. Add frequency placeholder and
help text. Fix stop button silently swallowing errors.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace hardcoded "rtl_fm" references in wefax.py with the actual SDR
tool name so error messages correctly show "rx_fm" for non-RTL devices.
Use get_tool_path('rx_fm') in all SoapySDR command builders to match
the pattern already used for rx_sdr.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add pre-flight check for I/Q capture binary before spawning process
- Capture stderr from I/Q process for better error diagnostics
- Sync effective span value back to UI when backend adjusts it
- Use get_tool_path('rx_sdr') in Airspy, HackRF, LimeSDR, and SDRPlay
command builders to support custom install locations
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add .gitignore entry for data/subghz/captures/ to prevent large
IQ recording files from being committed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When an external process (or stale handle from a crash) holds an SDR
device, claim_sdr_device() registry check passes but rtl_fm fails with
usb_claim_interface error -6. This adds a quick rtl_test probe inside
claim_sdr_device() so all modes get a clear error message before the
decoder pipeline is launched.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the batch rtl_power SSE pipeline with continuous I/Q streaming
via WebSocket for smooth ~25fps waterfall display. The server captures
raw I/Q samples (rtl_sdr/rx_sdr), computes Hann-windowed FFT, and
sends compact binary frames (1035 bytes vs ~15KB JSON, 93% reduction).
Client falls back to existing SSE path if WebSocket is unavailable.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reverts IQ pipeline and removes syncWaterfallToFrequency calls from
pager, sensor, rtlamr, DMR, SSTV, and SSTV general modes. Waterfall
is now exclusive to listening post mode.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace rtl_fm/rtl_433 with rtl_sdr for raw IQ capture when available,
enabling a Python IQ processor to compute FFT for the waterfall while
simultaneously feeding decoded data to multimon-ng (pager) or rtl_433
(sensor). Falls back to the legacy pipeline when rtl_sdr is unavailable.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add /devices/status endpoint showing which SDR is in use and by what mode
- Add real-time status panel on main dashboard with 5s auto-refresh
- Add Bias-T toggle to ADS-B dashboard with localStorage persistence
- Auto-detect correct dump1090 bias-t flag (--enable-biast vs unsupported)
- Standardize SDR device labels across all pages
Closes#102
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Set DYLD_LIBRARY_PATH and SOAPY_SDR_ROOT environment variables when
running SoapySDRUtil on macOS so Homebrew-installed modules (HackRF,
LimeSDR, etc.) are properly detected.
Fixes#77
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix bias-t option in rtl_433 for RTL-SDR and HackRF:
- rtl_433's -T flag is for timeout, not bias-t
- RTL-SDR: Use :biast=1 suffix on device string
- HackRF: Use bias_t=1 in SoapySDR device string
- Add "Listen (FM/AM)" buttons to TSCM RF signal details
- Switches to Listening Post mode and tunes to frequency
- Fix device detail header padding to prevent protocol badge
overlapping with close button
Adds support for SDRPlay RSP devices (RSPdx, RSP1A, RSPduo, etc.)
through the SoapySDR interface. Closes#44.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Same fix as build_fm_demod_command() - the parameter was being
passed but not defined in the method signatures.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The bias_t parameter was being passed to build_fm_demod_command()
but wasn't defined in the method signatures, causing an unexpected
keyword argument error.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously, RTL-SDR devices from SoapySDR were unconditionally skipped,
even if native rtl_test wasn't available. Now:
- Native detection runs first for RTL-SDR and HackRF
- SoapySDR only skips device types that were already found natively
- If native tools aren't available, SoapySDR detection is used as fallback
This fixes the issue where users with only SoapySDR installed couldn't
see their RTL-SDR or HackRF devices.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Airspy support:
- Add AIRSPY to SDRType enum and driver mappings
- Create AirspyCommandBuilder using SoapySDR tools (rx_fm, readsb, rtl_433)
- Register in SDRFactory and add to hardware type dropdown
- Supports Airspy R2/Mini (24MHz-1.8GHz) and HF+ devices
GPS coordinate persistence:
- Save observer location to localStorage when manually entered or via geolocation
- Restore saved coordinates on page load in both index.html and adsb_dashboard.html
- Coordinates are shared between both pages
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Features:
- Add rtl_tcp support for pager and sensor decoding
- Connect to remote RTL-SDR via rtl_tcp server
- New UI toggle and host:port inputs in sidebar
- Supports rtl_fm and rtl_433 with remote devices
- Add remote dump1090 support for ADS-B tracking
- Connect to dump1090 SBS output on remote machine
- New "Remote" checkbox with host:port in ADS-B dashboard
Backend changes:
- Add rtl_tcp_host/port fields to SDRDevice dataclass
- Add is_network property for detecting remote devices
- Update RTLSDRCommandBuilder to use rtl_tcp:host:port format
- Add create_network_device() to SDRFactory
- Add validate_rtl_tcp_host/port validation functions
- Update pager, sensor, and adsb routes to accept remote params
Note: dump1090 doesn't support rtl_tcp directly - use remote
dump1090's SBS output (port 30003) for remote ADS-B tracking.
- Add GPS dongle support with NMEA parsing (utils/gps.py, routes/gps.py)
- Add GPS device selector to ADS-B and Satellite observer location sections
- Add GPS dongle option to ADS-B dashboard
- Fix Python 3.7/3.8 compatibility by adding 'from __future__ import annotations'
to all SDR module files (fixes TypeError: 'type' object is not subscriptable)
- Add pyserial to requirements.txt
- Update README with GPS dongle documentation and troubleshooting
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>