@Andreas_Hegenberg I just installed this app called LidAngleSensor,
I thought having the current lid angle as a variable and/or trigger in BTT would be neat, enabling new use cases. What are your thoughts?
@Andreas_Hegenberg I just installed this app called LidAngleSensor,
I thought having the current lid angle as a variable and/or trigger in BTT would be neat, enabling new use cases. What are your thoughts?
hehe yes, I also saw this earlier and it sounds like a fun trigger/variable ![]()
Might be limited to some Macbook models tough
According to the GitHub issues and the README file, M1 isn't supported. But it's working perfectly well on my M1 MacBook Pro!
❯ ./diagnose_lid_sensor.sh
==============================================
MacBook Lid Angle Sensor Diagnostic Tool
==============================================
System Information:
- Model: MacBook Pro
- Chip: Apple M1 Max
- macOS: 15.6.1
Step 1: Looking for exact expected sensor...
Command: hidutil list --matching '{"VendorID":0x5ac,"ProductID":0x8104,"PrimaryUsagePage":32,"PrimaryUsage":138}'
✅ FOUND EXACT MATCH:
Services:
VendorID ProductID LocationID UsagePage Usage RegistryID Transport Class Product UserClass Built-In
0x5ac 0x8104 0x0 32 138 0x100000b7e SPU AppleSPUHIDDriver (null) (null) 1
Devices:
VendorID ProductID LocationID UsagePage Usage RegistryID Transport Class Product UserClass Built-In
0x5ac 0x8104 0x0 32 138 0x100000b51 SPU AppleSPUHIDDevice (null) (null) 1
Your sensor should work!
great! I‘m sure users will find creative ways to make use of it
I had a look at the code and the examples for different generic devices, but it seems it is only designed to trigger a device when certain conditions are set, but there's no way to just report the number?
I.e. I could create 131 triggers from 0˚ angle to 130˚ angle. But I can't create a trigger that mimics the battery charge triggers. Is that correctly understood?
Here's a sample for using the Generic Device BTT features with the lid sensor. It pops up a HUD when the lid closes to below 35˚:
Device JSON:
[
{
"BTTLastUpdatedAt" : 1757309391.03107,
"BTTTriggerType" : 763,
"BTTTriggerTypeDescriptionReadOnly" : "Generic Device & Input Analyzer",
"BTTTriggerTypeDescription" : "Apple:LidSensor",
"BTTTriggerClass" : "BTTTriggerTypeGenericDevice",
"BTTUUID" : "6AE63F0E-DA4F-455B-93F4-F2EA3DCFB62B",
"BTTOrder" : 0,
"BTTGenericDeviceConfiguration" : {
"BTTGenericDeviceActiveReports" : {
"1" : true
},
"BTTGenericDeviceVendorID" : "0x5ac",
"BTTGenericDeviceUsagePair2" : {
"BTTGenericDeviceUsagePage" : "",
"BTTGenericDeviceUsage" : ""
},
"BTTGenericDeviceSelectedTab" : 0,
"BTTGenericDeviceName" : "Apple:LidSensor",
"BTTGenericDeviceDropdownSelection" : {
"manufacturer" : "Apple",
"usagePairs" : [
{
"DeviceUsagePage" : 32,
"DeviceUsage" : 138
}
],
"productID" : 33028,
"serial" : "",
"vendorID" : 1452
},
"BTTGenericDeviceScript" : "function analyzeDeviceInput(targetDevice, reportID, reportDataHex) {\n let reportBuffer = buffer.Buffer.from(reportDataHex, 'hex');\n if(reportBuffer.readUInt8(1) < 0x23) {\n log('trigger!');\n bttTriggerDeviceTrigger(targetDevice, 'closing');\n}\n",
"BTTGenericDeviceProvidedTriggers" : "closing",
"BTTGenericDeviceUsagePair1" : {
"BTTGenericDeviceUsagePage" : "0x20",
"BTTGenericDeviceUsage" : "0x8a"
},
"BTTGenericDeviceProductID" : "0x8104",
"BTTGenericDeviceWatchedBytes" : {
"1" : [
1
]
}
},
"BTTGestureNotes" : "Apple:LidSensor"
}
]
Trigger JSON:
[
{
"BTTLastUpdatedAt" : 1757309172.5881009,
"BTTTriggerType" : 764,
"BTTTriggerTypeDescription" : "Apple:LidSensor: closing",
"BTTTriggerClass" : "BTTTriggerTypeGenericDevice",
"BTTUUID" : "C1270650-ECCE-418A-AA79-1BB7A9E7452B",
"BTTAdditionalConfiguration" : "6AE63F0E-DA4F-455B-93F4-F2EA3DCFB62B;;closing",
"BTTOrder" : 1,
"BTTActionsToExecute" : [
{
"BTTLastUpdatedAt" : 1757309181.780602,
"BTTTriggerParentUUID" : "C1270650-ECCE-418A-AA79-1BB7A9E7452B",
"BTTIsPureAction" : true,
"BTTTriggerClass" : "BTTTriggerTypeGenericDevice",
"BTTUUID" : "BABD05E7-D325-4BF7-858B-050B18D5A2D0",
"BTTPredefinedActionType" : 254,
"BTTPredefinedActionName" : "Show HUD Overlay",
"BTTHUDActionConfiguration" : "{\"BTTActionHUDBlur\":true,\"BTTActionHUDBackground\":\"0.000000, 0.000000, 0.000000, 0.000000\",\"BTTIconConfigImageHeight\":100,\"BTTActionHUDPosition\":0,\"BTTActionHUDDetail\":\"\",\"BTTActionHUDDuration\":0.89999997615814209,\"BTTActionHUDDisplayToUse\":0,\"BTTIconConfigImageWidth\":100,\"BTTActionHUDSlideDirection\":0,\"BTTActionHUDHideWhenOtherHUDAppears\":false,\"BTTActionHUDWidth\":220,\"BTTActionHUDAttributedTitle\":\"{\\\\rtf1\\\\ansi\\\\ansicpg1252\\\\cocoartf2822\\n\\\\cocoatextscaling0\\\\cocoaplatform0{\\\\fonttbl\\\\f0\\\\fnil\\\\fcharset0 SFPro-Bold;\\\\f1\\\\fswiss\\\\fcharset0 Helvetica;\\\\f2\\\\fnil\\\\fcharset0 SFPro-Regular;\\n}\\n{\\\\colortbl;\\\\red255\\\\green255\\\\blue255;\\\\red0\\\\green0\\\\blue0;}\\n{\\\\*\\\\expandedcolortbl;;\\\\cssrgb\\\\c0\\\\c0\\\\c0\\\\c84706\\\\cname labelColor;}\\n\\\\pard\\\\tx560\\\\tx1120\\\\tx1680\\\\tx2240\\\\tx2800\\\\tx3360\\\\tx3920\\\\tx4480\\\\tx5040\\\\tx5600\\\\tx6160\\\\tx6720\\\\pardirnatural\\\\qc\\\\partightenfactor0\\n\\n\\\\f0\\\\b\\\\fs80 \\\\cf2 NO!\\n\\\\f1\\\\b0\\\\fs24 \\\\\\n\\\\pard\\\\tx560\\\\tx1120\\\\tx1680\\\\tx2240\\\\tx2800\\\\tx3360\\\\tx3920\\\\tx4480\\\\tx5040\\\\tx5600\\\\tx6160\\\\tx6720\\\\pardirnatural\\\\qc\\\\partightenfactor0\\n\\n\\\\f2\\\\fs48 \\\\cf2 Please don't leave me!}\",\"BTTActionHUDBorderWidth\":0,\"BTTActionHUDTitle\":\"\",\"BTTActionHUDHeight\":220}",
"BTTOrder" : 0
}
],
"BTTGestureNotes" : "Apple:LidSensor: closing"
}
]
The link in the device analyzer code comments points at https://docs.folivora.ai/1500_generic_devices.html, which should be changed to Generic Devices · GitBook
I used it to create a trigger to pause spotify and set the system volume to 0% if the lid goes below 20˚. Very handy!
Is there a way to keep state in the analyzer script?
I'm basically trying to do this (non-working semi-pseudo-code):
function analyzeDeviceInput(targetDevice, reportID, reportDataHex) {
let reportBuffer = buffer.Buffer.from(reportDataHex, 'hex');
var closing = false;
var opening = false;
if(reportBuffer.readUInt8(1) < 0x14) {
log('trigger!');
if (!closing) {
bttTriggerDeviceTrigger(targetDevice, 'closing');
closing = true;
opening = false;
}
}
if(reportBuffer.readUInt8(1) > 0x14) {
log('trigger!');
if (!opening) {
bttTriggerDeviceTrigger(targetDevice, 'opening');
opening = true;
closing = false;
}
}
}
But it doesn't work. If I move the lid below 20˚, the closing trigger fires every degree. And the opening trigger fires every degree above 20˚. Is there a way to do what I'm trying to? Can I set some sort of persistent global variable?
Edit: I can't reply to myself any more, monologues are not permitted. But here is how I solved it:
So I have now made my lid into a media player!
Just realized that I could make it into a volume control... ![]()
to keep state put the variables outside the function:
Of course. Me and scopes...
Moved the var declarations up above the function, and it worked as intended.
Now I just need to write 100 if-statements to make my lid into a volume control. ![]()
in theory you could also change the volume from your script but that would make it less generic ![]()
set_number_variable({ variableName: "OutputVolume", to: value });
where value is a value between 0 and 1
Perfect!
I should do that and post it here: https://uxdesign.cc/the-worst-volume-control-ui-in-the-world-60713dc86950
yes! ![]()
Damn it! Someone already did!
https://miro.medium.com/v2/resize:fit:720/format:webp/1*x96b41G9y84eC--p18ghcQ.gif
haha too bad ![]()
This is the exact kind of creativity I was looking for with this new trigger ![]()
Here's a Preset that includes:
lid_angle_preset.bttpreset (8.3 KB)
Here's a preset that:
Displays a menu bar icon with the current angle. It turns red when below the cutoff.
Pause Spotify when lid is < the cutuff.
Play Spotify when lid is > the cutuff.
You can easily change the cutoff at the top of the analyzer script (default: 50˚), and/or add/change your own actions to the three triggers.
Why? Because you can never have too many menu bar icons.
Lid Angle.bttpreset (17.8 KB)
Edit: Updated it to only start Spotify when opening the lid if it was playing before it was closed.
@Andreas_Hegenberg : The alternate font color is flakey. It turns the icon red as expected, but the text is red for a little while and then turns white again. So the icon and the text has different colors. How is that even possible?
There's no way to send text / icon colors using update_menubar_item?
My regex is ^[0-4][0-9]˚$.
You can update the text/icon color using update_menubar_item like this:
tell application "BetterTouchTool" to update_menubar_item "2F307570-D516-42FB-89DC-6F3C5FB32771" text "new text" font_color "255,244,100,255"
When updating from JS you should be able to use these parameters:
{'text':'newTitle', 'sf_symbol_name': 'house', 'sf_symbol_size': 12, 'icon_data': 'base64_icon_data', 'icon_path':'path_to_new_icon', 'background_color': '255,85,100,255', 'font_color': '100,200,100,255', 'font_size': 10}
(Alternatively you can provide a basic html string as title like <html><span style="color:red">test</span></html> but this is harder to get to look right)
I'll check whether I can reproduce the regex font color issue!
If you use a script to define the item you can also return all of these parameters directly:
I already tried font_color and icon_color, but it didn't make any difference in behavior.