Sriganesh Srinivasan
← All work

SmartRoomThing.

A modded Spotify Car Thing that runs my room's speakers

2026–now · Solo — hardware, backend, UI · Active

SmartRoomThing
Problem
Three Google Cast speakers in one room (a Nest Audio, a Google Home and the TV) each had their own volume, and adjusting them meant using a phone and unbalanced speaker volumes.
Built
A Spotify Car Thing with no WiFi, tunnelled over USB to a Flask server on a Raspberry Pi 2. The server drives all three speakers and proxies Spotify. The dial scales the whole mix, buttons recall presets, and there's a now-playing screen and a playlist grid.
Stack
Python, Flask, PyChromecast, Raspberry Pi, JavaScript, ADB, systemd
Outcome
It runs 24/7 on the Pi. After profiling, dial-to-speaker latency fell from 1,177 ms to 84 ms, and idle CPU dropped to under 1% of one core.

What it does

The Car Thing was Spotify’s discontinued in-car gadget: a small touchscreen with a big dial and four buttons. Mine sits on my desk and controls the room.

Mixer screen: three volume faders labelled NEST, HOME and CAST at 60, 50 and 70, under the DESK preset
The mixer, with the DESK preset active. Rendered from the device's actual web app, with sample data.

How it works

The Car Thing has no WiFi and no internet, so everything goes through the Pi.

SmartRoomThing architectureThe Car Thing talks to a Flask server on a Raspberry Pi over a USB adb reverse tunnel. The server drives three Google Cast speakers over the local network and proxies the Spotify Web API over HTTPS.SPOTIFY CAR THINGDial + touchscreenVanilla JS web appKiosk Chromium 69No WiFi, no internetScreen sleeps if Pi is goneUSBadb reverseRASPBERRY PI 2 · 24/7Flask server~1,050 lines of PythonWriter thread × 3one per speaker, latest volume onlySpotify proxysecrets stay here · album-art cachePresets + statusDESK · BED · AMBIENTadb-watch (systemd)keeps the USB tunnel aliveCAST · LANGOOGLE CASTNest AudioGOOGLE CASTGoogle HomeGOOGLE CASTLiving-room TVHTTPSCLOUDSpotify Web API
How the pieces talk. The Car Thing has no network of its own; everything goes through the Pi.
  1. May 2026First version on my Mac, with Home Assistant in Docker, started whenever my monitor was plugged in.
  2. Jun 2026Moved to a Raspberry Pi 2 so it runs 24/7. Added playlists and speaker-group playback.
  3. Sep 2026Tracked down the volume runaway bug, rebuilt the USB tunnel watchdog, and profiled and overhauled performance for the Pi 2.
  4. Sep 2026Fixed Cast connections that died silently, and added a lint and test pipeline (28 tests).

What broke

Making a Pi 2 fast

The Pi 2 has a 900 MHz ARM chip and 1 GB of RAM, and turning the dial felt laggy. Before rewriting anything, I measured: a volume change took 1,177 ms of wall-clock time but only 47 ms of CPU. The server wasn’t slow; it was waiting. So a rewrite in a faster language wasn’t the answer.

The fixes were about waiting less:

Before After
Dial → speaker 1,177 ms 84 ms
Album art 364 ms 86 ms
Now playing 394 ms 225 ms
UI render CPU 5.2% 0.1%
Idle server CPU ~1.3% ~0.8%

What I’d do next

The lint and test pipeline (28 pytest tests, plus linters set up for the device’s old Chromium) is on a branch waiting to be merged. I’ve also started a second screen, an HDMI dashboard driven by the same Pi.

Next projectTV Ambilight →