npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

yeelight-client

v1.2.0

Published

TypeScript library for controlling Yeelight smart lights over LAN

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
  • ScenessetScene() atomically turns on the device and sets its state in one command (works on main and background channels)
  • Relative adjustmentssetAdjust(), adjustBrightness(), adjustColorTemp(), adjustColor() without knowing the current value
  • Sleep timercronAdd(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-client
pnpm add yeelight-client
yarn add yeelight-client

Quick 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 1000ms

Sleep 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 timer

Device 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 command

Color 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-cli

Or 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 color

Development

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 server

Contributing

  1. Fork the repo
  2. Create your feature branch (git checkout -b feat/my-feature)
  3. Commit your changes (git commit -m 'feat: add something')
  4. Push to the branch (git push origin feat/my-feature)
  5. Open a Pull Request

License

MIT © Alex Strelets