It is a work in progress and is not, in any way, affiliated or related to LIFX Labs.
The apps start by sending UDP "discovery" packets to the network broadcast address, port 56700. They do this repeatedly until a bulb responds by sending a UDP packet back to you on port 56700. Packets are identified via its type (of 0x03).
The first response which matches this is what I'm using as the "controller" bulb. The controller appears to continue sending UDP packets, but I have not yet dug in to these; my assumption is that they are general announcements to the rest of the network in case there are multiple apps running which want to control the bulbs.
An unconfigured bulb will listen at 172.16.0.1 and act as an access point, hosting a secure network with the name "LIFX Bulb" and password of 'lifx1234'.
Configuration of a bulb involves connecting to the bulb's hosted network and sending a "set access point" message to the bulb. This message contains the information it needs to join your existing wireless network infrastructure (such as SSID and password). Networks using WEP security are not supported.
After receipt of the message, the bulb will shut down the hosted network and attempt connection to the existing wireless network infrastructure.
The "get access point" message can be used to enumerate wireless access points visible by the bulb.
After finding a controller bulb, open a TCP connection to it on port 56700. All commands are sent down this stream.
The controller bulb appears to send data to the network as UDP packets, but it also sends similar packets down the TCP connection. These packets conform to the common elements detailed above.
If you have more than one bulb, you will get a packet for each bulb with the second address field changed to tell you which bulb the packet is referring to.
The network protocol uses UDP and TCP in various places, but there seems to be a common packet format used. Packet field data appears to be of mixed endianness.
packet
{
uint16 size; // LE
uint16 protocol;
uint32 reserved1; // Always 0x0000
byte target_mac_address[6];
uint16 reserved2; // Always 0x00
byte site[6]; // MAC address of gateway PAN controller bulb
uint16 reserved3; // Always 0x00
uint64 timestamp;
uint16 packet_type; // LE
uint16 reserved4; // Always 0x0000
varies payload; // Documented below per packet type
}
- 0x02 - Get PAN gateway - app to bulb
- 0x03 - PAN gateway - bulb to app
- 0x14 - Get power state - app to bulb
- 0x15 - Set power state - app to bulb
- 0x16 - Power state - bulb to app
- 0x10 - Get wifi info - app to bulb
- 0x11 - Wifi info - bulb to app
- 0x12 - Get wifi firmware state - app to bulb
- 0x13 - Wifi firmware state - bulb to app
- 0x12d - Get wifi state - app to bulb
- 0x12e - Set wifi state - app to bulb
- 0x12f - Wifi state - bulb to app
- 0x130 - Get access points - app to bulb
- 0x131 - Set access point - app to bulb
- 0x132 - Access point - bulb to app
- 0x17 - Get bulb label - app to bulb
- 0x18 - Set bulb label - app to bulb
- 0x19 - Bulb label - bulb to app
- 0x1a - Get tags - app to bulb
- 0x1b - Set tags - app to bulb
- 0x1c - Tags - bulb to app
- 0x1d - Get tag labels - app to bulb
- 0x1e - Set tag labels - app to bulb
- 0x1f - Tag labels - bulb to app
- 0x65 - Get light state - app to bulb
- 0x66 - Set light color - app to bulb
- 0x67 - Set waveform - app to bulb
- 0x68 - Set dim (absolute) - app to bulb
- 0x69 - Set dim (relative) - app to bulb
- 0x6b - Light status - bulb to app
- 0x04 - Get time - app to bulb
- 0x05 - Set time - app to bulb
- 0x06 - Time state - bulb to app
- 0x07 - Get reset switch - app to bulb
- 0x08 - Reset switch state - bulb to app
- 0x09 - Get dummy load - app to bulb
- 0x0a - Set dummy load - app to bulb
- 0x0b - Dummy load - bulb to app
- 0x0c - Get mesh info - app to bulb
- 0x0d - Mesh info - bulb to app
- 0x0e - Get mesh firmware - app to bulb
- 0x0f - Mesh firmware state - bulb to app
- 0x20 - Get version - app to bulb
- 0x21 - Version state - bulb to app
- 0x22 - Get info - app to bulb
- 0x23 - Info - bulb to app
- 0x24 - Get MCU rail voltage - app to bulb
- 0x25 - MCU rail voltage - bulb to app
- 0x26 - Reboot - app to bulb
- 0x27 - Set Factory Test Mode - app to bulb
- 0x28 - Disable Factory Test Mode - app to bulb
Sent to a network (UDP broadcast) or bulb (TCP direct) to retrieve its PAN gateway state.
This packet is typically broadcast to discover gateway bulbs on the local network. (UDP datagram, port 56700.) As the destination bulb is unknown, the packet frame's address field is zeroed out.
payload {
// None
}
Will hopefully cause a packet type 0x03 to be sent back; apps should treat the originator of this response as a PAN gateway bulb for further communication.
Received from a gateway bulb after a request for its PAN gateway state (direct or broadcast). One packet describes one gateway bulb (i.e. you will receive a few of these packets).
payload {
SERVICE service;
uint32 port; // LE
}
enum SERVICE : byte
{
UDP = 1,
TCP = 2
}
After receiving this packet, I open a TCP connection to the originator on TCP port 56700 for subsequent communication.
Sent to a bulb to get its internal time value.
payload {
// None
}
Sent to a bulb to set its internal time value.
payload {
uint64 time; // LE; microseconds since 00:00:00 UTC on 1 January 1970
}
Received from a bulb after a request for its current time value.
payload {
uint64 time; // LE; microseconds since 00:00:00 UTC on 1 January 1970
}
Sent to a bulb to get the position of the physical reset switch (up/down).
payload {
// None
}
Received from a bulb after a request is made for the position of the physical reset switch.
payload
{
RESET_SWITCH_POSITION position;
}
enum RESET_SWITCH_POSITION: uint8
{
UP = 0,
DOWN = 1
}
Sent to a bulb to retrieve wireless mesh info and other miscellany.
payload
{
// None
}
Received from a bulb after a request is made for its mesh info.
payload
{
float signal; // LE
int tx; // LE
int rx; // LE
short mcu_temperature;
}
Sent to a bulb to retrieve wireless mesh firmware state.
payload
{
// None
}
Received from a bulb after a request is made for its firmware state.
payload
{
LIFX_TIMESTAMP build;
LIFX_TIMESTAMP install;
uint32 version; // LE?
}
struct LIFX_TIMESTAMP
{
byte second;
byte minute;
byte hour;
byte day;
char month[3]; // LE; ASCII encoded
byte year;
}
Sent to a bulb to retrieve its wifi info.
payload
{
// None
}
Received from a bulb after a request is made for its wifi info.
payload
{
float signal; // LE
int tx; // LE
int rx; // LE
short mcu_temperature;
}
Sent to a bulb to retrieve its wifi firmware [state? version?].
payload
{
// None
}
Received from a bulb after a request is made for its firmware [state? version?].
payload
{
LIFX_TIMESTAMP build;
LIFX_TIMESTAMP install;
uint32 version; // LE?
}
struct LIFX_TIMESTAMP
{
byte second;
byte minute;
byte hour;
byte day;
char month[3]; // LE; ASCII encoded
byte year;
}
Sent to a bulb to retrieve its current power state (i.e. on or off). This packet is of questionable value.
payload
{
// None
}
Sent to a bulb to set its power state (i.e. on or off).
payload
{
ONOFF onoff;
}
enum ONOFF : uint16
{
OFF = 0,
ON = 1
}
Will generally cause a packet 0x16 in response.
Received from a bulb after a request for its power state.
payload
{
ONOFF onoff;
}
enum ONOFF : uint16
{
OFF = 0x0000,
ON = 0xffff
}
Sent to a bulb to get its label.
payload {
// None
}
Sent to a bulb to change its label.
payload
{
char label[32]; // UTF-8 encoded string
}
Generated responses of packet type 0x1b (over TCP to specific IPs), and 0x19 (over UDP to broadcast ip), and 0x6b.
Received from a bulb after a label request or change is made.
payload
{
char label[32]; // UTF-8 encoded string
}
Sent to a bulb to request its tags.
payload
{
// None
}
Sent to a bulb to set its tags.
payload
{
uint64 tags;
}
Received from a bulb after a request for its tags.
payload
{
uint64 tags;
}
Sent to a bulb to request its tag labels.
payload
{
uint64 tags;
}
Sent to a bulb to set its tag labels.
payload
{
uint64 tags;
char label[32]; // UTF-8 encoded string
}
Received from a bulb after a request for its tag labels.
payload
{
uint64 tags;
char label[32]; // UTF-8 encoded string
}
Sent to a bulb to request its version state.
payload
{
// None
}
Received from a bulb after a request for its version state.
payload
{
uint32 vendor;
uint32 product;
uint32 version;
}
Sent to a bulb to request its [info?].
payload
{
// None
}
Received from a bulb in response to a request for info state.
payload
{
uint64 time; // LE
uint64 uptime; // LE
uint64 downtime; // LE
}
Sent to a bulb to receive its microcontroller (MCU) rail voltage.
payload
{
// None
}
Received from a bulb after a microcontroller (MCU) rail voltage request.
payload
{
uint32 voltage; // LE; in mV
}
Reboots a target bulb. It has been observed that some bulbs rebooted in this manner reset their color and fail to reconnect to wireless infrastructure, necessitating a hardware reset (could be a timing related bug).
payload
{
// None
}
Sent to a bulb to set its factory test mode. Unless you know what you're doing, we recommend you do not use this packet type. (You've been warned!)
payload
{
byte on; // Unknown
}
Sent to a bulb to disable its factory test mode. Unless you know what you're doing, we recommend you do not use this packet type. (You've been warned!)
payload
{
// None
}
Sent to a bulb to request its current light state (which includes its color, dim level, power level, label, and tags).
payload {
// None
}
Will generally be followed by one or more 0x6b packets in response.
Sent to a bulb to configure its light color. Upon receipt, the bulb will fade towards the new color using specified timing information.
payload {
byte stream; // Unknown, potential "streaming" mode toggle? Set to
// 0x00 for now.
uint16 hue; // LE NOTE: Wraps around at 0xff 0xff back to 0x00 0x00
// which is a primary red colour.
uint16 saturation; // LE
uint16 brightness; // LE
uint16 kelvin; // LE i.e. colour temperature (whites wheel in apps)
uint32 fade_time; // LE Length of fade action, in seconds
}
Note that for the "whites", apps always sets hue and saturation to 0x00. The white colour appears to have a fairly narrow range, such that 0-10 is very yellow, 14 is a natural white, then 15-30 fades to blue. Anything beyond that seems to be very blue.
Sent to a bulb to configure its [waveform?]. [Advanced topic, needs expansion.]
payload {
byte stream;
byte transient;
uint16 hue; // LE
uint16 saturation; // LE
uint16 brightness; // LE
uint16 kelvin; // LE
uint32 period; // LE?
float cycles; // LE?
uint16 duty_cycles;
byte waveform;
}
Sent to a bulb to set its dim level.
payload {
int16 brightness; // LE
uint32 duration; // in seconds
}
Sent to a bulb to set its dim level, relative to the current value.
payload {
int16 brightness; // LE
uint32 duration; // in seconds
}
Sent by a bulb after a request for light state. If this packet is received mid-fade, the packet represents a snapshot of light status at transmission time.
payload {
uint16 hue; // LE
uint16 saturation; // LE
uint16 brightness; // LE
uint16 kelvin; // LE
uint16 dim; // LE?
uint16 power;
char bulb_label[32]; // UTF-8 encoded string
uint64 tags;
}
Sent to a bulb to retrieve state on one of its wireless interfaces.
payload
{
INTERFACE interface;
}
enum INTERFACE : byte
{
SOFT_AP = 1,
STATION = 2
}
Sent to a bulb to set a wireless interface's state.
payload
{
INTERFACE interface;
WIFI_STATUS wifi_status; // Leave 0x00
byte ip4_address[4]
byte ip6_address[16];
}
enum INTERFACE : byte
{
SOFT_AP = 1,
STATION = 2
}
Received from a bulb after a request for a wireless interface's state.
payload
{
INTERFACE interface;
WIFI_STATUS wifi_status; // Only valid if interface == STATION
byte ip4_address[4]
byte ip6_address[16];
}
enum INTERFACE : byte
{
SOFT_AP = 1,
STATION = 2
}
enum WIFI_STATUS : byte
{
CONNECTING = 0,
CONNECTED = 1,
FAILED = 2,
OFF = 3
}
Sent to a bulb to request a list of nearby access points.
payload
{
// None
}
Sent to a bulb to configure its wireless interface. (It's not yet clear if the bulbs can act in both SOFT_AP and STA modes.)
payload
{
INTERFACE interface;
char ssid[32]; // UTF-8 encoded string
char password[64]; // UTF-8 encoded string
SECURITY_PROTOCOL security_protocol;
}
enum INTERFACE : byte
{
SOFT_AP = 1, // i.e. act as an access point
STATION = 2 // i.e. connect to an existing access point
}
enum SECURITY_PROTOCOL : byte
{
OPEN = 1,
WEP_PSK = 2, // Not officially supported
WPA_TKIP_PSK = 3,
WPA_AES_PSK = 4,
WPA2_AES_PSK = 5,
WPA2_TKIP_PSK = 6,
WPA2_MIXED_PSK = 7
}
Received from a bulb after a request for nearby access points. One packet describes one access point (i.e. you will receive a bunch of these packets).
payload
{
INTERFACE interface; // seems to always be 0x00, bug?
char ssid[32]; // UTF-8 encoded string
SECURITY_PROTOCOL security_protocol;
uint16 strength;
uint16 channel;
}
enum SECURITY_PROTOCOL : byte
{
OPEN = 1,
WEP_PSK = 2, // Not officially supported
WPA_TKIP_PSK = 3,
WPA_AES_PSK = 4,
WPA2_AES_PSK = 5,
WPA2_TKIP_PSK = 6,
WPA2_MIXED_PSK = 7
}