Automation on MacOS -- Automatically Disconnecting Bluetooth Headset

Motivation: The Need to Remember to Disconnect Bluetooth

I usually wear my Bluetooth headset at work, this is necessary because I need to talk to people or attend meetings online. One of the things that annoys me is I have to remember to turn off my headset every time I leave my workplace, otherwise because the Bluetooth is not disconnected automatically when the Mac goes to sleep, I will find a headphone with very low battery the next day. If the Bluetooth is disconnected, the headphone will turn itself off in 5 mins, so it all comes down to remembering to disconnect Bluetooth on the laptop, or to turn off the battery on the headphone. This annoys me so much that I eventually decided to spend time to solve this problem.

Analysis

There are several ways to solve this issue, but everything comes down to a shell script, the only difference is how you would trigger the shell script.

  1. Manually trigger the shell script. This is obviously less than ideal, one would still remember to trigger the script every day from the terminal.
  2. Manually trigger from the Shortcut app. This improved a bit, but still not ideal cause it is still not automated to full potential.
    Now both 1 & 2 would require manual intervention, I would like things to be fully automated, and can run even when the laptop is locked, so I come up with the next option:
  3. Automatically trigger from calendar. This would be the most ideal, cause it is possible to control the time of the trigger, and is fully automated.

Prerequisite:

  • Blueutil
  • Automator
    (The builtin automation app in MacOS from Apple)

Attempt 1: Calendar Automation Through Shell Script

My first attempt was a simple POC through shell script through calendar automation. I first created an calendar alarm script within Automator, this depends on the Blueutil mentioned earlier. Here's the script:

Toggling Bluetooth Through CLI
1
2
3
4
5
6
7
8
9
10
11
12
if [[ $(/opt/homebrew/bin/blueutil --is-connected "REPLACE_WITH_BLUETOOTH_MAC_ADDRESS") == 1 ]]
then
/opt/homebrew/bin/blueutil --disconnect "REPLACE_WITH_BLUETOOTH_MAC_ADDRESS"
if [[ $? == 0 ]] then
osascript -e 'display notification "Headphone disconnected" with title "Headphone"'
fi
else
/opt/homebrew/bin/blueutil --connect "REPLACE_WITH_BLUETOOTH_MAC_ADDRESS"
if [[ $? == 0 ]] then
osascript -e 'display notification "Headphone connected" with title "Headphone"'
fi
fi

I tested this script in command line several times and made sure I'm happy with it. In the Automator, I created a calendar alarm automation, and chose the run shell script action, and put the command above as the script. Once this is saved, I created a calendar entry in the Calendar app, and chose alert and then select open file. The path to the workflow is ~/Library/Workflows/Applications/Calendar.

Caveats

While this works quite well, I would sometimes work after the time set in the calendar entry, this means I could be in a call with someone when the script is triggered, and my headphone would be disconnected during a call (which is really embarrassing)

Final Solution: Notification with Option to Continue or Cancel

After some struggling, I found a solution I'm happy with -- display a dialogue window asking for confirmation before disconnecting Bluetooth.
On top of the previous script, I added a new step to my Automator script, which is running an Apple Script, I added:

Toggling Bluetooth Through CLI
1
2
3
4
5
6
7
8
on run {input, parameters}

display dialog "Disconnecting Bluetooth automatically, click “Cancel” if you would like to cancel. Will auto continue in 15 seconds." with icon caution with title "Bluetooth Disconnecting.." buttons {"Cancel", "Continue"} default button 2 giving up after 15

if result = {button returned:"Cancel"} then
tell me to quits
end if
end run

This script is pretty straightforward, it will display a dialogue window, and give two option to choose from with the default behavior being Continue if no option was chosen within 15 seconds. If cancel was chosen, the entire workflow will be cancelled, so Bluetooth will not be disconnected. If continue was chosen, it will continue.

Future improvement

I can actually potentially combine the AppleScript and the Shell script and just use one step instead of two.

Lessons Learnt

I'm quite happy with the final solution I came up with. What I learnt is:

  • Apple Calendar events would still trigger alerts even when the laptop is locked.
  • One can use display dialog in AppleScript to trigger dialog confirmation.