---
title: I hacked a birthday-gift LED screen into an AI token usage monitor
description: "A friend gave me a pixel clock for my birthday. I flashed it, built a private dashboard for it, and now my Claude usage sits on my desk all day. The full setup, with links to build your own."
date: 2026-07-31
tags: [ai, build, hardware]
url: "https://mahdif.com/blog/i-hacked-a-birthday-gift-led-screen-into-an-ai-token-usage-monitor/"
---

# I hacked a birthday-gift LED screen into an AI token usage monitor

A friend gave me a pixel clock for my birthday. I flashed it, built a private dashboard for it, and now my Claude usage sits on my desk all day. The full setup, with links to build your own.

For my birthday last year, my friend [Ash Samhouri](https://www.linkedin.com/in/ashrafsam/) gave me a small LED pixel screen. Ash is the founder of [Activepieces](https://www.activepieces.com/), and he picked the kind of gift that says he knows me. Not a gadget to use. A gadget to open up and mess with.

The device is a Ulanzi TC001, a desk clock with a 32 by 8 pixel matrix. Out of the box it shows the time, the weather, some stock widgets. I will be honest about what happened next: it sat in my closet for ten months, because setting it up never made it to the top of the list. Last week it finally did. Within days, mine was showing my Claude token usage, live visitors on this site, and a ping every time someone asks the chat in the corner of this page a question.

This post is the full setup. What the device is, what I run on it, how it stays private, and the links you need to build your own.

<figure style="margin:2.75rem 0;">
<video autoplay muted loop playsinline controls preload="metadata" poster="/images/blog/i-hacked-a-birthday-gift-led-screen-into-an-ai-token-usage-monitor/videos/desk-rotation-poster.jpg" style="display:block;width:100%;border:1px solid var(--border);border-radius:var(--radius-lg);background:var(--card);">
  <source src="/images/blog/i-hacked-a-birthday-gift-led-screen-into-an-ai-token-usage-monitor/videos/desk-rotation.mp4" type="video/mp4">
  The TC001 on my desk, cycling through the usage screens.
</video>
<figcaption style="margin-top:0.85rem;text-align:center;font-size:0.85rem;color:var(--muted-foreground);">The clock, doing the one job it was never sold to do.</figcaption>
</figure>

## First, the thank you

The best gifts do not fill a need. They create one. I did not know I wanted a hackable pixel clock on my desk until one was there, and now I check it more than my phone. Ash, thank you. You handed me a new hobby disguised as a clock. Sorry it took me ten months to open it properly.

## Flashing it took an evening

The TC001 has a well-known community firmware called [AWTRIX 3](https://blueforcer.github.io/awtrix3/). You flash it straight from the browser, no toolchain, and the clock turns into a canvas. It exposes a simple HTTP API on your local network, and anything that can send JSON can draw on it. Send a payload, get pixels.

That is the entire trick. Everything else is deciding what deserves the pixels.

## The app that stuck: my Claude usage

I use Claude Code all day. Which means I live inside limits. Session windows, weekly caps, resets. The tab I kept opening was the usage page, always with the same question: can I keep working tonight, or do I need to pace myself until the account resets?

So the screen now rotates through my usage. How much of the current window I have burned, where I stand against the weekly cap, when the next reset lands. It sits at the edge of my desk and I absorb it without asking for it.

I stopped opening the usage page entirely. The glance replaced the check.

<figure style="margin:2.75rem 0;">
<div style="border:1px solid var(--border);border-radius:var(--radius-lg);overflow:hidden;background:var(--card);">
<svg viewBox="0 0 1200 630" xmlns="http://www.w3.org/2000/svg" style="display:block;width:100%;height:auto" role="img" aria-label="Three 32 by 8 pixel screens redrawn: session at 68 percent of the current window used, weekly at 82 percent against the weekly cap, and 4 hours 12 minutes before the window rolls over.">
<defs><pattern id="px-off" width="16" height="16" patternUnits="userSpaceOnUse"><circle cx="8" cy="8" r="5.6" fill="#FFFFFF" opacity=".05"/></pattern></defs>
<style>.px-bg{fill:var(--card)}.px-eye{fill:var(--muted-foreground);font-family:var(--font-mono);font-size:16px;letter-spacing:3px}.px-lbl{fill:var(--foreground);font-family:var(--font-heading);font-size:27px;font-weight:600}.px-sub{fill:var(--muted-foreground);font-family:var(--font-sans);font-size:17px}.p0 circle{fill:#34D399}.p0.dim circle{opacity:.17}.p1 circle{fill:#FBBF24}.p1.dim circle{opacity:.17}.p2 circle{fill:#A855F7}.p2.dim circle{opacity:.17}</style>
<rect class="px-bg" width="1200" height="630"/>
<text class="px-eye" x="150" y="72">WHAT ROTATES ON THE DESK</text>
<rect x="150" y="112" width="540" height="156" rx="14" fill="#0A0A0F"/><rect x="164" y="126" width="512" height="128" fill="url(#px-off)"/><g class="p0 on"><circle cx="188" cy="134" r="5.6"/><circle cx="204" cy="134" r="5.6"/><circle cx="220" cy="134" r="5.6"/><circle cx="252" cy="134" r="5.6"/><circle cx="268" cy="134" r="5.6"/><circle cx="284" cy="134" r="5.6"/><circle cx="316" cy="134" r="5.6"/><circle cx="348" cy="134" r="5.6"/><circle cx="188" cy="150" r="5.6"/><circle cx="252" cy="150" r="5.6"/><circle cx="284" cy="150" r="5.6"/><circle cx="348" cy="150" r="5.6"/><circle cx="188" cy="166" r="5.6"/><circle cx="204" cy="166" r="5.6"/><circle cx="220" cy="166" r="5.6"/><circle cx="252" cy="166" r="5.6"/><circle cx="268" cy="166" r="5.6"/><circle cx="284" cy="166" r="5.6"/><circle cx="332" cy="166" r="5.6"/><circle cx="188" cy="182" r="5.6"/><circle cx="220" cy="182" r="5.6"/><circle cx="252" cy="182" r="5.6"/><circle cx="284" cy="182" r="5.6"/><circle cx="316" cy="182" r="5.6"/><circle cx="188" cy="198" r="5.6"/><circle cx="204" cy="198" r="5.6"/><circle cx="220" cy="198" r="5.6"/><circle cx="252" cy="198" r="5.6"/><circle cx="268" cy="198" r="5.6"/><circle cx="284" cy="198" r="5.6"/><circle cx="316" cy="198" r="5.6"/><circle cx="348" cy="198" r="5.6"/><circle cx="188" cy="230" r="5.6"/><circle cx="204" cy="230" r="5.6"/><circle cx="220" cy="230" r="5.6"/><circle cx="236" cy="230" r="5.6"/><circle cx="252" cy="230" r="5.6"/><circle cx="268" cy="230" r="5.6"/><circle cx="284" cy="230" r="5.6"/><circle cx="300" cy="230" r="5.6"/><circle cx="316" cy="230" r="5.6"/><circle cx="332" cy="230" r="5.6"/><circle cx="348" cy="230" r="5.6"/><circle cx="364" cy="230" r="5.6"/><circle cx="380" cy="230" r="5.6"/><circle cx="396" cy="230" r="5.6"/><circle cx="412" cy="230" r="5.6"/><circle cx="428" cy="230" r="5.6"/><circle cx="444" cy="230" r="5.6"/><circle cx="460" cy="230" r="5.6"/><circle cx="476" cy="230" r="5.6"/><circle cx="492" cy="230" r="5.6"/><circle cx="188" cy="246" r="5.6"/><circle cx="204" cy="246" r="5.6"/><circle cx="220" cy="246" r="5.6"/><circle cx="236" cy="246" r="5.6"/><circle cx="252" cy="246" r="5.6"/><circle cx="268" cy="246" r="5.6"/><circle cx="284" cy="246" r="5.6"/><circle cx="300" cy="246" r="5.6"/><circle cx="316" cy="246" r="5.6"/><circle cx="332" cy="246" r="5.6"/><circle cx="348" cy="246" r="5.6"/><circle cx="364" cy="246" r="5.6"/><circle cx="380" cy="246" r="5.6"/><circle cx="396" cy="246" r="5.6"/><circle cx="412" cy="246" r="5.6"/><circle cx="428" cy="246" r="5.6"/><circle cx="444" cy="246" r="5.6"/><circle cx="460" cy="246" r="5.6"/><circle cx="476" cy="246" r="5.6"/><circle cx="492" cy="246" r="5.6"/></g><g class="p0 dim"><circle cx="508" cy="230" r="5.6"/><circle cx="524" cy="230" r="5.6"/><circle cx="540" cy="230" r="5.6"/><circle cx="556" cy="230" r="5.6"/><circle cx="572" cy="230" r="5.6"/><circle cx="588" cy="230" r="5.6"/><circle cx="604" cy="230" r="5.6"/><circle cx="620" cy="230" r="5.6"/><circle cx="636" cy="230" r="5.6"/><circle cx="652" cy="230" r="5.6"/><circle cx="508" cy="246" r="5.6"/><circle cx="524" cy="246" r="5.6"/><circle cx="540" cy="246" r="5.6"/><circle cx="556" cy="246" r="5.6"/><circle cx="572" cy="246" r="5.6"/><circle cx="588" cy="246" r="5.6"/><circle cx="604" cy="246" r="5.6"/><circle cx="620" cy="246" r="5.6"/><circle cx="636" cy="246" r="5.6"/><circle cx="652" cy="246" r="5.6"/></g><text class="px-lbl" x="740" y="186">Session</text><text class="px-sub" x="740" y="214">of the current window used</text>
<rect x="150" y="280" width="540" height="156" rx="14" fill="#0A0A0F"/><rect x="164" y="294" width="512" height="128" fill="url(#px-off)"/><g class="p1 on"><circle cx="188" cy="302" r="5.6"/><circle cx="204" cy="302" r="5.6"/><circle cx="220" cy="302" r="5.6"/><circle cx="252" cy="302" r="5.6"/><circle cx="268" cy="302" r="5.6"/><circle cx="284" cy="302" r="5.6"/><circle cx="316" cy="302" r="5.6"/><circle cx="348" cy="302" r="5.6"/><circle cx="188" cy="318" r="5.6"/><circle cx="220" cy="318" r="5.6"/><circle cx="284" cy="318" r="5.6"/><circle cx="348" cy="318" r="5.6"/><circle cx="188" cy="334" r="5.6"/><circle cx="204" cy="334" r="5.6"/><circle cx="220" cy="334" r="5.6"/><circle cx="252" cy="334" r="5.6"/><circle cx="268" cy="334" r="5.6"/><circle cx="284" cy="334" r="5.6"/><circle cx="332" cy="334" r="5.6"/><circle cx="188" cy="350" r="5.6"/><circle cx="220" cy="350" r="5.6"/><circle cx="252" cy="350" r="5.6"/><circle cx="316" cy="350" r="5.6"/><circle cx="188" cy="366" r="5.6"/><circle cx="204" cy="366" r="5.6"/><circle cx="220" cy="366" r="5.6"/><circle cx="252" cy="366" r="5.6"/><circle cx="268" cy="366" r="5.6"/><circle cx="284" cy="366" r="5.6"/><circle cx="316" cy="366" r="5.6"/><circle cx="348" cy="366" r="5.6"/><circle cx="188" cy="398" r="5.6"/><circle cx="204" cy="398" r="5.6"/><circle cx="220" cy="398" r="5.6"/><circle cx="236" cy="398" r="5.6"/><circle cx="252" cy="398" r="5.6"/><circle cx="268" cy="398" r="5.6"/><circle cx="284" cy="398" r="5.6"/><circle cx="300" cy="398" r="5.6"/><circle cx="316" cy="398" r="5.6"/><circle cx="332" cy="398" r="5.6"/><circle cx="348" cy="398" r="5.6"/><circle cx="364" cy="398" r="5.6"/><circle cx="380" cy="398" r="5.6"/><circle cx="396" cy="398" r="5.6"/><circle cx="412" cy="398" r="5.6"/><circle cx="428" cy="398" r="5.6"/><circle cx="444" cy="398" r="5.6"/><circle cx="460" cy="398" r="5.6"/><circle cx="476" cy="398" r="5.6"/><circle cx="492" cy="398" r="5.6"/><circle cx="508" cy="398" r="5.6"/><circle cx="524" cy="398" r="5.6"/><circle cx="540" cy="398" r="5.6"/><circle cx="556" cy="398" r="5.6"/><circle cx="572" cy="398" r="5.6"/><circle cx="188" cy="414" r="5.6"/><circle cx="204" cy="414" r="5.6"/><circle cx="220" cy="414" r="5.6"/><circle cx="236" cy="414" r="5.6"/><circle cx="252" cy="414" r="5.6"/><circle cx="268" cy="414" r="5.6"/><circle cx="284" cy="414" r="5.6"/><circle cx="300" cy="414" r="5.6"/><circle cx="316" cy="414" r="5.6"/><circle cx="332" cy="414" r="5.6"/><circle cx="348" cy="414" r="5.6"/><circle cx="364" cy="414" r="5.6"/><circle cx="380" cy="414" r="5.6"/><circle cx="396" cy="414" r="5.6"/><circle cx="412" cy="414" r="5.6"/><circle cx="428" cy="414" r="5.6"/><circle cx="444" cy="414" r="5.6"/><circle cx="460" cy="414" r="5.6"/><circle cx="476" cy="414" r="5.6"/><circle cx="492" cy="414" r="5.6"/><circle cx="508" cy="414" r="5.6"/><circle cx="524" cy="414" r="5.6"/><circle cx="540" cy="414" r="5.6"/><circle cx="556" cy="414" r="5.6"/><circle cx="572" cy="414" r="5.6"/></g><g class="p1 dim"><circle cx="588" cy="398" r="5.6"/><circle cx="604" cy="398" r="5.6"/><circle cx="620" cy="398" r="5.6"/><circle cx="636" cy="398" r="5.6"/><circle cx="652" cy="398" r="5.6"/><circle cx="588" cy="414" r="5.6"/><circle cx="604" cy="414" r="5.6"/><circle cx="620" cy="414" r="5.6"/><circle cx="636" cy="414" r="5.6"/><circle cx="652" cy="414" r="5.6"/></g><text class="px-lbl" x="740" y="354">Weekly</text><text class="px-sub" x="740" y="382">against the weekly cap</text>
<rect x="150" y="448" width="540" height="156" rx="14" fill="#0A0A0F"/><rect x="164" y="462" width="512" height="128" fill="url(#px-off)"/><g class="p2 on"><circle cx="268" cy="470" r="5.6"/><circle cx="300" cy="470" r="5.6"/><circle cx="332" cy="470" r="5.6"/><circle cx="364" cy="470" r="5.6"/><circle cx="412" cy="470" r="5.6"/><circle cx="460" cy="470" r="5.6"/><circle cx="476" cy="470" r="5.6"/><circle cx="492" cy="470" r="5.6"/><circle cx="524" cy="470" r="5.6"/><circle cx="556" cy="470" r="5.6"/><circle cx="268" cy="486" r="5.6"/><circle cx="300" cy="486" r="5.6"/><circle cx="332" cy="486" r="5.6"/><circle cx="364" cy="486" r="5.6"/><circle cx="396" cy="486" r="5.6"/><circle cx="412" cy="486" r="5.6"/><circle cx="492" cy="486" r="5.6"/><circle cx="524" cy="486" r="5.6"/><circle cx="540" cy="486" r="5.6"/><circle cx="556" cy="486" r="5.6"/><circle cx="268" cy="502" r="5.6"/><circle cx="284" cy="502" r="5.6"/><circle cx="300" cy="502" r="5.6"/><circle cx="332" cy="502" r="5.6"/><circle cx="348" cy="502" r="5.6"/><circle cx="364" cy="502" r="5.6"/><circle cx="412" cy="502" r="5.6"/><circle cx="460" cy="502" r="5.6"/><circle cx="476" cy="502" r="5.6"/><circle cx="492" cy="502" r="5.6"/><circle cx="524" cy="502" r="5.6"/><circle cx="540" cy="502" r="5.6"/><circle cx="556" cy="502" r="5.6"/><circle cx="300" cy="518" r="5.6"/><circle cx="332" cy="518" r="5.6"/><circle cx="364" cy="518" r="5.6"/><circle cx="412" cy="518" r="5.6"/><circle cx="460" cy="518" r="5.6"/><circle cx="524" cy="518" r="5.6"/><circle cx="556" cy="518" r="5.6"/><circle cx="300" cy="534" r="5.6"/><circle cx="332" cy="534" r="5.6"/><circle cx="364" cy="534" r="5.6"/><circle cx="396" cy="534" r="5.6"/><circle cx="412" cy="534" r="5.6"/><circle cx="428" cy="534" r="5.6"/><circle cx="460" cy="534" r="5.6"/><circle cx="476" cy="534" r="5.6"/><circle cx="492" cy="534" r="5.6"/><circle cx="524" cy="534" r="5.6"/><circle cx="556" cy="534" r="5.6"/><circle cx="188" cy="566" r="5.6"/><circle cx="204" cy="566" r="5.6"/><circle cx="220" cy="566" r="5.6"/><circle cx="236" cy="566" r="5.6"/><circle cx="252" cy="566" r="5.6"/><circle cx="268" cy="566" r="5.6"/><circle cx="284" cy="566" r="5.6"/><circle cx="300" cy="566" r="5.6"/><circle cx="316" cy="566" r="5.6"/><circle cx="332" cy="566" r="5.6"/><circle cx="348" cy="566" r="5.6"/><circle cx="364" cy="566" r="5.6"/><circle cx="380" cy="566" r="5.6"/><circle cx="396" cy="566" r="5.6"/><circle cx="412" cy="566" r="5.6"/><circle cx="428" cy="566" r="5.6"/><circle cx="444" cy="566" r="5.6"/><circle cx="460" cy="566" r="5.6"/><circle cx="476" cy="566" r="5.6"/><circle cx="492" cy="566" r="5.6"/><circle cx="188" cy="582" r="5.6"/><circle cx="204" cy="582" r="5.6"/><circle cx="220" cy="582" r="5.6"/><circle cx="236" cy="582" r="5.6"/><circle cx="252" cy="582" r="5.6"/><circle cx="268" cy="582" r="5.6"/><circle cx="284" cy="582" r="5.6"/><circle cx="300" cy="582" r="5.6"/><circle cx="316" cy="582" r="5.6"/><circle cx="332" cy="582" r="5.6"/><circle cx="348" cy="582" r="5.6"/><circle cx="364" cy="582" r="5.6"/><circle cx="380" cy="582" r="5.6"/><circle cx="396" cy="582" r="5.6"/><circle cx="412" cy="582" r="5.6"/><circle cx="428" cy="582" r="5.6"/><circle cx="444" cy="582" r="5.6"/><circle cx="460" cy="582" r="5.6"/><circle cx="476" cy="582" r="5.6"/><circle cx="492" cy="582" r="5.6"/></g><g class="p2 dim"><circle cx="508" cy="566" r="5.6"/><circle cx="524" cy="566" r="5.6"/><circle cx="540" cy="566" r="5.6"/><circle cx="556" cy="566" r="5.6"/><circle cx="572" cy="566" r="5.6"/><circle cx="588" cy="566" r="5.6"/><circle cx="604" cy="566" r="5.6"/><circle cx="620" cy="566" r="5.6"/><circle cx="636" cy="566" r="5.6"/><circle cx="652" cy="566" r="5.6"/><circle cx="508" cy="582" r="5.6"/><circle cx="524" cy="582" r="5.6"/><circle cx="540" cy="582" r="5.6"/><circle cx="556" cy="582" r="5.6"/><circle cx="572" cy="582" r="5.6"/><circle cx="588" cy="582" r="5.6"/><circle cx="604" cy="582" r="5.6"/><circle cx="620" cy="582" r="5.6"/><circle cx="636" cy="582" r="5.6"/><circle cx="652" cy="582" r="5.6"/></g><text class="px-lbl" x="740" y="522">Resets in</text><text class="px-sub" x="740" y="550">before the window rolls over</text>
</svg>
</div>
<figcaption style="margin-top:0.85rem;text-align:center;font-size:0.85rem;color:var(--muted-foreground);">The three usage screens, redrawn at 32 by 8. This is the whole display.</figcaption>
</figure>

## The other screens

The token monitor earned the permanent spot, but it shares the device. One app pings when there are visitors on this site. Another lights up when someone asks the chat in the corner of this page a question, which is a strange and great feeling: a stranger talks to my agent, and a little screen glows on my desk. There are screens for weather, messages, email notifications. Anything I want, really.

Building these has been half the fun. The distance between "I wonder if" and "it is on the screen" is about twenty minutes.

<figure style="margin:2.75rem 0;">
<video autoplay muted loop playsinline controls preload="metadata" poster="/images/blog/i-hacked-a-birthday-gift-led-screen-into-an-ai-token-usage-monitor/videos/visitor-ping-poster.jpg" style="display:block;width:100%;border:1px solid var(--border);border-radius:var(--radius-lg);background:var(--card);">
  <source src="/images/blog/i-hacked-a-birthday-gift-led-screen-into-an-ai-token-usage-monitor/videos/visitor-ping.mp4" type="video/mp4">
  A visitor notification firing on the device in real time.
</video>
<figcaption style="margin-top:0.85rem;text-align:center;font-size:0.85rem;color:var(--muted-foreground);">Someone lands on the site, the desk lights up.</figcaption>
</figure>

## How it runs

The screens are fed by a small dashboard app I built, running on a dedicated subdomain of this site. That is where I configure the apps, reorder the rotation, and toggle screens on and off. The dashboard pushes each screen to the clock through the AWTRIX HTTP API.

The dashboard is not public. It sits behind [Tailscale](https://tailscale.com), so the subdomain only resolves for devices on my private network. No login page, no auth code to maintain, no attack surface. If you are not one of my machines, it simply does not exist for you. For a personal tool, network as identity beats passwords every time.

<figure style="margin:2.75rem 0;">
<div style="border:1px solid var(--border);border-radius:var(--radius-lg);overflow:hidden;background:var(--card);">
<svg viewBox="0 0 1200 540" xmlns="http://www.w3.org/2000/svg" style="display:block;width:100%;height:auto" role="img" aria-label="How a number reaches the desk: sources such as Claude usage and site events feed a dashboard on a private subdomain, which posts JSON to the AWTRIX HTTP API on the clock. The dashboard, the API and the clock all sit inside a Tailscale private network that only Mahdi's devices can resolve.">
<defs><linearGradient id="flowgrad" x1="0" y1="0" x2="1200" y2="0" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#6366F1"/><stop offset="0.5" stop-color="#A855F7"/><stop offset="1" stop-color="#34D399"/></linearGradient></defs>
<style>.fl-bg{fill:var(--card)}.fl-dot{fill:var(--card)}.fl-num{fill:var(--muted-foreground);font-family:var(--font-mono);font-size:16px;letter-spacing:2px}.fl-lbl{fill:var(--foreground);font-family:var(--font-heading);font-size:26px;font-weight:600}.fl-sub{fill:var(--muted-foreground);font-family:var(--font-sans);font-size:16px}.fl-eye{fill:var(--muted-foreground);font-family:var(--font-mono);font-size:16px;letter-spacing:3px}.fl-cap{fill:var(--muted-foreground);font-family:var(--font-mono);font-size:15px;letter-spacing:3px}.fl-bound{fill:none;stroke:var(--border);stroke-width:1.5;stroke-dasharray:3 8}</style>
<rect class="fl-bg" width="1200" height="540"/>
<text class="fl-eye" x="140" y="80">HOW A NUMBER REACHES THE DESK</text>
<rect class="fl-bound" x="322" y="148" width="768" height="286" rx="20"/>
<line x1="150" y1="330" x2="1050" y2="330" stroke="url(#flowgrad)" stroke-width="2.5"/>
<g fill="none" stroke="url(#flowgrad)" stroke-width="2.5" stroke-linecap="round"><path d="M296,322 l9,8 l-9,8"/><path d="M561,322 l9,8 l-9,8"/><path d="M826,322 l9,8 l-9,8"/></g>
<g text-anchor="middle">
<text class="fl-num" x="175" y="196">01</text><text class="fl-lbl" x="175" y="230">Sources</text><text class="fl-sub" x="175" y="258">usage, site events</text>
<text class="fl-num" x="440" y="196">02</text><text class="fl-lbl" x="440" y="230">Dashboard</text><text class="fl-sub" x="440" y="258">a private subdomain</text>
<text class="fl-num" x="705" y="196">03</text><text class="fl-lbl" x="705" y="230">AWTRIX API</text><text class="fl-sub" x="705" y="258">JSON over HTTP</text>
<text class="fl-num" x="970" y="196">04</text><text class="fl-lbl" x="970" y="230">The clock</text><text class="fl-sub" x="970" y="258">256 pixels</text>
</g>
<g><circle class="fl-dot" cx="175" cy="330" r="10" stroke="url(#flowgrad)" stroke-width="2.5"/><circle class="fl-dot" cx="440" cy="330" r="10" stroke="url(#flowgrad)" stroke-width="2.5"/><circle class="fl-dot" cx="705" cy="330" r="10" stroke="url(#flowgrad)" stroke-width="2.5"/><circle class="fl-dot" cx="970" cy="330" r="10" stroke="url(#flowgrad)" stroke-width="2.5"/></g>
<text class="fl-cap" x="706" y="400" text-anchor="middle">INSIDE TAILSCALE. ONLY MY DEVICES RESOLVE IT.</text>
</svg>
</div>
<figcaption style="margin-top:0.85rem;text-align:center;font-size:0.85rem;color:var(--muted-foreground);">Everything past the first step lives on my private network. There is no public door.</figcaption>
</figure>

<figure style="margin:2.75rem 0;">
<img src="/images/blog/i-hacked-a-birthday-gift-led-screen-into-an-ai-token-usage-monitor/dashboard.jpg" alt="The private dashboard on its Device tab: a live mirror of the 32 by 8 screen reading FA 79% 2D, a row of app chips for claude-fable, claude-week and claude-5h, device readouts for battery, brightness, ambient light, temperature, humidity, signal, free RAM and uptime, plus a Notify composer and display controls." style="display:block;width:100%;height:auto;border:1px solid var(--border);border-radius:var(--radius-lg);" loading="lazy" decoding="async" width="1664" height="1164">
<figcaption style="margin-top:0.85rem;text-align:center;font-size:0.85rem;color:var(--muted-foreground);">Where the screens get built. It only loads on my own machines.</figcaption>
</figure>

## Build your own

The whole thing is more accessible than it looks.

- **The device:** [Ulanzi TC001](https://www.ulanzi.com/products/ulanzi-pixel-smart-clock-2882), around fifty dollars.
- **The firmware:** [AWTRIX 3](https://blueforcer.github.io/awtrix3/). Flashing happens in the browser and takes minutes.
- **The screens:** anything that can send an HTTP request. A cron job, a small script, an automation tool. Fittingly, an Activepieces flow would do it too.

You do not need a dashboard like mine to start. A ten line script posting JSON to the clock is a working first app. The dashboard came later, once I had enough screens to want a control panel.

If enough people want it, I will open source the dashboard. Tell me in the chat on this page or on LinkedIn.

## The honest part

I do not need this. Nothing on the screen is information I could not get by opening a tab. It is a fifty dollar clock showing me numbers that already live in a browser.

But that is exactly the finding. I had access to all of it before, and I still ran into limits mid-task, because checking requires remembering to check. The screen removed the remembering. Ambient information does not compete for attention. It waits at the edge of it.

I have spent a lot of my 17 years as a designer building dashboards that people had to remember to open. Most died of neglect, not of bad design. The most useful dashboard I have ever owned is 256 pixels, and nobody opens it at all. The information moved to where I already look.
