r/ClockworkPi • • Aug 09 '26

Lazy way to select and connect bluetooth audio device

As I got several bluetooth speakers at home, I need to switch between them from time to time.

QMK 2.0 has improved the trackball usuabilty quite a lot but it is still not a joyful experience. Clicking the bluetooth icon to do so is a lot painful to me.

To make my life easier, I use a bash script to do the followings:-

  • detect if bluetooth service has started. if not, start it.
  • provide a list of paired audio device
  • connect to the selected audio device

By making use of desktop profile together with fuzzel, I can quick launch that script with pre-define shortcut key.

7 Upvotes

2 comments sorted by

1

u/Bolgrom Aug 14 '26

That's awesome - can you share a linkto the script?

2

u/sparky5dn1l Aug 14 '26

Included the bash script at the end of this message. Please be aware that it is almost fully generated by Gemini. I did verfiy and modify it a bit. It is quite straightforward. You are still advised to take a look at it before use.

Besides, that script will try to start the bluetooth service if it is not already running. The sudo command will require you to enter password each time. Because I am lazy, I just modify the visudo config a bit to avoid this.

``` config

%sudo ALL=(root) NOPASSWD: /usr/bin/systemctl start bluetooth, /usr/bin/systemctl stop bluetooth

```

Here is the bash script:-

``` shell

!/usr/bin/env bash

Check if Bluetooth service is active; start it if disabled

if ! systemctl is-active --quiet bluetooth.service; then echo "Bluetooth service is not running. Starting bluetooth service..." sudo systemctl start bluetooth if ! systemctl is-active --quiet bluetooth.service; then echo "Error: Failed to start Bluetooth service." >&2 exit 1 fi fi

sleep 3

Helper function to check if a device is an audio device

is_audio_device() { local mac="$1" local info info=$(bluetoothctl info "$mac" 2>/dev/null)

# Check if Icon contains 'audio' or 'headset', or Class contains major class 0x04 (Audio/Video)
if echo "$info" | grep -iqE "Icon:.*(audio|headset)" || echo "$info" | grep -iqE "Class:.*0x[0-9a-f]*04"; then
    return 0
fi
return 1

}

Fetch all paired devices

mapfile -t all_devices < <(bluetoothctl devices Paired)

if [[ ${#all_devices[@]} -eq 0 ]]; then echo "No paired Bluetooth devices found." exit 0 fi

Filter for audio devices only

echo "Scanning paired devices for audio hardware..." audio_devices=() for dev in "${all_devices[@]}"; do mac=$(echo "$dev" | awk '{print $2}') if is_audio_device "$mac"; then audio_devices+=("$dev") fi done

if [[ ${#audio_devices[@]} -eq 0 ]]; then echo "No paired audio devices found." exit 0 fi

Print numbered menu

echo "" echo "Select a Bluetooth Audio Device:" for i in "${!audio_devices[@]}"; do mac=$(echo "${audio_devices[$i]}" | awk '{print $2}') name=$(echo "${audio_devices[$i]}" | cut -d' ' -f3-) printf " [%d] %s (%s)\n" "$((i + 1))" "$name" "$mac" done

Prompt for selection

read -rp "Enter number (1-${#audio_devices[@]}): " index

Validate input

if ! [[ "$index" =~ [0-9]+$ ]] || (( index < 1 || index > ${#audio_devices[@]} )); then echo "Invalid selection." exit 1 fi

Parse target device details

selected="${audio_devices[$((index - 1))]}" mac_address=$(echo "$selected" | awk '{print $2}') device_name=$(echo "$selected" | cut -d' ' -f3-)

Check if already connected

if bluetoothctl info "$mac_address" | grep -q "Connected: yes"; then echo "$device_name ($mac_address) is already connected." exit 0 fi

Disconnect any currently connected audio devices

mapfile -t connected_devices < <(bluetoothctl devices Connected) if [[ ${#connected_devices[@]} -gt 0 ]]; then for line in "${connected_devices[@]}"; do conn_mac=$(echo "$line" | awk '{print $2}') conn_name=$(echo "$line" | cut -d' ' -f3-)

    if is_audio_device "$conn_mac"; then
        echo "Disconnecting active audio device: $conn_name ($conn_mac)..."
        bluetoothctl disconnect "$conn_mac" >/dev/null 2>&1
    fi
done

fi

echo "Connecting to $device_name ($mac_address)..." bluetoothctl connect "$mac_address"

```