lotuslantern

package module
v0.0.0-...-f11a621 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 7, 2026 License: MIT Imports: 6 Imported by: 0

README

lotuslantern-go

Go client for Lotus Lantern / BLEDOM / ELK-BLEDOM / LED LIGHT STRIP / XSL- family of cheap BLE LED-strip controllers, sold under hundreds of brand names. Reverse-engineered from the stock Android app (wl.smartled, "宝莲灯") — see docs/PROTOCOL.md for the wire format.

No phone, no app, no cloud. Just BLE GATT writes from your machine.

addr, name, _ := lotuslantern.Discover(15 * time.Second)
lamp, _ := lotuslantern.Connect(addr, name)
defer lamp.Close()

lamp.LightOn(true)
lamp.ChangeColorRGB(255, 0, 128)
lamp.ChangeBrightness(180, 0)
lamp.ChangeMode(5)

Install

go get github.com/Rxflex/LotusLantern

Single dependency: tinygo.org/x/bluetooth. Works on Linux, macOS, Windows.

Compatibility

Device prefix Status Notes
ELK-BLEDOM* Tested Most common clone
ELK-* (encrypted) Supported XOR cipher applied for cmd ∈ {1, 3, 4}
ELK~* (wavy) Supported Untested, same protocol
LED LIGHT STRIP* Supported Untested
XSL-* Supported Untested

Examples

# List nearby lamps
go run ./examples/scan

# Color cycle on the first one found
go run ./examples/demo

API

Discovery & connection
  • Discover(timeout) — scan for first matching lamp.
  • Connect(addr, name) — connect to a known lamp.
  • (*Lamp).Close() — disconnect.
  • (*Lamp).SendBatch(frames, delay) — send raw 9-byte frames in sequence.
Power & color
  • LightOn(bool) — power.
  • ChangeColorRGB(r, g, b) / ChangeColor(0xRRGGBB) — static color.
  • ChangeColorTemperature(warm, cold) — white balance.
  • ChangeSingleColor(idx) — preset palette by index.
  • ChangeBrightness(level, lightMode) — 0..255.
  • ChangePinSequence(seq) — RGB pin remap (default 0x010203).
Effects
  • ChangeMode(mode) — built-in dynamic effect (0..N, device-specific).
  • ChangeModeSpeed(speed) — effect speed.
  • MusicAmplitude(color, brightness) — used by music-react mode.
Microphone (mic-equipped models)
  • ChangeExternalMicOnOff(bool)
  • ChangeExternalMicSensitive(level)
  • ChangeExternalMicEqMode(mode)
Laser (laser-projector models)
  • ChangeLaser(on)
  • ChangeLaserMode(mode)
  • ChangeLaserSpeed(speed)
Timing
  • SendSystemTime(hourMinute, weeks)
  • SendTimingStatus(hourMinute, timingMode, weeks)
  • ChangeCountDown(hourMinute, weeks, timingMode)
RGBW / channel control
  • ChangeRGBWStatus(rgbwOn, lightMode)

Notes for Windows users

BLEDOM clones interact poorly with the Windows BLE GATT stack (bthleenum.sys). Connect works around this by:

  1. Scanning briefly first so WinRT's advertisement cache is fresh.
  2. Retrying DiscoverServices up to 25 times.
  3. Reconnecting automatically when a write fails (BLEDOM commonly drops the link after 3–10 writes).

If you still get Unreachable errors:

  • Move closer to the lamp (RSSI > -75 helps).
  • Ensure no other host (phone, tablet) is connected — BLEDOM accepts only one BLE master.
  • Update the Intel/Realtek BT driver.
  • As last resort, plug in a USB BLE dongle (CSR8510 et al.) — it bypasses the buggy Intel BT stack.

Protocol summary

Service 0xFFF0, write characteristic 0xFFF3. Each command is 9 bytes:

0x7E  LEN  CMD  P1  P2  P3  P4  P5  0xEF

See docs/PROTOCOL.md for the full table — every change* method in the Android app maps to one row.

Status

Hobby project, reverse-engineered, no warranty. PRs welcome. Tested against ELK-BLEDOM hardware on Windows 11 with Intel Wireless Bluetooth.

Credits

Wire format extracted from com.easylink.colorful.service.BluetoothLEService in wl.smartled.apk v6-5-03. Original APK © its respective owners and not redistributed in this repo.

License

MIT — see LICENSE.

Documentation

Overview

Package lotuslantern is a Go client for "Lotus Lantern" / BLEDOM-clone LED strip controllers. The protocol is reverse-engineered from the official Android app (wl.smartled). See docs/PROTOCOL.md.

