Add rtl_tcp (remote SDR) support v1.1.0

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.
This commit is contained in:
Smittix
2026-01-05 08:44:58 +00:00
parent 27cbd47a80
commit ba4c6999a6
11 changed files with 279 additions and 16 deletions

View File

@@ -16,7 +16,10 @@ from flask import Blueprint, jsonify, request, Response, render_template
import app as app_module
from utils.logging import adsb_logger as logger
from utils.validation import validate_device_index, validate_gain
from utils.validation import (
validate_device_index, validate_gain,
validate_rtl_tcp_host, validate_rtl_tcp_port
)
from utils.sse import format_sse
from utils.sdr import SDRFactory, SDRType
@@ -238,6 +241,25 @@ def start_adsb():
except ValueError as e:
return jsonify({'status': 'error', 'message': str(e)}), 400
# Check for remote SBS connection (e.g., remote dump1090)
remote_sbs_host = data.get('remote_sbs_host')
remote_sbs_port = data.get('remote_sbs_port', 30003)
if remote_sbs_host:
# Validate and connect to remote dump1090 SBS output
try:
remote_sbs_host = validate_rtl_tcp_host(remote_sbs_host)
remote_sbs_port = validate_rtl_tcp_port(remote_sbs_port)
except ValueError as e:
return jsonify({'status': 'error', 'message': str(e)}), 400
remote_addr = f"{remote_sbs_host}:{remote_sbs_port}"
logger.info(f"Connecting to remote dump1090 SBS at {remote_addr}")
adsb_using_service = True
thread = threading.Thread(target=parse_sbs_stream, args=(remote_addr,), daemon=True)
thread.start()
return jsonify({'status': 'started', 'message': f'Connected to remote dump1090 at {remote_addr}'})
# Check if dump1090 is already running externally (e.g., user started it manually)
existing_service = check_dump1090_service()
if existing_service:

View File

@@ -18,7 +18,10 @@ from flask import Blueprint, jsonify, request, Response
import app as app_module
from utils.logging import pager_logger as logger
from utils.validation import validate_frequency, validate_device_index, validate_gain, validate_ppm
from utils.validation import (
validate_frequency, validate_device_index, validate_gain, validate_ppm,
validate_rtl_tcp_host, validate_rtl_tcp_port
)
from utils.sse import format_sse
from utils.process import safe_terminate, register_process
from utils.sdr import SDRFactory, SDRType, SDRValidationError
@@ -209,9 +212,25 @@ def start_decoding() -> Response:
except ValueError:
sdr_type = SDRType.RTL_SDR
# Create device object and get command builder
sdr_device = SDRFactory.create_default_device(sdr_type, index=device)
builder = SDRFactory.get_builder(sdr_type)
# Check for rtl_tcp (remote SDR) connection
rtl_tcp_host = data.get('rtl_tcp_host')
rtl_tcp_port = data.get('rtl_tcp_port', 1234)
if rtl_tcp_host:
# Validate and create network device
try:
rtl_tcp_host = validate_rtl_tcp_host(rtl_tcp_host)
rtl_tcp_port = validate_rtl_tcp_port(rtl_tcp_port)
except ValueError as e:
return jsonify({'status': 'error', 'message': str(e)}), 400
sdr_device = SDRFactory.create_network_device(rtl_tcp_host, rtl_tcp_port)
logger.info(f"Using remote SDR: rtl_tcp://{rtl_tcp_host}:{rtl_tcp_port}")
else:
# Create local device object
sdr_device = SDRFactory.create_default_device(sdr_type, index=device)
builder = SDRFactory.get_builder(sdr_device.sdr_type)
# Build FM demodulation command
rtl_cmd = builder.build_fm_demod_command(

View File

@@ -14,7 +14,10 @@ from flask import Blueprint, jsonify, request, Response
import app as app_module
from utils.logging import sensor_logger as logger
from utils.validation import validate_frequency, validate_device_index, validate_gain, validate_ppm
from utils.validation import (
validate_frequency, validate_device_index, validate_gain, validate_ppm,
validate_rtl_tcp_host, validate_rtl_tcp_port
)
from utils.sse import format_sse
from utils.process import safe_terminate, register_process
from utils.sdr import SDRFactory, SDRType
@@ -90,9 +93,25 @@ def start_sensor() -> Response:
except ValueError:
sdr_type = SDRType.RTL_SDR
# Create device object and get command builder
sdr_device = SDRFactory.create_default_device(sdr_type, index=device)
builder = SDRFactory.get_builder(sdr_type)
# Check for rtl_tcp (remote SDR) connection
rtl_tcp_host = data.get('rtl_tcp_host')
rtl_tcp_port = data.get('rtl_tcp_port', 1234)
if rtl_tcp_host:
# Validate and create network device
try:
rtl_tcp_host = validate_rtl_tcp_host(rtl_tcp_host)
rtl_tcp_port = validate_rtl_tcp_port(rtl_tcp_port)
except ValueError as e:
return jsonify({'status': 'error', 'message': str(e)}), 400
sdr_device = SDRFactory.create_network_device(rtl_tcp_host, rtl_tcp_port)
logger.info(f"Using remote SDR: rtl_tcp://{rtl_tcp_host}:{rtl_tcp_port}")
else:
# Create local device object
sdr_device = SDRFactory.create_default_device(sdr_type, index=device)
builder = SDRFactory.get_builder(sdr_device.sdr_type)
# Build ISM band decoder command
cmd = builder.build_ism_command(