API Reference
Channel Abstraction
All devices expose one or two independent channels. Each channel declares its own capabilities — consumer code never needs to check the device model.
YeelightDevice
├── main: LightChannel always present
└── background: LightChannel | null dual-zone devices onlyYeelightDevice
The main entry point. Handles discovery, connection, and exposes channels.
class YeelightDevice {
static discover(opts?: { timeout?: number }): Promise<YeelightDevice[]>
static scan(): Promise<YeelightDevice[]>
static connect(ip: string, port?: number, opts?: { discover?: boolean }): Promise<YeelightDevice>
readonly id: string
readonly ip: string
readonly model: string
readonly name: string
readonly support: string[]
readonly capabilities: Capabilities
readonly main: LightChannel
readonly background: LightChannel | null
connect(): Promise<void>
disconnect(): void
isConnected(): boolean
setScene(scene: SceneConfig): Promise<void> // delegates to main
setName(name: string): Promise<void>
devToggle(): Promise<void> // dual-zone devices only
cronAdd(minutes: number): Promise<void>
cronDel(): Promise<void>
cronGet(): Promise<CronTimer | null> // active timer or null
getRawProps(props: string[]): Promise<Record<string, string>>
on(event: 'props', listener: (props: Partial<ChannelState>) => void): this
on(event: 'disconnect', listener: () => void): this
off(event: string, listener: Function): this
}discover() uses SSDP multicast. scan() discovers via TCP port scan of the local /24 subnet — useful when SSDP multicast is blocked on the network. Both return devices that are not yet connected; call device.connect() before sending commands.
connect(ip) by default resolves device metadata (model, name, support list) via unicast SSDP; falls back to get_prop probe if SSDP times out. Pass { discover: false } to skip all discovery — pure TCP handshake, full capabilities assumed. Useful for single-shot CLI commands where the caller already knows what the device supports.
lamp15 extension — only present when capabilities.hasSegments:
setSegments(
left: [number, number, number],
right: [number, number, number]
): Promise<void>LightChannel
Primary unit of interaction. Wraps Transport with a command prefix ("" for main, "bg_" for background).
class LightChannel {
readonly type: 'main' | 'background'
readonly capabilities: ChannelCapabilities
setPower(on: boolean, opts?: PowerOptions): Promise<void>
toggle(): Promise<void>
setBrightness(value: number, opts?: TransitionOptions): Promise<void>
// Requires capabilities.hasColorTemp — throws UnsupportedError otherwise
setColorTemp(kelvin: number, opts?: TransitionOptions): Promise<void>
// Require capabilities.hasColor — throw UnsupportedError otherwise
setRGB(
r: number,
g: number,
b: number,
opts?: TransitionOptions
): Promise<void>
setHSV(
hue: number,
saturation: number,
opts?: TransitionOptions
): Promise<void>
// Requires capabilities.hasFlow — throws UnsupportedError otherwise
startFlow(flow: Flow): Promise<void>
stopFlow(): Promise<void>
// Turn on and apply state atomically (works on both main and background)
setScene(scene: SceneConfig): Promise<void>
setDefault(): Promise<void>
// Relative adjustments — no need to know the current value
setAdjust(
action: 'increase' | 'decrease' | 'circle',
prop: 'bright' | 'ct'
): Promise<void>
setAdjust(action: 'circle', prop: 'color'): Promise<void>
adjustBrightness(percentage: number, duration?: number): Promise<void>
adjustColorTemp(percentage: number, duration?: number): Promise<void>
adjustColor(duration?: number): Promise<void>
getState(): Promise<ChannelState>
}Calling setRGB() on a CT-only channel throws UnsupportedError at call time, not silently at runtime.
Flow Builder
class Flow {
static builder(): FlowBuilder
// Presets
static pulse(
r: number,
g: number,
b: number,
opts?: { count?: number; duration?: number }
): Flow
static strobe(
r: number,
g: number,
b: number,
opts?: { count?: number }
): Flow
static colorCycle(opts?: { duration?: number }): Flow
static candle(): Flow
static sunrise(durationMs: number): Flow
}
class FlowBuilder {
repeat(count: number): this
onEnd(action: 'recover' | 'stay' | 'off'): this
rgb(
r: number,
g: number,
b: number,
opts: { duration: number; brightness?: number }
): this
colorTemp(
kelvin: number,
opts: { duration: number; brightness?: number }
): this
sleep(ms: number): this
build(): Flow
}Errors
class UnsupportedError extends Error {} // method called on incapable channel
class ConnectionError extends Error {} // TCP connect/send failure
class DeviceError extends Error {
code: number // device responded with error object
}Shared Types
interface TransitionOptions {
effect?: 'smooth' | 'sudden' // default: 'smooth'
duration?: number // ms, default: 300
}
/** 0=normal, 1=CT, 2=RGB, 3=HSV, 4=color flow, 5=night (ceiling lights only) */
type PowerMode = 0 | 1 | 2 | 3 | 4 | 5
interface PowerOptions extends TransitionOptions {
mode?: PowerMode
}
interface ChannelState {
power: boolean
brightness: number // 1–100
colorTemp: number | null // Kelvin, null if channel has no CT
rgb: [number, number, number] | null // null if channel has no color
flowing: boolean
}
type SceneConfig =
| { type: 'color'; rgb: [number, number, number]; brightness: number }
| { type: 'hsv'; hue: number; saturation: number; brightness: number }
| { type: 'ct'; colorTemp: number; brightness: number }
| { type: 'cf'; flow: Flow }
| { type: 'auto_delay_off'; brightness: number; minutes: number }
interface Capabilities {
hasBackground: boolean
hasSegments: boolean
main: ChannelCapabilities
background: ChannelCapabilities | null
}
interface ChannelCapabilities {
hasColor: boolean
hasColorTemp: boolean
hasFlow: boolean
}
interface CronTimer {
delay: number // remaining minutes until power-off
}Exports
export { YeelightDevice } from 'yeelight-client'
export { Flow, FlowBuilder } from 'yeelight-client'
export { UnsupportedError, ConnectionError, DeviceError } from 'yeelight-client'
export type {
ChannelState,
TransitionOptions,
PowerMode,
PowerOptions,
SceneConfig,
ChannelCapabilities,
CronTimer
} from 'yeelight-client'
export type { Capabilities } from 'yeelight-client'LightChannel is not constructable directly — instances come from device.main / device.background only.