mirror of
https://github.com/smittix/intercept.git
synced 2026-06-13 08:13:32 -07:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7ed039564b | |||
| 8adfb3a40a | |||
| 9a9b1e9856 | |||
| 8aeb52380e | |||
| 05141b9a1b | |||
| dc0850d339 | |||
| 2bbf896e7c | |||
| faf57741a1 | |||
| fd7d01fc7d | |||
| 8ef9dca6ee |
@@ -2,6 +2,69 @@
|
||||
|
||||
All notable changes to iNTERCEPT will be documented in this file.
|
||||
|
||||
## [2.26.11] - 2026-03-14
|
||||
|
||||
### Fixed
|
||||
- **APRS map ignores configured observer position** — The APRS map always fell back to the centre of the US (39.8°N, 98.6°W) when no live GPS fix was available, ignoring the observer position configured in `.env` (`INTERCEPT_DEFAULT_LAT` / `INTERCEPT_DEFAULT_LON`). Now seeds the APRS user location from the shared observer location on page load, so the map centres correctly and distance calculations work. (#193)
|
||||
|
||||
---
|
||||
|
||||
## [2.26.10] - 2026-03-14
|
||||
|
||||
### Fixed
|
||||
- **APRS stop timeout and inverted SDR device status** — The APRS stop endpoint terminated two processes sequentially (up to 4s) while the frontend timed out at 2.2s, causing console errors and the SDR status panel to show stale state (active after stop, idle during use). Now releases the SDR device immediately and terminates processes in a background thread so the response returns instantly. (#194)
|
||||
|
||||
---
|
||||
|
||||
## [2.26.9] - 2026-03-14
|
||||
|
||||
### Fixed
|
||||
- **ADS-B bias-t support for RTL-SDR Blog V4** — When dump1090 lacks native `--enable-biast` support, the system now falls back to `rtl_biast` (from 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. (#195)
|
||||
|
||||
---
|
||||
|
||||
## [2.26.8] - 2026-03-14
|
||||
|
||||
### Fixed
|
||||
- **acarsdec build failure on macOS** — `HOST_NAME_MAX` is Linux-specific (`<limits.h>`) 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 warning on all macOS architectures (was only patched for arm64). (#187)
|
||||
|
||||
---
|
||||
|
||||
## [2.26.7] - 2026-03-14
|
||||
|
||||
### Fixed
|
||||
- **Health check SDR detection on macOS** — `timeout` (GNU coreutils) is not available on macOS, causing `rtl_test` to silently fail and report "No RTL-SDR device found" even when one is connected. Now tries `timeout`, then `gtimeout` (Homebrew coreutils), then falls back to a background process with manual kill. (#188)
|
||||
|
||||
---
|
||||
|
||||
## [2.26.6] - 2026-03-14
|
||||
|
||||
### Fixed
|
||||
- **Oversized branded 'i' logo on dashboards** — `.logo span { display: inline }` in dashboard CSS had higher specificity (0,1,1) than `.brand-i { display: inline-block }` (0,1,0), forcing the branded "i" SVG to render as inline which ignores width/height. Added `.logo .brand-i` selector (0,2,0) to retain `inline-block` display. (#189)
|
||||
|
||||
---
|
||||
|
||||
## [2.26.5] - 2026-03-14
|
||||
|
||||
### Fixed
|
||||
- **Database errors crash entire UI** — `get_setting()` now catches `sqlite3.OperationalError` and returns the default value instead of propagating the exception. Previously, if the database was inaccessible (e.g. root-owned `instance/` directory from running with `sudo`), the `inject_offline_settings` context processor would crash every page render with a 500 Internal Server Error. (#190)
|
||||
|
||||
---
|
||||
|
||||
## [2.26.4] - 2026-03-14
|
||||
|
||||
### Fixed
|
||||
- **Environment Configurator crash** — `read_env_var()` crashed with "Setup failed at line 2333" when `.env` existed but didn't contain the variable being looked up. `grep` returned exit code 1 (no match), which `pipefail` propagated and `set -e` turned into a fatal error. Fixed by appending `|| true` to the pipeline. (#191)
|
||||
|
||||
---
|
||||
|
||||
## [2.26.3] - 2026-03-13
|
||||
|
||||
### Fixed
|
||||
- **SatDump AVX2 crash** — SatDump now compiles with `-march=x86-64` on x86_64 platforms (Docker and `setup.sh`), preventing "Illegal instruction" crashes on CPUs without AVX2. SIMD plugins still use runtime detection for acceleration on capable hardware. (#185)
|
||||
|
||||
---
|
||||
|
||||
## [2.26.2] - 2026-03-13
|
||||
|
||||
### Fixed
|
||||
|
||||
+4
-1
@@ -130,7 +130,10 @@ RUN cd /tmp \
|
||||
&& git clone --depth 1 --branch 1.2.2 https://github.com/SatDump/SatDump.git \
|
||||
&& cd SatDump \
|
||||
&& mkdir build && cd build \
|
||||
&& cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_GUI=OFF -DCMAKE_INSTALL_LIBDIR=lib .. \
|
||||
&& ARCH_FLAGS=""; if [ "$(uname -m)" = "x86_64" ]; then ARCH_FLAGS="-march=x86-64"; fi \
|
||||
&& cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_GUI=OFF -DCMAKE_INSTALL_LIBDIR=lib \
|
||||
-DCMAKE_C_FLAGS="$ARCH_FLAGS" \
|
||||
-DCMAKE_CXX_FLAGS="$ARCH_FLAGS" .. \
|
||||
&& make -j$(nproc) \
|
||||
&& make install \
|
||||
&& ldconfig \
|
||||
|
||||
@@ -7,10 +7,59 @@ import os
|
||||
import sys
|
||||
|
||||
# Application version
|
||||
VERSION = "2.26.2"
|
||||
VERSION = "2.26.11"
|
||||
|
||||
# Changelog - latest release notes (shown on welcome screen)
|
||||
CHANGELOG = [
|
||||
{
|
||||
"version": "2.26.11",
|
||||
"date": "March 2026",
|
||||
"highlights": [
|
||||
"APRS map now centres on configured observer position from .env",
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "2.26.8",
|
||||
"date": "March 2026",
|
||||
"highlights": [
|
||||
"Fix acarsdec build failure on macOS (HOST_NAME_MAX undefined)",
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "2.26.7",
|
||||
"date": "March 2026",
|
||||
"highlights": [
|
||||
"Fix health check SDR detection on macOS (timeout command not available)",
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "2.26.6",
|
||||
"date": "March 2026",
|
||||
"highlights": [
|
||||
"Fix oversized branded 'i' logo on Aircraft & Vessel dashboards",
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "2.26.5",
|
||||
"date": "March 2026",
|
||||
"highlights": [
|
||||
"Fix database errors crashing the entire UI — pages now degrade gracefully",
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "2.26.4",
|
||||
"date": "March 2026",
|
||||
"highlights": [
|
||||
"Fix Environment Configurator crash when .env exists but variable is missing",
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "2.26.3",
|
||||
"date": "March 2026",
|
||||
"highlights": [
|
||||
"Fix SatDump AVX2 crash on older CPUs — build now targets baseline x86-64",
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "2.26.2",
|
||||
"date": "March 2026",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "intercept"
|
||||
version = "2.26.2"
|
||||
version = "2.26.11"
|
||||
description = "Signal Intelligence Platform - Pager/433MHz/ADS-B/Satellite/WiFi/Bluetooth"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.9"
|
||||
|
||||
+30
-16
@@ -1924,7 +1924,13 @@ def start_aprs() -> Response:
|
||||
|
||||
@aprs_bp.route('/stop', methods=['POST'])
|
||||
def stop_aprs() -> Response:
|
||||
"""Stop APRS decoder."""
|
||||
"""Stop APRS decoder.
|
||||
|
||||
Releases the SDR device immediately so the status panel updates
|
||||
without waiting for process termination. Process cleanup runs in a
|
||||
background thread to avoid blocking the HTTP response (which caused
|
||||
frontend timeout errors when two processes each took up to 2s to die).
|
||||
"""
|
||||
global aprs_active_device, aprs_active_sdr_type
|
||||
|
||||
with app_module.aprs_lock:
|
||||
@@ -1939,6 +1945,28 @@ def stop_aprs() -> Response:
|
||||
if not processes_to_stop:
|
||||
return api_error('APRS decoder not running', 400)
|
||||
|
||||
# Release SDR device immediately so status panel reflects the
|
||||
# change without waiting for process termination.
|
||||
if aprs_active_device is not None:
|
||||
app_module.release_sdr_device(aprs_active_device, aprs_active_sdr_type or 'rtlsdr')
|
||||
aprs_active_device = None
|
||||
aprs_active_sdr_type = None
|
||||
|
||||
# Capture refs to clear before releasing the lock
|
||||
master_fd = getattr(app_module, 'aprs_master_fd', None)
|
||||
app_module.aprs_process = None
|
||||
if hasattr(app_module, 'aprs_rtl_process'):
|
||||
app_module.aprs_rtl_process = None
|
||||
app_module.aprs_master_fd = None
|
||||
|
||||
# Terminate processes in background so the response returns fast.
|
||||
# Each proc.wait() can block up to PROCESS_TERMINATE_TIMEOUT (2s),
|
||||
# which previously caused the frontend 2200ms fetch to abort.
|
||||
def _cleanup():
|
||||
# Close PTY master fd first — this unblocks the stream thread
|
||||
if master_fd is not None:
|
||||
with contextlib.suppress(OSError):
|
||||
os.close(master_fd)
|
||||
for proc in processes_to_stop:
|
||||
try:
|
||||
proc.terminate()
|
||||
@@ -1948,21 +1976,7 @@ def stop_aprs() -> Response:
|
||||
except Exception as e:
|
||||
logger.error(f"Error stopping APRS process: {e}")
|
||||
|
||||
# Close PTY master fd
|
||||
if hasattr(app_module, 'aprs_master_fd') and app_module.aprs_master_fd is not None:
|
||||
with contextlib.suppress(OSError):
|
||||
os.close(app_module.aprs_master_fd)
|
||||
app_module.aprs_master_fd = None
|
||||
|
||||
app_module.aprs_process = None
|
||||
if hasattr(app_module, 'aprs_rtl_process'):
|
||||
app_module.aprs_rtl_process = None
|
||||
|
||||
# Release SDR device
|
||||
if aprs_active_device is not None:
|
||||
app_module.release_sdr_device(aprs_active_device, aprs_active_sdr_type or 'rtlsdr')
|
||||
aprs_active_device = None
|
||||
aprs_active_sdr_type = None
|
||||
threading.Thread(target=_cleanup, daemon=True).start()
|
||||
|
||||
return jsonify({'status': 'stopped'})
|
||||
|
||||
|
||||
@@ -174,7 +174,7 @@ read_env_var() {
|
||||
local fallback="${2:-}"
|
||||
if [[ -f "$SCRIPT_DIR/.env" ]]; then
|
||||
local val
|
||||
val=$(grep -E "^${key}=" "$SCRIPT_DIR/.env" 2>/dev/null | tail -1 | cut -d'=' -f2-)
|
||||
val=$(grep -E "^${key}=" "$SCRIPT_DIR/.env" 2>/dev/null | tail -1 | cut -d'=' -f2- || true)
|
||||
if [[ -n "$val" ]]; then
|
||||
# Strip surrounding quotes
|
||||
val="${val#\"}"
|
||||
@@ -751,9 +751,26 @@ install_acarsdec_from_source_macos() {
|
||||
|
||||
cd "$tmp_dir/acarsdec"
|
||||
|
||||
# Replace deprecated -Ofast (all macOS, not just arm64)
|
||||
if grep -q '\-Ofast' CMakeLists.txt 2>/dev/null; then
|
||||
sed -i '' 's/-Ofast/-O3 -ffast-math/g' CMakeLists.txt
|
||||
info "Patched deprecated -Ofast flag"
|
||||
fi
|
||||
|
||||
# macOS doesn't have -march=native on arm64
|
||||
if [[ "$(uname -m)" == "arm64" ]]; then
|
||||
sed -i '' 's/-Ofast -march=native/-O3 -ffast-math/g' CMakeLists.txt
|
||||
info "Patched compiler flags for Apple Silicon (arm64)"
|
||||
sed -i '' 's/ -march=native//g' CMakeLists.txt
|
||||
info "Removed -march=native for Apple Silicon"
|
||||
fi
|
||||
|
||||
# HOST_NAME_MAX is Linux-specific; macOS uses _POSIX_HOST_NAME_MAX
|
||||
if grep -q 'HOST_NAME_MAX' acarsdec.c 2>/dev/null; then
|
||||
sed -i '' '1i\
|
||||
#ifndef HOST_NAME_MAX\
|
||||
#define HOST_NAME_MAX 255\
|
||||
#endif
|
||||
' acarsdec.c
|
||||
info "Patched HOST_NAME_MAX for macOS compatibility"
|
||||
fi
|
||||
|
||||
if grep -q 'pthread_tryjoin_np' rtl.c 2>/dev/null; then
|
||||
@@ -957,8 +974,14 @@ install_satdump_from_source_debian() {
|
||||
) &
|
||||
progress_pid=$!
|
||||
|
||||
local arch_flags=""
|
||||
if [[ "$(uname -m)" == "x86_64" ]]; then
|
||||
arch_flags="-march=x86-64"
|
||||
fi
|
||||
|
||||
if cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_GUI=OFF -DCMAKE_INSTALL_LIBDIR=lib \
|
||||
-DCMAKE_CXX_FLAGS="-Wno-template-body" .. >"$build_log" 2>&1 \
|
||||
-DCMAKE_C_FLAGS="$arch_flags" \
|
||||
-DCMAKE_CXX_FLAGS="$arch_flags -Wno-template-body" .. >"$build_log" 2>&1 \
|
||||
&& make -j "$(nproc)" >>"$build_log" 2>&1; then
|
||||
kill $progress_pid 2>/dev/null; wait $progress_pid 2>/dev/null
|
||||
$SUDO make install >/dev/null 2>&1
|
||||
@@ -1918,7 +1941,18 @@ do_health_check() {
|
||||
info "SDR device detection..."
|
||||
if cmd_exists rtl_test; then
|
||||
local rtl_output
|
||||
rtl_output=$(timeout 3 rtl_test -d 0 2>&1 || true)
|
||||
if cmd_exists timeout; then
|
||||
rtl_output=$(timeout 3 rtl_test -d 0 2>&1 || true)
|
||||
elif cmd_exists gtimeout; then
|
||||
rtl_output=$(gtimeout 3 rtl_test -d 0 2>&1 || true)
|
||||
else
|
||||
# No timeout command (common on macOS) — run with background kill
|
||||
rtl_test -d 0 > /tmp/.rtl_test_out 2>&1 & local rtl_pid=$!
|
||||
sleep 2
|
||||
kill "$rtl_pid" 2>/dev/null; wait "$rtl_pid" 2>/dev/null
|
||||
rtl_output=$(cat /tmp/.rtl_test_out 2>/dev/null || true)
|
||||
rm -f /tmp/.rtl_test_out
|
||||
fi
|
||||
if echo "$rtl_output" | grep -q "Found\|Using device"; then
|
||||
ok "RTL-SDR device detected"
|
||||
((pass++)) || true
|
||||
|
||||
@@ -88,8 +88,11 @@
|
||||
}
|
||||
|
||||
/* Branded "i" — inline SVG that matches the logo icon.
|
||||
Sized to 0.9em so it sits naturally alongside text at any font-size. */
|
||||
.brand-i {
|
||||
Sized to 0.9em so it sits naturally alongside text at any font-size.
|
||||
Uses .logo .brand-i (0,2,0) to beat .logo span (0,1,1) in dashboard CSS
|
||||
which otherwise forces display:inline and breaks width/height. */
|
||||
.brand-i,
|
||||
.logo .brand-i {
|
||||
display: inline-block;
|
||||
width: 0.55em;
|
||||
height: 0.9em;
|
||||
|
||||
+21
-1
@@ -9849,8 +9849,28 @@
|
||||
let aprsMeterCheckInterval = null;
|
||||
const APRS_METER_TIMEOUT = 5000; // 5 seconds for "no signal" state
|
||||
|
||||
// APRS user location (from GPS)
|
||||
// APRS user location (from GPS or shared observer location)
|
||||
let aprsUserLocation = { lat: null, lon: null };
|
||||
|
||||
// Seed from configured observer location so the map centres on the
|
||||
// user's position even without a live GPS fix.
|
||||
(function _seedAprsLocation() {
|
||||
if (typeof ObserverLocation !== 'undefined' && ObserverLocation.getShared) {
|
||||
const shared = ObserverLocation.getShared();
|
||||
if (shared && shared.lat && shared.lon) {
|
||||
aprsUserLocation.lat = shared.lat;
|
||||
aprsUserLocation.lon = shared.lon;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Fallback: read the Jinja-injected defaults directly
|
||||
const lat = window.INTERCEPT_DEFAULT_LAT;
|
||||
const lon = window.INTERCEPT_DEFAULT_LON;
|
||||
if (lat && lon && Number.isFinite(lat) && Number.isFinite(lon)) {
|
||||
aprsUserLocation.lat = lat;
|
||||
aprsUserLocation.lon = lon;
|
||||
}
|
||||
})();
|
||||
let aprsUserMarker = null;
|
||||
|
||||
// Calculate distance in miles using Haversine formula
|
||||
|
||||
+28
-24
@@ -661,32 +661,36 @@ def get_setting(key: str, default: Any = None) -> Any:
|
||||
Returns:
|
||||
Setting value (auto-converted from JSON for complex types)
|
||||
"""
|
||||
with get_db() as conn:
|
||||
cursor = conn.execute(
|
||||
'SELECT value, value_type FROM settings WHERE key = ?',
|
||||
(key,)
|
||||
)
|
||||
row = cursor.fetchone()
|
||||
try:
|
||||
with get_db() as conn:
|
||||
cursor = conn.execute(
|
||||
'SELECT value, value_type FROM settings WHERE key = ?',
|
||||
(key,)
|
||||
)
|
||||
row = cursor.fetchone()
|
||||
|
||||
if row is None:
|
||||
return default
|
||||
|
||||
value, value_type = row['value'], row['value_type']
|
||||
|
||||
# Convert based on type
|
||||
if value_type == 'json':
|
||||
try:
|
||||
return json.loads(value)
|
||||
except json.JSONDecodeError:
|
||||
if row is None:
|
||||
return default
|
||||
elif value_type == 'int':
|
||||
return int(value)
|
||||
elif value_type == 'float':
|
||||
return float(value)
|
||||
elif value_type == 'bool':
|
||||
return value.lower() in ('true', '1', 'yes')
|
||||
else:
|
||||
return value
|
||||
|
||||
value, value_type = row['value'], row['value_type']
|
||||
|
||||
# Convert based on type
|
||||
if value_type == 'json':
|
||||
try:
|
||||
return json.loads(value)
|
||||
except json.JSONDecodeError:
|
||||
return default
|
||||
elif value_type == 'int':
|
||||
return int(value)
|
||||
elif value_type == 'float':
|
||||
return float(value)
|
||||
elif value_type == 'bool':
|
||||
return value.lower() in ('true', '1', 'yes')
|
||||
else:
|
||||
return value
|
||||
except sqlite3.OperationalError:
|
||||
logger.warning("Database unavailable reading setting '%s', using default", key)
|
||||
return default
|
||||
|
||||
|
||||
def set_setting(key: str, value: Any) -> None:
|
||||
|
||||
+36
-4
@@ -46,6 +46,35 @@ def _rtl_tool_supports_bias_t(tool_path: str) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def enable_bias_t_via_rtl_biast(device_index: int = 0) -> bool:
|
||||
"""Enable bias-t power using rtl_biast (RTL-SDR Blog drivers).
|
||||
|
||||
Runs rtl_biast to set the bias-t register on the device, then exits.
|
||||
The setting persists across device opens until the device is reset.
|
||||
|
||||
Returns True if bias-t was enabled successfully.
|
||||
"""
|
||||
rtl_biast_path = get_tool_path('rtl_biast') or 'rtl_biast'
|
||||
try:
|
||||
result = subprocess.run(
|
||||
[rtl_biast_path, '-b', '1', '-d', str(device_index)],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=5
|
||||
)
|
||||
if result.returncode == 0:
|
||||
logger.info(f"Bias-t enabled via rtl_biast on device {device_index}")
|
||||
return True
|
||||
logger.warning(f"rtl_biast failed (exit {result.returncode}): {result.stderr.strip()}")
|
||||
return False
|
||||
except FileNotFoundError:
|
||||
logger.warning("rtl_biast not found — install RTL-SDR Blog drivers for bias-t support")
|
||||
return False
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to enable bias-t via rtl_biast: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def _get_dump1090_bias_t_flag(dump1090_path: str) -> str | None:
|
||||
"""Detect the correct bias-t flag for the installed dump1090 variant.
|
||||
|
||||
@@ -197,10 +226,13 @@ class RTLSDRCommandBuilder(CommandBuilder):
|
||||
if bias_t_flag:
|
||||
cmd.append(bias_t_flag)
|
||||
else:
|
||||
logger.warning(
|
||||
f"Bias-t requested but {dump1090_path} does not support it. "
|
||||
"Consider using dump1090-fa or readsb for bias-t support."
|
||||
)
|
||||
# Fallback: use rtl_biast to set bias-t before starting dump1090
|
||||
if not enable_bias_t_via_rtl_biast(device.index):
|
||||
logger.warning(
|
||||
f"Bias-t requested but {dump1090_path} does not support it "
|
||||
"and rtl_biast is not available. Install RTL-SDR Blog drivers "
|
||||
"or use dump1090-fa/readsb for bias-t support."
|
||||
)
|
||||
|
||||
return cmd
|
||||
|
||||
|
||||
Reference in New Issue
Block a user