Skip to content

Commit

Permalink
bug fix
Browse files Browse the repository at this point in the history
1. add icons on menubar (default off).
2. fix connection status discrepancy between M1 & intel chips.
  • Loading branch information
noonchen committed Jan 5, 2021
1 parent f30044a commit eee6c92
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 150 deletions.
138 changes: 0 additions & 138 deletions AppleHeadphone.bttpreset

This file was deleted.

Binary file removed AppleHeadphone_0523.bttpresetzip
Binary file not shown.
18 changes: 12 additions & 6 deletions source/connect_appleBT.py
Expand Up @@ -5,13 +5,18 @@

disconnectedBGColor = "59,59,59,255"
connectedBGColor = "110,193,56,255"
disconnectedFontColor = "" # Empty string means default color
connectedFontColor = ""
# devNAME = "Noon’s AirPods Pro" # For testing only
devNAME = os.environ['devNAME'].strip('"')
devNAME = "" if not 'devNAME' in os.environ else os.environ['devNAME'].strip('"')
osascript = ['osascript']
asobjc = ['''use framework "IOBluetooth"''',
'''set deviceList to current application's IOBluetoothDevice's pairedDevices()''',
'''set devNames to (deviceList's valueForKey:"name") as list''',
'''set devStatus to (deviceList's valueForKey:"connected") as list''',
'''set devStatus to {}''',
'''repeat with dev in deviceList''',
'''set end of devStatus to dev's isConnected()''',
'''end repeat''',
'''set devAddress to (deviceList's valueForKey:"addressString") as list''',
'[devNames, devStatus, devAddress]']
BT_plist_path = "/Library/Preferences/com.apple.Bluetooth.plist"
Expand Down Expand Up @@ -59,7 +64,7 @@ def main():
BT_dict = dict(zip(rawInfo[:N_devs], [[rawInfo[N_devs+i], rawInfo[2*N_devs+i]] for i in range(N_devs)]))

if devNAME in BT_dict:
connected = True if BT_dict[devNAME][0] == "1" else False
connected = True if BT_dict[devNAME][0] == "true" else False
macAddr = BT_dict[devNAME][1]
# Get detailed data from BT device cache
devCache = plistlib.load(open(BT_plist_path, 'rb'))["DeviceCache"][macAddr]
Expand All @@ -69,12 +74,13 @@ def main():
IconPath = getIconPath(IOBTUI_resPath, ProductID)
fontsize, BatteryString = formatBatteryString(devCache, ProductID, connected)
BGcolor = connectedBGColor if connected else disconnectedBGColor
return jsonfy(text=BatteryString, icon_path=IconPath, font_size=fontsize, background_color=BGcolor)
font_color = connectedFontColor if connected else disconnectedFontColor
return jsonfy(text=BatteryString, icon_path=IconPath, font_size=fontsize, background_color=BGcolor, font_color=font_color)
else:
return jsonfy(text="ID not found", background_color=disconnectedBGColor)
return jsonfy(text="Product not\nfound", font_size=9)
else:
# Name is not correct or the device hasn't been connected to mac before
return jsonfy(text="Not configured", background_color=disconnectedBGColor)
return jsonfy(text="Headphones are\nnot configured", font_size=9)

if __name__ == "__main__":
print(main())
85 changes: 85 additions & 0 deletions source/connect_appleBT_menubar.py
@@ -0,0 +1,85 @@
#!/usr/bin/env python3
#encoding:utf-8
from subprocess import check_output
import plistlib, os

disconnectedColor = "59,59,59,255"
connectedColor = "110,193,56,255"
# devNAME = "Noon’s AirPods Pro" # For testing only
devNAME = "" if not 'devNAME' in os.environ else os.environ['devNAME'].strip('"')
osascript = ['osascript']
asobjc = ['''use framework "IOBluetooth"''',
'''set deviceList to current application's IOBluetoothDevice's pairedDevices()''',
'''set devNames to (deviceList's valueForKey:"name") as list''',
'''set devStatus to {}''',
'''repeat with dev in deviceList''',
'''set end of devStatus to dev's isConnected()''',
'''end repeat''',
'''set devAddress to (deviceList's valueForKey:"addressString") as list''',
'[devNames, devStatus, devAddress]']
BT_plist_path = "/Library/Preferences/com.apple.Bluetooth.plist"
IOBTUI_resPath = "/System/Library/Frameworks/IOBluetoothUI.framework/Versions/A/Resources"

def jsonfy(text="", icon_data="", icon_path="", background_color="", font_color="", font_size=0):
'''
Convert data into JSON string for BTT to render
'''
import json
dict = {}
if text != "": dict["text"] = text
if icon_data != "": dict["icon_data"] = icon_data
if icon_path != "": dict["icon_path"] = icon_path
if background_color != "": dict["background_color"] = background_color
if font_color != "": dict["font_color"] = font_color
if font_size != 0: dict["font_size"] = font_size
return json.dumps(dict, ensure_ascii=False)

