raspberry-pi

chatbox: A Desk Terminal With Exactly One Job

A Pi Zero W, a 3D printer display board, and a microphone in a printed wedge: press the knob, ask out loud, and the answer streams onto a 128×64 LCD or to an Amazon Eco.

Every device I own that can answer a question is also a device that can show me a notification. I ask my phone something, and forty seconds later I'm in an app I didn't intend to open. The answer was never the problem. The surface was.

So I built something with one job: press the knob, ask out loud, read the answer. No app, no feed, no second thing it can do. It sits on the desk, shows a clock, and waits.

The chatbox case — a 45° printed wedge with the LCD window and knob on the face plate

Code, case, and wiring are all here: github.com/drkpxl/chatbox

The star of the show

The display is a BigTreeTech Mini12864 which is a part made for 3D printers, not for this. And it is an absurdly good deal for what I needed, A: Because I already had it but also because BTT put four things on one PCB: a 128×64 LCD, a rotary encoder with a push switch, three addressable WS2812 LEDs, and a piezo buzzer. One board, one bundle of jumper wires, and I have a screen, an input device, a status light, and a speaker.

Add a Raspberry Pi Zero W, an INMP441 I2S microphone, and about 150g of filament. Nineteen jumper leads, and the microphone's pads are the only soldering.

The Pi is deliberately stupid

A Pi Zero W is ARMv6 with 512 MB of RAM. It is not running Whisper. It is not running inference. It's not even close.

That turned out to be a feature, because it forced the architecture to be honest:

knob press ──> record to RAM (16 kHz mono WAV, never touches the SD card)
           ──> POST the audio to a transcription endpoint  ──> text
           ──> POST that text to a chat endpoint (SSE)      ──> tokens
           ──> draw them as they arrive

That's the whole thing. The box records, uploads, and renders. All the intelligence is a Hermes Agent host on my LAN, but nothing in the Pi code is Hermes-specific, it's just a multipart upload and an OpenAI-compatible /v1/chat/completions stream. Any Whisper-style transcriber and any OpenAI-shaped chat endpoint will drop in.

Because it streams, the answer starts appearing while the model is still writing it, which matters a lot on a screen this small. And an X-Hermes-Session-Id header scoped to the service run means consecutive questions continue a warm thread instead of starting cold every time.

Text that holds still

Long answers page rather than scroll. Each chunk sits still for a few seconds and then cuts to the next one.

The knob's LEDs carry the state, so you're never wondering whether it heard you — blue while listening, pulsing blue while transcribing, breathing amber while thinking, green while streaming, a double-pulse when it's done, red when it isn't.

It can also just say it

The most recent addition: flip on Speak answers, pick a speaker, and the box stops drawing text entirely. It hands the finished answer to Home Assistant and shows an animated speaker icon. Same reasoning as the paging, if you asked out loud, you shouldn't then have to read if you don't want to.

Two things I learned wiring that up. Home Assistant acknowledges a TTS call immediately, so the box never learns when the speaker actually stops talking — the animation runs on a 150-wpm word-count estimate and a click cuts it short. And long answers get split into ~240-character chunks on sentence boundaries, because Alexa's notify TTS silently truncates past some length that moves between releases.

If HA refuses the call, it falls back to the text screen and plays the error tone.

The case is code

The enclosure is a 45° wedge, 143 × 82 × 65 mm, and it's a parametric build123d script.

The useful trick: BigTreeTech publishes a STEP model of the display board, so the script self-checks against the manufacturer's own geometry. --check boolean-tests the case against the real board. --qa goes further and measures the things a slicer can't tell you — that every screw has material to bite into, that every bore is actually clear, and the true minimum distance from the face plate to each of the 176 individual solids in BTT's model.

All four parts print without supports. The image above is a render.

Build one

Everything's in the repo: wiring tables and assembly, install and architecture, the case source with print-ready STLs, and the diagnostic scripts I used for bring-up. Roughly $40 of parts if you have a printer and a spare Pi.

github.com/drkpxl/chatbox