From b01598753da8f92e56782c1b9d014c8a4cce68d7 Mon Sep 17 00:00:00 2001 From: Smittix Date: Mon, 13 Apr 2026 13:18:50 +0100 Subject: [PATCH] fix(adsb): disable bias-T on stop and warn when toggled while running (#207) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(adsb): disable bias-T on stop and warn when toggled while running The RTL-SDR bias-T hardware register persists after the device is closed, so toggling bias-T off in the UI and stopping the SDR had no effect on the actual hardware — verified with a multimeter in issue #205. - Add disable_bias_t_via_rtl_biast() to rtlsdr.py (mirrors enable, uses -b 0) - Track adsb_bias_t_active in adsb.py; call disable on stop_adsb() so the hardware register is cleared when ADS-B is stopped - Show an inline warning in the UI when the bias-T checkbox is toggled while any SDR mode is active, since the setting only takes effect at start time Co-Authored-By: Claude Sonnet 4.6 * fix(lint): remove unused imports in tscm sweep.py Co-Authored-By: Claude Sonnet 4.6 --------- Co-authored-by: Claude Sonnet 4.6 --- routes/adsb.py | 13 +++++++++++-- routes/tscm/sweep.py | 3 --- templates/index.html | 8 ++++++++ utils/sdr/rtlsdr.py | 29 +++++++++++++++++++++++++++++ 4 files changed, 48 insertions(+), 5 deletions(-) diff --git a/routes/adsb.py b/routes/adsb.py index e582df1..430347b 100644 --- a/routes/adsb.py +++ b/routes/adsb.py @@ -79,6 +79,7 @@ adsb_bytes_received = 0 adsb_lines_received = 0 adsb_active_device = None # Track which device index is being used adsb_active_sdr_type: str | None = None +adsb_bias_t_active = False # Track if bias-t was enabled at start (for cleanup on stop) _sbs_error_logged = False # Suppress repeated connection error logs # Track ICAOs already looked up in aircraft database (avoid repeated lookups) @@ -859,7 +860,7 @@ def adsb_session(): @adsb_bp.route('/start', methods=['POST']) def start_adsb(): """Start ADS-B tracking.""" - global adsb_using_service, adsb_active_device, adsb_active_sdr_type + global adsb_using_service, adsb_active_device, adsb_active_sdr_type, adsb_bias_t_active with app_module.adsb_lock: if adsb_using_service: @@ -991,6 +992,7 @@ def start_adsb(): # Build ADS-B decoder command bias_t = data.get('bias_t', False) + adsb_bias_t_active = bias_t cmd = builder.build_adsb_command( device=sdr_device, gain=float(gain), @@ -1139,7 +1141,7 @@ def start_adsb(): @adsb_bp.route('/stop', methods=['POST']) def stop_adsb(): """Stop ADS-B tracking.""" - global adsb_using_service, adsb_active_device, adsb_active_sdr_type + global adsb_using_service, adsb_active_device, adsb_active_sdr_type, adsb_bias_t_active data = request.get_json(silent=True) or {} stop_source = data.get('source') stopped_by = request.remote_addr @@ -1162,6 +1164,13 @@ def stop_adsb(): clear_dump1090_pid() logger.info("ADS-B process stopped") + # Turn off bias-T if it was enabled at start — the hardware register + # persists after the device is closed, so we must explicitly disable it. + if adsb_bias_t_active and (adsb_active_sdr_type or 'rtlsdr') == 'rtlsdr': + from utils.sdr.rtlsdr import disable_bias_t_via_rtl_biast + disable_bias_t_via_rtl_biast(adsb_active_device or 0) + adsb_bias_t_active = False + # Release device from registry if adsb_active_device is not None: app_module.release_sdr_device(adsb_active_device, adsb_active_sdr_type or 'rtlsdr') diff --git a/routes/tscm/sweep.py b/routes/tscm/sweep.py index 701578b..6dea2ee 100644 --- a/routes/tscm/sweep.py +++ b/routes/tscm/sweep.py @@ -19,12 +19,9 @@ from flask import Response, jsonify, request from data.tscm_frequencies import get_all_sweep_presets, get_sweep_preset from routes.tscm import ( _baseline_recorder, - _current_sweep_id, _emit_event, _start_sweep_internal, - _sweep_running, tscm_bp, - tscm_queue, ) from utils.database import get_tscm_sweep, update_tscm_sweep from utils.event_pipeline import process_event diff --git a/templates/index.html b/templates/index.html index d810531..249f2b4 100644 --- a/templates/index.html +++ b/templates/index.html @@ -6349,6 +6349,14 @@ function saveBiasTSetting() { const enabled = document.getElementById('biasT')?.checked || false; localStorage.setItem('biasTEnabled', enabled); + // Warn if any SDR mode is currently running — bias-T is applied at + // start time and cannot be toggled on a running device. + const anyRunning = isRunning || isSensorRunning + || (typeof isAdsbRunning !== 'undefined' && isAdsbRunning) + || (typeof isAisRunning !== 'undefined' && isAisRunning); + if (anyRunning) { + showInfo('Bias-T change will take effect after restarting the active SDR mode'); + } } function getBiasTEnabled() { diff --git a/utils/sdr/rtlsdr.py b/utils/sdr/rtlsdr.py index 9437338..51a9264 100644 --- a/utils/sdr/rtlsdr.py +++ b/utils/sdr/rtlsdr.py @@ -75,6 +75,35 @@ def enable_bias_t_via_rtl_biast(device_index: int = 0) -> bool: return False +def disable_bias_t_via_rtl_biast(device_index: int = 0) -> bool: + """Disable bias-t power using rtl_biast (RTL-SDR Blog drivers). + + Should be called when stopping an SDR mode that had bias-t enabled, + since the hardware register persists after the device is closed. + + Returns True if bias-t was disabled successfully. + """ + rtl_biast_path = get_tool_path('rtl_biast') or 'rtl_biast' + try: + result = subprocess.run( + [rtl_biast_path, '-b', '0', '-d', str(device_index)], + capture_output=True, + text=True, + timeout=5 + ) + if result.returncode == 0: + logger.info(f"Bias-t disabled 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 — bias-t may remain on after stop") + return False + except Exception as e: + logger.warning(f"Failed to disable 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.