A two-device hardware and software system for passively capturing and replaying raw Bluetooth Low Energy (BLE) manufacturer payloads that trigger lighting effects on interactive smart wristbands and reactive BLE devices.
DISCLAIMER: This project is provided for educational, research, and hobbyist purposes only. It is not affiliated with, endorsed by, authorized by, or connected to any theme park, entertainment company, or manufacturer. All trademarks and registered trademarks are the property of their respective owners. Users are solely responsible for ensuring their use of this software complies with all applicable local laws, radio frequency regulations, and venue policies.
| Device | Hardware | Purpose |
|---|---|---|
| Broadcaster | Any ESP32-WROOM-32 | Connects to WiFi/Home Assistant, serves a Web UI, and acts as a base station to broadcast customizable BLE hexadecimal payloads natively to smart wristbands at home |
| Scanner | LilyGo LoRa32 T3 v1.6.1 | Portable standalone scanner to passively capture and log relevant BLE payload hex signatures to an SD card |
Certain smart wristbands and reactive entertainment devices respond to specific BLE (Bluetooth Low Energy) advertisement packets. When the device detects a manufacturer payload it recognizes, it reacts natively (lighting up in different colors, pulsing, vibrating, or animating). The device does all of this passively; it just listens for the right signal.
MagicMaker captures and replicates that signal.
The ESP32 connects to your WiFi and Home Assistant via MQTT, then operates an automated broadcasting engine that emits whatever raw hexadecimal payload you configure.
Web UI / Home Assistant
│
│ JSON payload with HEX data & TX power
▼
ESP32 (MagicMaker)
│
│ BLE Hexadecimal advertisement (0.5s burst or infinite loop)
▼
Smart Wristband ✨
- Web UI Dashboard — Web dashboard hosted on the ESP32 for broadcast control, live real-time logs, and settings.
- Massive Favorites Library — Save up to 100 manual hexadecimal payloads directly to the ESP32's non-volatile storage (NVS) for instant one-click playback without needing an active internet connection.
- Infinite Interval Looping — Automatically repeat a 500ms broadcast burst every 20 seconds (configurable) to keep wristbands illuminated continuously.
- Home Assistant Auto-Discovery — The device and all controls appear in HA automatically over MQTT, no manual YAML required.
- Captive Portal Setup — On first boot, the ESP32 creates a WiFi AP to collect your network and MQTT credentials.
- Real-Time Logs — Live WebSocket log stream in the browser with level filtering.
- Python 3.8+ — required by PlatformIO
- A running Home Assistant instance with an MQTT broker (optional but recommended)
Clone the repo and run the flash tool from the project root:
git clone https://github.com/Coral-coder/MagicMaker.git
cd MagicMaker
.\flash.ps1Select [4] Full flash (firmware + web UI) on first flash. On subsequent firmware-only updates use [2].
On first boot the ESP32 creates a WiFi access point:
Network: MagicMaker-Setup
Password: (none — open network)
Connect with your phone or laptop — a captive portal opens automatically (or navigate to 192.168.4.1). Fill in your WiFi settings and MQTT parameters. Save and the device reboots, connects to your network, and starts listening.
Navigate to http://<device-ip>/ in any browser on the same network to access the interface.
- Scanner/Dashboard: Submit manual payloads, adjust TX broadcast power, and start loop repeats.
- Favorites: Manage your saved 100-slot library using the dropdown menu.
- Logs: View real-time WebSocket logs.
- Settings: Adjust MQTT parameters and set the global Repeat Interval time.
No configuration is needed for Home Assistant — MagicMaker publishes its own MQTT discovery payloads on connect. Within a few seconds of booting, a MagicMaker device will appear under Settings → Devices & Services → MQTT.
| Topic | Direction | Description |
|---|---|---|
magicmaker/beacon/set |
HA → Device | Start broadcasting — JSON payload (see below) |
magicmaker/beacon/stop |
HA → Device | Stop broadcasting immediately |
magicmaker/status |
Device → HA | Heartbeat + current state (retained, every 30 s) |
magicmaker/config/reset |
HA → Device | Wipe config and reboot into setup AP |
{
"hex": "8301XXXXXXXXXXXXXX...",
"tx_power": -59,
"loop": true
}
tx_poweris the measured signal strength at 1 metre in dBm.-59is the standard default. Lower values mean the wristband must be physically closer to the transmitter to trigger.
Hold the BOOT button (GPIO0) for 3 seconds while the device is running. All WiFi and MQTT credentials are wiped and the device reboots into setup AP mode.
The scanner is a standalone pocket device used to passively listen to Bluetooth advertisements in the real world and log relevant BLE manufacturer payloads to an SD card. Bring the card home, type the captured Hex codes into your broadaster's Favorites tab, and your wristbands will light up exactly as they did in the field.
- Insert a FAT32-formatted MicroSD card into the LilyGo's slot.
- Power on — the OLED displays the startup splash, then switches to the STATUS screen.
- Scanning starts automatically — the LED blinks on each new unique BLE signature captured.
- Short press the boot button to cycle through display screens (Status, Statistics, Last Beacon, SD Card info).
Each power cycle creates a new session file: scan_001.csv, scan_002.csv, etc.
timestamp_ms,hex_payload,rssi
45231,83010E010B0000000000,-67
45812,8301E1010A0000000000,-71The system automatically deduplicates codes. The same payload is only logged again if it hasn't been heard for 30 seconds or if the RSSI shifts significantly (5 dBm+), minimizing SD card wear and spam.
- NimBLE-Arduino - Efficient BLE advertising and scanning
- PubSubClient - MQTT client communications
- ArduinoJson - JSON serialization
- WiFiManager - WiFi management and captive portal
- ESP Async WebServer - Web UI delivery and WebSocket handling
All libraries are downloaded and installed automatically by PlatformIO.