Fully reverse-engineered BLE protocol and working ESPHome integration for MagicHome2 LED string lights — sold under brand names including SurpLife, YIQU, and others.
These are Zengge-platform BLE LED controllers that use the MagicHome2 app (com.zennge.magichome2), distinct from the original MagicHome/LEDnetWF app.
- YIQU/SurpLife BLE String Lights (Amazon B0FFSPTG67)
- Likely compatible with other devices using the MagicHome2 app and GATT service
0xFFFF
docs/
protocol_map.md # Full protocol specification
EFFECTS_REFERENCE.md # All 30+ named effects with color palettes
esphome/
decklights.yaml # Complete ESPHome config with effects, color, speed
decklights-minimal.yaml # Minimal config for quick testing
tools/
surplife_ble.py # Standalone Python BLE controller (bleak)
discover_gatt.py # GATT service discovery tool
parse_btsnoop.py # HCI snoop log parser for protocol analysis
- ESP32 board (tested on ESP32-C6-DevKitC-1-N8)
- ESPHome installed
- Home Assistant (optional, for full integration)
- Copy
esphome/decklights.yamlto your ESPHome config directory - Update the
mac_addressunderble_clientto match your device - Create a
secrets.yamlwith your WiFi credentials:
wifi_ssid: "your_ssid"
wifi_password: "your_password"
ap_password: "fallback_ap_password"
ota_password: "ota_password"- Flash:
esphome run decklights.yaml- Add to Home Assistant — the device will be auto-discovered via the ESPHome native API.
- Light entity — on/off, color picker, brightness
- Effect selector — 30+ named effects (holidays, atmospheres, animations)
- Speed slider — animation speed control (1-100)
- BLE connection status — binary sensor
Control the lights directly from any machine with Bluetooth, no ESP32 needed:
pip install bleak
python tools/surplife_ble.pyThe device uses GATT service 0xFFFF with two characteristics:
| Characteristic | UUID | Handle | Function |
|---|---|---|---|
| Write | 0xFF01 |
0x0017 |
Send commands |
| Notify | 0xFF02 |
0x0014 |
Receive responses |
Six command families, all sharing a common packet header:
| Command | Prefix | Function |
|---|---|---|
| Scene/Effect | 0a e1 21 |
Animated effects with colors, speed, brightness |
| Music Mode | 0a ec 03 |
Music-reactive lighting (6 modes) |
| Music Enable | 0a ec 04 |
Activate music mode |
| Color Set | 0a ec 07 |
Zone-based color assignment |
| Solid Color | e0 01 00 c1 |
Direct HSB color |
| Power Toggle | e0 01 00 24 |
Toggle on/off |
The transport layer is compatible with the Zengge LEDnetWF protocol — same 8-byte header with cmd_family=0x0a.
Full protocol details: docs/protocol_map.md
Use the GATT discovery tool to find and verify your device:
pip install bleak
python tools/discover_gatt.pyLook for a device advertising GATT service 0xFFFF with characteristics 0xFF01 and 0xFF02.
- ESP32-C6 (single-core): Use passive BLE scanning with reduced intervals to avoid overloading. See the config for tuned parameters.
- ESP-IDF 5.3.2 recommended for C6. Version 5.5.2 has an efuse duplicate target bug.
- USB CDC logging: Required for serial output on boards with CP2102N USB bridge.
- BLE + WiFi coexistence: Works reliably with the scan parameters in the provided config.
Protocol was decoded from Android HCI snoop logs captured while exercising every feature of the SurpLife app:
- Enable HCI snoop logging (Developer Options)
- Systematically exercise all app features with timed gaps
- Extract via
adb bugreport - Parse with
tools/parse_btsnoop.py
- 8none1/lednetwf_ble — Home Assistant integration for the original MagicHome/LEDnetWF BLE devices (different app, compatible transport layer)
- 8none1/zengge_lednetwf — Protocol docs for the original Zengge LEDnetWF platform (retired, see above)
MIT