Here’s a fun little project I did to put the AirPods battery level on my MacBook’s Touch Bar. Heads up: This is a not a guide for beginners!
First part is a quick how to, then I’ll go into detail about how each part works.
Bonus points: I had to work out how to get a lot of bluetooth information via the command line, so there’s some nice shell scripts for it too!
UPDATE 1 – The script is updated to V1.2 thanks to ankushg and spetkowski. It’s more efficient and works on BeatsX Headphones too!
UPDATE 4: You can skip creating a .sh file and paste the code straight into Better Touch Tool. I’ve updated the How To to reflect this.
How To
You’ll need a copy of Better Touch Tool for this, grab it from here.
Note: As of Update 4 of this post, I’ve rewritten this section!! The script will automatically grab the MAC Address of your AirPods, and you can even skip downloading the script and copy/paste in the code 😀
Fire up Better Touch Tool, go to the TouchBar section, click the “+ Widget” button.
Under Select Touch Bar Widget, go to “Run AppleScript and Show Return Value”
In here enter the following:
return do shell script "OUTPUT='🎧'; BLUETOOTH_DEFAULTS=$(defaults read /Library/Preferences/com.apple.Bluetooth); SYSTEM_PROFILER=$(system_profiler SPBluetoothDataType); MAC_ADDR=$(grep -b2 \"Minor Type: Headphones\"<<<\"${SYSTEM_PROFILER}\"|awk '/Address/{print $3}'); CONNECTED=$(grep -ia6 \"${MAC_ADDR}\"<<<\"${SYSTEM_PROFILER}\"|awk '/Connected: Yes/{print 1}'); BLUETOOTH_DATA=$(grep -ia6 '\"'\"${MAC_ADDR}\"'\"'<<<\"${BLUETOOTH_DEFAULTS}\"); BATTERY_LEVELS=(\"BatteryPercentCombined\" \"HeadsetBattery\" \"BatteryPercentSingle\" \"BatteryPercentCase\" \"BatteryPercentLeft\" \"BatteryPercentRight\"); if [[ \"${CONNECTED}\" ]]; then for I in \"${BATTERY_LEVELS[@]}\"; do declare -x \"${I}\"=\"$(awk -v pat=\"${I}\" '$0~pat{gsub (\";\",\"\"); print $3 }'<<<\"${BLUETOOTH_DATA}\")\"; [[ ! -z \"${!I}\" ]] && OUTPUT=\"${OUTPUT} $(awk '/BatteryPercent/{print substr($0,15,1)\": \"}'<<<\"${I}\")${!I}%\"; done; printf \"%s\\n\" \"${OUTPUT}\"; else printf \"%s Not Connected\\n\" \"${OUTPUT}\"; fi" # Version 2.3
Click Compile/Check Syntax, then Run Script to make sure it runs okay. Hit Save and you’re good!
Old How To
Below is the old version, I’m leaving this here if you want to use a .sh file for AirPods Power (for programmers etc, you can use the output to do more fun things)
There’s a little command line script you’ll need. Click here to download it.
Put the .sh file somewhere nice, I put mine in /Users/duck/Scripts/AirPodsPower.sh
For the rest of this article, wherever you see /Users/duck/Scripts/AirPodsPower.sh, replace it with wherever you put the file.
For the rest of this article, wherever you see /Users/duck/Scripts/AirPodsPower.sh, replace it with wherever you put the file.
Open up your favourite text editor (I like Sublime Text), you’ll want to change the line at the top that says: MACADDR to be the MAC address of your AirPods.
You can get this by holding option down, clicking on the Bluetooth Icon in your menu bar, then going to your AirPods (when they’re connected).
Open up a Terminal window and type:
chmod +x /Users/duck/Scripts/AirPodsPower.sh
(Change this to wherever you put the script)
You can test the script by typing: /Users/duck/Scripts/AirPodsPower.sh
Now, to the Better Touch Tool part of it:
Go to the TouchBar section, click the “+ Widget” button.
Under Select Touch Bar Widget, go to “Run AppleScript and Show Return Value”
In here enter the following:
return do shell script "/Users/duck/Scripts/AirPodsPower.sh"
Click Compile/Check Syntax, then Run Script to make sure it runs okay. Hit Save and you’re good!
Extra Notes
While I was working this out, I worked out a bunch of extra bits that I couldn’t easily google. These pretty much *only* apply to AirPods in their current form, but can be modified to read all sorts of other bits.
First up, here’s how to see if a Bluetooth device is connected via the command line (Replace $MACADDR with the MAC Address of the device):
system_profiler SPBluetoothDataType | /usr/local/bin/pcregrep -Mi "$MACADDR(\n.*){6}" | grep "Connected: Yes" | sed 's/.*Connected: Yes/1/'
Using system_profiler, you can get the state of a whole bunch of stuff on the system in either XML (using the -xml switch) or indented form. I just run that command showing me all the Bluetooth Devices, grep for the MAC Address of my AirPods, grab the next 6 lines of text (this includes the line saying “Connected: Yes”, then replaces the words “Connected: Yes” with a 1 to make it neater for working with the shell script.
This was built just for AirPods, so for other devices you may need to change the pcregrep bit to check for more/less lines after the MAC address is found.
Secondly, getting the data for the battery levels from a device via Command Line (again, replace $MACADDR with the MAC Address of the device).
BTDATA=`defaults read /Library/Preferences/com.apple.Bluetooth | /usr/local/bin/pcregrep -Mi "\"$MACADDR\".=\s*\{[^\}]*\}"` CASEBATT=`echo "$BTDATA" | grep BatteryPercentCase | sed 's/.*BatteryPercentCase = //' | sed 's/;//'`
defaults read /Library/Preferences/com.apple.Bluetooth will return all the info about bluetooth in json form, which seems to include every bluetooth device that has farted anywhere near the machine, so the next part will pcregrep for the MAC Address and include everything until the closing tag.
Then the next line grabs just the BatteryPercentCase part.
Also note it’s only really reading a cached value rather than a “live” value. So it’ll be a little bit behind (little bit being like 10-30seconds or so, good enough for what I want to do).
Hopefully this helped you! If you like this article, leave a comment and say hi 🙂
Update 4 – Skipping the .sh file part
In Better Touch Tool, when you get to the step to paste in the AppleScript, paste the following:
return do shell script "OUTPUT='🎧'; BLUETOOTH_DEFAULTS=$(defaults read /Library/Preferences/com.apple.Bluetooth); SYSTEM_PROFILER=$(system_profiler SPBluetoothDataType); MAC_ADDR=$(grep -b2 \"Minor Type: Headphones\"<<<\"${SYSTEM_PROFILER}\"|awk '/Address/{print $3}'); CONNECTED=$(grep -ia6 \"${MAC_ADDR}\"<<<\"${SYSTEM_PROFILER}\"|awk '/Connected: Yes/{print 1}'); BLUETOOTH_DATA=$(grep -ia6 '\"'\"${MAC_ADDR}\"'\"'<<<\"${BLUETOOTH_DEFAULTS}\"); BATTERY_LEVELS=(\"BatteryPercentCombined\" \"HeadsetBattery\" \"BatteryPercentSingle\" \"BatteryPercentCase\" \"BatteryPercentLeft\" \"BatteryPercentRight\"); if [[ \"${CONNECTED}\" ]]; then for I in \"${BATTERY_LEVELS[@]}\"; do declare -x \"${I}\"=\"$(awk -v pat=\"${I}\" '$0~pat{gsub (\";\",\"\"); print $3 }'<<<\"${BLUETOOTH_DATA}\")\"; [[ ! -z \"${!I}\" ]] && OUTPUT=\"${OUTPUT} $(awk '/BatteryPercent/{print substr($0,15,1)\": \"}'<<<\"${I}\")${!I}%\"; done; printf \"%s\\n\" \"${OUTPUT}\"; else printf \"%s Not Connected\\n\" \"${OUTPUT}\"; fi" # Version 2.3
When you’ve pasted that in, press Compile/Check Syntax, then Run Script and make sure it works (I’m not sure if WordPress will mangle the code on me).
Thanks to Danoz for his help with this script!
[…] AirPods Power In TouchBar […]
This is great! any way to do the same with Magic Mouse?
Thanks a lot!
Thanks for sharing, super useful for me! Anyway, I’m using a Wacom Pen Tablet and wondering if it’s also possible to show the battery status 🤔
By any chance there is any way to change the size of font? I’d like to see something smaller..
Thanks for the great post! I’ve used your code as a base to really make the Touchbar useful with my Airpods.
I found the case battery was always 0% so I left that out and reduced space so just says something like “L50 R50”, changed “Not Connected” to simply N/C and have an icon of AirPods added. Also have a match on return so background colour/icon is changed if not connected (dimmed)
Big change though was to add more AppleScript code the Predefined Action in BTT to allow me to press the button to connect the AirPods in the morning when I get to the office. Works brilliantly. Code for that was taken from:
https://medium.com/@igloude/using-applescript-and-btt-to-make-the-airpods-experience-a-little-bit-better-6e78b12d33bd
Thought it could be useful!
Would be great if the script accounted for the fact that the case only connects when open and at any other time the script outputs c: 0%. My idea is to hide the C part when it is 0%
Hey dude, I don’t have time to work on this at the moment, I moved to using the menu bar widget as part of iStat Menus and it seems to be working better.
If you’re keen, the source code is on Github so you could alter it to suit?
Question: Any way to show the result in two lines, something like:
L:96% R:94%
Case:64%
I managed to do this with other scripts by running two separate scripts and end up with
return value1 & ”
” & value2
This would be much nicer in the Touch Bar I think. A version that shows only the AirPod’s Battery on two lines (one per AirPod) would be a nice option too I guess!
Thanks guys!
[…] 「AirPods Power」はキーボードオールラウンドのBetter Touch […]
When I try this, my output is doubled:
🎧 Case: 9690% Left: 100100% Right: 100100%
It appears that there are two entries within the BT_DATA for BatteryPercentCase/Right/Left and I’d like to get rid of the first one (as it appears to be older value).
Any thoughts on what I’m missing here?
When I run the .sh version, my output gets doubled as below:
🎧 Case: 9689% Left: 100100% Right: 100100%
BatteryPercentCase/Right/Left appears to show up twice in BT_DATA, any idea on how to get only the second which appears to more correctly match what shows in the Bluetooth menu bar applet?
Thanks,
[…] AirPods Power ist ein Script für den Tastatur-Alleskönner Better Touch Tool. Kopiert den hier abgelegten Code einfach in eure BTT-Konfiguration und freut euch anschließend über die dauerhafte Anzeige des AirPod-Akku-Status in der Touch Bar. […]
The script does not work in my case. I use AirPods Pro with a MacBook Pro from 2020. When they are not connected it successfully says “Not connected” otherwise, it just prints out the headphones symbol.
What can I try to fix it? 🙂
Thank you in Advance!
I think I fixed it.
The problem was that (may be due to a 2020 update) neither BTT nor my shell had direct access to the MAC_ADDR. So I had to split the Bluetooth data at the AccessoryVersion.
Maybe a dirty fix if this will be changed in future, but for now it works.
Everything is doubled… Not working.