bthandler/bt

286 lines
10 KiB
Bash
Executable File

#!/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 paired-devices for new devices to be hardcoded into pair list
update_pair_list(){
btctl_paired_devices="$(bluetoothctl paired-devices)"
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 paired-devices && 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/' )"
#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
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<NF; i++) printf $i " "; print $NF}' )"
bt_IDS="$( echo "$all_devices" | awk '{print $2}' )"
else
filtered_devices="$( echo "$all_devices" | grep -v "$paired_devices")"
bt_IDS="$( echo "$filtered_devices" | awk '{print $2}' )"
new_devices="$( echo "$filtered_devices" | awk '{for (i=3; i<NF; i++) printf $i " "; print $NF}' )"
fi
[ "$new_devices" = "" ] && options="rescan" || options=$(echo "$new_devices" && echo 'rescan')
choice=$( echo "$options" | dmenu -l 10 -i -p 'pair with which device?' )
if [ -n "$choice" ]; then
if [ "$choice" = "rescan" ]; then
start_scan="$( date +'%s')"
echo "$start_scan" > /tmp/bt_start_scan$$
pair
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;;
"unpair") choice=$( echo "$paired_devices" | dmenu -l 10 -i -p 'remove which paired device?')
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
choice=$( echo "$untrusted_devices" | dmenu -l 10 -i -p 'trust which paired device?')
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 )"
#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
#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")
choice=$( echo "$paired_devices" | dmenu -l 10 -i -p 'blacklist which paired device from selection?')
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 paired-devices | 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