dotfiles

personal configuration files and scripts
git clone https://tongong.net/git/dotfiles.git
Log | Files | Refs | README

dmenu-bluetooth (7178B)


      1 #!/usr/bin/env bash
      2 #             __ _       _     _            _              _   _
      3 #  _ __ ___  / _(_)     | |__ | |_   _  ___| |_ ___   ___ | |_| |__
      4 # | '__/ _ \| |_| |_____| '_ \| | | | |/ _ \ __/ _ \ / _ \| __| '_ \
      5 # | | | (_) |  _| |_____| |_) | | |_| |  __/ || (_) | (_) | |_| | | |
      6 # |_|  \___/|_| |_|     |_.__/|_|\__,_|\___|\__\___/ \___/ \__|_| |_|
      7 #
      8 # Author: Nick Clyde (clydedroid)
      9 #
     10 # A script that generates a rofi menu that uses bluetoothctl to
     11 # connect to bluetooth devices and display status info.
     12 #
     13 # Inspired by networkmanager-dmenu (https://github.com/firecat53/networkmanager-dmenu)
     14 # Thanks to x70b1 (https://github.com/polybar/polybar-scripts/tree/master/polybar-scripts/system-bluetooth-bluetoothctl)
     15 #
     16 # Depends on:
     17 #   Arch repositories: rofi, bluez-utils (contains bluetoothctl)
     18 
     19 # Checks if bluetooth controller is powered on
     20 power_on() {
     21     if bluetoothctl show | grep -q "Powered: yes"; then
     22         return 0
     23     else
     24         return 1
     25     fi
     26 }
     27 
     28 # Toggles power state
     29 toggle_power() {
     30     if power_on; then
     31         bluetoothctl power off
     32         show_menu
     33     else
     34         bluetoothctl power on
     35         show_menu
     36     fi
     37 }
     38 
     39 # Checks if controller is scanning for new devices
     40 scan_on() {
     41     if bluetoothctl show | grep -q "Discovering: yes"; then
     42         echo "Scan: on"
     43         return 0
     44     else
     45         echo "Scan: off"
     46         return 1
     47     fi
     48 }
     49 
     50 # Toggles scanning state
     51 toggle_scan() {
     52     if scan_on; then
     53         kill $(pgrep -f "bluetoothctl scan on")
     54         bluetoothctl scan off
     55         show_menu
     56     else
     57         bluetoothctl scan on &
     58         echo "Scanning..."
     59         sleep 5
     60         show_menu
     61     fi
     62 }
     63 
     64 # Checks if controller is able to pair to devices
     65 pairable_on() {
     66     if bluetoothctl show | grep -q "Pairable: yes"; then
     67         echo "Pairable: on"
     68         return 0
     69     else
     70         echo "Pairable: off"
     71         return 1
     72     fi
     73 }
     74 
     75 # Toggles pairable state
     76 toggle_pairable() {
     77     if pairable_on; then
     78         bluetoothctl pairable off
     79         show_menu
     80     else
     81         bluetoothctl pairable on
     82         show_menu
     83     fi
     84 }
     85 
     86 # Checks if controller is discoverable by other devices
     87 discoverable_on() {
     88     if bluetoothctl show | grep -q "Discoverable: yes"; then
     89         echo "Discoverable: on"
     90         return 0
     91     else
     92         echo "Discoverable: off"
     93         return 1
     94     fi
     95 }
     96 
     97 # Toggles discoverable state
     98 toggle_discoverable() {
     99     if discoverable_on; then
    100         bluetoothctl discoverable off
    101         show_menu
    102     else
    103         bluetoothctl discoverable on
    104         show_menu
    105     fi
    106 }
    107 
    108 # Checks if a device is connected
    109 device_connected() {
    110     device_info=$(bluetoothctl info "$1")
    111     if echo "$device_info" | grep -q "Connected: yes"; then
    112         return 0
    113     else
    114         return 1
    115     fi
    116 }
    117 
    118 # Toggles device connection
    119 toggle_connection() {
    120     if device_connected $1; then
    121         bluetoothctl disconnect $1
    122         show_menu
    123     else
    124         bluetoothctl connect $1
    125         show_menu
    126     fi
    127 }
    128 
    129 # Checks if a device is paired
    130 device_paired() {
    131     device_info=$(bluetoothctl info "$1")
    132     if echo "$device_info" | grep -q "Paired: yes"; then
    133         echo "Paired: yes"
    134         return 0
    135     else
    136         echo "Paired: no"
    137         return 1
    138     fi
    139 }
    140 
    141 # Toggles device paired state
    142 toggle_paired() {
    143     if device_paired $1; then
    144         bluetoothctl remove $1
    145         show_menu
    146     else
    147         bluetoothctl pair $1
    148         show_menu
    149     fi
    150 }
    151 
    152 # Checks if a device is trusted
    153 device_trusted() {
    154     device_info=$(bluetoothctl info "$1")
    155     if echo "$device_info" | grep -q "Trusted: yes"; then
    156         echo "Trusted: yes"
    157         return 0
    158     else
    159         echo "Trusted: no"
    160         return 1
    161     fi
    162 }
    163 
    164 # Toggles device connection
    165 toggle_trust() {
    166     if device_trusted $1; then
    167         bluetoothctl untrust $1
    168         show_menu
    169     else
    170         bluetoothctl trust $1
    171         show_menu
    172     fi
    173 }
    174 
    175 # Prints a short string with the current bluetooth status
    176 # Useful for status bars like polybar, etc.
    177 print_status() {
    178     if power_on; then
    179         printf ''
    180 
    181         mapfile -t paired_devices < <(bluetoothctl paired-devices | grep Device | cut -d ' ' -f 2)
    182         counter=0
    183 
    184         for device in "${paired_devices[@]}"; do
    185             if device_connected $device; then
    186                 device_alias=$(bluetoothctl info $device | grep "Alias" | cut -d ' ' -f 2-)
    187 
    188                 if [ $counter -gt 0 ]; then
    189                     printf ", %s" "$device_alias"
    190                 else
    191                     printf " %s" "$device_alias"
    192                 fi
    193 
    194                 ((counter++))
    195             fi
    196         done
    197 
    198        if [ $counter -eq 0 ]; then
    199            printf " On"
    200        fi
    201     else
    202         echo " Off"
    203     fi
    204 }
    205 
    206 # A submenu for a specific device that allows connecting, pairing, and trusting
    207 device_menu() {
    208     device=$1
    209 
    210     # Get device name and mac address
    211     device_name=$(echo $device | cut -d ' ' -f 3-)
    212     mac=$(echo $device | cut -d ' ' -f 2)
    213 
    214     # Build options
    215     if device_connected $mac; then
    216         connected="Connected: yes"
    217     else
    218         connected="Connected: no"
    219     fi
    220     paired=$(device_paired $mac)
    221     trusted=$(device_trusted $mac)
    222     options="$connected\n$paired\n$trusted"
    223 
    224     # Open rofi menu, read chosen option
    225     chosen="$(echo -e "$options" | $rofi_command "$device_name")"
    226 
    227     # Match chosen option to command
    228     case $chosen in
    229         "")
    230             echo "No option chosen."
    231             ;;
    232         $connected)
    233             toggle_connection $mac
    234             ;;
    235         $paired)
    236             toggle_paired $mac
    237             ;;
    238         $trusted)
    239             toggle_trust $mac
    240             ;;
    241     esac
    242 }
    243 
    244 # Opens a rofi menu with current bluetooth status and options to connect
    245 show_menu() {
    246     # Get menu options
    247     if power_on; then
    248         power="Power: on"
    249 
    250         # Human-readable names of devices, one per line
    251         # If scan is off, will only list paired devices
    252         devices=$(bluetoothctl devices | grep Device | cut -d ' ' -f 3-)
    253 
    254         # Get controller flags
    255         scan=$(scan_on)
    256         pairable=$(pairable_on)
    257         discoverable=$(discoverable_on)
    258         divider="---------"
    259 
    260         # Options passed to rofi
    261         options="$devices\n$divider\n$power\n$scan\n$pairable\n$discoverable\nExit"
    262     else
    263         power="Power: off"
    264         options="$power\nExit"
    265     fi
    266 
    267     # Open rofi menu, read chosen option
    268     chosen="$(echo -e "$options" | $rofi_command "bluetooth:")"
    269 
    270     # Match chosen option to command
    271     case $chosen in
    272         "" | $divider)
    273             echo "No option chosen."
    274             ;;
    275         $power)
    276             toggle_power
    277             ;;
    278         $scan)
    279             toggle_scan
    280             ;;
    281         $discoverable)
    282             toggle_discoverable
    283             ;;
    284         $pairable)
    285             toggle_pairable
    286             ;;
    287         *)
    288             device=$(bluetoothctl devices | grep "$chosen")
    289             # Open a submenu if a device is selected
    290             if [[ $device ]]; then device_menu "$device"; fi
    291             ;;
    292     esac
    293 }
    294 
    295 # Rofi command to pipe into, can add any options here
    296 rofi_command="dmenu -p"
    297 
    298 case "$1" in
    299     --status)
    300         print_status
    301         ;;
    302     *)
    303         show_menu
    304         ;;
    305 esac