A tiny standalone device that shows your Claude Code rate-limit usage in real time. Polls the Anthropic API and displays your 5-hour and 7-day usage windows, reset countdowns, signal strength, and battery level.
Supports six boards:
- M5StickC Plus (ESP32-PICO, 240x135 LCD)
- M5StickC Plus2 (ESP32-PICO-V3-02, 240x135 LCD)
- LilyGo T-Display S3 (ESP32-S3, 320x170 LCD)
- LilyGo T-Display S3 AMOLED 1.91" (ESP32-S3, 240x536 RM67162 AMOLED — H712/H713/H705/H681/H717)
- TTGO T-Display ESP32 (ESP32, 1.14" 135x240 ST7789 LCD)
- ESP32-C3-OLED (ESP32-C3, 0.42" 72x40 OLED) — breadboard-friendly; bring your own buttons
- Live usage bars for the 5-hour and 7-day rate-limit windows
- Reset countdowns so you know when capacity frees up
- PIN-protected — your OAuth token is AES-256-GCM encrypted on-device; the PIN is never stored
- Captive-portal setup — connect your phone to the device's WiFi AP and configure everything in a browser
- Battery & signal info shown on the dashboard
- Button controls — cycle brightness (A), force refresh (B), factory reset (hold A+B on boot)
Use one of these supported boards:
| Board | MCU | Display | Battery | Supported | Buy |
|---|---|---|---|---|---|
| M5StickC Plus | ESP32-PICO | 1.14" 240x135 | 120 mAh | ✅ | aliexpress.com |
| M5StickC Plus2 | ESP32-PICO-V3-02 | 1.14" 240x135 | 200 mAh | ✅ | aliexpress.com |
| LilyGo T-Display S3 | ESP32-S3 | 1.9" 320x170 LCD | 1300 mAh | ✅ | aliexpress.com |
| LilyGo T-Display S3 AMOLED (1.91") | ESP32-S3 | 1.91" 240x536 AMOLED | varies | ✅ | aliexpress.com |
| TTGO T-Display ESP32 | ESP32 | 1.14" 240x135 LCD | external (JST 1.25mm) | ✅ | aliexpress.com |
| ESP32-C3-OLED | ESP32-C3 | 0.42" 72x40 OLED | external | ✅ | aliexpress.com |
| M5Stack StickS3 | — | — | — | 🚧 In progress | aliexpress.com |
Plus any USB-C cable for flashing and power.
The ESP32-C3-OLED module has no built-in buttons, so you wire two externally. The firmware expects both inputs to be active-HIGH (HIGH = pressed, LOW = idle) with internal pull-downs enabled.
| Signal | GPIO | Notes |
|---|---|---|
| Button A (cycle brightness / cycle digit) | GPIO 3 | active-HIGH |
| Button B (force refresh / confirm digit) | GPIO 7 | active-HIGH |
| I²C SDA | GPIO 5 | display (built-in) |
| I²C SCL | GPIO 6 | display (built-in) |
| Onboard LED | GPIO 8 | active-LOW (HIGH = off) |
Do not wire anything to GPIO 9 (BOOT/BOOT0) — it is a strapping pin used for download mode.
Wire each button between the GPIO pin and 3.3 V. When the button is open the internal pull-down holds the pin LOW; pressing it pulls it HIGH.
3.3 V ──┤button├── GPIO 3 (Button A)
3.3 V ──┤button├── GPIO 7 (Button B)
Any module that outputs a logic-HIGH signal when touched works as a drop-in replacement (e.g. TTP223-based pads). Wire the sensor's output to the GPIO pin and its power pins to 3.3 V and GND. The signal polarity and pull-down behaviour are identical to Option A.
- The device sends a minimal API request (
max_tokens: 1) to the Anthropic Messages endpoint using your OAuth token - It reads the
anthropic-ratelimit-unified-5h-utilizationandanthropic-ratelimit-unified-7d-utilizationresponse headers - The dashboard updates on a configurable interval (30s–5min)
The token never leaves the device. It is encrypted with AES-256-GCM using a key derived from your PIN (PBKDF via iterated SHA-256, 10 000 rounds).
- PlatformIO CLI installed
- A supported board connected via USB-C
- A Claude Code OAuth token (run
claude setup-tokenin your terminal)
# Clone the repo
git clone https://github.com/oauramos/claude-usage-stick.git
cd claude-usage-stick
# M5StickC Plus
pio run -e m5stick-cplus -t upload
pio run -e m5stick-cplus -t uploadfs
# M5StickC Plus2
pio run -e m5stick-cplus2 -t upload
pio run -e m5stick-cplus2 -t uploadfs
# LilyGo T-Display S3 (regular LCD variant)
pio run -e tdisplay-s3 -t upload
pio run -e tdisplay-s3 -t uploadfs
# LilyGo T-Display S3 AMOLED 1.91" (H712/H713/H705/H681/H717)
pio run -e tdisplay-s3-amoled -t upload
pio run -e tdisplay-s3-amoled -t uploadfs
# TTGO T-Display ESP32 (1.14" ST7789 LCD)
pio run -e tdisplay-esp32 -t upload
pio run -e tdisplay-esp32 -t uploadfs
# ESP32-C3-OLED
pio run -e esp32c3-oled -t upload
pio run -e esp32c3-oled -t uploadfsAMOLED note: the panel variant is auto-detected at runtime by the LilyGo_AMOLED library, so a single
tdisplay-s3-amoledbuild covers all 1.91" AMOLED revisions (touch and non-touch, V1.0/V2.0/Black Shell). On touch-equipped variants (H705/H681/H717), tapping the screen anywhere acts as Button B.
Apple Silicon note: If
uploadfsfails with "Bad CPU type", install Rosetta (softwareupdate --install-rosetta) or use the included Python fallback:python3 upload_data.py
- On first boot (or after factory reset), the device creates a WiFi access point named
ClaudeMonitor-XXXX - Connect your phone or laptop to that network
- LCD boards — the password is shown on the device screen
- ESP32-C3-OLED — a simple 8-digit password is shown on the OLED (
Pass:line)
- Open
http://192.168.4.1in a browser - Fill in your WiFi credentials, OAuth token, and a 4–8 digit encryption PIN
- Hit Save & Reboot — the device encrypts the token, stores it, and connects to your WiFi
On each boot, enter your PIN using the device buttons:
- Button A — cycle the current digit (0–9)
- Button B — confirm and move to the next digit
Once unlocked, the dashboard appears and auto-refreshes.
| Button | Dashboard action |
|---|---|
| A | Cycle screen brightness (off → dim → normal → bright); ESP32-C3-OLED: toggle on/off only |
| B | Force an immediate refresh |
| A+B held on boot | Factory reset (wipes all stored data) |
src/
main.cpp — boot flow, WiFi, PIN entry, main loop
hal.cpp/h — hardware abstraction (display, buttons, battery, backlight)
api.cpp/h — HTTPS request to Anthropic, header parsing
crypto.cpp/h — AES-256-GCM encrypt/decrypt with PIN-derived key
provision.cpp/h — captive portal WiFi AP + web server
ui.cpp/h — all LCD drawing (boot, PIN, dashboard, errors)
config.h — tunables (poll interval, timeouts, PIN attempts)
data/
setup.html — web UI served during provisioning
server/
usage_proxy.py — optional local caching proxy (reads token from macOS Keychain)
- The OAuth token is encrypted with AES-256-GCM before being written to NVS flash
- The encryption key is derived from your PIN + device MAC salt through 10 000 rounds of SHA-256
- The PIN is never stored — wrong PIN = failed decryption (GCM tag mismatch)
- After 10 failed PIN attempts, all credentials are wiped and the device resets to setup mode
- Lockout delay doubles after each failure (60s → 120s → 240s → ...)
MIT




