Skip to content
All projects

02Portfolio

WireAmbi — car ambient lighting from the phone and Android Auto

An Android app that drives ELK-BLEDOM/MELK LED strips from the phone and from the Android Auto screen. It has a music mode with its own audio analysis pipeline, offline voice control and a car panel linked to the led-auto gateway.

  • 01/07
  • 02/07
  • 03/07
  • 04/07

By the numbers

Unit tests
359
Beat → BLE write
6 ms
Music reaction styles
9
01

Problem

Cheap ELK-BLEDOM-family LED controllers come with no documentation, and the vendor app does not run on the car screen. The same frame exists in several incompatible dialects: the controller in the car ignored commands even though every Bluetooth write reported success. The controller does not report its state, accepts one connection at a time and cannot be encrypted. In Android Auto the sound never leaves the phone speaker, so music mode has nothing to hear through the microphone.

02

Approach

I took the 7E…EF frames from the public model table of the elkbledom Home Assistant integration and verified them on hardware. The protocol layer picks one of three dialects by device name, and effects that mean different things on different models are computed on the phone. The Bluetooth write pump waits for the stack’s acknowledgement and retries refusals, while real-time colours go through a one-slot channel so the strip never falls behind. Music mode captures audio through AudioPlaybackCapture and runs it through an FFT, a logarithmic filter bank, a SuperFlux onset detector and a tempo tracker that predicts beats. The logic lives in a :core module with no Android or Bluetooth dependency, so tests check the bytes that would go to the controller. Android Auto screens stay within template limits dug out of the library bytecode. The app talks to the led-auto gateway over the encrypted WireLink channel.

03

Outcome

The app runs on real hardware (MELK-OC21 controller, Android 15), and the car screen is tested in the Desktop Head Unit. The repository has over 350 unit tests, lint is clean, the compiler reports no warnings, and the release build passes cleanly through R8. From a beat detected in the analysis to the Bluetooth write takes 6 ms on average. On a 123 BPM track the median gap between flashes was 487 ms, against a theoretical 488 ms. The interface is in Polish and English.

How it works

The key features, in short clips.

  1. 01

    Pairing without guesswork

    A wizard walks through permissions and the Bluetooth scan and sorts controllers by signal strength. The chosen controller is remembered, so in the car WireAmbi reconnects on its own — including inside Android Auto.

  2. 02

    Colours, scenes and a colour wheel

    Eight preset colours, an HSV wheel for the full range and scenes that save colour, brightness, mode and speed under a name. The slider sends only the value where the finger stopped, and Bluetooth writes wait for the stack’s acknowledgement — no frame is silently lost.

  3. 03

    Light that follows the music

    Audio comes from the playback mix (AudioPlaybackCapture), not the microphone, so it also works with Android Auto. On the way: an FFT, a logarithmic filter bank, a SuperFlux onset detector and a tempo tracker that predicts beats. Nine reaction styles, from pulse to rainbow and sparks.

  4. 04

    Calibration for any controller

    Cheap controllers speak three incompatible dialects of the same 7E…EF frame — the app picks the right one by device name. When a strip is wired differently, the colour test shows it at once and a single tap sets the channel order.

  5. 05

    Car panel with the led-auto gateway

    With the led-auto gateway, the phone talks over the encrypted WireLink channel and shows lock and door state live on a 3D car model. Opening the door turns on the entry light. Unlocking and opening windows require the owner’s biometrics or PIN.

  6. 06

    Android Auto and offline voice

    On the car screen: a colour grid, scenes and shortcut tiles arranged on the phone. Voice commands are recognised by Vosk offline against a closed grammar — a result counts only when every word has at least 0.7 confidence.

Write