Compact AirPods widget with User-Friendly Setup

@Irthen guess you'll have to fix this part of the code, if I remember correctly GC, AT and C3 are based on the same script regarding the AirPods!

@Caliguvara

Is the AirPods Widget download at the top of the thread the latest version? Its been a while and I have a feeling it might not be

1 Like

I've got d1.2 working with my Power Beats Pros.

1 Like

Should be. Sorry for the long delay had some busy days at work :upside_down_face:

Hey
is there a known issue with the battery display? Everything except the right AirPod is working.

I think something on this won't work for me :

       return   OUTPUT2 & "
  " & OUTPUT1

The script returns

"70

62%

76

69%"

Or do I forget something?


1 Like

You'll need to replace the MAC address with the address for your AirPods, but try this:

use framework "Foundation"

use framework "IOBluetooth"

use scripting additions

set pairedNames to ((current application's IOBluetoothDevice's pairedDevices())'s valueForKey:"nameOrAddress") as list

set connectedValue to ((current application's IOBluetoothDevice's pairedDevices())'s valueForKey:"connected") as list

set btInfo to {}

set i to 0

repeat with i from 1 to count pairedNames

set btInfo to btInfo & (item i of pairedNames & ", " & item i of connectedValue) as list

end repeat

set i to 0

set deviceConnected to false

repeat with i from 1 to count btInfo

if item i of btInfo contains "AirPods" and item i of btInfo contains ", 1" then

set deviceConnected to true

else if item i of btInfo contains "24-1B-7A-EC-B0-A6" and item i of btInfo contains ", 1" then

set deviceConnected to true

end if

end repeat

if deviceConnected is true then

set batteryPercentLeft to do shell script "BLUETOOTH_DEFAULTS=$(defaults read /Library/Preferences/com.apple.Bluetooth); SYSTEM_PROFILER=$(system_profiler SPBluetoothDataType); MAC_ADDR=24-1B-7A-EC-B0-A6; CONNECTED=$(grep -ia6 "${MAC_ADDR}"<<<"${SYSTEM_PROFILER}"|awk '/Connected: Yes/{print 1}'); BLUETOOTH_DATA=$(grep -ia6 '"'"${MAC_ADDR}"'"'<<<"${BLUETOOTH_DEFAULTS}"); BATTERY_LEVELS=("BatteryPercentLeft"); 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 <<<"${I}")${!I}%"; done; printf "%s" "${OUTPUT}"; else printf "%s Not Connected" "${OUTPUT}"; fi"

set batteryPercentRight to do shell script "BLUETOOTH_DEFAULTS=$(defaults read /Library/Preferences/com.apple.Bluetooth); SYSTEM_PROFILER=$(system_profiler SPBluetoothDataType); MAC_ADDR=24-1B-7A-EC-B0-A6; CONNECTED=$(grep -ia6 "${MAC_ADDR}"<<<"${SYSTEM_PROFILER}"|awk '/Connected: Yes/{print 1}'); BLUETOOTH_DATA=$(grep -ia6 '"'"${MAC_ADDR}"'"'<<<"${BLUETOOTH_DEFAULTS}"); BATTERY_LEVELS=("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 <<<"${I}")${!I}%"; done; printf "%s" "${OUTPUT}"; else printf "%s Not Connected" "${OUTPUT}"; fi"

return "L: " & batteryPercentLeft & " " & return & "R: " & batteryPercentRight

else

return ""

end if

I have a similar problem as a couple other users here where only the left AirPods battery information shows, but the right AirPods does not. Can anyone help me in layman terms how to fix it? I'm not too familiar when people are just posting scripts...sorry.

Thanks so much!

I do have this working on my end. Also added Case battery percentage (not in this code below).

AirPods CONNECTED: (Touch Icon to disconnect)

AirPods NOT CONNECTED: (Touch button to connect)

use framework "Foundation"
use framework "IOBluetooth"
use scripting additions

set pairedNames to ((current application's IOBluetoothDevice's pairedDevices())'s valueForKey:"nameOrAddress") as list
set connectedValue to ((current application's IOBluetoothDevice's pairedDevices())'s valueForKey:"connected") as list
set btInfo to {}

set i to 0
repeat with i from 1 to count pairedNames
	set btInfo to btInfo & (item i of pairedNames & ", " & item i of connectedValue) as list
end repeat

set i to 0
set deviceConnected to false
repeat with i from 1 to count btInfo
	if item i of btInfo contains "AirPods" and item i of btInfo contains ", 1" then
		set deviceConnected to true
	else if item i of btInfo contains "Nothing Special" and item i of btInfo contains ", 1" then
		set deviceConnected to true
	end if
end repeat

if deviceConnected is true then
	set batteryPercentLeft to do shell script "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=(\"BatteryPercentLeft\"); 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 <<<\"${I}\")${!I}%\"; done; printf \"%s\" \"${OUTPUT}\"; else printf \"%s Not Connected\" \"${OUTPUT}\"; fi"
	set batteryPercentRight to do shell script "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=(\"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 <<<\"${I}\")${!I}%\"; done; printf \"%s\" \"${OUTPUT}\"; else printf \"%s Not Connected\" \"${OUTPUT}\"; fi"
	return "L " & batteryPercentLeft & "   " & "R " & batteryPercentRight
else
	return ""
end if

Did anyone ever give you an answer on how to fix this? I'm having the exact same issue and cannot figure it out.

@yuuiko @Caliguvara Any idea why mine is doing this too?

"The script returns

"70

62%

76

69%"

Or do I forget something?"

Just like the other guy mentioned, it's adding random numbers into the battery percentage. I've spent a few hours now trying to debug the code to figure out why but can't figure it out.

As far as I'm aware it seems to be a Catalina issue as these reports have been coming in after the Catalina Release.

Unfortunately I don't have AirPods or Catalina to debug myself, so...

@Caliguvara @GoldenChaos

1 Like

Gotcha, that makes sense. Thought I was going to go insane trying to figure out why it was happening lol. I'll wait for a bit and see if anyone else has any solutions for it. Thank you for the reply.

Interesting result indeed. Didn't actually use the Widget in ages and am quite surprised now to come back here and discover this. Gonna dive into it one of these days and try to upload a patch.

The problem though seems to be deeper in the code. Basically all the widgets are based on a script a great man wrote:

	set OUTPUT1 to do shell script "
OUTPUT1='';
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\" \"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}\" ]] && 
   OUTPUT1=\"${OUTPUT}$(awk '/BatteryPercent/{print substr($0)}'<<<\"${I}\")${!I}%\";
    done;
    printf \"%s\" \"${OUTPUT1}\";
fi"
	
	set OUTPUT2 to do shell script "
OUTPUT2='';
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\" \"BatteryPercentLeft\"); 

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}\" ]] && 
   OUTPUT2=\"${OUTPUT}$(awk '/BatteryPercent/{print substr($0)}'<<<\"${I}\")${!I}%\";
    done;
    printf \"%s\" \"${OUTPUT2}\";
fi"
	
	set BatteryLevel to OUTPUT2 & "
" & OUTPUT1
	
return BatteryLevel

And for now I have no idea where Catalina hands out the extra values :man_shrugging:t2:

1 Like

Yeah, for now I just have it showing the Left AirPod's battery. Not very clean, but it gives me an idea since both AirPods are generally within 5% of eachother lol. I really don't know what Catalina could have changed with this that causes it to behave so oddly, but I'll keep my eyes on the forums in case someone has a solution

Ah, how did you manage to get this? Because if you got one you could just associate it to a new variable, set a new variable to the other battery and display both of them.

Oh wow you're right, perhaps I could. Nothing special in my code really. I was messing with it a bit but I don't think there's anything groundbreaking in it. I messed with the actual size of the widget icon in the bar. I'll attach an image and some code.

return checkStatus()

on checkStatus()
	--GET STORED NAME
	--END GET STORED NAME
	
	--set myString to button returned of (display dialog "Connected?" buttons {"Yes", "No"})
	--set myString to "name: DR-BT101 Connected: " & myString
	
	(*uncomment line below when done testing*)
	set myString to do shell script "system_profiler SPBluetoothDataType"
	
	--initial check if it's not even there
	if myString does not contain "yeet" then
		return " "
	else
		
		--find out if connected/disconnected
		set AppleScript's text item delimiters to "name:"
		set myList to the text items of myString --each item of mylist is now one of the devices
		
		set numberOfDevices to count of myList
		set counter to 1
		repeat numberOfDevices times --loop through each devices checking for Connected string
			if item counter of myList contains "yeet" then
				if item counter of myList contains "Connected: Yes" then
					return checkBattery()
				else if item counter of myList contains "Connected: No" then
					return " "
				else
					display dialog "Error Parsing" --this shouldn't happen
				end if
			end if
			set counter to counter + 1
		end repeat
	end if
end checkStatus

on checkBattery()
	set OUTPUT1 to do shell script "
OUTPUT1='';
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\" \"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}\" ]] && 
   OUTPUT1=\"${OUTPUT}$(awk '/BatteryPercent/{print substr($0)}'<<<\"${I}\")${!I}%\";
    done;
    printf \"%s\" \"${OUTPUT1}\";
fi"
	
	set OUTPUT2 to do shell script "
OUTPUT2='';
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\" \"BatteryPercentLeft\"); 

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}\" ]] && 
   OUTPUT2=\"${OUTPUT}$(awk '/BatteryPercent/{print substr($0)}'<<<\"${I}\")${!I}%\";
    done;
    printf \"%s\" \"${OUTPUT2}\";
fi"
	
	set BatteryLevel to OUTPUT2 & "
" & OUTPUT1
	
	if BatteryLevel is "" & "
" & "" then
		return " "
	else
		return BatteryLevel
	end if
	
end checkBattery

And attached is the screenshot showing the icon on my TouchBar.

It's been a few years since I've programmed so if there's an easy way to clean it up to make it so that it doesn't include the random numbers in there, I'm all for testing that out. Here's the result of my code right now:

"Script result:
"60
91%
52
90%""

If there were any doubts that the widget would work with the new Air Pods Pro, I can confirm that it does work.

3 Likes

I'm having the same problem.

Please try this: go to system Settings → Bluetooth and copy your AirPods' Name there. Then paste it in BTT. There is some issue from macOS with the apostrophe in the name.

I've tried copying and pasting this code into the Apple Script button several times and can't get it to work. I'm not an experienced coder guy, admittedly. I can't figure out if I need to change something to my AirPods name, and if I do, where I do it.

After I compile and Run Script, I keep getting " " as a result.

Could I get a little help?