HermannBjorgvin/Clawdmeter
GitHub: HermannBjorgvin/Clawdmeter
一款基于 ESP32 的桌面仪表盘硬件项目,通过蓝牙连接实时显示 Claude Code 使用率并提供快捷键控制。
Stars: 1888 | Forks: 258
# Clawdmeter
我为自己桌面制作的一个小型 ESP32 仪表盘,用于随时了解 Claude Code 的使用情况。
它运行在 [Waveshare ESP32-S3-Touch-AMOLED-2.16](https://www.waveshare.com/esp32-s3-touch-amoled-2.16.htm?&aff_id=149786) 以及其他几个替代开发板上,并通过蓝牙配对。启动屏幕会播放像素风 Clawd 动画,随着你的使用率上升,动画会变得更加忙碌。两侧的按钮会通过 BLE HID 发送 Space 和 Shift+Tab,作为 Claude Code 的语音模式和模式切换快捷键。
| 用量计 | Clawd 动画屏幕 |
| :-----------------------------------: | :----------------------------------------------: |
|  |  |
Clawd 动画来自 [claudepix](https://claudepix.vercel.app),即 [@amaanbuilds](https://x.com/amaanbuilds) 的像素风 Clawd 精灵图库,快去看看吧,非常可爱。
## 屏幕
设备开机后会进入启动动画。点击屏幕上的任意位置可切换到用量视图;再次点击即可返回启动动画。
| 启动动画 | 用量 |
| :-------------------------------: | :-----------------------------: |
|  |  |
| 启动动画;随时触摸切换 | 会话和每周使用率 |
在显示启动动画时,中间的(PWR)按钮可以循环切换动画。**长按电源按钮 3 秒然后松开,可使设备进入配对模式** —— 这会清除已保存的蓝牙绑定并重新广播。固件还会在当前使用率分组内,每 20 秒自动轮播动画,因此在启动动画上停留很长时间也不会只是循环播放同一个 Clawd。
## 硬件
开箱即支持的开发板:
- [Waveshare ESP32-S3-Touch-AMOLED-2.16](https://www.waveshare.com/esp32-s3-touch-amoled-2.16.htm?&aff_id=149786)
- [Waveshare ESP32-C6-Touch-AMOLED-2.16](https://www.waveshare.com/esp32-c6-touch-amoled-2.16.htm?&aff_id=149786)
- [Waveshare ESP32-S3-Touch-AMOLED-1.8](https://www.waveshare.com/esp32-s3-touch-amoled-1.8.htm?&aff_id=149786)
- [Waveshare ESP32-C6-Touch-AMOLED-1.8](https://www.waveshare.com/esp32-c6-touch-amoled-1.8.htm?&aff_id=149786)
- [Waveshare ESP32-S3-Touch-AMOLED-2.06](https://www.waveshare.com/esp32-s3-touch-amoled-2.06.htm?&aff_id=149786)
**移植到其他开发板:**该固件是一个轻量的 HAL,在 `firmware/src/boards/` 下有针对各开发板的独立文件夹。只需放入一个新文件夹和新的 PlatformIO 环境配置 —— `main.cpp`、`ui.cpp` 和 `splash.cpp` 无需任何修改。有关详细操作指南,请参阅 [`docs/porting/adding-a-board.md`](docs/porting/adding-a-board.md);有关移植必须实现的接口,请参阅 [`docs/porting/hal-contract.md`](docs/porting/hal-contract.md)。
## 前置条件
- Linux(已在 Ubuntu 上测试)、macOS 或 Windows 10/11
- [PlatformIO CLI](https://docs.platformio.org/en/latest/core/installation/index.html)
- Linux:`curl`、`bluetoothctl`、`busctl`(BlueZ Bluetooth 协议栈)
- macOS:`python3`(安装程序将设置包含 `bleak` 和 `httpx` 的 venv)
- Windows:`python3` 3.11+(安装程序将设置包含 `bleak`、`httpx` 和 `pystray` 的 venv)
- 带有活跃订阅的 Claude Code
## macOS 安装说明
macOS 主机端的组件 —— Python 守护进程、LaunchAgent 和烧录助手 —— 由 [Chris Davidson (@lorddavidson)](https://github.com/lorddavidson) 移植。感谢 Chris!
### 烧录固件
```
./flash-mac.sh waveshare_amoled_216 # auto-detects /dev/cu.usbmodem*
./flash-mac.sh waveshare_amoled_18 /dev/cu.usbmodem1101 # or pass an explicit USB serial port
```
必须提供开发板环境名称。直接运行不带参数的 `./flash-mac.sh` 即可查看可用的环境(从 `firmware/platformio.ini` 中提取)。
### 配对设备
烧录完成后,打开**系统设置 → 蓝牙**,点击 "Clawdmeter" 旁边的*连接*。守护进程仅会连接到此 Mac 已配对/连接的外设 —— 它绝不会扫描附近的设备 —— 因此只要在这里连接成功,守护进程就会在下次轮询(约 60 秒)时识别到它。
### 安装守护进程
守护进程会从 macOS 钥匙串(服务名 `Claude Code-credentials`)中读取你的 Claude OAuth token,每 60 秒轮询一次使用情况,并通过 BLE 将其推送到显示屏。
```
./install-mac.sh
```
安装程序会在 `daemon/.venv/` 中创建一个 Python venv,安装 `bleak` 和 `httpx`,将 LaunchAgent 渲染到 `~/Library/LaunchAgents/com.user.claude-usage-daemon.plist` 并加载它。首次运行将以交互方式启动,以便 macOS 弹出蓝牙权限提示。
常用命令:
```
launchctl list | grep claude-usage # check it's running
tail -F ~/Library/Logs/claude-usage-daemon.out.log # live logs
launchctl unload ~/Library/LaunchAgents/com.user.claude-usage-daemon.plist # stop
launchctl load -w ~/Library/LaunchAgents/com.user.claude-usage-daemon.plist # start
```
## Linux 安装说明
### 烧录固件
```
./flash.sh waveshare_amoled_216 # defaults to /dev/ttyACM0
./flash.sh waveshare_amoled_18 /dev/ttyACM1 # or pass an explicit USB serial port
```
必须提供开发板环境名称。直接运行不带参数的 `./flash.sh` 即可查看可用的环境(从 `firmware/platformio.ini` 中提取)。
### 配对设备
烧录完成后,设备将以 "Clawdmeter" 的名义进行广播。只需配对一次:
```
# 扫描设备
bluetoothctl scan le
# 当出现 "Clawdmeter" 时,进行配对并信任
bluetoothctl pair F4:12:FA:C0:8F:E5 # use your device's MAC
bluetoothctl trust F4:12:FA:C0:8F:E5
```
如果需要重新配对,长按电源按钮 3 秒后松开 —— 设备将清除已保存的绑定并重新广播。
### 安装守护进程
守护进程每 60 秒轮询一次你的 Claude 使用情况,并通过 BLE 将其发送到显示屏。
```
./install.sh
systemctl --user start claude-usage-daemon
```
检查状态:`systemctl --user status claude-usage-daemon`
查看日志:`journalctl --user -u claude-usage-daemon -f`
## Windows 安装说明
原生运行在 Windows 上 —— 无需 WSL。系统托盘应用会轮询你的使用情况并通过 BLE 推送数据,且会在登录时自动启动。
### 前置条件
- **原生 Windows**(非 WSL)。
- 来自 [python.org](https://www.python.org/downloads/) 的 **Python 3.11+** —— 安装时请勾选*“将 python.exe 添加到 PATH”*。
- 已安装 **Claude Code**,并已完成 `claude login`。token 将从 `%USERPROFILE%\.claude\.credentials.json` 中读取(备选路径依次为 `%LOCALAPPDATA%\Claude\` 和 `%APPDATA%\Claude\`)。
- 仓库需位于**原生 Windows 路径**下(例如 `%USERPROFILE%\Clawdmeter`),**不能**是 `\\wsl$` 共享路径 —— 安装程序会拒绝 WSL 路径。
### 烧录固件
```
pio run -d firmware -e waveshare_amoled_216 -t upload --upload-port COM5 # use your device's COM port
```
运行不带环境参数的 `pio run -d firmware` 以查看可用的开发板环境。
### 配对设备
该设备是一个绑定的 BLE HID 键盘,只需配对一次:**设置 → 蓝牙和其他设备 → 添加设备 → 蓝牙**,然后选择 "Clawdmeter"。**必须**进行配对 —— 这会启用物理按钮并保持持久连接(即使在守护进程退出后,设备也会继续显示你上次同步的使用情况)。若要取消配对,请使用**移除设备**(这将禁用按钮)。
### 安装守护进程(推荐)
在 PowerShell 中从仓库根目录运行:
```
powershell -ExecutionPolicy Bypass -File install-windows.ps1
```
这将创建一个 venv,从仓库内的 requirements 文件安装 `bleak`/`httpx`/`pystray`/`Pillow`(无需网络下载),注册一个用户级的开机自启项(`HKCU\…\Run`,无需管理员权限),并无头启动托盘应用(无控制台窗口)。
### 改为手动运行(可选)
```
python -m venv .venv
.venv\Scripts\Activate.ps1 # if blocked: Set-ExecutionPolicy -Scope CurrentUser RemoteSigned, then retry
pip install -r daemon\requirements-windows.txt
python daemon\claude_usage_daemon_windows.py # runs in the foreground; Ctrl+C to stop
```
### 托盘图标和菜单
图标角落的气泡会显示状态 —— **绿色**表示已连接,**琥珀色**表示扫描中,**红色**表示错误 —— 鼠标悬停时会显示状态(`已连接 · 上次更新 HH:MM`)。进入错误状态(例如 token 过期)时会触发一次通知。右键点击可打开菜单:
- **状态标题** —— 实时状态 + 上次同步时间。
- **开机自启** —— 开启/关闭自启动。
- **退出** —— 干净地停止守护进程;保留 Windows 的配对状态(设备会保留上次的读数)。
### 日志和故障排除
```
Get-Content $env:LOCALAPPDATA\Clawdmeter\daemon.log -Tail 30 # view logs
reg delete "HKCU\Software\Microsoft\Windows\CurrentVersion\Run" /v Clawdmeter /f # remove autostart
```
| 症状 | 修复方法 |
|---------|-----|
| `找不到设备` | 给设备开机;确保其在范围内并已配对。 |
| `token 过期`提示 / `API HTTP 401` | 重新运行 `claude login`,然后重启守护进程。 |
| `连接失败` | 在设置中关闭再打开 Windows 蓝牙。 |
| `警告:正在 Linux/WSL 下运行` | 请在原生 PowerShell 窗口中运行,而不是在 WSL shell 中。 |
## 工作原理
1. 守护进程读取你的 Claude Code OAuth token —— 在 macOS 上是从 macOS 钥匙串(服务名 `Claude Code-credentials`)读取,在 Linux 上是从 `~/.claude/.credentials.json` 读取(在 Windows 上则是从 `%USERPROFILE%\.claude\.credentials.json` 读取)。
2. 它会向 `api.anthropic.com/v1/messages` 发起一次极简的 API 调用 —— 基本上只消耗 1 个 token 的 Haiku,几乎是免费的。
3. 使用率数据直接从响应头中提取(`anthropic-ratelimit-unified-5h-utilization` 等字段)。
4. 守护进程通过 BLE 连接到 ESP32,并将 JSON payload 写入 GATT RX 特征值。
5. 固件对其进行解析并更新 LVGL 仪表盘。
6. 固件还会跟踪 5 分钟窗口内会话百分比的变化率,并从匹配的情绪分组中选择启动动画。
7. 两侧的按钮独立于上述所有过程 —— 它们直接向配对的主机发送 Space 和 Shift+Tab,作为 BLE HID 键盘输入。
## 物理按钮
开发板侧面有三个按钮。左右按钮发送 HID 按键;中间的(PWR)按钮用于循环切换启动动画,长按 3 秒可触发配对模式。
| 按钮 | GPIO | 功能 |
| ---------------- | ------------ | -------------------------------------------------------------- |
| **左** | GPIO 0 | 长按发送 Space(Claude Code 语音模式按键通话) |
| **中** (PWR) | AXP2101 PKEY | 启动画面下:循环切换动画。长按 3 秒 + 松开:配对模式 |
| **右** | GPIO 18 | 按下发送 Shift+Tab(Claude Code 模式切换) |
Space 和 Shift+Tab 作为标准的 BLE HID 键盘报告发送,因此它们会在配对主机上当前具有焦点的任何窗口中触发 —— 不仅仅是 Claude Code。
## BLE 协议
该设备在标准的 HID 键盘服务之外,还提供了一个自定义的 GATT 服务:
| | UUID |
| -------------------------- | -------------------------------------- |
| **数据服务** | `4c41555a-4465-7669-6365-000000000001` |
| RX 特征值 (写入) | `4c41555a-4465-7669-6365-000000000002` |
| TX 特征值 (通知) | `4c41555a-4465-7669-6365-000000000003` |
| **HID 服务** | `00001812-0000-1000-8000-00805f9b34fb` |
JSON payload 格式(写入到 RX):
```
{ "s": 45, "sr": 120, "w": 28, "wr": 7200, "st": "allowed", "ok": true }
```
字段说明:`s` = 会话百分比,`sr` = 会话重置(分钟),`w` = 每周百分比,`wr` = 每周重置(分钟),`st` = 状态,`ok` = 成功标志。
## 重新编译字体
`firmware/src/font_*.c` 文件是预编译的 LVGL 位图字体。
```
npm install -g lv_font_conv
```
使用 `--no-compress`(LVGL 9 必需)逐个生成它们(一次只能生成一个 —— `lv_font_conv` 不支持循环调用):
```
# Tiempos Text (标题,56px)
lv_font_conv --font assets/TiemposText-400-Regular.otf -r 0x20-0x7E \
--size 56 --format lvgl --bpp 4 --no-compress \
-o firmware/src/font_tiempos_56.c --lv-include "lvgl.h"
# Styrene B (大数字 48,面板标签 28,小文字 24,最小 20)
for size in 48 28 24 20; do
lv_font_conv --font assets/StyreneB-Regular.otf -r 0x20-0x7E \
--size $size --format lvgl --bpp 4 --no-compress \
-o firmware/src/font_styrene_${size}.c --lv-include "lvgl.h"
done
# DejaVu Sans Mono (32px,带 spinner Unicode 字符)
lv_font_conv --font assets/DejaVuSansMono.ttf \
-r 0x20-0x7E,0xB7,0x2026,0x2722,0x2733,0x2736,0x273B,0x273D \
--size 32 --format lvgl --bpp 4 --no-compress \
-o firmware/src/font_mono_32.c --lv-include "lvgl.h"
```
**重要:** `lv_font_conv` v1.5.3 输出的是 LVGL 8 格式。每个生成的文件都必须经过修补才能兼容 LVGL 9:
1. 移除 `font_dsc` 和 font struct 周围的 `#if LVGL_VERSION_MAJOR >= 8` 保护宏
2. 从 `font_dsc` 中移除 `.cache` 字段
3. 在 font struct 中添加 `.release_glyph = NULL`, `.kerning = 0`, `.static_bitmap 0`
4. 在 font struct 中添加 `.fallback = NULL`, `.user_data = NULL`
如果不进行这些修补,字体虽然可以编译,但渲染时将不可见。
## 转换 Lucide 图标
UI 使用了一小组 [Lucide](https://lucide.dev) 图标(蓝牙 + 电池状态),它们已被转换为 LVGL 的 RGB565 / RGB565A8 C 数组。
```
node tools/png_to_lvgl.js assets/icon_bluetooth_48.png icon_bluetooth_data ICON_BLUETOOTH_WIDTH ICON_BLUETOOTH_HEIGHT
```
默认的着色为白色(`0xFFFFFF`);Lucide 的 PNG 图片本身是黑色透明背景的,如果不进行着色,在深色 UI 中将无法看见。对于像 Logo 这样已经有颜色的图形,请传入 `--no-tint` 参数。电池图标使用 RGB565A8(Alpha 通道),以便它们在启动动画上能干净地混合;其余图标则是在面板颜色上直接烘焙为 RGB565。将转换器的输出粘贴到 `firmware/src/icons.h` 中。
## 启动动画
这些动画来自于 [claudepix.vercel.app](https://claudepix.vercel.app),
一个 Clawd 精灵图库。`tools/scrape_claudepix.js` 会在 Node VM 中执行
该网站的 JavaScript 以提取帧数据和调色板,然后
`tools/convert_to_c.js` 会将所有内容转换为 RGB565 C 数组并写入
`firmware/src/splash_animations.h`。
如需重新拉取(例如当源图库更新时):
```
node tools/scrape_claudepix.js
node tools/convert_to_c.js
pio run -d firmware -t upload
```
详情请参阅 `tools/README.md`。
## 致谢
- 像素风 Clawd 动画由 [@amaanbuilds](https://x.com/amaanbuilds) 制作,源自 [claudepix.vercel.app](https://claudepix.vercel.app)。帧数据和调色板由 `tools/` 中的工具进行抓取和转换。
- Lucide 图标集([lucide.dev](https://lucide.dev),MIT 协议),用于蓝牙和电池 UI 图形。
- Anthropic 品牌字体(Tiempos Text, Styrene B) —— 请参阅下方的许可警告。
## 许可灰色地带警告
本仓库中的软件使用并遵循了 Anthropic 的品牌指南,并使用了 Anthropic 拥有许可的相同专有字体,但本软件的使用并未获得许可,同时还使用了 Anthropic 的资产(如受版权保护的 Clawd 吉祥物)。因此,尽管本仓库中的代码是非专有的,但我本人不会将其按 copyleft 许可授权,因为本仓库包含专有字体和受版权保护的资产。如果您 fork 或复制本仓库中的代码,请注意这一点。**特此警告!**
标签:Claude Code, ESP32, 客户端加密, 嵌入式, 桌面仪表盘, 物联网, 硬件项目, 蓝牙HID, 运行时操纵, 逆向工具