esp32.diy

Tokpet: ESP32-S3 Desk Pet That Watches Your AI Token Usage

Oct 11, 2026 · 6 min read

Intermediate 105 stars 2 forks C Apache-2.0 Updated 2026-06-30

The Tokpet browser console showing live usage rings, the mood-driven cat, provider cards, and connected device discovery.

TL;DR Tokpet is a two-part project: a Node.js companion service that normalizes AI provider quotas into a single LAN feed, and an ESP32-S3 desk pet with a round AMOLED screen that renders your usage as glowing rings around a mood-driven cat. When the cat looks calm, you have headroom; when it looks stressed, you are close to a limit.
What you need
  • M5Stack StopWatch board
  • ESP32-S3 (dual-core, 8 MB PSRAM)
  • CO5300 466×466 round AMOLED display
  • CST820 capacitive touchscreen
BoardM5Stack StopWatch (ESP32-S3)
Display466×466 round AMOLED (CO5300), driven by LVGL 9
FrameworkESP-IDF + LVGL 9 (firmware) / Node.js (companion)
LanguageC (firmware), TypeScript (companion)
LicenseApache-2.0
DifficultyIntermediate

What You Will Build

Tokpet turns abstract AI token quotas into something you can glance at across the desk. The project has two halves that work together.

The first half is a small Node.js companion service that runs on your laptop or desktop. It polls your connected AI providers — Claude, Codex, and DeepSeek today — normalizes their wildly different billing models (rolling-window quotas, prepaid balances, API-key spend) into one common shape, and serves the result as a single GET /state JSON feed on your local network. The setup and configuration routes are locked to loopback; only the read-only /state endpoint is visible to the rest of your LAN.

The second half is an ESP32-S3 desk pet built on the M5Stack StopWatch board, featuring a 466×466 round AMOLED screen. The firmware discovers the companion over mDNS, polls /state, and renders your usage as concentric glowing rings around a cat whose expression shifts from calm to panicked as you burn through your quota. Usage below 50 % is chill; 50–79 % is alert; 80 % and above is stress.

You do not need the hardware to get value from Tokpet — the browser console at http://localhost:4717 is a full client on its own. But the physical device is what makes it ambient and actually glanceable.

A Tokpet ESP32-S3 desk pet displaying the halo-cat usage rings on its 466×466 round AMOLED screen.\2
A Tokpet ESP32-S3 desk pet displaying the halo-cat usage rings on its 466×466 round AMOLED screen.

What You Need

Hardware (for the device)

Software for the companion service

Software for the firmware

AI provider credentials — at least one of:

No soldering or wiring is required if you use the M5Stack StopWatch board — the display, touch, and ESP32-S3 are already integrated. Wi-Fi credentials are provisioned directly on the device through a captive-portal hotspot; you never need to hardcode a network password into the firmware.

Typical use cases

Ambient Usage Awareness

Keep a physical reminder of your AI quota on your desk without opening a browser tab. The cat's mood gives you an instant read at a glance.

Multi-Provider Normalization

Claude, Codex, and DeepSeek each expose usage in completely different ways. Tokpet collapses them into one versioned feed so you see everything in one place.

Local-First LAN Feed

The /state endpoint is a stable, versioned JSON contract any device on your network can consume — build secondary displays, automations, or dashboards on top of it.

Provider Plugin Development

The companion is designed for contribution: each provider is a self-contained directory. It is a practical starting point for anyone who wants to learn how to normalize AI billing APIs.

How It Works

Understanding the data flow makes the build easier to troubleshoot.

The companion service polls each activated provider using that provider's native API. Every provider's data is mapped onto a common Usage shape, cached with a TTL, and aggregated into a single snapshot. The snapshot is served at GET /state as versioned JSON. The top-level primary field carries the hero metric — the provider and window that matter most right now — along with usedPct (0–100) and mood.

The companion also advertises itself over mDNS as _tokpet._tcp.local, so devices on the same LAN can find it without any manual IP configuration.

On the device side, the ESP32-S3 firmware boots and immediately creates a captive-portal Wi-Fi hotspot. You connect a phone or laptop to that hotspot and enter your network credentials through the portal — no USB serial interaction, no companion involvement. Once the device joins your network, it resolves _tokpet._tcp.local over mDNS and begins polling /state. The LVGL 9 halo-cat UI updates on each poll: the concentric rings reflect per-provider usage percentages, and the cat sprite changes expression based on the mood field in the response.

The /state schema is versioned ("version": 1) and is the only stability guarantee the project makes. Any hardware or client you build on top of it can rely on that contract remaining stable across minor releases.

Setting Up the Companion Service

Pick the install method that matches your system.

Homebrew (macOS — recommended)

brew install grpcer/tokpet/tokpet
brew services start tokpet

The service starts in the background and restarts automatically on login.

npm (cross-platform)

npm install -g tokpet
tokpet service install

tokpet service install registers a launchd background service on macOS. To run it in the foreground instead, just run tokpet.

From source (for hacking)

git clone https://github.com/grpcer/tokpet.git
cd tokpet
npm install
npm run dev

Once the companion is running, open the console:

tokpet open

or visit http://localhost:4717 directly in your browser.

To add a provider, click Add provider in the console, choose the usage mode (subscription or API key), select your provider, and click Test. If the test succeeds, the provider activates immediately and starts appearing in /state. Your configuration is saved to ~/.tokpet/config.json and restored on the next launch.

You can verify the feed is working at any time:

curl http://localhost:4717/state | jq

You should see a JSON object with version, fetchedAt, providers, and primary fields.

Flashing the ESP32-S3 Firmware

The firmware lives in the firmware/ directory of the repository and is a standard ESP-IDF project. If you cloned the repo during the source install above, it is already on your machine. If not, clone it now:

git clone https://github.com/grpcer/tokpet.git
cd tokpet

Connect the M5Stack StopWatch board via USB, navigate to the firmware directory, and flash:

idf.py flash

After flashing, the device reboots and displays a prompt to provision Wi-Fi. It creates a temporary hotspot — connect your phone or laptop to that hotspot and follow the captive portal to enter your home or office network credentials. The device then connects to your network, discovers the companion via mDNS (_tokpet._tcp.local), and starts displaying your usage.

If the device shows "open the console to add a provider", that message means the companion is reachable but has no providers configured yet. Go back to the browser console and add at least one provider.

If the device cannot find the companion after you move it to a new network, you will need to re-run the Wi-Fi provisioning flow. The project's TROUBLESHOOTING.md walks through the LAN, mDNS, and re-provisioning checks step by step.

Ideas to Extend It — and Current Limitations

Where to take it next

Current limitations to be aware of

Verdict

Tokpet is a well-scoped project with a clear separation between the companion service and the firmware, making it approachable even if you only want one half. The local-first design, mDNS auto-discovery, and on-device Wi-Fi provisioning mean the device genuinely requires no manual network configuration after flashing. The main constraint right now is macOS-only background service support and the limited provider list, both of which the roadmap addresses directly.

Sources

github.comgrpcer/tokpet — repository & README npmjs.comOfficial website

Facts in this article come from the project's public README and GitHub metadata at the time of writing. Images belong to their respective owners and link back to the original source.