← AK-mee™ · Case study · Internal IP

Car Thing — Spotify Superbird fleet display

Car Thing

Superbird resurrection — discontinued hardware, brought back as a fleet-aware Matrix display.

Spotify retired the Car Thing in late 2024. We turned ours into a 480×800 living UI with Spotify playback control, fleet messaging overlay, an OTA pipeline, and a full desktop simulator — all wired through a Bluetooth-PAN bridge to the lab network.

Python 3.7FastAPIWebSocketBlueZ / BT PANADBSpotify Web APIAstro

Why this was interesting

Most discontinued consumer hardware is bricked by one of three things: a dead cloud service, a sealed bootloader, or a network stack that can't be coerced into talking to anything else. The Car Thing — Spotify's Superbird — was hit by the first. The bootloader was open. The 480×800 capacitive panel was healthy. The Amlogic S905D2 was running a real kernel. There was nothing wrong with it that a different reason to exist couldn't fix.

The build

The first decision was the network path. The device has a USB gadget interface — useful for ADB and power, useless for IP. It has Bluetooth, but the kernel ships with the BNEP module built in and no user-space helpers. So I made the lab Linux box the internet bridge: BlueZ running with the --compat flag, a Python NAP server, dnsmasq on the bridge interface, and a tiny pairing agent that auto-accepts. Two things bit me here. First, the SDP NAP record (UUID 0x1116) has to be re-registered after every bluetoothd start, or the device's BlueZ never exposes its Network1 interface and the connect call silently fails. Second, modern systemd renames bnep0 to something like enxAA…, which breaks the bridge silently — fix is one /etc/systemd/network/90-bnep.link file.

On the device side, we don't have Python dbus bindings, but dbus-send is on the PATH, so connect is a shell-out: dbus-send … org.bluez.Network1.Connect string:nap. Static IP, default route, and a 30-second watchdog. From boot to playable Spotify on a cold device takes about 12 seconds.

The UI is a single-file HTML app served by a Python HTTP server running locally on the device. The webapp polls a /state endpoint and posts commands to /cmd — the same endpoints the rotary encoder, GPIO buttons, and capacitive touch all flow through. Aesthetic is Matrix rain over a portrait album-art card; the brand wordmark sits on the screen as a quiet watermark. We wrote a separate desktop simulator that runs the same HTML at the same 480×800 dimensions in a browser, against a stand-alone Spotify server using spotipy.SpotifyOAuth. Build-test-fix on the simulator, sideload to the device, done.

Spotify control is two-tier. On the device, an HTTP client refreshes an authorization-code token every hour and posts to /me/player/play, /me/player/pause, /me/player/next. On the workstation, a FastAPI service keeps a WebSocket open to any connected dashboard and republishes now-playing state at 2-second cadence. The fleet messaging overlay is the same channel — any machine on the lab network can POST /api/message and it lands as a green subtitle on the device within a frame.

System architecture

Car Thing system architecture Spotify cloud connects to a Mac mini OAuth proxy, which bridges to a Linux box providing BT PAN, which connects to the Car Thing display running a local UI. Spotify Cloud accounts.spotify.com api.spotify.com OAuth · Web API Workstation (Mac mini) FastAPI server.py :8888 spotipy SpotifyOAuth /api/message broadcast ADB · OTA trigger refresh-token cache · 1h cycle Bridge (Linux box) bluetoothd --compat sdptool add NAP (0x1116) bt-nap.py · pan0 bridge dnsmasq DHCP pool iptables NAT → enp1s0 auto-accept pairing agent Car Thing Superbird · S905D2 · 480×800 dude_local.py :9999 webapp/index.html /state · /cmd · /announce supervisord chromium · backlight bt watchdog · 30s /dev/input/event0 GPIO /dev/input/event1 rotary /dev/input/event3 touch AK-mee HTTPS Tailscale · LAN BT PAN · bnep0 static · BT subnet USB · ADB · OTA sideload Legend Bidirectional API / data LAN / Tailscale Out-of-band (debug · OTA) All traffic stays on owned hardware. No cloud broker. AK-mee™ fleet messaging uses the same WebSocket as Spotify state.

Lessons learned

  • Discontinued hardware is a system problem, not a firmware problem. The Superbird itself was the easy part. The hard part was the path between it and the internet — a Linux box running BlueZ in compat mode, an SDP record that has to be re-registered every boot, and a kernel that silently renames the bridge interface unless you nail it down with a systemd link file.
  • Build the simulator before you ship to the device. The 480×800 webapp runs in a desktop browser at the same dimensions, with the same touch and dial event model, against a stand-alone simulator server. Iteration loop dropped from minutes-per-cycle (sideload, restart, reconnect) to seconds.
  • Static IP everywhere the kernel is old enough to argue. udhcpc on Linux 4.9.113 is unreliable on Bluetooth bridge interfaces. We assign a static address on the BT PAN subnet and a default route by hand on every connect. A 30-second watchdog thread re-runs the connect sequence if the link drops.
  • OTA without an app store. A small shell script on the device pulls a manifest from the project repo, compares git SHAs, and rsyncs only the files that changed. Trigger is one ADB command from any machine on Tailscale. No build server, no CDN, no mystery.
  • Treat third-party APIs as a moving target. Mid-build, Spotify deprecated implicit-grant OAuth, banned some redirect hosts, and renamed half the playlist endpoints. We logged the changes, pinned to authorization-code-with-secret, and switched our redirect to a localhost callback. Worth keeping a per-device drift log for exactly this kind of upstream change.

What's next

The Car Thing is now the always-on display in the lab — Spotify control on the rotary, fleet status overlay across the bottom, AK-mee™ wordmark glowing under the Matrix rain. Next stops are a generalized phone-tethering profile so the same image runs untethered from the bridge host, and treating the device as a reference for our wider embedded display work — anything portrait, anything constrained, anything that needs a UI without an app store.

← Back to AK-mee™

Acknowledgements

The Spotify Car Thing (Superbird) was not designed to be hackable. That it is hackable at all is the work of a dedicated open-source community. We built our firmware on top of that foundation, and we want to name it properly.

The ADB jailbreak procedure used in our install tooling was documented and maintained by the Car-Thing-Hax Community Edition project — a community-maintained collection of reverse-engineering notes, jailbreak documentation, and tooling for the Superbird. Without that work, ADB access to the device would not be possible.

Low-level bootloader access on factory-locked units relies on superbird-tool by bishopdynamics — a USB/ADB utility for the Amlogic S905D2 that makes initial device setup possible. Thank you for building and maintaining it.

Thank you to every contributor who reverse-engineered this hardware, published teardowns, and kept the knowledge alive after Spotify discontinued the device. This project stands on your shoulders.