https://github.com/numberonebot/yeelight-client
TypeScript library + CLI for controlling 💡 Yeelight smart lights over LAN
https://github.com/numberonebot/yeelight-client
bun cli home-automation iot lan library node npm-package smart-home smart-lights typescript yeelight yeelight-api yeelight-devices yeelight-lamp
Last synced: about 2 months ago
JSON representation
TypeScript library + CLI for controlling 💡 Yeelight smart lights over LAN
- Host: GitHub
- URL: https://github.com/numberonebot/yeelight-client
- Owner: NumberOneBot
- License: mit
- Created: 2026-03-21T17:51:03.000Z (3 months ago)
- Default Branch: main
- Last Pushed: 2026-03-30T14:44:45.000Z (3 months ago)
- Last Synced: 2026-04-03T00:39:02.713Z (2 months ago)
- Topics: bun, cli, home-automation, iot, lan, library, node, npm-package, smart-home, smart-lights, typescript, yeelight, yeelight-api, yeelight-devices, yeelight-lamp
- Language: TypeScript
- Homepage: https://numberonebot.github.io/yeelight-client/
- Size: 666 KB
- Stars: 2
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Funding: .github/FUNDING.yml
- License: LICENSE
Awesome Lists containing this project
README
yeelight-client
TypeScript library for controlling Yeelight smart lights over LAN
---
> **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
```bash
npm install yeelight-client
```
```bash
pnpm add yeelight-client
```
```bash
yarn add yeelight-client
```
## Quick Start
```ts
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
```ts
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:
```ts
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:
```ts
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:
```ts
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:
```ts
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:
```ts
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
```ts
await device.setName('Desk Light')
```
### Dual-Zone Toggle
Devices with a background channel (Bedside Lamp 2, ceiling lights) can toggle both channels simultaneously:
```ts
await device.devToggle() // toggles main + background in one command
```
### Color Flows
Built-in presets for common animations:
```ts
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:
```ts
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:
```ts
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`:
```ts
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
```ts
device.on('props', (props) => {
console.log('State changed:', props)
})
device.on('disconnect', () => {
console.log('Device disconnected')
})
```
| Event | Payload | Description |
| ------------ | ---------------------------------------------------------------- | ------------------------------- |
| `props` | `main: Partial, bg: Partial \| null` | 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
```ts
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:
```ts
const raw = await device.getRawProps([
'power',
'bright',
'ct',
'rgb',
'color_mode'
])
// { power: 'on', bright: '80', ct: '4000', rgb: '16737280', color_mode: '2' }
```
### Capabilities
```ts
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` | Find devices via SSDP (default timeout: 3000ms) |
| **Static** | `connect(ip: string, port?: number): Promise` | Connect directly (default port: 55443) |
| | `connect(): Promise` | Reconnect a disconnected device |
| | `disconnect(): void` | Close the connection |
| | `isConnected(): boolean` | Connection status |
| | `setSegments(left, right): Promise` | Set left/right segment colors (lamp15) |
| | `setScene(scene: SceneConfig): Promise` | Turn on and apply state atomically (delegates to `main`) |
| | `setName(name: string): Promise` | Persist device name to device memory |
| | `devToggle(): Promise` | Toggle main + background simultaneously |
| | `cronAdd(minutes: number): Promise` | Set sleep timer (auto power-off) |
| | `cronDel(): Promise` | Cancel sleep timer |
| | `cronGet(): Promise` | Read active timer (remaining minutes), or `null` |
| | `getRawProps(props: string[]): Promise>` | 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
```ts
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`](https://www.npmjs.com/package/yeelight-client) | Core library — this package |
| [`yeelight-cli`](https://www.npmjs.com/package/yeelight-cli) | Terminal tool (`ylc`) — interactive TUI + one-shot commands |
## CLI
The companion [`yeelight-cli`](https://www.npmjs.com/package/yeelight-cli) package provides a terminal tool:
```bash
npm install -g yeelight-cli
```
Or download a precompiled binary from [Releases](https://github.com/NumberOneBot/yeelight-client/releases).
```bash
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
```bash
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](LICENSE) © Alex Strelets