The protocol at a glance
Yeelight Client implements the Yeelight WiFi Light Inter-Operation Specification, which Yeelight publishes for software that wants to work with its lights. You do not need to know the protocol to use the library, but it explains what the library sends, what the properties are called, and why some things are the way they are. This page is a summary and not a copy: where it matters, read the specification itself.
The protocol has two parts:
- Discovery finds the lights: UDP messages in the style of SSDP, on port 1982, to a multicast group.
- Control is a TCP connection to a light, over which commands and their answers are exchanged as JSON, one message on each line.
The protocol has no authentication and no encryption. A light only takes these connections when LAN Control is switched on in the Yeelight app.
Discovery messages
A search is sent by whoever wants to find lights, to the multicast group 239.255.255.250 on UDP port 1982. It is four lines, each ended with
CR LF. The MAN and ST headers are required (ST has to be wifi_bulb), the HOST header is optional, and a message that does not follow the
rules is dropped by the light without an answer, which looks like the absence of lights.
M-SEARCH * HTTP/1.1
HOST: 239.255.255.250:1982
MAN: "ssdp:discover"
ST: wifi_bulb
On the lights that were measured, a search was answered the same with and without a closing empty line, and with and without an MX header.
They did not answer other search targets (ssdp:all, yeelight), or a search to port 1900, the port of standard SSDP.
An answer is sent by every light that hears a search, to the address and port that the search came from. It says where the control service of the light is, who the light is, what it supports, and what it is doing (this is an example; the values are those of a made-up light):
HTTP/1.1 200 OK
Cache-Control: max-age=3600
Location: yeelight://192.168.1.50:55443
Server: POSIX UPnP/1.0 YGLC/1
id: 0x00000000045d8e21
model: color
fw_ver: 24
support: get_prop set_default set_power toggle set_bright set_ct_abx set_rgb set_hsv set_name
power: on
bright: 80
color_mode: 2
ct: 2700
rgb: 16711680
hue: 0
sat: 100
name: desk
| Header | Means | In the library |
|---|---|---|
Location |
Where the control service is: yeelight:// with the address and the TCP port. |
Location, Address, Port |
id |
The id of the light, which is what tells lights apart. | Id |
model |
The product model. The specification names mono (brightness only), color, stripe, ceiling and bslamp, and says that more will follow; real lights say others, for example colora and strip6. |
Model |
fw_ver |
The firmware version. | FirmwareVersion |
support |
The methods that the light supports, separated by spaces. A light refuses any method that is not in it. | SupportedMethods |
power |
on or off. Off is switched off by software, and not without power. |
IsOn |
bright |
The brightness, a percentage. | Brightness |
color_mode |
1 colour (RGB), 2 colour temperature, 3 HSV. |
ColorMode |
ct, rgb, hue, sat |
The colour temperature, the colour as a number, the hue and the saturation. Each is only valid in its own colour mode. | ColorTemperature, Rgb, Hue, Saturation |
name |
The name that was stored on the light with set_name. |
Name |
Cache-Control |
max-age is the interval at which the light announces itself (3600 seconds in the example of the specification). |
An announcement is sent by a light by itself, to the multicast group, right after it joined the network and then at a fixed interval. It starts with
NOTIFY * HTTP/1.1, has NTS: ssdp:alive, and the same headers as an answer. Whoever receives it must not answer it.
Control messages
After discovery, a program connects to the TCP port of the Location. Every message is one JSON object on one line, ended with CR LF. A light
accepts four connections at once. There are three kinds of message.
A command goes to the light. It has an id that the sender chooses, a method and an array of params. The light accepts only the methods that it
listed in support.
{"id":1,"method":"set_bright","params":[60,"smooth",1000]}
A result comes back with the same id: result is an array, with "ok" for a command that was carried out, or the values for get_prop.
When the command failed, there is an error with a code and a message instead. A light answers -1 to everything that it refuses. A line that
has an id and neither a result array nor an error object is not an answer: the library ignores it (it is logged at the debug level), and
the command ends with a Timeout.
{"id":1,"result":["ok"]}
{"id":2,"error":{"code":-1,"message":"unsupported method"}}
{"id":3,"method":"get_prop","params":["power","bright","not_a_property"]}
{"id":3,"result":["on","60",""]}
A property that the light does not know is an empty string in the result of get_prop.
A notification is sent by a light, to every connection that it has, whenever its state changes. Its method is props, and its params are the
properties that changed, with their values as text:
{"method":"props","params":{"power":"on","bright":"75"}}
These are the properties of the protocol, and what the library calls them:
| Property | Values | In the library |
|---|---|---|
power |
on, off |
IsOn |
bright |
1 to 100 | Brightness |
ct |
1700 to 6500 kelvin | ColorTemperature |
rgb |
the colour as a number | Rgb, Color |
hue, sat |
0 to 359, 0 to 100 | Hue, Saturation |
color_mode |
1 colour, 2 colour temperature, 3 HSV | ColorMode |
flowing, flow_params |
whether a colour flow runs, and its parameters | IsFlowing, FlowParameters |
delayoff |
the remaining time of the sleep timer, in minutes | SleepTimerRemaining |
music_on |
1 when music mode is on | IsMusicModeOn |
name |
the name stored on the light | Name |
nl_br |
the brightness of the night light of a ceiling light | NightLightBrightness |
active_mode |
0 daylight, 1 moonlight (ceiling lights) | ActiveMode |
bg_power, bg_bright, bg_ct, bg_rgb, bg_hue, bg_sat, bg_flowing, bg_flow_params |
the same, for the background light | the same properties of Background |
bg_lmode |
the colour mode of the background light | ColorMode of Background |
The methods
The specification lists 35 methods. This is every one of them, and the member of the library that sends it. A command that changes what a light
shows takes an effect (sudden or smooth) and a duration in milliseconds, which the library makes of a
transition.
Main light and device
| Method | Parameters | Sent by | Notes |
|---|---|---|---|
get_prop |
the names of properties | GetPropertiesAsync, RefreshAsync (all the names) |
The keep-alive uses it for power. |
set_power |
on or off, effect, duration, mode |
SetPowerAsync, TurnOnAsync, TurnOffAsync |
The mode is only sent when it is not Normal. |
toggle |
none | ToggleAsync |
|
set_bright |
brightness, effect, duration | SetBrightnessAsync |
Light on. |
set_ct_abx |
kelvin, effect, duration | SetColorTemperatureAsync |
Light on. |
set_rgb |
colour as a number, effect, duration | SetRgbAsync |
Light on. |
set_hsv |
hue, saturation, effect, duration | SetHsvAsync |
Light on. |
set_default |
none | SetDefaultAsync |
Light on. |
start_cf |
count, action, expression | StartColorFlowAsync |
Light on. |
stop_cf |
none | StopColorFlowAsync |
|
set_scene |
class, and values that depend on it | SetSceneAsync |
Light on or off. The classes are color, hsv, ct, cf and auto_delay_off: see YeelightScene. |
set_adjust |
action, property | AdjustAsync |
The colour can only be adjusted with circle. |
adjust_bright |
percentage, duration | AdjustBrightnessAsync |
|
adjust_ct |
percentage, duration | AdjustColorTemperatureAsync |
|
adjust_color |
percentage, duration | AdjustColorAsync |
The light ignores the percentage, and the library sends 0. |
cron_add |
type 0 (switch off), minutes | SetSleepTimerAsync |
Light on. |
cron_get |
type 0 | GetSleepTimerAsync |
|
cron_del |
type 0 | CancelSleepTimerAsync |
|
set_name |
the name | SetNameAsync |
|
set_music |
1 or 0, the address and the port of the server | StartMusicModeAsync (1, and 0 when the light accepted it and did not connect), and disposing the session (0) |
See Music mode. |
dev_toggle |
none | ToggleAllAsync |
Main light and background light. |
Background light
The 14 methods of the background light have the name of the method of the main light with bg_ in front, and the same parameters. The library
sends them from the members of Background that have the same name as the member of the main light:
| Method | Sent by (on Background) |
|---|---|
bg_set_power |
SetPowerAsync, TurnOnAsync, TurnOffAsync |
bg_toggle |
ToggleAsync |
bg_set_bright |
SetBrightnessAsync |
bg_set_ct_abx |
SetColorTemperatureAsync |
bg_set_rgb |
SetRgbAsync |
bg_set_hsv |
SetHsvAsync |
bg_set_default |
SetDefaultAsync |
bg_start_cf |
StartColorFlowAsync |
bg_stop_cf |
StopColorFlowAsync |
bg_set_scene |
SetSceneAsync |
bg_set_adjust |
AdjustAsync |
bg_adjust_bright |
AdjustBrightnessAsync |
bg_adjust_ct |
AdjustColorTemperatureAsync |
bg_adjust_color |
AdjustColorAsync |
SendCommandAsync sends any method, as you name it. The specification spells one class of
set_scene in two ways in its text (auto_dealy_off once, auto_delay_off in its description and in its example); the library sends
auto_delay_off.
What the library adds
The protocol is a set of messages. The library turns it into something that you can use in a program:
- Discovery on real networks: the search from every network of the computer, as a multicast and as a broadcast, three times, and a probe of one address. Both because of what real lights do: see Troubleshooting.
- Identity: a light is its
id, and its connection follows it to a new address when the connection to the old one is down. A light that is connected is not moved by an announcement, so that nobody on the network can take a light over by announcing its id. - Checks before sending: ranges, durations and the list of supported methods, so that a command that a light would refuse is not sent.
- State: the properties of a light are kept from the answers to a search, the answers to
get_propand thepropsnotifications, and are read again when a connection is made. - Limits: one connection for each light, a pace of 60 commands a minute, and commands that fail at once when they cannot be sent.
- A connection that holds up: a keep-alive, reconnecting with a growing wait, and pending commands that fail the moment that a connection is lost.
- Events: the notifications are handed to your code by a dispatcher, one at a time and in order.
- Music mode: the TCP server that the light connects to, and the check that it is the light that connects.
- Safety with input: the messages of a light, and of anything that pretends to be one, are read as input that may be malformed, too large or lying.
What it does not do: it does not use the cloud of Yeelight or its app, it does not talk to a light that has LAN Control off, and it does not find or control a light that answers no search (the id, the model and the supported methods only come from the answer to a search).