Drive a Mould King building-block RC toy — over a reverse-engineered BLE protocol, through one clean WebSocket API.
jrichter24.github.io/moldqueen — explore the project website
Free & open source. No ads, no affiliate links.
- Download — install the app
- The idea: API-first — thin transport, smart client
- Quickstart — Raspberry Pi · ESP32-S3 · Android · Docker
- What it does
- Connection wizard
- Architecture
- Roadmap
- Contributing
- Credit & attribution
- Credits, license & disclaimer
📲 Latest signed release — the standalone Android app, signed by the author.
- Download
moldqueen-v0.1.2.apkfrom the latest release. - On your phone, allow install from unknown sources for your browser or file manager (Android prompts the first time).
- Open the APK to install, then launch MoldQueen → Connect → Ready → drive.
It's one self-contained app — it owns the radio and serves the UI on-device, so no Pi or network is needed.
Prefer to build it yourself? cd android-core && ./gradlew installDebug (over USB).
Also available on F-Droid:
The Raspberry Pi path is in Quickstart below.
moldqueen is built around one documented WebSocket contract and an unusual split:
- The radio core is a thin transport. It takes a raw
set {slot, channel, value}, turns it into a Mould King BLE "telegram," crypts it, and broadcasts it. It knows nothing about functions, channel maps, inversion, caps, or your specific toy. - A single web client is the smart half. It resolves function → (slot, channel, value), owns the per-layout channel map, and runs the keepalive + STOP safety latch.
Because all the smarts live above the contract, the radio core is swappable: a Raspberry Pi (raw HCI/BlueZ), a standalone Android app (native BLE), and an ESP32-S3 (ESP-IDF + NimBLE, over WiFi) each expose the identical WebSocket API and serve the same client — so the UI is written once and the hardware is pluggable (swap the radio core, keep the client). (The hubs are driven by broadcasting crafted BLE adverts, not over GATT.) The Mould King 13112 excavator is the hardware-proven reference; the layout system + auto-assign let you drive any Mould King toy on these hubs.
Pi with a USB BLE dongle, Python 3.13, a solid 5 V/3 A PSU:
git clone https://github.com/jrichter24/moldqueen && cd moldqueen
scripts/start.sh # frees the adapter from bluetoothd, brings the dongle up by MAC, runs both processes
# → open http://<pi>:8080/ → Connect → button one hub to slot 1 → Ready → driveWith avahi-utils installed the Pi is discoverable by name as moldqueenrasp.local
(ws://moldqueenrasp.local:8765), mirroring the ESP32's moldqueenesp.local — additive, the IP
still works. Full prep (disable onboard BT, mask bluetoothd, caps), mDNS, and a dry-run mode:
dev-docs/QUICKSTART.md.
A tiny ESP-IDF + NimBLE board that drives real toys
over WiFi today, exposing the same WebSocket contract as the Pi and Android cores. It's a
usable standalone appliance: no credentials are baked in, so on first boot it opens a setup
WiFi (moldqueen-setup) for you to enter your network; after that it's discoverable as
moldqueenesp.local and carries a built-in management page at moldqueenesp.local:8080
(status, restart, switch-to-setup, change-network). Point the client at
ws://moldqueenesp.local:8765 and drive.
🔌 Download the firmware: grab moldqueen-esp32-<tag>.bin from the
latest release (current:
esp-v0.1.0) and flash the single image at offset 0x0:
esptool.py --chip esp32s3 write_flash 0x0 moldqueen-esp32-<tag>.binStep-by-step setup walkthrough: dev-docs/ESP32_SETUP.md.
Own native radio + bundled client in one APK:
cd android-core && ./gradlew installDebug # build + install to a connected device
# → open the MoldQueen app → Connect → Ready → driveBuild/device detail: dev-docs/ANDROID.md.
A published, public client-only image serves the web UI with one command, no Python, no
build. It hosts the client over http://localhost, so it can connect to a plain ws://
device on your LAN (same protocol, no mixed-content block). It's a real local-hosting
option for driving your own device, not a hosted demo:
docker run --rm -p 8080:8080 ghcr.io/jrichter24/moldqueen-client:latest
# → open http://localhost:8080/ → point the WS endpoint at your device
# (ws://moldqueenrasp.local:8765 / ws://moldqueenesp.local:8765 / ws://<ip>:8765)The host port is the left number, so remap freely (e.g. -p 9090:8080). Use
:latest for the newest build or pin :0.1.0 for the current version. Image on
the GitHub Packages page;
depth in dev-docs/REMOTE_CLIENT.md.
Just exploring? Run the client alone against a Pi —
dev-docs/DEV_CLIENT.md(dev server) ordev-docs/REMOTE_CLIENT.md(Docker).
- Layouts — pick one from the start-page chooser:
- Excavator (model-specific): landscape HMI dashboard, drag-joysticks + hold buttons.
- 12-axis and Brick / PS-like (model-agnostic): generic gamepads with 12 motors you map to any toy.
- RAW (debug): a protocol bench over the raw
set/stoppath (slot/channel/value, telegram + on-air bytes console).
- Chooser / start page — cards with a Generic / Model badge and MK4 / MK6 protocol badges (both MK4 and MK6 are live; MK6 ships on the Pi + web client), a jump-to-layout dropdown, and the RAW bench behind a debug icon.
- One shared chrome (MK4Chrome) — every layout gets the same menu, settings, connect wizard, status light, language picker, keyboard STOP, and gamepad path.
- Profile-driven auto-assign — map a generic controller's 12 motors to channels by toy profile (vehicle / car / custom) with an inline editor and a zero-box guide.
- Gamepad — pair a DualSense (or any) controller over Bluetooth and drive, on the
excavator and the generic layouts — in the browser or the Android app; touch always
works too. (detail:
dev-docs/GAMEPAD.md)
- 6 languages (EN/DE complete; ZH/KO/ES/FR seeded, EN fallback), editable per-layout title + colour.
- Safety — affirmative keepalive (the client re-affirms intent ~10/s; the server auto-neutralizes any un-refreshed channel) + STOP = kill-and-reconnect-at-neutral. More ↓ · 📸 Screenshots.
Cold-starting these hubs is fiddly, so the shared client chrome (MK4Chrome) has a guided connection wizard: it walks you from power on to Ready, and it shows the hub's real LED-flash patterns so you can confirm you're talking to the right hub and assigning the right slot (one long flash = powered on; fast flashing = connecting; button a hub to one/two/three fast flashes to put it on slot 0/1/2). It's a client feature, so you get it on every layout and against every radio core (Raspberry Pi or the standalone Android app), not something Pi- or Android-specific.
The wizard's real hub-LED flash patterns: one long flash = powered on, fast flashing = connecting.
Thin transport (server) + smart client (UI), with a swappable radio core behind one WebSocket contract:
client/ # the INDEPENDENT smart web client (chooser · layouts · MK4Chrome · channel maps)
│ ws://…:8765 (the contract: setup · set · stop · state · info)
├── linux-core/ # Pi radio core — raw HCI/BlueZ; serves the client (Python)
├── android-core/ # standalone Android radio core — native BLE; serves the client (Kotlin)
└── esp32-core/ # ESP32-S3 radio core — ESP-IDF + NimBLE over WiFi (C)
The client resolves function → channel and sends only low-level set; the core makes a
nibble, crypts it (MouldKingCrypt), and broadcasts the BLE telegram. One MK4 telegram
drives all hubs at once (12 nibbles = 3 slots × 4 channels). The Raspberry Pi + web
client also speak MK6 (a byte-per-channel, per-device-addressed telegram) and can
drive an MK4 box and an MK6 box at the same time, which the official Mould King app
can't do (how mixed mode works); the ESP32 and Android cores are
MK4-only for now. Deep dive: protocol, crypto, the dual-radio finding, the WS contract:
dev-docs/PROJECT.md (the source of truth) and the
machine-readable asyncapi.yaml.
| Run it… | How | Detail |
|---|---|---|
| On the Pi (served) | scripts/start.sh → http://<pi>:8080/ |
QUICKSTART |
| Android (standalone) | ./gradlew installDebug |
ANDROID |
| On an ESP32-S3 (over WiFi) | idf.py flash → join moldqueen-setup, enter WiFi → ws://moldqueenesp.local:8765 |
PORTING |
| Client on the desktop | client/serve.py → point at a Pi |
DEV_CLIENT |
| Client in Docker | docker run … ghcr.io/jrichter24/moldqueen-client:latest → point at a device |
REMOTE_CLIENT |
| On another board | port the thin-transport core (the cores are hardware-bound) | PORTING |
| Add your own toy/layout | a generic slot/channel layout, no core fork | ADDING_A_LAYOUT |
The ESP32-S3 radio core is now a working third sibling, a usable standalone appliance.
It drives real toys over WiFi today (clean-room C MouldKingCrypt port, NimBLE 0xFFF0
advertiser, 300 ms auto-neutral safety, WiFi WebSocket server mirroring the Pi's api.py),
plus WiFi provisioning (no creds baked in: a fallback moldqueen-setup AP + a branded
bilingual setup page), mDNS discovery as moldqueenesp.local, a management page
at moldqueenesp.local:8080 (status, restart, switch-to-setup, change-network), Pi mDNS
(moldqueenrasp.local for linux-core), and a binary/release pipeline (a downloadable .bin,
published per esp-v* tag). The ESP32 core is complete and stays a thin-transport radio
core that a hosted client drives; serving the client from the board's own flash was decided
against (the several-MB client vs limited flash, and the page-load asset burst coexisting with
BLE on the shared 2.4 GHz radio). What's still ahead:
- MK6 on the ESP32 & Android cores. MK6 (and simultaneous mixed MK4+MK6) already ships on the Pi + web client; the remaining work is the MK6 telegram path on the ESP32 and Android radios.
- Camera, ToF sensor — telemetry over/alongside the API.
- AI brain / console client — an agent driving the toy through the same WebSocket API.
Detail + status: dev-docs/ROADMAP.md.
Issues, PRs, and especially new toy layouts are welcome. See
CONTRIBUTING.md for how to contribute and the conventions to
respect (thin transport / smart client, one client / no forks, the safety model). It
also explains why this repo keeps its AI-assisted-workflow files (CLAUDE.md + the
.claude/agents/) in version control on purpose — for transparency about how the
project is built, and as a working example you can copy for your own setup.
Building on, forking, or reusing moldqueen? A credit back is genuinely appreciated — it's MIT-licensed, so this is a request, not a requirement. Drop this line in your README, About screen, or docs:
Built with [MoldQueen](https://github.com/jrichter24/moldqueen) — https://jrichter24.github.io/moldqueen/→ Built with MoldQueen — https://jrichter24.github.io/moldqueen/
- Author: Dr. Jens Richter — physics & electrical engineering; by day, tour optimization with genetic/AI algorithms at DNA Evolutions (LinkedIn · Website). Built for my son Jonas, who loves excavators. AI coding assistants helped with implementation. Architecture, product decisions, testing, and final code review remained under human control.
- Protocol groundwork:
J0EK3R/mkconnect-python— ourmouldking_crypt.pyis a port/derivative ofMouldKingCrypt, used under the MIT License (© 2024 J0EK3R), verified byte-exact against the MK+tech app; seeTHIRD-PARTY-NOTICES.md. Additional reference: BrickController2. - Independent & unofficial — not affiliated with, authorized by, or endorsed by Mould King / Shenzhen Yuxing; trademarks used descriptively. The BLE protocol was reverse-engineered for interoperability with hardware the author owns, for educational / personal use. Provided "as is", without warranty — you assume all risk.
License: MIT © 2026 Jens Richter. Bundled third-party code keeps its own
license — see THIRD-PARTY-NOTICES.md.







