Control Divoom pixel-art devices (Pixoo, Ditoo, Timebox, Tivoo, …) from Home Assistant — as real devices with entities and actions, over Bluetooth or through a web-flashable ESP32 gateway.
This repo combines and extends two projects by @d03n3rfr1tz3: hass-divoom (the Home Assistant integration) and esp32-divoom (the ESP32 Bluetooth-Classic proxy firmware).
| Part | Where | What's new here |
|---|---|---|
| HA integration | custom_components/divoom |
Full device with entities (light, channel select, brightness/volume sliders, buttons) + 23 device-targeted actions. Notify service still works. |
| ESP32 firmware | firmware/ |
Flash from your browser, WiFi setup via Improv (no code editing), on-device web UI for configuration, OTA updates, captive portal fallback. |
| Web flasher | flasher/ |
ESP Web Tools installer page, deployed to GitHub Pages by CI. |
Divoom devices use Bluetooth Classic (SPP) — not BLE. Home Assistant's ESPHome Bluetooth proxies are BLE-only and cannot talk to Divoom devices, and many HA servers don't have (working) Bluetooth Classic at all. The gateway firmware turns a ~$5 ESP32 dev board into a WiFi→Bluetooth Classic bridge that the integration talks to over TCP. Note: only the original ESP32 chip has Bluetooth Classic — the S2/S3/C3 variants don't work.
If your Home Assistant host has working Bluetooth Classic, you can skip the gateway entirely and connect directly.
- Open the web installer in Chrome or Edge
- Plug your ESP32 in via USB and click Install
- Enter your WiFi credentials when prompted (Improv)
- Done — the gateway announces itself on your network via mDNS/zeroconf
The gateway's own web page (http://divoom-gateway.local) shows live status (WiFi, Bluetooth, MQTT, heap)
and lets you change WiFi, hostname, MQTT and Bluetooth settings, install firmware updates over the air,
restart, or factory-reset. If it can't reach your WiFi it opens an access point
(Divoom-Gateway / password divoom1234) with a captive setup portal.
Building/flashing manually with PlatformIO instead
The firmware is a PlatformIO project in firmware/. Open the folder in VS Code with the
PlatformIO extension and hit Upload, or:
cd firmware
pio run -e esp32dev -t upload
Runtime configuration lives in NVS (set via web UI/Improv), so you no longer need a config_local.h —
but it still works for pre-seeding defaults.
Install via HACS (or copy custom_components/divoom into your config folder), restart Home Assistant,
then add the Divoom integration. If the gateway already discovered your Divoom device, it shows up
automatically via zeroconf — otherwise add it manually and pick your device from the scanned list.
Your Divoom device then appears as a device with:
| Entity | Description |
|---|---|
| Light | The light channel — on/off, brightness, RGB color |
| Channel (select) | Switch between clock / light / effects / visualization / design / lyrics |
| Brightness (number) | Display brightness 0–100% |
| Volume (number) | Speaker volume (audio devices: Ditoo, Tivoo, Timoo, Timebox) |
| Sync time (button) | Set the device clock to current time |
| Keyboard buttons | Toggle / next / previous keyboard LED effect (Ditoo) |
States are optimistic: the Divoom protocol is mostly write-only, so Home Assistant assumes commands succeeded.
All device functions are exposed as actions (Developer tools → Actions → search "Divoom"), targeted
at the device — with proper UI fields:
show_image, show_text, show_clock, show_effects, show_visualization, show_design,
show_lyrics, show_scoreboard, show_timer, show_countdown, show_noise, show_radio,
show_sleep, show_equalizer, play_game, game_control, set_keyboard, set_playstate,
set_datetime, set_weather, set_alarm, set_memorial, send_raw
# Example: show a GIF when the doorbell rings
action: divoom.show_image
target:
device_id: abc123...
data:
file: doorbell.gif# Example: scoreboard
action: divoom.show_scoreboard
target:
device_id: abc123...
data:
player1: 2
player2: 1GIFs go into a pixelart/ folder in your HA config directory and must exactly match your screen size
(16×16 for Pixoo/Ditoo, 32×32 for Pixoo Max), non-interlaced, with a global color palette.
See Troubleshooting.
Legacy notify service (still supported)
The classic notify.divoom_* service keeps working exactly as documented in the
original README, including configuration.yaml
setups. Config-entry devices share one connection between the notify service and the entities.
aurabox, backpack, ditoo, ditoomic, pixoo, pixoomax, timebox, timeboxmini, timoo, tivoo
Bluetooth port is usually 1; audio devices (Ditoo, Timoo, Tivoo) often use 2, Timebox Mini uses 4.
The config flow pre-fills the right one based on the device name.
Besides TCP (port 7777, used by the integration), the gateway also accepts commands via Serial and
MQTT — useful standalone, without Home Assistant. See the
firmware README for the CONNECT / SEND / MODE … command reference
(brightness, clock, light, effects, games, alarms, radio, and more).
Cannot connect — Make sure your phone's Divoom app isn't currently connected (most devices allow only
one connection). If it connects but drops on the first command, you picked the wrong port — try 2
(audio devices) or 4 (Timebox Mini).
Wrong MAC: use the -Audio one — Many Divoom devices advertise two Bluetooth personalities, e.g.
DitooPro-Light (BLE, what Home Assistant's own Bluetooth sees) and DitooPro-Audio (Bluetooth Classic).
The gateway can only connect to the -Audio MAC — it's the one shown under "Divoom devices found" on
the gateway's web page. If your config entry was created from HA's -Light discovery, delete it and re-add
with the -Audio MAC.
Gateway host format — Enter just the hostname or IP (e.g. 192.168.50.57), not a URL. The integration
sanitizes http://…/ automatically since v2.0.3, but older entries with a URL in the host field should be
re-added.
GIF doesn't display — The image must exactly match the screen size (16×16/32×32), be non-interlaced and use a global color palette. GIMP: export with the animation box checked and interlace unchecked, resize with no interpolation. Details in this comment.
Web installer can't find the port — Use a USB data cable, install the CP210x/CH340 driver for your board, and use Chrome or Edge (Web Serial isn't available in Firefox/Safari).
Gateway web page sometimes hangs / "took too long to respond" — The original ESP32 shares one radio between WiFi and Bluetooth Classic, so the web server can be briefly unresponsive during Bluetooth discovery. (Note: modem sleep cannot be disabled to fix this — the coexistence layer requires it and the device will boot-loop without it.) Mitigations that help: give the gateway a DHCP reservation / static IP, keep it on 2.4 GHz with a decent signal (the status page shows RSSI — aim for better than −75 dBm), and avoid hitting it from the web UI and Home Assistant at the exact same moment. A power-cycle clears a wedged radio.
Protecting the settings page — Set a PIN under Security on the gateway's web page. Once set, saving settings, OTA updates, restart and factory reset require it (the browser prompts and remembers it for the session). To remove it, tick Remove the PIN and save. Note this guards configuration changes, not a login wall — keep the gateway on a trusted network.
All protocol reverse-engineering credit goes to @d03n3rfr1tz3 and the projects referenced in the original credits: node-divoom-timebox-evo, fhem-Divoom, timebox, and the Divoom protocol docs.