Control Divoom pixel-display devices (Pixoo / Tivoo / Timebox / Ditoo …) as a Python library, a headless daemon (local or over the network), and a desktop Control Center app.
The project has three Python packages, two native Rust binaries (the daemon and the menu-bar agent), and a native accelerator:
divoom_lib/— the shared protocol core: SPP framing, the command and capability models, the transport interface, cloud auth, the native-library loader, plus the CLI (divoom-control) and the MCP server, both of which are daemon clients. Runs on macOS and Linux. (The direct-to-device Python library — theDivoomfacade and its BLE/LAN/SPP transports — is retired from the product and lives on asexamples/divoom_legacy/, standalone.)divoomd/— the native Rust daemon: a headless, always-on agent that is the single owner of the device connection and serves a command/event protocol over a Unix socket and (optionally) TCP. On macOS it also does notification monitoring. Runs on macOS and Linux. Paired with a native Rust menu-bar agent,divoom-menubar/— together these are what the shipped app runs.divoom_client/(the Python package) is client-only: the shared NDJSON-socket client library every consumer (GUI, menubar, CLI, MCP) uses to talk to whichever daemon is running. The original Python daemon server implementation was archived (2026-07-13) and then removed from the tree in R66 (2026-08-17) -- recover from git history (archived in 046cdf8, removed in R66 2026-08-17) once the Rust daemon reached parity — kept for historical reference only, not built, run, or tested by anything in this repo.divoom_gui/— a pywebview desktop Control Center (macOS): live previews, channel grid, live widgets (album art / stocks / system monitor), a gallery, a multi-panel "virtual wall", and a tools/settings area. It is a thin client of the daemon — it owns no BLE connection and auto-spawns the daemon if one isn't running.
There is no native library any more. divoom_lib/libdivoom_compact.{dylib|so}
— the palette encoder, the downsampler, the frame escaping, built from
divoom_lib/native_src/ — was deleted on 2026-09-25, and with it the Python
encoders beside it. Both live in the Rust daemon now (divoomd::framing,
divoomd::image_encode), and what the C produced byte for byte is recorded in
divoomd/tests/{framing,image}_vectors.json, which the Rust side asserts
against. The old arrangement had three implementations of one protocol — C,
Python, and the FFI wrapper that chose between them — and the C had to exist,
be rebuilt per platform, and be committed to the tree so the Python side could
call it.
Unofficial project, not affiliated with Divoom. Use at your own risk.
- Discovery — scan for Divoom devices over BLE; manage known LAN devices.
- Channels — Clock, Cloud, VJ Effects, EQ/visualizer, Ambient light, Scoreboard, Text.
- Image & animation push — static images and GIFs, palette-encoded and streamed via the 0x8B 3-phase protocol (16px today; 32px encoder included).
- Live widgets — auto-push album cover art on track change (Spotify / Apple Music, macOS), stock tickers, and a system monitor.
- Gallery — browse + sync the Divoom "monthly best" gallery to the device.
- Virtual wall — drive a multi-panel grid as one composite display.
- Tools — alarms, sleep aid, timer / countdown / noise meter, FM radio, anniversary/memorial countdown.
- Device settings — brightness, 12/24h, °C/°F, orientation & mirror, name, auto-power-off, time sync, weather push, factory reset.
- Notification mirroring — trigger the device's notification display (macOS).
- Headless / networked — run the daemon on one machine (e.g. a Linux box near the device) and control it from another over TCP with a shared token.
- macOS (Apple silicon) or Linux (x86_64 / aarch64) for
divoom_lib+divoomd. Intel Macs are not supported — Apple has dropped them, so have we; note this is macOS-specific, Linux x86_64 remains fully supported. 32-bit targets (i686 / armv7) are not supported on any OS. (BLE viableakin Python /btleplugin Rust — CoreBluetooth on macOS, BlueZ on Linux). The GUI + menu-bar + now-playing sync are macOS-only today. - Python 3.14 (uses
X | Nonetype syntax). CI and the shipped app build on Python 3.14. - Python deps in
requirements.txt(bleak,aiohttp,pillow,pywebview, …). - Rust (stable, via
rustup) to build the daemon (divoomd) + menu-bar —./build.sh. - A C compiler (clang/gcc) is optional — only to build the native accelerator; without it everything falls back to pure Python.
The packaged Control Center app installs via the ztomer/tap
Homebrew tap — no Python setup required:
brew install --cask ztomer/tap/divoom-control
# later:
brew upgrade --cask ztomer/tap/divoom-controlThis installs a self-contained Divoom.app (GUI + menu-bar agent + bundled
daemon). The first scan prompts once for Bluetooth — grant it. Requires macOS 11
(Big Sur) or later on Apple silicon; Intel Macs are not supported.
pip install -r requirements.txt # or: pip install -e .
# build the native Rust daemon + menu-bar (+ the C accelerator dylib):
./build.sh
# then run the GUI (it auto-spawns the daemon + menu-bar):
./run.sh./build.sh --debug for a debug build; ./run.sh --menubar runs just the tray
agent for a quick smoke. (Rust only? cargo build -p divoomd --no-default-features
builds just the daemon, without the Bluetooth radio — safe in a terminal with no
TCC grant.)
Run the native divoomd binary directly (the GUI auto-spawns it for you; this
is only for headless/networked use):
# local only (Unix socket; the GUI auto-spawns this for you)
./target/release/divoomd --socket /tmp/divoom.sock
# headless network server on a LAN, token-authenticated (R19)
./target/release/divoomd --host 0.0.0.0 --port 9009 --token "$DIVOOM_DAEMON_TOKEN"Remote clients (including the GUI) target it by setting DIVOOM_DAEMON_HOST,
DIVOOM_DAEMON_PORT, and DIVOOM_DAEMON_TOKEN.
./run.sh # preferred: GUI + native daemon + menu-bar
# or directly:
python3 -m divoom_gui.gui_mainOn macOS, BLE access is gated by per-app permission (TCC). The first scan prompts for Bluetooth permission; grant it to the launching terminal/app. The GUI auto-spawns the daemon, which owns the device connection.
The product path is the daemon: divoom_client.DaemonDeviceProxy talks to a
running divoomd, which owns the Bluetooth connection.
from divoom_client.daemon_client import ensure_daemon, DaemonDeviceProxy
client = ensure_daemon() # spawn or find divoomd
device = DaemonDeviceProxy(client)
device.set_brightness(80)The old direct-to-device library (Divoom(mac=...), its own BLE/LAN/SPP
transports, every command group) is retired from the product and kept
runnable under examples/divoom_legacy/ with its scripts and its own test
suite — see examples/README.md. Nothing in the product imports it, and a
gate keeps it that way.
divoom_lib/ Shared protocol core (macOS + Linux)
framing.py SPP framing/escaping (native-accelerated + Python)
models/ command tables, capabilities, constants
transport.py transport interface + command routing map
divoom_auth.py cloud credentials (Keychain-backed)
fonts/ the device bitmap font blobs (divoomd include_bytes!)
cli.py the `divoom-control` CLI. `cli mcp-server` is the
documented MCP entry point and hands off to
`divoomd mcp` (the server is Rust; see
docs/MCP_SERVER.md). Daemon clients: need a running
divoomd, open no Bluetooth.
examples/ The retired direct-to-device library, standalone
divoom_legacy/ Divoom facade, BLE/LAN/SPP transports, display/ system/
scheduling/ media/ tools/, Python encoders (77 modules)
tests/ its own suite: python3 -m pytest examples/tests
*.py usage scripts (run from the repo root)
divoom_client/ Daemon CLIENT library (spawn/find/talk to divoomd)
daemon_client.py spawn_daemon()/ensure_daemon(), DaemonDeviceProxy
daemon_protocol.py NDJSON wire protocol + DaemonClient
macos_notifications.py notification_router.py notification plumbing (macOS)
divoomd/ The daemon (Rust): device ownership, command dispatch,
Unix/TCP server, macOS notification monitoring
divoom_gui/ Desktop Control Center (pywebview, macOS) — daemon client
gui_main.py launcher + Python↔JS bridge; spawns divoomd + divoom-menubar
daemon_bridge.py re-exports ensure_daemon()/DaemonDeviceProxy for the GUI
web_ui/ frontend (app.js, channels.js, widgets.js, …)
divoom-menubar/ the menu-bar/tray agent, Rust (winit + tray-icon)
build.sh / run.sh build the Rust binaries / run the GUI (+ daemon + menubar)
scripts/build_release.sh build the shippable Divoom.app + dmg (py2app)
docs/ ROADMAP, protocol refs, release docs
tests/ pytest suite
This repo is worked by multiple agents and sessions sharing one git tree. See
AGENTS.md for conventions, docs/ROADMAP.md for what is open,
CHANGELOG.md for what shipped, and ARCHITECTURE.md for the system map.
Keep tests green and update the roadmap and changelog each round.
