Yeelight LAN control bridge — REST API compatible with matter_webcontrol federation.
Project description
Yeelight Web Controller
A Python REST bridge that exposes Yeelight LAN-control bulbs through the same wire contract as a matter_webcontrol v0.25 logical bridge. A Matter server can register this service and federate Yeelight bulbs alongside its native Matter devices — no embedded scripts, no exec().
- REST — control bulbs by IP-derived ID, get / set Matter-style level (0-254) and mireds (153-500)
- Federation-ready —
/api/devicesand/api/metadata(api_version"2") matchLogicalBridgeClient - Discovery resilient — TCP probe fallback when SSDP multicast is blocked or bulbs stop broadcasting
Quick start
pip install yeelight-web-controller # or: pip install -e .
# Generate an API key (used by all clients via X-API-Key header)
export YEELIGHT_SRV_KEY=$(openssl rand -hex 32)
# Start the server (auto-probe LAN /24 if SSDP returns nothing)
yeelight-srv --host 0.0.0.0 --port 9800 --auto-probe
# In another terminal — talk to it
curl -H "X-API-Key: $YEELIGHT_SRV_KEY" http://127.0.0.1:9800/api/devices
Requires Python 3.12+. Bulbs must have LAN Control enabled in the Yeelight Classic app.
How it works
┌─────────────────────┐ ┌──────────────────────┐
│ matter-srv │ │ REST clients │
│ (federation peer) │ │ curl / app │
└──────────┬──────────┘ └──────────┬───────────┘
│ X-API-Key │ X-API-Key
▼ ▼
┌────────────────────────────────────────────────┐
│ yeelight-srv (FastAPI) │
│ ┌─────────────┐ ┌────────────────────┐ │
│ │ SSDP cache │ │ TCP/55443 probe │ │
│ └──────┬──────┘ └──────────┬─────────┘ │
└─────────┼──────────────────────┼───────────────┘
▼ ▼
yeelight bulbs /24 subnet scan
(port 55443) (fallback)
- Bulbs are identified by
capabilities.idfrom SSDP, oryeelight_<ip>when SSDP is unavailable. Both forms are stable across server restarts viacache.json. /api/devicesand/api/metadatamirror the schema thatmatter_webcontrol'sLogicalBridgeClientconsumes (states.{on_off, brightness_raw, color_temp_mireds},names: list[str],bridge.api_version: "2").- Authentication is a single
X-API-Keyheader. Same key used by federation peers when they register this server via/api/bridge?…&api_key=…on the matter side.
CLI options
| Flag | Default | Description |
|---|---|---|
--port |
9800 |
REST port |
--host |
127.0.0.1 |
Bind address. Use 0.0.0.0 to expose on LAN (api-key strongly recommended) |
--api-key |
$YEELIGHT_SRV_KEY |
Required header value. If unset and --host 0.0.0.0, a warning is logged |
--seed-ip |
(none) | Pre-register a bulb by IP at startup. Repeatable, or comma-separated. Also reads $YEELIGHT_SEED_IPS |
--probe-subnet |
(none) | TCP-scan this CIDR (e.g. 192.168.1.0/24) for bulbs at startup. Repeatable |
--auto-probe |
off | When SSDP returns no bulbs and the cache is empty, lazily TCP-scan the local /24 on first request |
REST API
All endpoints require X-API-Key: $YEELIGHT_SRV_KEY (when --api-key is set).
Devices are addressed by their id field (the SSDP capabilities.id, or yeelight_<ip> if seeded without SSDP). Aliases set via /api/name are display-only and not accepted as IDs.
Error mapping: 404 (device unknown), 400 (bad parameters), 401 (auth), 500 (other).
Read
| Method & Path | Description |
|---|---|
GET /api/devices |
Federation feed — every device with id, endpoint_id, states, names |
GET /api/lights |
Human view: kelvin + percent, includes IP and primary alias |
GET /api/level?id=… |
Read raw brightness (0-254). Add &level=N (or POST) to set |
GET /api/mired?id=… |
Read color temperature in mireds. Add &mireds=N (or POST) to set |
GET /api/metadata |
Declarative bridge info (bridge.api_version: "2", capabilities + states) |
Control
| Method & Path | Body / Params |
|---|---|
POST /api/set |
{"id":"…","brightness":0.0–1.0,"temperature":Kelvin} — both fields optional |
POST /api/level |
{"id":"…","level":0–254} |
POST /api/mired |
{"id":"…","mireds":153–500} (clamped to Matter spec) |
# 80 % warm white on a bulb
curl -H "X-API-Key: $YEELIGHT_SRV_KEY" \
-X POST -H "Content-Type: application/json" \
-d '{"id":"yeelight_192.168.1.7","brightness":0.8,"temperature":2700}' \
http://127.0.0.1:9800/api/set
/api/set brightness < 0.01 activates Yeelight Moonlight where the bulb supports it.
Management
| Method & Path | Params |
|---|---|
POST /api/name |
{"id":"…","name":"…"} — append alias (multiple per device) |
GET /api/name/remove?id=&name= |
Remove a single alias |
GET /api/refresh |
Re-probe every cached IP |
GET /api/seed?ips=192.168.1.7,192.168.1.236 |
Add IPs to cache without SSDP |
GET /api/probe?subnet=192.168.1.0/24 |
TCP-scan a CIDR (subnet optional → local /24) |
Federation with matter_webcontrol
Pair this server with a running matter-srv so Yeelight bulbs appear alongside native Matter devices:
# On the Yeelight bridge host (e.g. 10.0.0.20)
export YEELIGHT_SRV_KEY=keyY
yeelight-srv --host 0.0.0.0 --port 9800 --auto-probe
# On the matter-srv host — register this bridge as a logical peer
curl -H "X-API-Key: $MATTER_SRV_KEY" \
"http://127.0.0.1:8080/api/bridge?ip=10.0.0.20&port=9800&api_key=keyY"
# matter-srv now exposes the Yeelight bulbs through its own endpoints:
curl -H "X-API-Key: $MATTER_SRV_KEY" http://127.0.0.1:8080/api/lights
matter-srv's LogicalBridgeClient calls /api/devices, /api/level, /api/mired, and /api/set directly over plain HTTP — no script execution, no events blobs.
Tests
The test suite drives a real bulb. Skipped by default unless an IP is provided.
pip install -e '.[test]'
export YEELIGHT_TEST_IP=192.168.1.7 # required
export YEELIGHT_TEST_ID=0x000000002ce4355f # optional; auto-discovered if unset
export YEELIGHT_TEST_KEY=optional-secret # optional; used by the live-server auth test
pytest -v
Coverage: /api/devices, metadata v2 schema, level (set / get / clamp), mireds (set / get / clamp), /api/set float brightness, alias add / remove, X-API-Key auth, plus an end-to-end test that mirrors the HTTP calls LogicalBridgeClient issues.
Known issues
- SSDP discovery returns empty for long-running bulbs. Yeelight bulbs only emit SSDP
NOTIFYframes for a short window after power-on. After thatdiscover_bulbs()returns[]even though TCP/55443 still works. Use--auto-probe,--seed-ip, or/api/probeto bypass SSDP. - Bulbs occasionally drop off the LAN (~every 2 weeks). Symptom: the bulb stops answering on TCP/55443 and ignores commands. The only known recovery is a hardware power-cycle (cut mains for ~10 s, then restore). The Yeelight LAN protocol does not expose a reboot / reset command, so this cannot be triggered from the web interface — recovery requires either a smart plug upstream of the bulb or someone flipping the wall switch.
- One subnet per host.
--auto-probeand/api/probe(withoutsubnet=) scan only the /24 of each local interface. Multi-VLAN setups should pass--probe-subnetexplicitly per network.
Limitations
- Only color-temperature and dimmable LAN-control Yeelight bulbs are tested. RGB-only models are not exercised by the current control mappings.
- The Yeelight LAN protocol is unauthenticated on the wire —
--api-keyonly gates the REST front, not the bulb-side TCP. Anyone on the same L2 segment as a bulb can still control it directly on port 55443.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file yeelight_web_controller-0.5.0.tar.gz.
File metadata
- Download URL: yeelight_web_controller-0.5.0.tar.gz
- Upload date:
- Size: 16.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9e72d4148894918c087007749a775a32e71b8a8c14f1ad89a2b252ee67f12338
|
|
| MD5 |
f45c87ea59cd98731ab7fb59b49b246c
|
|
| BLAKE2b-256 |
cf919f2e39d144e542d7fd4c553e21e39e082885350b2329f8923bb62f2b6433
|
Provenance
The following attestation bundles were made for yeelight_web_controller-0.5.0.tar.gz:
Publisher:
python-publish.yml on dongnh/yeelight_webcontrol
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
yeelight_web_controller-0.5.0.tar.gz -
Subject digest:
9e72d4148894918c087007749a775a32e71b8a8c14f1ad89a2b252ee67f12338 - Sigstore transparency entry: 1437034074
- Sigstore integration time:
-
Permalink:
dongnh/yeelight_webcontrol@0cdd31efe6dd535a8d2621acb554c04d95dcc0af -
Branch / Tag:
refs/tags/v0.5.0 - Owner: https://github.com/dongnh
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@0cdd31efe6dd535a8d2621acb554c04d95dcc0af -
Trigger Event:
release
-
Statement type:
File details
Details for the file yeelight_web_controller-0.5.0-py3-none-any.whl.
File metadata
- Download URL: yeelight_web_controller-0.5.0-py3-none-any.whl
- Upload date:
- Size: 12.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
75a00b2159f7a9866e1865dabed3ea1f2753b43d14ba3eced5c45b2eb48c612d
|
|
| MD5 |
748b95791c54942798135f2842093ff6
|
|
| BLAKE2b-256 |
90245101dc24f674f8818bef8352de948236066d1a9e626ab3d3bc9de8e8e910
|
Provenance
The following attestation bundles were made for yeelight_web_controller-0.5.0-py3-none-any.whl:
Publisher:
python-publish.yml on dongnh/yeelight_webcontrol
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
yeelight_web_controller-0.5.0-py3-none-any.whl -
Subject digest:
75a00b2159f7a9866e1865dabed3ea1f2753b43d14ba3eced5c45b2eb48c612d - Sigstore transparency entry: 1437034078
- Sigstore integration time:
-
Permalink:
dongnh/yeelight_webcontrol@0cdd31efe6dd535a8d2621acb554c04d95dcc0af -
Branch / Tag:
refs/tags/v0.5.0 - Owner: https://github.com/dongnh
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@0cdd31efe6dd535a8d2621acb554c04d95dcc0af -
Trigger Event:
release
-
Statement type: