mirror of
https://github.com/jbranchaud/til
synced 2026-07-03 08:08:24 +00:00
Add Read The Lid Angle Sensor For A MacBook as a Mac TIL
This commit is contained in:
@@ -10,7 +10,7 @@ working across different projects via [VisualMode](https://www.visualmode.dev/).
|
|||||||
|
|
||||||
For a steady stream of TILs, [sign up for my newsletter](https://visualmode.kit.com/newsletter).
|
For a steady stream of TILs, [sign up for my newsletter](https://visualmode.kit.com/newsletter).
|
||||||
|
|
||||||
_1793 TILs and counting..._
|
_1794 TILs and counting..._
|
||||||
|
|
||||||
See some of the other learning resources I work on:
|
See some of the other learning resources I work on:
|
||||||
|
|
||||||
@@ -753,6 +753,7 @@ If you've learned something here, support my efforts writing daily TILs by
|
|||||||
- [Open Finder.app To Specific Directory](mac/open-finder-app-to-specific-directory.md)
|
- [Open Finder.app To Specific Directory](mac/open-finder-app-to-specific-directory.md)
|
||||||
- [Prevent Sleep With The Caffeinate Command](mac/prevent-sleep-with-the-caffeinate-command.md)
|
- [Prevent Sleep With The Caffeinate Command](mac/prevent-sleep-with-the-caffeinate-command.md)
|
||||||
- [Quickly Type En Dashes And Em Dashes](mac/quickly-type-en-dashes-and-em-dashes.md)
|
- [Quickly Type En Dashes And Em Dashes](mac/quickly-type-en-dashes-and-em-dashes.md)
|
||||||
|
- [Read The Lid Angle Sensor For A MacBook](mac/read-the-lid-angle-sensor-for-a-macbook.md)
|
||||||
- [Require Additional JS Libraries In Postman](mac/require-additional-js-libraries-in-postman.md)
|
- [Require Additional JS Libraries In Postman](mac/require-additional-js-libraries-in-postman.md)
|
||||||
- [Resize App Windows With AppleScript](mac/resize-app-windows-with-applescript.md)
|
- [Resize App Windows With AppleScript](mac/resize-app-windows-with-applescript.md)
|
||||||
- [Resizing Both Corners Of A Window](mac/resizing-both-corners-of-a-window.md)
|
- [Resizing Both Corners Of A Window](mac/resizing-both-corners-of-a-window.md)
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
# Read The Lid Angle Sensor For A MacBook
|
||||||
|
|
||||||
|
MacOS has a bunch of internal HID (Human Interface Device) data that can surface
|
||||||
|
details about all kinds of "devices" that comprise your machine. Some obvious
|
||||||
|
ones are the keyboard and trackpad as well as external mice and keyboards. The
|
||||||
|
battery and power source details are another which is sometimes integrated into
|
||||||
|
tools that display battery status (e.g.
|
||||||
|
[`tmux-battery`](https://github.com/tmux-plugins/tmux-battery)), though it uses
|
||||||
|
`pmset` directly). And many, many more.
|
||||||
|
|
||||||
|
One example I'd never considered is that there is a sensor for the lid angle of
|
||||||
|
the laptop that can tell the system whether the lid is open or closed and how
|
||||||
|
open it is (i.e. at what angle). There is no public interface for this lid angle
|
||||||
|
sensor, but people exploring all the HID devices have found the identifiers that
|
||||||
|
correspond to it (e.g.
|
||||||
|
[`pybooklid`](https://github.com/tcsenpai/pybooklid/blob/main/pybooklid/macbook_lid.py)).
|
||||||
|
|
||||||
|
Here is a minimal script that uses `uv`, `hidapi` (python bindings), and
|
||||||
|
`libhidapi` (shared runtime lib for those bindings):
|
||||||
|
|
||||||
|
```python
|
||||||
|
#!/usr/bin/env -S uv run --quiet --script
|
||||||
|
# /// script
|
||||||
|
# requires-python = ">=3.10"
|
||||||
|
# dependencies = ["hidapi"]
|
||||||
|
# ///
|
||||||
|
"""Print MacBook lid angle in degrees."""
|
||||||
|
import os, sys
|
||||||
|
|
||||||
|
if sys.platform == "darwin":
|
||||||
|
brew = "/opt/homebrew/lib"
|
||||||
|
if os.path.exists(brew):
|
||||||
|
os.environ["DYLD_LIBRARY_PATH"] = f"{brew}:{os.environ.get('DYLD_LIBRARY_PATH','')}"
|
||||||
|
|
||||||
|
import hid
|
||||||
|
|
||||||
|
VENDOR_ID, PRODUCT_ID = 0x05AC, 0x8104
|
||||||
|
USAGE_PAGE, USAGE = 0x0020, 0x008A
|
||||||
|
REPORT_ID = 1
|
||||||
|
|
||||||
|
def read_angle():
|
||||||
|
for info in hid.enumerate(VENDOR_ID, PRODUCT_ID):
|
||||||
|
if info.get("usage_page") == USAGE_PAGE and info.get("usage") == USAGE:
|
||||||
|
d = hid.device()
|
||||||
|
path = info["path"]
|
||||||
|
d.open_path(path if isinstance(path, bytes) else path.encode())
|
||||||
|
try:
|
||||||
|
data = d.get_feature_report(REPORT_ID, 8)
|
||||||
|
if data and len(data) >= 3:
|
||||||
|
return float((data[2] << 8) | data[1])
|
||||||
|
finally:
|
||||||
|
d.close()
|
||||||
|
return None
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
a = read_angle()
|
||||||
|
if a is None:
|
||||||
|
sys.exit("sensor not available")
|
||||||
|
print(f"{a:.0f}")
|
||||||
|
```
|
||||||
|
|
||||||
|
These IDs and usage values are the undocumented values that allow the script to
|
||||||
|
navigate specifically to the lid angle sensor and specifically to the usage page
|
||||||
|
and value that represent the current lid angle reading.
|
||||||
|
|
||||||
|
```
|
||||||
|
VENDOR_ID, PRODUCT_ID = 0x05AC, 0x8104
|
||||||
|
USAGE_PAGE, USAGE = 0x0020, 0x008A
|
||||||
|
REPORT_ID = 1
|
||||||
|
```
|
||||||
|
|
||||||
|
I added [this
|
||||||
|
script](https://github.com/jbranchaud/dotfiles/blob/cbc7196607d1d6b25885f5387ca85b658bd765de/bin/lidangle)
|
||||||
|
to [my dotfiles](https://github.com/jbranchaud/dotfiles) and made it executable
|
||||||
|
(`chmod +x bin/lidangle`) so that I can try it out. I first ran it while it was
|
||||||
|
closed and connected to my external monitor (`0`), then I opened it as far as it
|
||||||
|
could go (`129`), and then I tried angling it close to what I thought was 90
|
||||||
|
degress (`92`, so close).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
❯ lidangle
|
||||||
|
0
|
||||||
|
|
||||||
|
❯ lidangle
|
||||||
|
129
|
||||||
|
|
||||||
|
❯ lidangle
|
||||||
|
92
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user