OSRAM Lightify Binary Protocol Documentation
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.
Disclaimer
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.
Basics about the Protocol
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.
Headers
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.
Error Response
In case of an illegally addressed packet or any other type of error, an error response packet is returned from the gateway. The packet consists of the header only and the last byte seems to define an error code. See previous table for a list of known? error codes.
Device Types
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) |
Device and Zone Addressing
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 |
Device address
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!
Zone address
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.
Lightify Gateway Discovery
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
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.
Command data
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.
PACKET_LIST_PAIRED_DEVICES
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 |
PACKET_LIST_ZONES
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.
PACKET_LIST_SCENES
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 |
PACKET_GET_ZONE_INFO
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 |
PACKET_SET_LUMINANCE
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 |
PACKET_SET_SWITCH
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 |
PACKET_SET_TEMPERATURE
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 |
PACKET_SET_COLOR
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 |
PACKET_ACTIVATE_SCENE
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 |
PACKET_GET_DEVICE_INFO
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.
PACKET_GET_WIFI_CONFIGURATION
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 |
PACKET_GET_GATEWAY_FIRMWARE_VERSION
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 → |