- Add authenticated client fixture to test_weather_sat_routes.py so
require_login() before_request doesn't redirect test clients to /login
- Save timer mock references before disable()/skip_pass() clear _timer = None
- Patch app.claim_sdr_device to return None in execute_capture and
scheduling cycle tests to avoid real USB hardware probing in CI
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When pip installs flask-sock into the venv, it finds simple-websocket
already satisfied in ~/.local (user site-packages from a prior install)
and skips installing it into the venv. The venv Python cannot import from
~/.local (user site-packages are disabled in venvs), so flask_sock's
top-level "from simple_websocket import Server" raises ImportError, and
all WebSocket features are silently disabled.
Fix: explicitly list simple-websocket>=0.5.1 as an install target in
setup.sh and requirements.txt so pip installs it into the venv
regardless of what is already present in user or system site-packages.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add immediate keepalive to /adsb/stream generator so the Werkzeug dev
server flushes response headers immediately on tracking start, preventing
the 30-second delay before the aircraft map begins receiving data
- Same fix for /controller/stream/all used by the ADSB dashboard in agent mode
- Widen WebSocket init exception guards in app.py from ImportError to
Exception so any startup failure (e.g. RuntimeError from flask-sock on
an unsupported WSGI server) is caught instead of propagating
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Werkzeug's dev server buffers SSE response headers until the first body byte
is written. With keepalive_interval=30s, opening two SSE connections on
DOMContentLoaded (satellite stream + new ground station stream) meant the
browser waited 30 seconds before receiving any response bytes from either
connection. Browsers keep their loading indicator active while connections are
pending, causing the satellite dashboard to appear stuck loading.
Fix: yield an immediate keepalive at the start of sse_stream_fanout so every
SSE endpoint flushes headers + first data to the browser instantly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- OBSERVATION PROFILES section with list of configured satellites
- + ADD button opens inline form pre-filled from currently selected satellite
and SatNOGS transmitter data (frequency, decoder type auto-detected)
- EDIT / ✕ buttons per profile row
- Form fields: frequency, decoder (FM/AFSK/GMSK/BPSK/IQ-only), min elevation,
gain, record IQ checkbox
- UPCOMING PASSES section below profiles with friendlier empty-state message
- gsOnSatelliteChange hook updates form when satellite dropdown changes
- CSS for .gs-form-row, .gs-profile-item, .gs-form-label
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add auto-refresh on window focus so the dropdown updates automatically when
switching back from the sidebar, plus a manual ↺ refresh button next to the
dropdown. Also preserves the current selection across refreshes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add --no-cache-dir and --timeout 120 to all pip calls to prevent hanging
on corrupt/stale pip HTTP cache (cachecontrol .pyc issue)
- Replace silent python -c import verification with pip show to avoid
import-time side effects hanging the installer
- Switch optional packages to --only-binary :all: to skip source compilation
on Python versions without pre-built wheels (prevents gevent/numpy hangs)
- Warn early when Python 3.13+ is detected that some packages may be skipped
- Add ground track caching with 30-minute TTL to satellite route
- Add live satellite position tracker background thread via SSE fanout
- Add satellite_predict, satellite_telemetry, and satnogs utilities
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
On first boot, unattended-upgrades or apt-daily often holds the dpkg
lock, causing silent hangs with no user feedback. Added wait_for_apt_lock()
that polls for up to 120s with status messages, called before apt-get
update and inside apt_try_install_any.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Dispatch observer-location-changed event from settings manager and
listen for it in APRS mode so manual location saves propagate to
the map and distance calculations. Also refresh ObserverLocation in
initAprsMap() to catch changes between page load and first map use.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The core pip install was suppressing errors with 2>/dev/null, and the
verification check was finding packages in ~/.local/site-packages
instead of the venv. When run with sudo, ~/.local isn't visible,
causing the flask-compress warning.
- Remove --quiet and stderr suppression from core package install
- Use python -s flag in verification to ignore user site-packages
- Update health check to also verify flask-compress and flask-wtf
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
These packages were in requirements.txt but missing from the explicit
pip install commands in setup.sh, causing warnings on fresh installs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pass DEFAULT_LATITUDE/DEFAULT_LONGITUDE from config to both standalone
dashboard templates so observer-location.js uses .env values instead of
falling back to hardcoded London coordinates on first visit.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The APRS map initialisation only checked for a live GPS fix, falling
back to the centre of the US (39.8N, 98.6W) when none was available.
It never read the observer position configured in .env via
INTERCEPT_DEFAULT_LAT / INTERCEPT_DEFAULT_LON.
Seed aprsUserLocation from ObserverLocation.getShared() (or the
Jinja-injected defaults) on page load so the map centres on the
user's configured position and distance calculations work without GPS.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The APRS stop endpoint terminated two processes sequentially (up to 4s
with PROCESS_TERMINATE_TIMEOUT=2s each) while the frontend fetch timed
out at 2.2s. This caused console errors and left the SDR device claimed
in the registry until termination finished, making the status panel show
the device as active after the user clicked stop.
Fix: release the SDR device from the registry immediately inside the
lock, clear process references, then terminate processes in a background
thread so the HTTP response returns instantly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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>
HOST_NAME_MAX is Linux-specific and undefined on macOS, causing 3
compile errors in acarsdec.c. Now patched with #define HOST_NAME_MAX 255
before building. Also fixed deprecated -Ofast flag on all macOS archs
(was only patched for arm64).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
timeout (GNU coreutils) is not available on macOS, causing rtl_test to
silently fail and report no SDR device found. Now tries timeout, then
gtimeout (Homebrew coreutils), then falls back to background process
with manual kill.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
.logo span { display: inline } in dashboard CSS had specificity (0,1,1),
overriding .brand-i { display: inline-block } at (0,1,0). Inline elements
ignore width/height, so the SVG rendered at intrinsic size (~80px tall).
Added .logo .brand-i selector at (0,2,0) to retain inline-block display.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
get_setting() now catches sqlite3.OperationalError and returns the
default value. Previously, an inaccessible database (e.g. root-owned
instance/ from sudo) caused inject_offline_settings to crash every
page render with 500 Internal Server Error.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
read_env_var() grep pipeline failed under set -euo pipefail when .env
existed but didn't contain the requested key. grep returned 1 (no match),
pipefail propagated it, and set -e killed the script.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
On x86_64, explicitly pass -march=x86-64 so the compiler emits only
baseline instructions. SatDump's SIMD plugins still compile with their
own per-target flags and do runtime CPU detection, so AVX2 acceleration
remains available on capable hardware. ARM builds are unaffected.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The data/ directory became a Python package (oui.py, patterns.py, satellites.py)
in v2.26.0, but .dockerignore still blanket-excluded it as runtime data.
This caused ModuleNotFoundError: No module named 'data.oui' on container startup.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Apply the branded SVG "i" glyph to nav logo, hero heading, and footer
on the GitHub Pages landing page, matching the main app's branding.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Patch release for #186 — default ADMIN_PASSWORD now matches README,
and credential changes in config.py sync to DB on restart.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The default ADMIN_PASSWORD was an empty string, triggering random
password generation on first run — contradicting the README which
states admin:admin. Additionally, editing config.py after first run
had no effect since init_db() only seeded users on an empty table.
- Change default ADMIN_PASSWORD from '' to 'admin'
- Sync admin credentials from config on every startup so that
changes to config.py or env vars take effect without wiping the DB
Fixes#186
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>
Scale down the branded "i" to sit as a proper lowercase glyph beside
the uppercase "NTERCEPT" text, with the stem bottom on the baseline
and the dot just above cap height.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Scale the branded "i" glyph proportionally to each SVG's font size
(scale 0.94 for 64px, 1.24 for 84px) and align the stem bottom to
the text baseline so the glyph sits naturally beside "NTERCEPT".
Also adds brand-pack.html (logos, profiles, banners, stickers, release
templates) and wallpapers.html (12 themes, 8 resolutions, PNG export).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the plain cyan text "i" with the logo-style SVG glyph (green dot
+ cyan stem/bars) in both the README banner and social preview images.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The CSS ::after dot positioning was unreliable across fonts and sizes.
Switch to an inline SVG of the "i" glyph (green dot + cyan stem/bars)
extracted from the logo — renders pixel-perfect at any size.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The dotless i (ı) wasn't rendering in all fonts. Switch to a regular "i"
with the green dot CSS overlay positioned on top of the native dot.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Matches the logo icon — the "i" in iNTERCEPT now renders with a cyan
letter and green dot via CSS, consistent across the main header, welcome
card, dashboard headers, help modal, settings modal, and all popout pages.
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>