OSRAM Lightify is a smart home, connected lightning technology. Lights, switches and other paired devices are controlled using the Lightify gateway device. This gateway is an always-on, always-connected device which can be controlled using the official Lightify REST API on the Lightify Cloud. That, however, means that all commands need to be routed through the internet.
The official Lightify app, on the other hand, communicates directly with the gateway and uses a proprietary binary protocol which is not publicly specified.
This document is meant to create a public specification of the known facts about how to discover gateway devices, paired devices and zones/groups, as well as how to control those devices.
All information in this document are collected using reverse engineering practices or are available by other implementations / people on the internet. Certain information might be incorrect, outdated or unspecific. Any help completing this document is appreciated, please file pull requests.
Using and/or implementing information in this document might brick your device, render it unfunctional, change behavior of any connected device and/or may void your warranty. Any action taken upon information in this document is strictly at your own risk. The author(s) are not liable for any losses and damages in connection with the use of this document.
The author(s) are not affiliated to OSRAM Light AG in any way. Furthermore is this document not official publicated or approved by OSRAM Licht AG.
The OSRAM Lightify gateway protocol is a binary protocol with a specified header.
The underlying protocol is a persistent TCP connection which does not seem to support multiplexing, therefore multiple requests should be sent one after another. To support multithreading, multiple connections should be used.
The TCP protocol works over port 4000 and discovery can be implemented using mDNS (multicast DNS, aka Bonjour). Further information in Lightify Gateway Discovery.
Multibyte values encoded using little-endian encoding and considered unsigned values.
String values are encoded using UTF-8 encoding and of fixed length. Unused bytes are filled with 0x00 and should be trimmed out to get the real string.
The protocol defines a common header for both requests and responses. The header consists of the packet’s length, a packet type and the command id.
Furthermore the header contains a request id which is recommended, but not required, to be monotonly increasing but must wrapping around to startover when surpassing 0xFFFFFFFF. The response will feature the same request id and can be used to correlate responses with requests.
Byte(s) | Description | Data type |
---|---|---|
0-1 |
Length of the packet, excl header length |
uint16_t |
2 |
Packet type (flag) |
uint8_t: enum { |
3 |
Command Id |
uint8_t: See Lightify Commands |
4-7 |
Unique, increasing request id |
uint32_t |
Response packets have an additional field in the header, which seems to return a status / error code for the request.
Byte(s) | Description | Data type |
---|---|---|
8 |
Status code? |
uint8_t: enum { |
If the packet is not a broadcast (addressing type != 0x02), the device or zone address header is following up right after the header. In case of a broadcast, the header is followed by the commands data. Addressing of specific zones or devices is defined in the following section.
The OSRAM Lightify gateway uses the Zigbee Light Link communication protocol, however it is also able to communicate with certain other device types of the Lightify series, such as switches, motion sensors and power plugs / sockets.
A device type is sent with status updates to identify the type of the device as well as the capabilities of a specific device.
Id | Description |
---|---|
1 |
Bulb: Fixed white, dimmable, non-softswitch |
2 |
Bulb: Tunable white, dimmable, soft-switchable |
4 |
Bulb: Fixed white, dimmable, soft-switchable |
10 |
Bulb: RGB, tunable white, dimmable, soft-switchable |
16 |
Plug / Power socket |
32 |
Motion Sensor |
64 |
Switch (2 switches) |
65 |
Switch (4 switches) |
Each paired device has a unique address (MAC). Multiple paired devices can be controlled at once by adding them to zones / groups, which are addressed using the zone’s id.
An address always contains 8 byte, no matter it’s adressing a device or zone and is directly followed by the command’s specific data.
Byte(s) | Description | Data type |
---|---|---|
8-15 |
Address |
uint64_t: See the following specification |
16-… |
Command specific data |
Devices are addressed by, what seems to be, a hardware address, similar to MAC addresses used in networking devices.
Byte(s) | Description | Data type |
---|---|---|
0-7 |
Device address |
uint64_t |
While discovering devices the device’s address is made known to the application, controlling the gateway, and the paired device can be addressed directly (whereas the command packet is still routed through the gateway).
Attention: Device addresses are transmitted as 8 bytes, not as strings!
Zones are identified by their zone id. Addressing itself, however, is still using 8 bytes, even if zone ids seem to be limited to 0xFFFF. That said, the addressing is built as following:
Byte | Data type |
---|---|
1 |
uint8_t: lower significant byte |
2 |
uint8_t: higher significant byte |
3-7 |
uint8_t[6]: 0x00 |
Attention: Also note, that zone commands have a packet type of 0x02 at byte position 2 in the packet’s header.
To discover the OSRAM Lightify gateway’s IP address, a mDNS (multicast DNS) request is used. mDNS is also known as Bonjour and is originally developed by Apple.
To find the gateway’s address a SSDP lookup request is sent to the UDP broadcast address 224.0.0.251 (IPv4) or FF02::FB (IPv6). The service type to search for is _http._tcp
which will find a Lightify device named as Lightify-XXXXXXXX
, where XXXXXXXX
is a part of the gateway’s serial number (S/N: OSRXXXXXXXX-YY
) which is also used in the gateway’s own SSID (last 6 numbers of the code).
Since more items, especially of other vendors, might be found, the instance name should be tested for starting with Lightify-
to make sure only the Lightify gateway is discovered.
According to the search type and the mDNS response, there is supposed to be a HTTP service on port 80, which does not seem to exist. However, the gateway seems to communicate over QUIC to the OSRAM servers, so maybe the port 80 is also available using QUIC.
After discovering the gateway’s IP address, the communication port to use the described protocol is TCP/4000.
Lightify devices and zones will be discovered using the gateway binary protocol, using tge commands PACKET_LIST_PAIRED_DEVICES and PACKET_LIST_ZONES.
Lightify commands are either used for broadcasts, like device or zone discovery, or contain information to control a specfic device or zone.
The following table is most probably incomplete and more commands are available. Response packets often follow a very similar scheme, therefore it should be easy to find new packets and analyze their content.
Known command ids are put into the following list:
Command Id | Description | Addressing | Packet Definition |
---|---|---|---|
0x02 |
Unknown, 1 byte data ⇒ no error |
BROADCAST? |
??? |
0x0A |
Unknown, byte data ⇒ no error |
BROADCAST? |
??? |
0x0B |
Unknown, 1 byte data ⇒ error 0x01 |
BROADCAST? |
??? |
0x13 |
List paired devices |
BROADCAST |
|
0x15 |
Unknown, 1 byte data ⇒ no error |
BROADCAST? |
??? |
0x16 |
Unknown, error code 15 (wrong addressing) |
ZONE?, DEVICE? |
??? |
0x1C |
Unknown, 1 byte data ⇒ error 0x0B, 0x19 |
BROADCAST? |
??? |
0x1D |
Unknown, 1 byte data ⇒ no error |
BROADCAST? |
??? |
0x1E |
List configured zones |
BROADCAST |
|
0x1F |
List defined scenes |
BROADCAST |
|
0x20 |
Add Device to Zone |
DEVICE? |
??? |
0x21 |
Remove Device from Zone |
DEVICE? |
??? |
0x26 |
Get Zone information |
ZONE |
|
0x27 |
Set Zone name |
ZONE? |
??? |
0x28 |
Set Device name |
DEVICE? |
??? |
0x29 |
Unknown, 1 byte data ⇒ ~1k bytes returned (all zero) |
BROADCAST? |
??? |
0x31 |
Set luminance of light or zone |
ZONE, DEVICE |
|
0x32 |
Set power switch on/off (also set default???) |
ZONE, DEVICE |
|
0x33 |
Set white light temperature |
ZONE, DEVICE |
|
0x34 |
Unknown, wrong addressing |
ZONE?, DEVICE? |
??? |
0x36 |
Set light color (RGB) |
ZONE, DEVICE |
|
0x37 |
Unknown, wrong addressing |
ZONE?, DEVICE? |
??? |
0x38 |
Unknown, wrong addressing |
ZONE?, DEVICE? |
??? |
0x51 |
Unknown, wrong addressing |
ZONE?, DEVICE? |
??? |
0x52 |
Activate scene |
BROADCAST |
|
0x53 |
Unknown, wrong addressing |
ZONE?, DEVICE? |
??? |
0x54 |
Unknown, returned actual data (uint16_t(0,0)) |
BROADCAST? |
??? |
0x55 |
Unknown, wrong addressing |
ZONE?, DEVICE? |
??? |
0x56 |
Unknown, wrong addressing |
ZONE?, DEVICE? |
??? |
0x57 |
Unknown, wrong addressing |
ZONE?, DEVICE? |
??? |
0x58 |
Unknown, wrong addressing |
ZONE?, DEVICE? |
??? |
0x61 |
Unknown, retured unknown error code 0xD1, 0xC2 |
BROADCAST? |
??? |
0x62 |
Unknown, retured unknown error code 0xD1 |
BROADCAST? |
??? |
0x63 |
Unknown, retured unknown error code 0xD1 |
BROADCAST? |
??? |
0x64 |
Unknown, wrong addressing |
ZONE?, DEVICE? |
??? |
0x66 |
Unknown, wrong addressing |
ZONE?, DEVICE? |
??? |
0x67 |
Unknown, wrong addressing |
ZONE?, DEVICE? |
??? |
0x68 |
Get device information |
DEVICE |
|
0x6A |
Unknown, retured unknown error code 0xD1 |
BROADCAST? |
??? |
0x6B |
Unknown, retured unknown error code 0xD1 |
BROADCAST? |
??? |
0x6D |
Unknown, retured unknown error code 0xD1 |
BROADCAST? |
??? |
0x6F |
Gateway Firmware version |
BROADCAST |
|
0x70 |
Unknown, wrong addressing |
ZONE?, DEVICE? |
??? |
0x71 |
Unknown, wrong addressing |
ZONE?, DEVICE? |
??? |
0x76 |
Unknown, wrong addressing |
ZONE?, DEVICE? |
??? |
0x79 |
Unknown, wrong addressing |
ZONE?, DEVICE? |
??? |
0x7A |
Unknown, wrong addressing |
ZONE?, DEVICE? |
??? |
0x7B |
Unknown, 1 byte data ⇒ no error |
BROADCAST? |
??? |
0x7C |
Unknown, 1 byte data ⇒ wrong addressing |
ZONE?, DEVICE? |
??? |
0x7D |
Unknown, retured unknown error code 0x16 - no return with data, maybe firmware update? |
??? |
??? |
0x91 |
Unknown, retured unknown error code 0xA7, 0xC2 |
??? |
??? |
0xC0 |
Unknown, no error |
BROADCAST? |
??? |
0xC1 |
Unknown, no error |
BROADCAST? |
??? |
0xC3 |
Unknown, wrong addressing |
ZONE?, DEVICE? |
??? |
0xC4 |
Unknown, wrong addressing |
ZONE?, DEVICE? |
??? |
0xC6 |
Unknown, no error |
BROADCAST? |
??? |
0xC7 |
Unknown, wrong addressing |
ZONE?, DEVICE? |
??? |
0xC8 |
Unknown, wrong addressing |
ZONE?, DEVICE? |
??? |
0xD0 |
Unknown, retured unknown error code 0xD1 |
??? |
??? |
0xD1 |
Unknown, no response, system reset? |
??? |
??? |
0xD2 |
Unknown, 1 byte data ⇒ 0xD1, crashed? needs restart |
??? |
??? |
0xD3 |
Unknown, no answer (0x00), firmware update or more data? |
??? |
??? |
0xD4 |
Unknown, no answer (0x00), firmware update or more data? |
??? |
??? |
0xD5 |
Set Color Wheel? HSL? |
ZONE?, DEVICE? |
??? |
0xD6 |
Unknown, wrong addressing |
ZONE?, DEVICE? |
??? |
0xD8 |
Unknown, wrong addressing |
ZONE?, DEVICE? |
??? |
0xD9 |
Unknown, wrong addressing (scene builder???) |
ZONE?, DEVICE? |
??? |
0xDA |
Unknown, wrong addressing |
ZONE?, DEVICE? |
??? |
0xDB |
Soft on, wrong addressing |
ZONE?, DEVICE? |
??? |
0xDC |
Soft off, wrong addressing |
ZONE?, DEVICE? |
??? |
0xDD |
Remove all scenes and groups |
ZONE?, BROADCAST? |
??? |
0xD0 |
Unknown, no error (0x00) |
BROADCAST? |
??? |
0xE1 |
Unknown, wrong addressing |
ZONE?, DEVICE? |
??? |
0xE2 |
Unknown, no answer |
BROADCAST? |
??? |
0xE3 |
Get / Scan / Set Wifi Configuration |
BROADCAST |
|
0xE4 |
Unknown, activates light (with 1 byte data) - seems to reset the light |
BROADCAST? |
??? |
0xE5 |
Unknown, returned actual data (uint64_t(1,0,0,0)) |
BROADCAST? |
??? |
0xE6 |
Unknown, returned actual data (uint16_t(1,15)) |
BROADCAST? |
??? |
0xE6 |
Unknown, returned actual data (uint16_t(1,15)) |
BROADCAST? |
??? |
0xE7 |
Unknown, no answer |
BROADCAST? |
??? |
0xE8 |
Unknown, retured unknown error code 0x16 |
BROADCAST? |
??? |
0xE9 |
Unknown, retured unknown error code 0xD1 |
BROADCAST? |
??? |
0xEA |
Unknown, retured unknown error code 0xD1 |
BROADCAST? |
??? |
As visible from the list, a lot of command ids seem either unused or, what is more presumable, unknown at the current point in time.
Most commands carry additional information starting after the header (for broadcast packets) or after the addressing header (non-broadcast packets).
The following sections define the packet’s structure after either of both headers, according to the command type.
Returns a list of all paired devices.
Byte(s) | Description | Data type |
---|---|---|
16 |
Unknown |
uint8_t: always? 0x01 |
Byte(s) | Description | Data type |
---|---|---|
9-10 |
Number of devices |
uint16_t |
…50 bytes each device |
Device status information |
See following table |
Byte(s) | Description | Data type |
---|---|---|
0-1 |
Device id? |
uint16_t |
2-9 |
Device address |
uint64_t: See Device address |
10 |
Device type? |
uint8_t: See Device Types |
11-14 |
Firmware version |
uint8_t[5]: Translation into firmware version string → |
15 |
Reachable |
uint8_t: 0x00 online, 0xFF offline |
16-17 |
Zone Id |
uint16_t |
18 |
Power switch status |
uint8_t: bool |
19 |
Luminance value / Battery value (Motion Detector) |
uint8_t |
20-21 |
Temparature value (in Kelvin) |
uint16_t: 2,000 >= x ⇐ 6,500 |
22 |
Red value / Enabled value (Motion Detector) |
uint8_t |
23 |
Green value / Triggered value (Motion Detector) |
uint8_t |
24 |
Blue value |
uint8_t |
25 |
Alpha value |
uint8_t: always? 0xFF |
26-41 |
Device name |
uint8_t[16]: UTF-8 encoded, zero terminated string |
42-45 |
Time since last seen by gateway |
uint32_t |
46-49 |
Joining? |
uint32_t |
Returns a list of all configured zones.
Byte(s) | Description | Data type |
---|---|---|
- |
No additional information to send |
- |
Byte(s) | Description | Data type |
---|---|---|
9-10 |
Number of zones |
uint16_t |
…18 bytes each zone |
Zone information |
See following table |
Byte(s) | Description | Data type |
---|---|---|
0-1 |
Zone id |
uint16_t |
2-17 |
Zone name |
uint8_t[16]: UTF-8 encoded, zero terminated string |
Assigned devices need to be discovered using PACKET_GET_ZONE_INFO after the zone id has been seen with this packet.
Returns a list of defined scenes.
Byte(s) | Description | Data type |
---|---|---|
- |
No additional information to send |
- |
Byte(s) | Description | Data type |
---|---|---|
0-1 |
Number of Scenes |
uint16_t |
…20 bytes each scene |
Scene information |
See following table |
Byte(s) | Description | Data type |
---|---|---|
0 |
Scene id |
uint8_t |
1 |
Unknown, seems to always be 0x64 (@-sign) |
uint8_t |
2-17 |
Scene name |
uint8_t[16]: UTF-8 encoded, zero terminated string |
18-19 |
Unknown |
uint16_t |
20 |
Next Scene id (chaining scenes?) |
uint8_t |
Returns information about the requested zone, including assigned devices.
Byte(s) | Description | Data type |
---|---|---|
- |
No additional information to send |
- |
Byte(s) | Description | Data type |
---|---|---|
9-10 |
Zone id |
uint32_t |
11-27 |
Zone name |
uint8_t[16]: UTF-8 encoded, zero terminated string |
28 |
Number of assigned devices |
uint8_t |
…8 bytes each device |
Device addresses |
See Device address |
Sets the luminance value of the addressed device or zone.
Byte(s) | Description | Data type |
---|---|---|
16 |
Luminance value |
uint8_t |
17-18 |
Transition time in millis |
uint16_t |
Byte(s) | Description | Data type |
---|---|---|
9-10 |
Device or zone id |
uint16_t |
11-18 |
Device or zone address |
uint64_t: See Device and Zone Addressing |
Sets the power switch state of the addressed device or zone.
Byte(s) | Description | Data type |
---|---|---|
16 |
Power switch state |
uint8_t: bool |
Byte(s) | Description | Data type |
---|---|---|
9-10 |
WRONG:Device or zone id??? Number of devices changed? |
uint16_t |
11-18 |
Device or zone address |
uint64_t: See Device and Zone Addressing |
Sets the white light temperature of the addressed device or zone between 2,000 and 6,500 Kelvin.
Byte(s) | Description | Data type |
---|---|---|
16 |
White light temperature |
uint16_t: 2,000 >= x ⇐ 6,500 |
17-18 |
Transition time in millis |
uint16_t |
Byte(s) | Description | Data type |
---|---|---|
9-10 |
Device or zone id |
uint16_t |
11-18 |
Device or zone address |
uint64_t: See Device and Zone Addressing |
Sets the RGB color value of the addressed device or zone.
Byte(s) | Description | Data type |
---|---|---|
16 |
Red value |
uint8_t |
17 |
Green value |
uint8_t |
18 |
Blue value |
uint8_t |
19 |
Alpha value |
uint8_t: always 0xFF? |
20-21 |
Transition time in millis |
uint16_t |
Byte(s) | Description | Data type |
---|---|---|
9-10 |
Device or zone id |
uint16_t |
11-18 |
Device or zone address |
uint64_t: See Device and Zone Addressing |
Activates a predefined scene on the addressed device or zone.
Byte(s) | Description | Data type |
---|---|---|
16 |
Scene id |
uint8_t: 0x00 to 0x0F for the different predefined scenes |
Byte(s) | Description | Data type |
---|---|---|
9-10 |
Device or zone id |
uint16_t |
11-18 |
Device or zone address |
uint64_t: See Device and Zone Addressing |
Returns information about the requested device.
Byte(s) | Description | Possible values |
---|---|---|
- |
No additional information to send |
- |
Byte(s) | Description | Data type |
---|---|---|
9-10 |
Device id? |
uint16_t |
11-18 |
Device address |
uint64_t: See Device address |
19 |
Reachable |
uint8_t: 0x00 online, 0xFF offline |
20 |
Unknown |
uint8_t: ??? |
21 |
Power switch status |
uint8_t: bool |
22 |
Luminance value / Battery value (Motion Detector) |
uint8_t |
23-24 |
Temparature value (in Kelvin) |
uint16_t: 2,000 >= x ⇐ 6,500 |
25 |
Red value / Enabled value (Motion Detector) |
uint8_t |
26 |
Green value / Triggered value (Motion Detector) |
uint8_t |
27 |
Blue value |
uint8_t |
28 |
Alpha value |
uint8_t: always 0xFF? |
29-31 |
Unknown |
uint8_t[3]: ??? |
If the response packet’s byte at index 19 is 0xFF (the device is offline / non-reachable) the packet is only those 20 bytes, otherwise the full packet comes back.
Retrieves or configures the wifi configuration.
Byte(s) | Description | Data type |
---|---|---|
16 |
Subcommand |
uint8_t: enum { |
Byte(s) | Description | Data type |
---|---|---|
9 |
Number of profiles |
uint8_t |
…97 bytes each profile |
Profile information |
See following table |
Byte(s) | Description | Data type |
---|---|---|
0-31 |
Profile Name |
uint8_t[32]: UTF-8 encoded, zero terminated string |
32-64 |
SSID |
uint8_t[33]: UTF-8 encoded, zero terminated string |
65-70 |
BSSID |
uint8_t[6]: UTF-8 encoded, zero terminated string |
71-74 |
Channel |
uint32_t |
75-76 |
Unknown |
uint16_t: ??? |
77-80 |
IP Address |
uint64_t: 4 bytes of IP address |
81-84 |
Gateway |
uint64_t: 4 bytes of IP address |
85-88 |
Netmask |
uint64_t: 4 bytes of IP address |
89-92 |
DNS #1 |
uint64_t: 4 bytes of IP address |
93-96 |
DNS #2 |
uint64_t: 4 bytes of IP address |
Retrieves the current firmware version of the gateway.
Byte(s) | Description | Data type |
---|---|---|
- |
No additional information to send |
- |
Byte(s) | Description | Data type |
---|---|---|
9-12 |
Firmware version |
uint8_t[4]: Translation into firmware version string → |