10 KiB
RF Tooling
TDS RF tooling is designed for a local collector host with attached SDR and RF interfaces. Replace the placeholder hostnames, serials, and paths below with your own deployment values.
The canonical source ownership map is in docs/capture-map.md. In short:
- Kismet owns passive Wi-Fi, Linux Bluetooth, ADS-B, rtl433 datasource state, GPS datasource context, datasource health, and Kismet server health.
- Intercept owns Intercept service health and attached SDR inventory, including HackRF Pro and RTL-SDR devices.
- WCH BLE Analyzer Pro is ingested through short standalone
wch_capturePCAP windows parsed bytools/ble_analyzer_collect.py.
Intercept
Intercept is installed in /opt/intercept and runs as a system service.
sudo systemctl status intercept.service
sudo systemctl restart intercept.service
sudo journalctl -u intercept.service -n 100 --no-pager
Runtime details:
- URL:
http://127.0.0.1:5050 - Service:
intercept.service - Config:
/opt/intercept/.env - Source checkout:
/opt/intercept - MQTT export:
127.0.0.1:1883, topic prefixtds/intercept
Credentials are stored in /opt/intercept/.env; do not copy them into docs or
operator notes.
Installed Intercept profiles:
- Core SIGINT: RTL-SDR, multimon-ng, rtl_433, ADS-B, ACARS, VDL2, GPS, ffmpeg
- RF Security: aircrack-ng, HackRF, BlueZ, hcxtools, SoapySDR
The full Intercept health check may warn about AIS, weather satellite, radiosonde, Ubertooth, or rtlamr tooling. Those are not required for the first TDS RF validation pass.
Intercept does not currently use the WCH BLE Analyzer Pro directly. Its
Bluetooth path uses the local BlueZ/bleak/bluetoothctl adapter flow, while the
WCH analyzer is a USB packet sniffer. TDS ingests WCH captures through
tools/ble_analyzer_collect.py.
Kismet
Kismet should run on the collector host.
kismet --version
systemctl status kismet.service
Runtime details:
- URL:
http://127.0.0.1:2501 - Service:
kismet.service - Site config:
/etc/kismet/kismet_site.conf - Logs:
/var/log/kismet - UI user:
tds
The Kismet password is stored in /etc/kismet/kismet_site.conf; do not copy it
into docs or operator notes.
Installed capture helpers include:
kismet_cap_linux_wifikismet_cap_linux_bluetoothkismet_cap_sdr_rtl433kismet_cap_sdr_rtladsb
The installed Kismet package does not include a WCH BLE Analyzer capture helper. Kismet continues to collect Bluetooth through the Linux Bluetooth adapter source.
Configured capture sources:
wlan1: MediaTek USB Wi-Fi adapter in monitor modehci1: MediaTek Bluetooth controllerrtl433-<UTILITY_SDR_SERIAL>: RTL-SDR Blog V3 for 433 MHz sensorsrtladsb-<ADSB_SDR_SERIAL>: RTL-SDR Blog V3 for ADS-Bgpsd: GPS receiver on local gpsdtds_nrf52840: nRF52840 802.15.4 source on the stable/dev/serial/by-idpath
The systemd service has a local override with KillMode=control-group so Kismet
capture helpers are stopped cleanly during restarts.
Hardware Validation
Use /settings or the control-sidecar USB inventory to confirm that the
collector host sees the expected hardware before assigning collectors:
- RTL-SDR Blog V3 dongles should have unique serials before they are assigned to Kismet, ADS-B, rail RF, or utility RF collection.
- A monitor-capable Wi-Fi adapter should appear as a Linux wireless interface and support monitor mode for Kismet.
- A Bluetooth controller can be used by Kismet's Linux Bluetooth source.
- A GPS dongle is optional; site coordinates can also be set directly in the dashboard.
- nRF52840, HackRF, YARD Stick One, LibreSDR/B210-compatible hardware, and WCH BLE Analyzer devices should be validated with their vendor tools before TDS collectors are enabled.
YARD Stick One non-root access is handled by /etc/udev/rules.d/60-yardstick-one.rules.
WCH BLE Analyzer non-root access is handled by /etc/udev/rules.d/99-wch-ble-analyzer.rules;
capture files are written under /var/log/tds/ble-analyzer with group
plugdev.
Current RF Role Split
The preferred live split is:
<ADSB_SDR_SERIAL>: ADS-B aircraft through Kismetrtladsb-<ADSB_SDR_SERIAL>.<UTILITY_SDR_SERIAL>: utility/ISM decodes through Kismetrtl433-<UTILITY_SDR_SERIAL>, initially at 433.92 MHz.rtl_433supports many TPMS, weather, utility meter, door/window contact, keyfob, thermometer, and other low-power ISM decoders.<RAIL_SDR_SERIAL>: passive rail-band energy detection throughtools/rail_rf_collect.pyandrtl_power. TDS records frequency, band, RSSI-like peak power, and timestamp asrail_rf/rail/rail_activity; it does not decode train-control traffic.- HackRF Pro: receive-only rotating SubGHz profile collector through Intercept
/subghz/sweep/start.tools/intercept_mqtt_collect.py --hackrf-rotationcycles TPMS, utility meter, leak sensor, smart thermostat, and door/window sensor windows long enough to capture useful bursts, while tagging MQTT sweep peaks with the active profile. Targeted profile peaks are ingested asintercept/subghz/spectrum_peakrecords withdecode_status=candidate; they remain in the Unknown RF discovery layer until a decoder promotes them to a real device/protocol class. - YARD Stick One: CC1111/RfCat packet work for compatible sub-GHz OOK/ASK/FSK devices around common ISM bands such as 315, 433, 868, and 902-928 MHz. It is hardware-validated, but not auto-started by TDS because it is a protocol-specific transceiver, not a general wideband scanner. Use it once modulation, sync word, rate, and packet format are known; it is not the right path for ADS-B, Wi-Fi, or BLE.
As of this validation, /v1/map/rf is populated with Wi-Fi, BLE, ADS-B,
HackRF discovery peaks, and any decoded rtl433/Kismet utility records. HackRF
sweep/profile peaks remain Unknown RF until Yardstick One, rtl_433, rtlamr, or
another decoder identifies them.
nRF52840 802.15.4
Kismet supports nRF52840 Zigbee/802.15.4 sources with an explicit serial
device path. The TDS drop-in source definition is in
deploy/kismet/kismet_site_nrf52840.conf:
source=nrf52840:device=/dev/serial/by-id/usb-Nordic_Semiconductor_nRF52_USB_Product_<SERIAL>-if00,name=tds_nrf52840,channels="11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26"
After adding that line to /etc/kismet/kismet_site.conf, restart Kismet:
sudo systemctl restart kismet.service
systemctl --user start tds-kismet-collect.service
curl -fsS 'http://127.0.0.1:8080/v1/state?source=kismet&kind=iot_device'
Kismet reports these devices as phy 802.15.4; TDS stores them as zigbee
protocol with kind=iot_device and rf_family=802.15.4 metadata so Thread or
Zigbee evidence can be reviewed without flattening it into unknown RF.
Rail RF
The rail collector watches AAR VHF rail channels around 160.215-161.565 MHz with the third RTL-SDR. It is passive energy-only collection:
cd /opt/tds/TDS
.venv/bin/python tools/rail_rf_collect.py --dry-run
systemctl --user status tds-rail-rf-collect.timer
curl -fsS 'http://127.0.0.1:8080/v1/state?source=rail_rf'
Use TDS_RAIL_RTL_DEVICE=<RAIL_SDR_SERIAL> to pin the collector to the train SDR.
Avoid auto in production; rail must fail closed instead of falling back to a
Kismet-owned RTL-SDR.
The collector also calculates the nearest AAR channel and can add local
operator/route hints from TDS_RAIL_RF_CATALOG. Start by copying
config/rail_channels.example.json to config/rail_channels.local.json, then
replace the example rows with local channel assignments. These fields are
shown as inferred context in /v1/map/rf and the presence dossier; they do not
prove exact train identity without decoded audio or another rail data source.
802.15.4 devices from Kismet are enriched with protocol-family, PAN, channel, packet-direction, vendor, and role hints before being shown as IoT mesh context. This keeps Zigbee/Thread traffic visible to operators while making clear that encrypted payloads may hide exact product type.
WCH BLE Analyzer Pro
The WCH BLE Analyzer Pro is ingested as a standalone BLE packet capture source. It is not wired into Intercept directly.
Short capture:
mkdir -p /var/log/tds/ble-analyzer
timeout 30 wch_capture -w /var/log/tds/ble-analyzer/ble-$(date +%Y%m%d-%H%M%S).pcap
Verbose validation:
timeout 12 wch_capture -v -w /var/log/tds/ble-analyzer/test-$(date +%Y%m%d-%H%M%S).pcap
Expected startup:
- Three MCU devices open successfully.
- MCU 0 maps to BLE channel 37.
- MCU 1 maps to BLE channel 38.
- MCU 2 maps to BLE channel 39.
- PCAP output is written under
/var/log/tds/ble-analyzer.
Do not run a long unattended wch_capture session without a rotation policy;
PCAP files can grow quickly in a busy BLE environment.
TDS runtime collection uses 8-second capture windows every 30 seconds:
systemctl --user status tds-ble-analyzer-collect.timer
systemctl --user start tds-ble-analyzer-collect.service
The collector parses advertising address, RSSI, RF channel, PDU type, device
name, manufacturer company IDs, service UUIDs, and service data from tshark.
It aggregates packets by advertiser and submits ble_analyzer /
ble_advertiser observations to POST /v1/observations.
RTL-SDR Driver Prep
RTL-SDR userspace access is prepared for dongle validation:
- RTL-SDR udev rules are installed in
/etc/udev/rules.d/20-rtlsdr.rules - Conflicting DVB kernel drivers are blacklisted in
/etc/modprobe.d/blacklist-rtlsdr.conf - initramfs was regenerated after the blacklist was added
After plugging in RTL-SDR hardware, unplug/replug once if rtl_test cannot
claim the device immediately.
Hardware Validation
Baseline checks before plugging in RF dongles:
lsusb
rtl_test -t
hackrf_info
SoapySDRUtil --find
systemctl is-active intercept.service
Expected pre-hardware result:
- Intercept service is active.
- Kismet is installed and inactive.
rtl_test,hackrf_info, andSoapySDRUtil --findreport no external SDR devices until dongles are attached.
First hardware pass:
- Plug in the RTL-SDR dongle and run
lsusb,rtl_test -t, andrtl_433 -A. - Plug in the monitor-mode Wi-Fi adapter and confirm it appears with
iw devand Kismet can see it as a source. - Plug in HackRF or LimeSDR hardware, if available, and run
hackrf_infoorSoapySDRUtil --find. - Confirm Intercept still serves
http://127.0.0.1:5050. - Start only the specific Intercept or Kismet capture mode being tested.