def getIconPath(IOBTUI_resPath, ProductID):
with os.scandir(IOBTUI_resPath) as it:
for item in it:
if item.name.startswith("AssetPaths") and item.name.endswith(".plist"):
info_dict = plistlib.load(open(item.path, 'rb'))
if ProductID in info_dict:
return os.path.join(IOBTUI_resPath, info_dict[ProductID]['ImageName'])

def formatBatteryString(devCache, ProductID, connected):
TwoBatteryProduct = ["0x2002", "0x200F", "0x200E"]
font_color = connectedColor if connected else disconnectedColor

if ProductID in TwoBatteryProduct:
fontsize = 9
Lbat = str(devCache["BatteryPercentLeft"]) if connected else '0'
Rbat = str(devCache["BatteryPercentRight"]) if connected else '0'
return fontsize, "🅛 %s\n🅡 %s"%(Lbat+'%' if Lbat!='0' else 'NC', Rbat+'%' if Rbat!='0' else 'NC'), font_color
else:
fontsize = 12
bat = str(devCache["BatteryPercentSingle"]) if connected else '0'
return fontsize, "%s"%(bat+'%' if bat!='0' else 'NC'), font_color

def main():
# Get name, status and mac addr of current BT devices
[osascript.extend(["-e", L]) for L in asobjc]
rawInfo = check_output(osascript).decode('utf-8').strip().split(', ')
N_devs = int(len(rawInfo)/3)
BT_dict = dict(zip(rawInfo[:N_devs], [[rawInfo[N_devs+i], rawInfo[2*N_devs+i]] for i in range(N_devs)]))

if devNAME in BT_dict:
connected = True if BT_dict[devNAME][0] == "true" else False
macAddr = BT_dict[devNAME][1]
# Get detailed data from BT device cache
devCache = plistlib.load(open(BT_plist_path, 'rb'))["DeviceCache"][macAddr]

if "ProductID" in devCache:
ProductID = "0x%X"%int(devCache["ProductID"])
IconPath = getIconPath(IOBTUI_resPath, ProductID)
fontsize, BatteryString, font_color = formatBatteryString(devCache, ProductID, connected)
# BGcolor = connectedBGColor if connected else disconnectedBGColor
return jsonfy(text=BatteryString, icon_path=IconPath, font_size=fontsize, font_color=font_color)
else:
return jsonfy(text="Product not\nfound", font_size=9)
else:
# Name is not correct or the device hasn't been connected to mac before
return jsonfy(text="Headphones are\nnot configured", font_size=9)

if __name__ == "__main__":
print(main())
27 changes: 21 additions & 6 deletions source/updateEnvVar.js
Expand Up @@ -3,12 +3,27 @@
//Change it to the name of your device
let devNAME = "Someone's AirPods Pro"

var props = await callBTT('get_trigger', {uuid: 'D0657B9A-53F4-49CE-8568-6D8248D0000E'});
var oldConfig = JSON.parse(props)["BTTShellScriptWidgetGestureConfig"]
var newConfig = oldConfig.split('=')[0].concat('="', devNAME, '"')
let TB_uuid = 'D0657B9A-53F4-49CE-8568-6D8248D0000E';
let MB_uuid = '3F38EE27-E68A-49D2-8969-787AAB07C3B9';

var updateDefinition = {"BTTShellScriptWidgetGestureConfig" : newConfig}
callBTT('update_trigger', {uuid: 'D0657B9A-53F4-49CE-8568-6D8248D0000E',json: JSON.stringify(updateDefinition)});
//update TB trigger
var props_tb = await callBTT('get_trigger', {uuid: TB_uuid});
var oldConfig_tb = JSON.parse(props_tb)["BTTShellScriptWidgetGestureConfig"];
var newConfig_tb = oldConfig_tb.split('=')[0].concat('="', devNAME, '"');
var updateDefinition_tb = {"BTTShellScriptWidgetGestureConfig" : newConfig_tb};
callBTT('update_trigger', {uuid: TB_uuid, json: JSON.stringify(updateDefinition_tb)});

returnToBTT(newConfig);
//update MB trigger
var props_mb = await callBTT('get_trigger', {uuid: MB_uuid});
var oldConfig_mb = JSON.parse(props_mb)["BTTAdditionalConfiguration"];
var newConfig_mb = oldConfig_mb.split('=')[0].concat('="', devNAME, '"');
var updateDefinition_mb = {"BTTAdditionalConfiguration" : newConfig_mb};
callBTT('update_trigger', {uuid: MB_uuid, json: JSON.stringify(updateDefinition_mb)});

//toggle device
let shellscript = "\"BTT_PRESET_PATH\"/BTAudioSwitch -toggleSwitch -devName=".concat('\"', devNAME, '\"');
let shellScriptWrapper = {
script: shellscript};
let result = await runShellScript(shellScriptWrapper);
returnToBTT(result);
})();

0 comments on commit eee6c92

Please sign in to comment.