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