yeelight-client
v1.2.0
Published
TypeScript library for controlling Yeelight smart lights over LAN
Maintainers
Readme
Zero-dependency TypeScript library for Yeelight devices. SSDP discovery, dual-channel control, color flows, segment lighting — all over your local network.
Features
- Auto-discovery — find devices on your LAN via SSDP multicast
- Direct connection — connect by IP when you know the address
- Dual-channel — independent control of main and background lights (
devToggle()switches both at once) - Segment control — left/right colors on lamp15 (YLTD003)
- Color flows — built-in presets (pulse, strobe, candle, sunrise, color cycle) and a chainable FlowBuilder
- Scenes —
setScene()atomically turns on the device and sets its state in one command (works on main and background channels) - Relative adjustments —
setAdjust(),adjustBrightness(),adjustColorTemp(),adjustColor()without knowing the current value - Sleep timer —
cronAdd(minutes)/cronGet()/cronDel()— built-in device timer - Full state — read power, brightness, color temp, RGB, flow status
- Real-time events — property change notifications pushed from the device
- ESM + CJS — works everywhere, ships with TypeScript declarations
- Zero dependencies — only Node.js built-ins (
net,dgram,events,os)
Requirements
- Node.js 18+
- LAN Control enabled on your Yeelight device (Yeelight app → device settings → LAN Control)
Install
npm install yeelight-clientpnpm add yeelight-clientyarn add yeelight-clientQuick Start
import { YeelightDevice } from 'yeelight-client'
// Discover devices on the network
const devices = await YeelightDevice.discover({ timeout: 3000 })
const device = devices[0]
await device.connect()
// Control the main light
await device.main.setPower(true)
await device.main.setBrightness(80)
await device.main.setColorTemp(4000)
await device.main.setRGB(255, 100, 0)
device.disconnect()Usage
Connect by IP
const device = await YeelightDevice.connect('192.168.1.42')When connecting by IP, capabilities are auto-detected via a property probe.
Dual-Channel Devices
Some Yeelight devices (ceiling lights, desk lamps) have a background channel:
if (device.background) {
await device.background.setRGB(0, 100, 255)
await device.background.setBrightness(50)
}Segment Control
The lamp15 (YLTD003) supports independent left/right segment colors:
if (device.capabilities.hasSegments) {
await device.setSegments([255, 0, 0], [0, 0, 255])
}Scenes
setScene() turns the device on and applies the target state atomically. Useful when the device may be off.
Works on both main and background channels:
import type { SceneConfig } from 'yeelight-client'
await device.setScene({ type: 'color', rgb: [255, 100, 0], brightness: 80 })
await device.setScene({ type: 'ct', colorTemp: 4000, brightness: 60 })
await device.setScene({ type: 'hsv', hue: 200, saturation: 80, brightness: 70 })
await device.setScene({ type: 'cf', flow: Flow.colorCycle() })
await device.setScene({ type: 'auto_delay_off', brightness: 50, minutes: 30 })
// background channel too
if (device.background) {
await device.background.setScene({
type: 'color',
rgb: [0, 0, 255],
brightness: 50
})
}Relative Adjustments
Change brightness or color temperature relative to the current value — no need to know the current state:
await device.main.setAdjust('increase', 'bright') // step up brightness
await device.main.setAdjust('decrease', 'ct') // step down color temp
await device.main.setAdjust('circle', 'color') // cycle through hues
await device.main.adjustBrightness(+20) // +20% brightness
await device.main.adjustBrightness(-10, 500) // -10% over 500ms
await device.main.adjustColorTemp(-30) // -30% color temp
await device.main.adjustColor() // cycle through basic colors
await device.main.adjustColor(1000) // cycle over 1000msSleep Timer
Turn off the device automatically after a number of minutes:
await device.cronAdd(30) // turn off in 30 minutes
const timer = await device.cronGet() // { delay: 28 } or null
await device.cronDel() // cancel the timerDevice Name
await device.setName('Desk Light')Dual-Zone Toggle
Devices with a background channel (Bedside Lamp 2, ceiling lights) can toggle both channels simultaneously:
await device.devToggle() // toggles main + background in one commandColor Flows
Built-in presets for common animations:
import { Flow } from 'yeelight-client'
await device.main.startFlow(Flow.pulse(255, 0, 0, { count: 3, duration: 400 }))
await device.main.startFlow(Flow.strobe(0, 255, 0, { count: 10 }))
await device.main.startFlow(Flow.colorCycle({ duration: 1000 }))
await device.main.startFlow(Flow.candle())
await device.main.startFlow(Flow.sunrise(5000))Build custom flows with the chainable API:
const flow = Flow.builder()
.rgb(255, 0, 0, { duration: 500, brightness: 100 })
.colorTemp(4000, { duration: 500, brightness: 80 })
.sleep(200)
.repeat(0) // loop forever
.onEnd('recover') // restore previous state on stop
.build()
await device.main.startFlow(flow)
await device.main.stopFlow()Transition Options
All setter methods accept an optional TransitionOptions argument:
await device.main.setBrightness(50, { effect: 'smooth', duration: 1000 })
await device.main.setRGB(255, 0, 0, { effect: 'sudden' })Default: { effect: 'smooth', duration: 300 }.
setPower() accepts PowerOptions which extends TransitionOptions with an optional mode:
import type { PowerOptions } from 'yeelight-client'
await device.main.setPower(true, { mode: 5 }) // night mode (ceiling lights)
await device.main.setPower(true, { mode: 1, duration: 500 }) // turn on in CT mode| Mode | Constant | Description |
| ---- | -------- | --------------------------------- |
| 0 | normal | Default mode |
| 1 | CT | Color temperature mode |
| 2 | RGB | RGB color mode |
| 3 | HSV | HSV color mode |
| 4 | CF | Color flow mode |
| 5 | Night | Night light (ceiling lights only) |
Events
device.on('props', (props) => {
console.log('State changed:', props)
})
device.on('disconnect', () => {
console.log('Device disconnected')
})| Event | Payload | Description |
| ------------ | ----------------------- | ------------------------------- |
| props | Partial<ChannelState> | Device pushed a property change |
| disconnect | — | Connection lost or closed |
| tx | string | Outgoing JSON-RPC frame (debug) |
| rx | string | Incoming JSON-RPC frame (debug) |
Reading State
const state = await device.main.getState()
// { power: true, brightness: 80, colorTemp: 4000, rgb: null, flowing: false }Raw Properties
Query any Yeelight property by its protocol name:
const raw = await device.getRawProps([
'power',
'bright',
'ct',
'rgb',
'color_mode'
])
// { power: 'on', bright: '80', ct: '4000', rgb: '16737280', color_mode: '2' }Capabilities
device.capabilities
// {
// hasBackground: true,
// hasSegments: false,
// main: { hasColor: true, hasColorTemp: true, hasFlow: true },
// background: { hasColor: true, hasColorTemp: true, hasFlow: true }
// }API
YeelightDevice
| | Signature | Description |
| ---------- | ------------------------------------------------------------------ | -------------------------------------------------------- |
| Static | discover(opts?: { timeout?: number }): Promise<YeelightDevice[]> | Find devices via SSDP (default timeout: 3000ms) |
| Static | connect(ip: string, port?: number): Promise<YeelightDevice> | Connect directly (default port: 55443) |
| | connect(): Promise<void> | Reconnect a disconnected device |
| | disconnect(): void | Close the connection |
| | isConnected(): boolean | Connection status |
| | setSegments(left, right): Promise<void> | Set left/right segment colors (lamp15) |
| | setScene(scene: SceneConfig): Promise<void> | Turn on and apply state atomically (delegates to main) |
| | setName(name: string): Promise<void> | Persist device name to device memory |
| | devToggle(): Promise<void> | Toggle main + background simultaneously |
| | cronAdd(minutes: number): Promise<void> | Set sleep timer (auto power-off) |
| | cronDel(): Promise<void> | Cancel sleep timer |
| | cronGet(): Promise<CronTimer \| null> | Read active timer (remaining minutes), or null |
| | getRawProps(props: string[]): Promise<Record<string, string>> | Query raw Yeelight properties |
Properties: id, ip, model, name, support, capabilities, main, background
LightChannel
| Method | Description |
| ----------------------------------------- | ------------------------------------------------------- |
| setPower(on, opts?) | Turn on/off; opts is PowerOptions (supports mode) |
| toggle() | Toggle power |
| setBrightness(1–100, opts?) | Set brightness |
| setColorTemp(kelvin, opts?) | Color temperature (1700–6500 K) |
| setRGB(r, g, b, opts?) | RGB color (0–255 each) |
| setHSV(hue, sat, opts?) | HSV color (hue 0–359, sat 0–100) |
| startFlow(flow) | Start a color flow animation |
| stopFlow() | Stop the current flow |
| setDefault() | Save current state as power-on default |
| setScene(scene) | Turn on and apply state atomically |
| setAdjust(action, prop) | Relative adjustment (no current value needed) |
| adjustBrightness(percentage, duration?) | Change brightness by ±% (−100…+100) |
| adjustColorTemp(percentage, duration?) | Change color temp by ±% (−100…+100) |
| adjustColor(duration?) | Cycle through basic colors |
| getState() | Read ChannelState |
Methods that require specific hardware throw UnsupportedError if the capability is missing.
Flow
| Factory | Description |
| ----------------------------- | ---------------------------------------- |
| Flow.pulse(r, g, b, opts?) | Pulsing RGB (default: 3×, 500ms) |
| Flow.strobe(r, g, b, opts?) | Fast strobe (default: 10×, 50ms) |
| Flow.colorCycle(opts?) | Rainbow loop (default: 1000ms per step) |
| Flow.candle() | Warm flicker (1700–1900 K) |
| Flow.sunrise(durationMs) | Gradual warm-up to daylight |
| Flow.builder() | Returns a FlowBuilder for custom flows |
FlowBuilder
Chainable: .rgb() → .colorTemp() → .sleep() → .repeat() → .onEnd() → .build()
Error Classes
| Class | When |
| ------------------ | -------------------------------------------- |
| UnsupportedError | Device/channel doesn't support the operation |
| ConnectionError | Network failure, timeout, or disconnection |
| DeviceError | Device rejected the RPC call (has .code) |
Types
interface ChannelState {
power: boolean
brightness: number // 1–100
colorTemp: number | null // Kelvin
rgb: [number, number, number] | null // [R, G, B]
flowing: boolean
}
interface TransitionOptions {
effect?: 'smooth' | 'sudden'
duration?: number // ms
}
type PowerMode = 0 | 1 | 2 | 3 | 4 | 5
// 0 = normal, 1 = CT, 2 = RGB, 3 = HSV, 4 = CF, 5 = night
interface PowerOptions extends TransitionOptions {
mode?: PowerMode
}
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
}Packages
| Package | Description |
| ------------------------------------------------------------------ | ----------------------------------------------------------- |
| yeelight-client | Core library — this package |
| yeelight-cli | Terminal tool (ylc) — interactive TUI + one-shot commands |
CLI
The companion yeelight-cli package provides a terminal tool:
npm install -g yeelight-cliOr download a precompiled binary from Releases.
ylc discover # find devices on the network
ylc interactive # TUI with device picker + controls
ylc status --ip 192.168.1.42 # show device state
ylc power on # turn on
ylc brightness 50 --duration 1000 # set brightness with transition
ylc ct 3000 # color temperature
ylc color "#ff6400" # hex color
ylc color "#ff640080" # hex with alpha → brightness
ylc segment "#ff0000" "#0000ff" # lamp15 left/right
ylc power on --bg # background channel
ylc toggle # toggle main + background at once
ylc name "Desk Light" # set device name
ylc timer set 30 # sleep timer (auto power-off)
ylc timer status # check remaining time
ylc timer cancel # cancel timer
ylc adjust brightness 20 # relative adjust (+/- 1..100)
ylc adjust ct -10
ylc adjust colorDevelopment
pnpm install
pnpm dev # library watch mode
pnpm build # build library (ESM + CJS + DTS)
pnpm --filter yeelight-cli dev # CLI dev
pnpm --filter yeelight-client-docs dev # docs dev serverContributing
- Fork the repo
- Create your feature branch (
git checkout -b feat/my-feature) - Commit your changes (
git commit -m 'feat: add something') - Push to the branch (
git push origin feat/my-feature) - Open a Pull Request
License
MIT © Alex Strelets
