Idempotent host bootstrap, diagnostics, and capture tooling for Nordic/Adafruit BLE sniffer workflows on Ubuntu.
SupraBlueSniffer is an operations-focused helper project for getting an Adafruit/Nordic BLE sniffer host into a known-good state quickly and repeatably. It focuses on:
- Host setup and dependency checks
- Wireshark/tshark extcap readiness
- Firmware package selection/staging
- Flash orchestration checks
- Repeatable diagnostics and capture tooling
- Adafruit BLE Sniffer Python API: https://github.com/adafruit/Adafruit_BLESniffer_Python
- Python capture workflow for Adafruit Bluefruit LE Sniffer with PCAP output.
- Raccoon BLE Sniffer: https://github.com/bluekitchen/raccoon
- Open-source BLE sniffer firmware + host tooling for Nordic/compatible devices.
- Bsniffhub: https://github.com/homewsn/bsniffhub
- Multi-sniffer BLE capture/decryption bridge for Wireshark/PCAP pipelines.
More detail: docs/OPEN_SOURCE_ECOSYSTEM.md
Quick chooser table: docs/OPEN_SOURCE_ECOSYSTEM.md (Which Project Should I Use?)
scripts/run_all.sh- End-to-end runner: setup, optional firmware actions, diagnostics.
scripts/setup_host.sh- Installs missing dependencies
- Ensures permissions/groups (
dialout,wireshark) - Removes
brlttyconflict - Installs Wireshark extcap (optional zip/url)
- Configures tshark extcap integration (optional)
- Uses sniffer state detection to skip unnecessary firmware download/flash
scripts/check_sniffer_state.sh- Single source of truth for readiness:
- USB serial present, Wireshark extcap ready, tshark extcap ready, capture readiness, firmware state
scripts/configure_tshark_extcap.sh- Idempotently syncs personal extcap into tshark global extcap path
scripts/fetch_nordic_firmware.sh- Detects device class from udev metadata
- Chooses firmware package and
.hex - Downloads, checksum-verifies, extracts, stages
current.hex - Skips download if device is already capture-capable (unless forced)
scripts/flash_firmware.sh- Idempotent flashing orchestration
- Skips flash when sniffer is already capture-capable (unless forced)
- Uses
nrfjprogfirst,pyocdfallback
scripts/collect_diagnostics.sh- Generates timestamped report in
diagnostics/
- Generates timestamped report in
Run full setup + diagnostics:
./scripts/run_all.shCheck current readiness:
./scripts/check_sniffer_state.sh --format textConfigure tshark extcap:
./scripts/configure_tshark_extcap.shDownload/stage firmware:
./scripts/fetch_nordic_firmware.shForce firmware redownload:
./scripts/fetch_nordic_firmware.sh --force-downloadCollect diagnostics with redaction for safer sharing:
./scripts/collect_diagnostics.sh diagnostics --redactAuto-flash (best effort):
./scripts/setup_host.sh --auto-flashForce flash even when already capture-capable:
./scripts/setup_host.sh --auto-flash --flash-forceAssume your sniffer interface is:
IFACE="/dev/ttyUSB0-3.6"List available tshark interfaces and confirm sniffer entry:
tshark -D | grep -i nrf1-minute baseline capture (good starting point):
tshark -i "$IFACE" -a duration:60 -w captures/baseline-60s.pcapngSee which BLE advertising addresses are most active:
tshark -r captures/baseline-60s.pcapng -T fields -e btle.advertising_address \
| grep -v '^$' | sort | uniq -c | sort -nr | head -30Break down advertising/scan/connect mode usage by PDU type:
tshark -r captures/baseline-60s.pcapng -T fields -e btle.advertising_header.pdu_type \
| grep -v '^$' | sort | uniq -c | sort -nrQuickly check for connection attempts:
tshark -r captures/baseline-60s.pcapng -Y "btle.advertising_header.pdu_type==5" \
-T fields -e frame.number -e frame.time -e btle.initiator_address -e btle.advertising_addressFollow one specific device address (replace target MAC):
TARGET="cd:93:51:a3:0d:59"
tshark -i "$IFACE" -Y "btle.advertising_address==$TARGET || btle.initiator_address==$TARGET || btle.advertising_address_resolved==$TARGET" \
-a duration:90 -w "captures/target-${TARGET//:/}.pcapng"Check if ATT/GATT application traffic is present:
tshark -r captures/baseline-60s.pcapng -Y btatt -T fields -e frame.number -e btatt.opcode -e btatt.handle | headLive decoded ATT view (when connection traffic exists):
tshark -i "$IFACE" -Y btatt -VHelpful workflow:
- Capture baseline traffic.
- Rank top advertiser addresses.
- Pick a target MAC and run focused capture while triggering actions in the companion app/device.
- Re-check for
btattframes to identify command/data exchanges.
Shell scripts support both environment and CLI-based log controls:
BLUESNIFFER_LOG_LEVEL=DEBUG ./scripts/run_all.sh
BLUESNIFFER_QUIET=1 ./scripts/run_all.sh
./scripts/run_all.sh --log-level DEBUG
./scripts/setup_host.sh --quietPython capture tools support CLI log controls:
./scripts/capture_scapy_lookup_crosscheck.py --log-level DEBUG
./scripts/track_ble_lifecycle.py --quietProject-managed runtime data uses non-hidden directories:
captures/for capture filesdiagnostics/for report outputstate/cache/for cached remote registry datastate/locks/for capture lock coordinationstate/firmware/fallback firmware state when home cache is unavailable
Use this script to collect a sample capture, parse packet examples with Scapy, run device/vendor lookups, and cross-check what each source reports:
- Bluetooth SIG Company Identifiers
- IEEE OUI registry
- macvendors API
- maclookup API
- iplocation API
Prerequisite:
pip3 install --user scapyRun with live capture (auto-detects nRF interface):
./scripts/capture_scapy_lookup_crosscheck.py --duration 60Recommended stability flags for busy environments:
./scripts/capture_scapy_lookup_crosscheck.py --duration 60 --heartbeat-sec 5 --lock-timeout 30 --max-scapy-packets 5000 --lookup-workers 6 --max-unique-devices 2000 --display-filter "btle || btatt"Run against an existing capture file:
./scripts/capture_scapy_lookup_crosscheck.py --capture ../captures/baseline-60s.pcapngWrite report to a specific path:
./scripts/capture_scapy_lookup_crosscheck.py --duration 60 --output-json diagnostics/lookup-report.jsonDetect when BLE devices enter discovery mode (connectable advertising), then track scan, connect, ATT, and termination lifecycle events.
Analyze live traffic:
./scripts/track_ble_lifecycle.py --duration 60Use bounded timeline and explicit parse timeout controls:
./scripts/track_ble_lifecycle.py --duration 60 --max-events-per-device 2000 --parse-timeout-sec 180 --heartbeat-sec 5 --display-filter "btle || btatt"Track a specific device only:
./scripts/track_ble_lifecycle.py --duration 90 --target cd:93:51:a3:0d:59Analyze an existing capture:
./scripts/track_ble_lifecycle.py --capture captures/lookup-sample-20260221_165843.pcapng --output-json diagnostics/lifecycle-report.json- Package installs run only for missing packages.
- Group membership changes only when needed.
- tshark extcap sync is skipped when tshark already lists nRF Sniffer.
- Firmware download and flash are skipped when sniffer is already capture-capable, unless force flags are used.
See docs/REFLASH_GUIDE.md for hardware/software prerequisites and Adafruit-specific constraints.
Adafruit references:
- https://learn.adafruit.com/introducing-the-adafruit-bluefruit-le-sniffer/faqs
- https://learn.adafruit.com/introducing-the-adafruit-bluefruit-le-sniffer/usb-driver-install
- https://learn.adafruit.com/introducing-the-adafruit-bluefruit-le-sniffer
- https://learn.adafruit.com/introducing-the-adafruit-bluefruit-le-sniffer/using-with-sniffer-v2-and-python3
- https://learn.adafruit.com/introducing-the-adafruit-bluefruit-le-sniffer/python-api
See docs/SESSION_REVIEW.md for a retrospective and concrete recommendations.
See docs/BACKLOG.md for deferred correctness/operability work items.