miniVirgil

miniVirgil demo

miniVirgil is a palm-sized voice endpoint for an AI assistant. Hold a button, speak, release — the ESP32-S3 records raw PCM and ships it over WebSocket to the IA backend, which may run STT → LLM → TTS. The microcontroller does no on-device AI: it is a thin, reliable physical front-end (mic + button + screen + WiFi).

The idea is simple: put an assistant on a desk without a keyboard or a phone. Press, talk, watch the TFT flip through the cycle states while the heavy lifting happens on the server.

How it works (software)

Firmware is a single Arduino sketch (firmware/main.ino). After boot it joins WiFi, opens a WebSocket to /ws/chat-audio, and sits in a small state machine:

STARTING → CONNECTED / DISCONNECTED
         → RECORDING...   (button held: I2S mic → PCM buffer in PSRAM)
         → PROCESSING → SENDING...  (binary PCM over WebSocket)
         → CONNECTED again

Design choices that matter in practice:

Libraries: Adafruit ST7789 + GFX + BusIO, and WebSocketsClient. Board profile: ESP32S3 Dev Module, 240 MHz, 16 MB flash, OPI PSRAM enabled.

On the backend side, audio goes through STT (e.g. ElevenLabs Scribe / local OpenAI), an LLM (Qwen) with RAG and tools, then TTS — miniVirgil just waits for the next press.

Electronics

Part Role
ESP32-S3 N16R8 MCU + WiFi, 8 MB PSRAM, 16 MB flash
INMP441 I2S MEMS mic, 16 kHz voice capture
ST7789V2 240×280 IPS TFT for state feedback
Tactile button Push-to-talk (GPIO 42)

Power and layout live in electronic_design/ (schematic, PCB, BOM). The display is SPI; the mic is I2S; the button is a plain GPIO with the usual debounce in firmware. PSRAM is what makes “hold and speak for a few seconds” safe without fragmenting the internal heap.

Rough BOM

Item Notes
ESP32-S3 N16R8 module / DevKit for proto Final board hosts the module footprint
INMP441 breakout (proto) / MEMS on PCB Left channel at 16 kHz
ST7789 1.69″ 240×280 IPS Status UI only
Momentary push button Front-panel PTT
Custom PCB (2-layer) From PCBWay
3D-printed shell Body + faceplate in mechanical_design/
USB-C / LiPo path (as wired on the board) Desk or battery use
Passives, headers, mounting hardware Per the KiCad BOM

Exact quantities and footprints: see the repo’s electronic_design/ folder.

Build story

Prototyping the display

First: prove the TFT and bitmap pipeline before worrying about audio.

Breadboard

Then the honest prototype: ESP32-S3, jumpers, mic path, button, and the IPS panel on a breadboard.

Once WiFi and the WebSocket handshake stuck, the screen showed CONNECTED — end-to-end loop alive.

check that guy anyway

Soldering & cleanup

Cable work and soldering before freezing the pinout into copper.

Custom PCBs

Boards from PCBWay:

[!IMPORTANT]

Huge thanks to PCBWay for manufacturing these boards. The silkscreen printing is precise and clear, and the board surface is well-finished, making it very easy to clean with isopropyl alcohol.

If you want to order with them: their prices and turnaround are excellent — check them out at pcbway.com.

Into the shell

Fitting the PCB and display into the printed body:

Desk companion, assembled:

What’s next

Roadmap highlights from the repo: play TTS back on-device (I2S amp), wake-word instead of the button, status LED, OTA, and a BLE fallback for locked-down networks.

Schematic, PCB, firmware, and mechanics: github.com/agarnung/miniVirgil.

miniVirgil demo