Backend support for these SDR types (SDRFactory/SDRType) was added in
prior commits, but the frontend hardware type selector was never
updated, so detected devices of these types could never be selected
and always showed as idle.
Adds two thin wrappers around pip:
- _pip_run: used for pip upgrade and core installs. Filters the
send2trash malformed-extras WARNING that fires on every pip invocation
on systems where that package has broken metadata, while keeping all
real output (download progress, install summaries, errors).
- _pip_optional: used for the optional-packages loop. Runs pip with -q
so "Requirement already satisfied" walls are suppressed on re-runs,
and only shows output (filtered) when a package actually fails.
Install step now uses --ignore-installed for core packages so pip always
puts them in the venv, even when they already exist in ~/.local (user
site-packages). Without this, pip skips the venv install and the health
check fails because it runs with 'python -s' which excludes ~/.local.
Health check now attempts a silent auto-fix before reporting failure,
and if the fix also fails, shows the exact command to resolve it rather
than a bare error message.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New GET /adsb/history/playback endpoint returns time-bucketed snapshots
(one position per aircraft per N-second bucket) via a SQL window function
- Playback tab added to adsb_history.html: Leaflet map with animated
aircraft markers, play/pause, 1x–20x speed, scrubber, and time display
- Configurable window (15 min – 24 h) and bucket step (10 s – 5 min)
- Requires the history Docker profile or INTERCEPT_ADSB_HISTORY_ENABLED=true
- Bump version to 2.32.0
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- BladeRF 2.0 micro / x40 / x115 detected via SoapyBladeRF (47 MHz–6 GHz,
TX capable, gain 0–66 dB)
- HydraSDR RFOne detected via SoapyHydraSDR (24 MHz–1800 MHz, RX only,
linear gain 0–21)
- Both follow the established SoapySDR command-builder pattern and support
FM demod, ADS-B, ISM, AIS, and I/Q capture
- Bump version to 2.31.0
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- GET /aprs/export?format=json|csv downloads all tracked APRS stations
- USRP (Ettus N200/B200/B210) detected via SoapyUHD and supported across
all signal modes (FM demod, ADS-B, ISM, AIS, I/Q capture)
- Optional MQTT publisher broadcasts decoded events from every module;
enabled by setting INTERCEPT_MQTT_BROKER, disabled by default
- paho-mqtt added to requirements.txt (optional dep)
- .gitignore: add *.kismet, aircraft_db.json/meta, SoapySDR/
- Bump version to 2.30.0
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The feed column (.pdir-feed-col) was left as a flex sibling with flex:1
while only its child #output was hidden, causing the sensor dashboard to
occupy ~50% width. Hide/restore the column itself in applyViewState().
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Cover TSCM sweep metadata/cleared-devices/ignore-list/report category
filter features and the ADS-B Postgres password fix. Updates the
in-app dashboard changelog (config.py), CHANGELOG.md, and the GitHub
Pages TSCM feature description.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
setup.sh wrote/read the local Postgres wizard password under
INTERCEPT_ADSB_DB_PASS, but config.py and docker-compose.yml expect
INTERCEPT_ADSB_DB_PASSWORD — any custom password set via the wizard
was silently ignored. Also make docker-compose actually honor
INTERCEPT_ADSB_DB_PASSWORD instead of hardcoding "intercept" for both
the app and Postgres containers, and correct a misleading .env.example
comment about admin password auto-generation.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
First-time run of ruff-format via pre-commit hook normalises quote
style, trailing commas, and whitespace across 188 Python files.
No logic changes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fixes 4 linting errors that were failing CI:
- Remove unused `shutil` import from bin/import_artemis.py
- Sort/format import blocks in routes/signalid.py and
tests/test_signalid_match_route.py
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Four new features requested by TSCM users:
- Site/Location and Examiner name fields appear at the top of the
sweep config; both are embedded in HTML and PDF/annex reports.
- Mark Cleared button on every live device item dims the entry with a
CLEARED badge and excludes it from generated reports. Cleared state
resets at the start of each new sweep. The report executive summary
shows a count of cleared devices.
- Ignore List stores the examiner's own devices persistently in
localStorage. Ignored devices are filtered from the live display and
all report exports. An Ignore button appears on every device item;
the sidebar Examiner Ignore List section shows current entries with
per-item removal and a clear-all button.
- Site/examiner params forwarded to PDF and annex server routes so
the text report header includes them.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove docs/plans/, docs/specs/, and docs/design/ from tracking and
add them to .gitignore. History also purged of instance/intercept.db
(user auth DB accidentally committed in January).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Users can now choose which risk categories to include in generated
reports — High Interest, Needs Review, and Informational — via three
checkboxes that appear after a sweep completes. Applies to the HTML
report, PDF, JSON annex, and CSV annex. Defaults to High Interest +
Needs Review (Informational excluded) to keep reports concise.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Bump version to 2.28.0, update changelog, and add Signal ID to the
GitHub Pages feature listing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Imports 574 signals from AresValley/Artemis-DB (v73) into data/signals.json,
growing the bundled offline database from 20 to 594 signals. Adds
bin/import_artemis.py to refresh the database when Artemis-DB releases updates.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Added signal-id-modal.js script to base_dashboard.html (nav button was silent on dashboard pages)
- Added else branch to clear "Searching…" status when zero matches returned
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Removed unused `import pytest` from line 5. The file uses no pytest
fixtures, marks, or raises, making this import dead code and causing
an F401 lint violation.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implements lazy-cached load_signals() and pure match_signals() with
frequency/bandwidth/modulation/region scoring for the signal ID feature.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Create data/signals.json with 20 seed signals (FM broadcast, airband,
ISM bands, maritime VHF, AIS, ACARS, ADS-B, POCSAG, cellular, WiFi/BT,
amateur radio, DAB, PMR446, FRS/GMRS, NOAA weather radio). Point
frequencies adjusted to ±500 Hz windows; fixed-value bandwidth_ranges
widened to strict min < max windows required by schema.
Add tests/test_signals_json.py with 9 schema validation tests covering
id uniqueness, required string fields, frequency range validity,
bandwidth range, modulation casing, categories, region codes, and
sigidwiki URLs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix _pollUntilConnected overwriting real error with generic timeout
message — stop polling once backend reaches error state
- Fix battery % calculation: was battery_mv/42 (71% at empty); now
(battery_mv-3000)/12 for a proper 0-100% LiPo curve
- Improve auto-detect: scan available ports rather than blindly using
/dev/ttyUSB0; update label to show fallback so users know what to expect
- Add port refresh button (↻) — previously required switching modes
and back if device was plugged in after panel opened
- Add baud rate selector to serial config strip (default 115200,
options up to 921600) and wire it through to the connect request
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The body > *:not(#bg-canvas) rule carried ID-level specificity (1,0,1)
which overrode .lightbox's position:fixed and z-index:1000, leaving the
overlay stuck in document flow and invisible. Excluding #lightbox from
that rule lets the lightbox CSS take effect correctly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Reverts the <a target="_blank"> wrappers added previously — those were
opening images in a new tab and interfering with the existing lightbox.
Images now click-to-expand via the overlay lightbox as intended.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The system metrics collector daemon thread ran vcgencmd via subprocess
every 3s even on non-Pi hosts, where it always failed — and leaked
Popen calls into any later test mocking subprocess (intermittent
test_weather_sat_decoder failure in full-suite runs).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
confidence_boost and the manufacturer-data-length signal applied without
any identifying indicator match, giving every device a phantom AirTag
baseline (a 22+ byte payload from any vendor scored 0.30 and was flagged
as an AirTag). Both now require a matched indicator, mirroring the
score>0 gating already used in _check_generic_tracker_indicators.
Name-pattern weight raised 0.15 -> 0.30 so a device advertising a known
tracker name yields a LOW-confidence detection, consistent with the
TSCM BLE scanner's name-only detection and the engine docstring.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Bluetooth aggregator/api/heuristics tests updated to current behavior;
deauth detector integration test rewritten to exercise the tracker and
alert path directly instead of patching __globals__ (read-only on
Python 3.14).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Matches the agent's established try/except import convention; the
agent now starts and reports empty capabilities when utils.capabilities
(or its dependency chain) is unavailable.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Caught by test_dependency_files_integrity, which had been buried in the
never-reached tail of the test suite.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Phase 5 decision gate of the architecture refactor plan: dedicated
dashboard pages are the pattern for map-centric modes; APRS and
Meshtastic migrations to follow under separate plans.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
detect_mode_availability accepts a pre-computed dep_status so the agent
probes once; interface and fallback paths now have content-level tests.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
utils/capabilities.py now owns interface detection and mode
availability; the agent delegates via detect_interfaces() and
detect_mode_availability(). The agent keeps config gating and
tool_details population to preserve its result shape exactly.
The moved fallback path uses utils.dependencies.check_tool instead of
the agent's old shutil.which fallback; check_tool also searches
Homebrew paths, a strict superset (strictly better detection).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A failing mode init now logs instead of aborting the remainder of
switchMode (deliberate hardening; previously an exception skipped
title/visuals updates).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
requests/urllib3 collapse dot segments before sending, so traversal
like wifi/v2/../../x escaped the prefix allowlist. Only canonical
paths are now forwarded; regression tests included.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Removes the one-off proxy_wifi_clients route and the dead getApiBase()
helper; the allowlisted passthrough now covers agent wifi traffic.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Removes the agent's own CelesTrak download (the source of the stray
gp.php artifact) — the store is now the single TLE source for app and
agent alike.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Both silently fell back to static bundled TLEs after the removal of
routes.satellite._tle_cache.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>