#!/bin/sh #load config CONFIG="${XDG_CONFIG_HOME:-$HOME/.config}/bt/config" #shellcheck disable=SC1090 . "$CONFIG" "$AUTOTRUST" || actions="$(printf '%s\ntrust\n' "$actions")" power(){ powerstatus="$( bluetoothctl show | grep Powered | awk '{print $2}' )" if [ "$powerstatus" = "no" ]; then [ "$1" = on ] && bluetoothctl power on elif [ "$powerstatus" = "yes" ]; then [ "$1" = off ] && bluetoothctl power off fi } scan(){ scanstatus="$( bluetoothctl show | grep Discovering | awk '{print $2}' )" if [ "$1" = on ]; then #sets variable in case scanning was no already on before the start of bt [ -f /tmp/bt_start_scan$$ ] || start_scan="$( date +'%s' )" if [ "$scanstatus" = "no" ]; then bluetoothctl scan on & start_scan="$( date +'%s' )" fi echo "$start_scan" > /tmp/bt_start_scan$$ elif [ "$1" = off ]; then if [ "$scanstatus" = "yes" ]; then bluetoothctl scan off fi fi } #Check bluetoothctl devices Paired for new devices to be hardcoded into pair list update_pair_list(){ btctl_paired_devices="$(bluetoothctl devices Paired)" if [ -n "$btctl_paired_devices" ] then #do not modify files when issues occur if echo "$btctl_paired_devices" | grep -q "No default controller available"; then return fi #needs temp var as it writes into the same file as it reads from btctl_not_in_list="$( echo "$btctl_paired_devices" | grep -vf "$PAIRLIST")" [ -n "$btctl_not_in_list" ] && echo "$btctl_not_in_list" >> "$PAIRLIST" fi } #start scanning as early as possible to speed up pairing process startup(){ if $AUTOSCAN then power on scan on fi } if [ "$1" = "edit" ]; then case $2 in "config")${EDITOR:-vim} "$CONFIG";; "paired")${EDITOR:-vim} "$PAIRLIST";; "alias")${EDITOR:-vim} "$ALIASLIST";; "blacklist")${EDITOR:-vim} "$BLACKLIST";; *)echo "options: config/paired/alias/blacklist" && exit 1;; esac exit fi startup & update_pair_list & # shellcheck disable=SC1091 connected_ids="$(bluetoothctl devices | awk '{print "bluetoothctl info "$2}' | . /dev/stdin | grep -E '(^Device |Connected:)' | sed -e 'N;s/\n/;/' | grep 'Connected: yes' | cut -d' ' -f2,5)" de_alias(){ while read -r id; do if grep -q "$id" "$ALIASLIST"; then grep "$id" "$ALIASLIST" | cut -d' ' --complement -f1 else grep "$id" "$PAIRLIST" | cut -d' ' --complement -f1,2 fi done } [ -z "$connected_ids" ] || connected_devices="$( echo "$connected_ids" | de_alias )" # shellcheck disable=SC2154 "$include_disconnect_option" && [ -n "$connected_devices" ] && actions="$(printf "disconnect\n%s" "$actions")" #Compile list of all device ids of paired devices (from bluetoothctl and from hardcoded list) connected_ids="$( ( bluetoothctl devices Paired && cat "$PAIRLIST" ) | sort -u | cut -d' ' -f2)" paired_devices="$( echo "$connected_ids" | de_alias )" echo "paired_devices:" echo "$paired_devices" disp_devices="$( echo "$paired_devices" | grep -vf "$BLACKLIST" )" #show which devices are connected in menu disp_devices_with_links="$(echo "$paired_devices" | while read -r device; do printf '%s' "$device" if [ -n "$connected_devices" ] && echo "$device" | grep -q "$connected_devices" then printf '🔗' fi printf '\n' done )" #detects current power mode of controller and adjusts options accordingly powerstatus="$( bluetoothctl show | grep Powered | awk '{print $2}' )" poweroption="$( echo "$powerstatus" | sed 's/yes/power off/; s/no/power on/' )" #read cmd arguments if available if [ -z "$1" ]; then #Don't print empty device list, removes unnecessary empty choice in dmenu if [ "$disp_devices" = "" ];then choice=$( printf "%s\n%s" "$actions" "$poweroption" | dmenu -i -p 'What BT action would you like to perform:') else choice=$( ( echo "$disp_devices_with_links" && printf "%s\n%s" "$actions" "$poweroption" ) | dmenu -i -p 'What BT action would you like to perform:' | sed 's/🔗$//') fi else choice="$1" fi cleanup(){ scan off rm -f /tmp/bt_start_scan* pkill -RTMIN+$barsignal $bar exit 0 } pair(){ #since this function can get called indefinitely, make sure to always be scanning and controller has power in the case that it got deactived by some other process. power on scan on > /dev/null #check whether $SCAN_PERIOD seconds has already passed since starting scanning, if not, wait for the rest of that time. start_scan="$(cat /tmp/bt_start_scan$$)" if [ $(( $(date +'%s') - start_scan )) -lt "$SCAN_PERIOD" ]; then sleep_period="$(( SCAN_PERIOD - $( date +'%s') + start_scan ))" [ "$sleep_period" -gt 1 ] && plural="s" notify-send "bt" "Searching for devices, please wait $sleep_period second$plural" sleep "$sleep_period" unset plural fi all_devices="$( bluetoothctl devices )" if [ "$paired_devices" = "" ]; then new_devices="$( echo "$all_devices" | awk '{for (i=3; i /dev/stderr exit 1 fi fi if [ -n "$choice" ]; then if [ "$choice" = "rescan" ]; then start_scan="$( date +'%s')" echo "$start_scan" > /tmp/bt_start_scan$$ pair "$1" else dev_no=$( echo "$new_devices" | nl | grep "$choice" | awk '{print $1}') dev_id=$( echo "$bt_IDS" | nl | grep -P "^ *$dev_no\t" | awk '{print $2}' ) #only attempt to connect if pairing succeeds bluetoothctl pair "$dev_id" && ( pair_succesful=true && bluetoothctl connect "$dev_id" ) || pair_succesful=false if $AUTOTRUST; then bluetoothctl trust "$dev_id" fi #if device is not already hard coded as paired, add to paired devices list if $pair_succesful && [ "$( grep "$dev_id" "$PAIRLIST")" = "" ] || [ "$(wc -l < "$PAIRLIST")" -eq 0 ] then echo to be added to "$PAIRLIST": echo Device "$dev_id" "$choice" echo Device "$dev_id" "$choice" >> "$PAIRLIST" fi fi fi } case $choice in "power on") bluetoothctl power on;; "power off") bluetoothctl power off;; "scan on") bluetoothctl power on && echo power on && sleep 2 ([ -n "$TERMINAL" ] && $TERMINAL -e bluetoothctl scan on ) || st bluetoothctl scan on > /dev/null;; "pair") pair "$2";; "unpair") if [ -z "$2" ]; then choice=$( echo "$paired_devices" | dmenu -l 10 -i -p 'remove which paired device?') else if echo "$paired_devices" | grep -q "$2";then choice="$2" else echo "Device $2 not found." > /dev/stderr exit 1 fi fi if [ -n "$choice" ]; then dev_no=$( echo "$paired_devices" | nl | grep -P "[0-9]+\t$choice$" | awk '{print $1}') dev_id=$( echo "$bt_IDS" | nl | grep -P "^.*$dev_no\t" | awk '{print $2}' ) bluetoothctl remove "$dev_id" #remove device to unpair from hard coded paired devices list new_paired_list="$( grep -v "$dev_id" "$PAIRLIST" )" if [ "$new_paired_list" != "" ] then echo "$new_paired_list" > "$PAIRLIST" else rm -rf "$PAIRLIST" touch "$PAIRLIST" fi fi;; "trust") #search through all devices which are connected and only list those as options # shellcheck disable=SC1091 untrusted_device_ids="$( awk '{print "bluetoothctl info "$2}' "$PAIRLIST" | . /dev/stdin | grep -E '(Device |Trusted:)' | sed -e 'N;s/\n/;/;s/^.?*Alias: //' | grep "Trusted: no" | cut -d' ' -f2 )" untrusted_devices="$( echo "$untrusted_device_ids" | de_alias )" if [ "$( echo "$untrusted_devices" | wc -l )" -gt 0 ] then if [ -z "$2" ]; then choice=$( echo "$untrusted_devices" | dmenu -l 10 -i -p 'trust which paired device?') else if echo "$untrusted_devices" | grep -q "$2"; then choice="$2" else echo "Device $2 not found." > /dev/stderr exit 1 fi fi else notify-send "bt" "No paired devices that are not trusted already." fi if [ -n "$choice" ]; then dev_no=$( echo "$paired_devices" | nl | grep -P "[0-9]+\t$choice$" | awk '{print $1}') dev_id=$( echo "$bt_IDS" | nl | grep -P "^.*$dev_no\t" | awk '{print $2}' ) bluetoothctl trust "$dev_id" fi;; "disconnect") #search through all devices and check which are connected #only list those connceted devices as options # shellcheck disable=SC1091 connected_ids="$(bluetoothctl devices | awk '{print "bluetoothctl info "$2}' | . /dev/stdin | grep -E '(^Device |Connected:)' | sed -e 'N;s/\n/;/' | grep 'Connected: yes' | cut -d' ' -f2,5)" connected_devices="$( echo "$connected_ids" | de_alias )" if [ -z "$2" ]; then #only open dmenu prompt if there is more than one connected device if [ "$( echo "$connected_devices" | wc -l )" -gt 1 ] then choice=$( echo "$connected_devices" | dmenu -l 10 -i -p 'disconnect which paired device?') else choice="$connected_devices" fi else if echo "$connected_devices" | grep -q "$2"; then choice="$2" else echo "Device $2 not found." > /dev/stderr exit 1 fi fi #only there was a choice (instead of canceling the dmenu) if [ -n "$choice" ]; then dev_no=$( echo "$paired_devices" | nl | grep -P "[0-9]+\t$choice$" | awk '{print $1}') dev_id=$( echo "$bt_IDS" | nl | grep -P "^.*$dev_no\t" | awk '{print $2}' ) bluetoothctl disconnect "$dev_id" fi;; "blacklist") if [ -z "$2" ]; then choice=$( echo "$paired_devices" | dmenu -l 10 -i -p 'blacklist which paired device from selection?') else if echo "$paired_devices" | grep -q "$2"; then choice="$2" else echo "Device $2 not found." > /dev/stderr exit 1 fi fi if [ -n "$choice" ]; then echo "$choice" >> "$BLACKLIST" fi;; *) echo "choice: $choice" dev_no=$( echo "$paired_devices" | nl | grep -P "[0-9]+\t$choice$" | awk '{print $1}') [ "$dev_no" != "" ] && dev_id=$( echo "$connected_ids" | nl | grep -P "^.*$dev_no\t" | awk '{print $2}') echo "dev_id: $dev_id" if [ -n "$dev_id" ]; then power on if bluetoothctl info "$dev_id" | grep -q "Connected: yes" then echo Was connceted... disconnecting bluetoothctl disconnect "$dev_id" else if ! bluetoothctl devices Paired | grep -q "$dev_id"; then echo "not in paired-devices list, re-adding (device needs to be in pairing mode for this)" notify-send "bt" "device not in paired-devices list, re-pairing" all_devices="$(bluetoothctl devices | cut -d' ' -f2)" if ! echo "$dev_id" | grep -q "$all_devices"; then scan on start_scan="$(cat /tmp/bt_start_scan$$)" echo "Scan on" notify-send "bt" "Scanning for new devices until wanted device has been found" until echo "$dev_id" | grep -q "$all_devices"; do sleep 1 all_devices="$(bluetoothctl devices | cut -d' ' -f2)" time_scanned="$(( $(date +'%s') - start_scan ))" [ "$time_scanned" -gt 30 ] && exit 1 done fi echo Attempting to pair... bluetoothctl pair "$dev_id" scan off fi echo connecting... bluetoothctl connect "$dev_id" fi fi;; esac cleanup