Selected work
Projects
A run of things I've built for the fun of it — small services wired together with Kafka, a bit of hardware and radio, and a homelab to run it all on. The throughline: turning noisy real-world signals into something useful, with no cloud bill.
The Chair™
Load cells × KafkaCuriosity about load cells turned into a fully event-driven sensor platform. A load cell under my living-room chair streams weight data into Kafka, where a pipeline of small services turns raw readings into meaningful sit events — driving everything from automated lighting to a live analytics dashboard. Built to scale: more sensors to come.
A Raspberry Pi, HX711 amplifier, and load cell read weight off the chair and publish to a raw-sit topic.
Joins a sit-down and a sit-up reading into a single Sit event — average weight, start/end timestamps, and duration.
Reacts to sit events: turns on the light behind the chair when you sit, and dims it when you get up.
Derives the live status of each device from the raw-sit stream — the source of truth for "in use / free".
Aggregates every sit and serves it over REST, plus WebSockets that push live device status to subscribers.
A leaner rewrite of the stats API in Go — same data, less overhead.
A Vue.js UI over the API: filter by weight, time, and duration; click a device for live status and details.
Whisper Bot
ML pipelines on KafkaMy friends share an anonymous meme chat with a constant firehose of messages — a perfect playground for Kafka and machine learning. Whisper Bot consumes the chat, trains a model on it, and once a day posts a (gloriously absurd) message of its own. The results are silly; the pipeline behind them is the fun part — now evolving toward LLAMA 2 with embeddings.
Uses the Telegram bot API to ingest every message from the anonymous group into a raw-message topic.
Cleans and normalizes the raw messages, then emits a tidy, training-ready set to its own topic.
Trains a TensorFlow model on the cleaned data, exports it to a compact TFLite file, and publishes it to a model topic.
Loads the latest model and generates text from a seed and word count — hot-swapping new models as they arrive.
Schedules one whisper to be posted to the chat each day, always using the freshest model.
Embeds each message and generates with a LLAMA 2 model. Next up: embedding the links and images people share for richer context.
Scores the sentiment of messages — an experiment in feeding the room's mood back into future models.
Farm Sensor Network
LoRa IoTA long-range, solar-powered sensor network for monitoring conditions out in the field, where Wi-Fi doesn't reach. Battery-friendly ESP32 nodes speak raw point-to-point LoRa — deliberately skipping LoRaWAN and Meshtastic overhead — to a Raspberry Pi hub that feeds a Go API and a live dashboard. Designed for nodes that run for years on a small panel, and the dashboard can even flash new firmware to a board straight from the browser.
ESP32 (Heltec V3) firmware sending a compact binary payload over SX1262 LoRa, with solar and deep-sleep power budgeting — and nRF52 boards under evaluation for even lower sleep current.
A Go daemon on a Raspberry Pi that receives LoRa packets off the radio and relays them upstream.
Go services handling auth, farms, hubs, and nodes, with secrets managed in HashiCorp Vault.
A React/TypeScript dashboard with live sensor charts — and in-browser ESP32 flashing for new nodes.
Personal Health Pipeline
Self-hosted data engineeringA self-hosted pipeline that turns phone and wearable sensor data into a personal health dashboard — end to end, with no cloud dependency. The same Kafka instincts from my day job, pointed at my own data.
Home Assistant exposes phone and wearable sensors and streams every reading into the pipeline.
A single Kafka topic carries it all, with consumer-side filtering that keeps the producers dumb and simple.
CouchDB persists each reading under an idempotent {entity_id}:{last_updated} document id, so replays never double-count.
A mobile-first React + Vite + Recharts frontend for vitals, activity, and sleep trends — built to extend to new data sources.
More builds
Smaller experiments — a place to try an idea end to end.
A citizen-science dashboard exploring whether geomagnetic activity affects sleep — live NOAA space-weather data vs. crowdsourced sleep reports. sleep.devinbutts.net
Detects passing cars by sound alone — covering the gap where cameras fail in the dark. A Raspberry Pi with a Google Coral Edge TPU runs YAMNet classification and publishes events to the same Kafka topic as the camera pipeline.
A remote-controlled RC car that live-streams its video feed and takes driving input over Redis.
Data pipelines that pull NOAA's entire buoy network and turn it into something worth looking at.
Automates a Blichmann grain mill so it stops itself after each fill — a small homebrewing quality-of-life win.
Reusable database sinks I drop into side projects to land streaming data without reinventing the wheel.
A guided tool that turns a fuzzy sense of career or life direction into concrete next actions, then tracks follow-through. Self-contained React, AI-facilitated, with local persistence.
Homelab & self-hosting
Most of these projects don't run on a cloud bill — they run at home. The homelab is where I deploy, break, and rebuild things on real infrastructure.
A Proxmox cluster that self-hosts most of the projects on this page — LXC and Docker behind Cloudflare Tunnels, no cloud dependency. My always-on playground for shipping side projects to real URLs.
A self-hosted LLM server running entirely on home hardware — Ollama with AMD ROCm GPU acceleration — so experiments never depend on a third-party API.
A privacy-first, self-hosted password manager (Vaultwarden) running in a lightweight Alpine LXC.
A Meshtastic LoRa mesh (Heltec V4, LongFast preset) tuned for internet-free, multi-hop communication — range work through antenna placement and hop-limit configuration.