bluetoothtoolslinux

Bluetooth Fox Hunting with RSSI Sonar

Setup guide for tracking Bluetooth devices using RSSI signal strength with audio feedback.

A quick guide for setting up Bluetooth fox hunting tools on Linux to locate devices by RSSI signal strength.

Installation

Install required dependencies:

rpm-ostree install sox bluez-tools

Test Audio

Verify audio output is working:

play -n -c1 synth 10 sine 1000

This should produce a 1000 Hz tone for 10 seconds.

Usage

Run the sonar script with your target device:

./majestic_sonar.sh -t D0:04:B0:57:B4:A4 -a

Options

  • -t, --targetRequired: MAC address of target Bluetooth device
  • -a, --audio — Enable audio feedback (pitch increases with signal strength)
  • -s, --sleep — Time between RSSI checks in seconds (default: 1)
  • -v, --verbose — Enable debug output
  • -h, --help — Show help menu

The Script

Save this as majestic_sonar.sh and make it executable with chmod +x majestic_sonar.sh:

#!/bin/bash

set -e

usage() {
  echo -e "\nUsage: $0 --target <mac address> [--sleep 1]"
  echo -e "\t-h, --help      Show this help menu"
  echo -e "\t-t, --target    REQUIRED: MAC address of target device"
  echo -e "\t-s, --sleep     Time between RSSI checks (default: 1)"
  echo -e "\t-a, --audio     Enable audio feedback"
  echo -e "\t-v, --verbose   Enable debug output"
  echo
}

readonly PROGRESS='#####################################################################'
readonly red=$'\e[0;31m'
readonly end=$'\e[0m'
readonly ISNUMBER='^[0-9.]+$'
readonly ISMAC='^([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}$'

target=""
sleep=1
audio=0
quiet=0
sim=0
minrssi=128
maxrssi=-128

cleanup() {
  echo -e "\nStopping scan..."
  # Kill tmux session if it exists
  if tmux has-session -t bluetoothctl 2>/dev/null; then
    tmux kill-session -t bluetoothctl
  fi
  bluetoothctl scan off >/dev/null
}
trap cleanup EXIT
trap cleanup INT TERM

# --- Get RSSI from bluetoothctl ---
get_rssi_btctl() {
  local target_mac="$1"
  output=$(bluetoothctl info "$target_mac" 2>/dev/null)
  echo "$output" | grep -i "RSSI" | awk -F'[()]' '{print $2}'
}

control_c() {
  echo
  [[ "$minrssi" != "128" ]] && echo "MIN RSSI: $minrssi"
  [[ "$maxrssi" != "-128" ]] && echo "MAX RSSI: $maxrssi"
  echo "Thanks for tracking with majestic_sonar."
  exit 0
}

# --- Parse Args ---
while [[ $# -gt 0 ]]; do
  case "$1" in
    -h|--help) usage; exit 0 ;;
    -t|--target)
      [[ "$2" =~ $ISMAC ]] || { echo "Invalid MAC: $2"; exit 1; }
      target="$2"; shift ;;
    -s|--sleep)
      [[ "$2" =~ $ISNUMBER ]] || { echo "Sleep must be a number"; exit 1; }
      sleep="$2"; shift ;;
    -a|--audio) audio=1 ;;
    -v|--verbose) quiet=1 ;;
    --sim) sim=1; rssi=-70 ;;
    *) echo "Unknown option: $1"; usage; exit 1 ;;
  esac
  shift
done

[[ -z "$target" && "$sim" -ne 1 ]] && { echo "Error: --target is required"; usage; exit 1; }

# --- Ensure Bluetooth is ready ---
echo "Ensuring Bluetooth is powered on..."
bluetoothctl power on >/dev/null

# --- Start bluetoothctl scan in tmux ---
start_bluetoothctl_scan() {
  # Start bluetoothctl in a tmux session
  tmux new-session -d -s bluetoothctl "bluetoothctl"
  sleep 1
  tmux send-keys -t bluetoothctl "scan on" Enter
}

# Start the Bluetooth scan
start_bluetoothctl_scan

# Allow time for the scan to run
sleep 3

# --- Optional: wait until device appears ---
if [[ "$sim" -ne 1 ]]; then
  echo "Waiting for device $target to appear in scan..."
  found=""
  for i in {1..10}; do
    if bluetoothctl devices | grep -iq "$target"; then
      found=1
      break
    fi
    sleep 1
  done

  if [[ -z "$found" ]]; then
    echo "⚠️  Warning: Device $target not seen during scan. Continuing anyway..."
  fi
fi

# --- Main Loop ---
while true; do
  if [[ "$sim" -eq 1 ]]; then
    rssi=$((rssi + 1))
    [[ "$rssi" -ge 21 ]] && control_c
  else
    rssi=$(get_rssi_btctl "$target")
    if [[ -z "$rssi" ]]; then
      echo "Out of range or no signal from $target"
      sleep "$sleep"
      continue
    fi
  fi

  # --- Display Bar ---
  bars=$((rssi + 65))
  if (( bars <= 0 )); then
    echo -e "RSSI: ${rssi}  ${PROGRESS:0:1}${red}${PROGRESS:1}${end}"
  elif (( bars > ${#PROGRESS} )); then
    echo -e "RSSI: ${rssi}  ${PROGRESS}"
  else
    echo -e "RSSI: ${rssi}  ${PROGRESS:0:$bars}${red}${PROGRESS:$bars}${end}"
  fi

  (( rssi < minrssi )) && minrssi=$rssi
  (( rssi > maxrssi )) && maxrssi=$rssi

  # --- Optional Audio ---
  if [[ "$audio" -eq 1 ]]; then
    RSSIN=$((rssi*-1))
    freq=$(((65+rssi)/5*300))
    dur=.3
    spd=$((RSSIN+10))
    dur=.$spd
    PULSE_SERVER=unix:/run/user/1000/pulse/native play -n -c1 synth "$dur" sine "$freq" 2>/dev/null
  fi

  sleep "$sleep"
done

How It Works

  1. Scans for Bluetooth devices using bluetoothctl in a tmux session
  2. Reads RSSI (Received Signal Strength Indicator) from the target device
  3. Visualizes signal strength with a progress bar (green to red)
  4. Audio feedback generates tones that increase in pitch as you get closer to the device
  5. Tracks min/max RSSI values during the session

The stronger the signal (closer to 0 dBm), the higher the pitch and the fuller the progress bar.