Index

Constants

View Source
const (
	NameFilter        = "ELK-"
	NameWavyFilter    = "ELK~"
	NameLEDLightStrip = "LED LIGHT STRIP"
	NameNewStrength   = "XSL-"
	EncryptionMarker  = "ELK-*" // BluetoothLEService.isEncryptedDevice
)

Supported device-name prefixes (Global.java).

Variables

This section is empty.

Functions

func Discover

func Discover(timeout time.Duration) (addr, name string, err error)

Discover scans for the first lamp matching one of the supported name prefixes within timeout.

Types

type Lamp

type Lamp struct {
	// contains filtered or unexported fields
}

Lamp is an active connection to a single LED controller.

func Connect

func Connect(addr, name string) (*Lamp, error)

Connect scans briefly to refresh Windows' BLE cache, then connects to the given lamp. BLEDOM clones drop GATT after a few writes; sendCommand will auto-reconnect on failure.

func (*Lamp) ChangeBrightness

func (l *Lamp) ChangeBrightness(brightness, lightMode int) error

ChangeBrightness sets brightness 0..255 with optional lightMode (0 default).

func (*Lamp) ChangeColor

func (l *Lamp) ChangeColor(rgb int) error

ChangeColor takes a packed 0xRRGGBB int.

func (*Lamp) ChangeColorRGB

func (l *Lamp) ChangeColorRGB(r, g, b int) error

ChangeColorRGB sets a static RGB color.

func (*Lamp) ChangeColorTemperature

func (l *Lamp) ChangeColorTemperature(warm, cold int) error

ChangeColorTemperature sets warm/cold balance for color-temperature mode.

func (*Lamp) ChangeCountDown

func (l *Lamp) ChangeCountDown(hourMinute, weeks, timingMode int) error

func (*Lamp) ChangeExternalMicEqMode

func (l *Lamp) ChangeExternalMicEqMode(mode int) error

func (*Lamp) ChangeExternalMicOnOff

func (l *Lamp) ChangeExternalMicOnOff(on bool) error

func (*Lamp) ChangeExternalMicSensitive

func (l *Lamp) ChangeExternalMicSensitive(level int) error

func (*Lamp) ChangeLaser

func (l *Lamp) ChangeLaser(laser int) error

func (*Lamp) ChangeLaserMode

func (l *Lamp) ChangeLaserMode(mode int) error

func (*Lamp) ChangeLaserSpeed

func (l *Lamp) ChangeLaserSpeed(speed int) error

func (*Lamp) ChangeMode

func (l *Lamp) ChangeMode(mode int) error

ChangeMode picks one of the built-in dynamic modes (the device adds 0x80).

func (*Lamp) ChangeModeSpeed

func (l *Lamp) ChangeModeSpeed(speed int) error

ChangeModeSpeed sets dynamic mode speed (0..255).

func (*Lamp) ChangePinSequence

func (l *Lamp) ChangePinSequence(seq int) error

ChangePinSequence reorders the RGB output pins. Default = 0x010203.

func (*Lamp) ChangeRGBWStatus

func (l *Lamp) ChangeRGBWStatus(rgbwOn, lightMode int) error

ChangeRGBWStatus toggles individual RGBW channels — port of Android logic.

func (*Lamp) ChangeSingleColor

func (l *Lamp) ChangeSingleColor(color int) error

ChangeSingleColor sets a single-color preset by index byte.

func (*Lamp) Close

func (l *Lamp) Close() error

Close disconnects from the lamp.

func (*Lamp) LightOn

func (l *Lamp) LightOn(on bool) error

LightOn turns the strip on or off.

func (*Lamp) MusicAmplitude

func (l *Lamp) MusicAmplitude(color, brightness int) error

MusicAmplitude is used by the app's music-react mode.

func (*Lamp) SendBatch

func (l *Lamp) SendBatch(frames [][]byte, interDelay time.Duration) error

SendBatch sends a sequence of frames, sleeping interDelay between each.

func (*Lamp) SendSystemTime

func (l *Lamp) SendSystemTime(hourMinute, weeks int) error

func (*Lamp) SendTimingStatus

func (l *Lamp) SendTimingStatus(hourMinute, timingMode, weeks int) error

Directories

Path Synopsis
examples
demo command
Demo: discover the first nearby lamp, connect, run a color cycle.
Demo: discover the first nearby lamp, connect, run a color cycle.
scan command
Scan: print every lamp matching a known prefix.
Scan: print every lamp matching a known prefix.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL