Skip to content
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time

The droids we are looking for

Subject appearance

This document describes GATT characteristics used to control Zengge smart RGBW BLE bulbs (like on the picture above). All the text below is a result of my own experience of reverse-engineering its protocol. Use it at your own risk, I am not responsible for your hardware.

Looking through the reverse engineered code I figured out that there are potentially two slightly different kinds of bulbs. They differ by names and versions. Bulbs whose names start with LEDBlue or LEDBLE belong to the first group, not subject of this doc. Second group of devices is described here. Also, some commands differ depending on the device version (can be known by querying it's status). The commands below are tested on LEDnet-...-named bulb of third version.

Communication principles

There are three main ways to interact with a bulb:

  1. Fire and forget. Only writes are supported. No response or acknowledgement.
  2. Write and listen for notifications. Write a characteristic while subscribed for notifications. As a result of value write, another characteristics may fire a notification.
  3. Direct read of a characteristic. Read-only access to some parameters.

Most of the communication with a bulb is done via two characteristcs — FFE9 and FFE4 — in a write-and-listen manner: you write a data into FFE9 and listen for FFE4's notifications.

The protocol

Status

Status request is used to query some generic bulb parameters, like power status, device version, color or predefined mode id. Status query is done in "write and listen" manner, so it will not work in non-interactive gatttool mode (you won't be able to see the result).

Request

Type Write and listen
Write to FFE9
Notification from FFE4
Payload Constant, [0xEF, 0x01, 0x77]
Notification See the description below

Notification description

Resulting notification must be 12 bytes long.

  1. result[0] must be equal to magic constant 0x66
  2. result[1]: ???
  3. result[2]: power status:
    • 0x23 is for "ON".
    • 0x24 is for "OFF".
  4. result[3]: mode:
  5. result[4]: ???
  6. result[5]: speed
  7. result[6]: red color component
  8. result[7]: green color component
  9. result[8]: blue color component
  10. result[9]: ???
  11. result[10]: device version
  12. result[11] must be equal to magic constant 0x99

Examples

Magic ??? Power Mode ??? Speed R G B ??? Version Magic Description
0x66 0x14 0x23 0x41 0x21 0x1F 0xFF 0x00 0x00 0x00 0x03 0x99 Static red color
0x66 0x14 0x23 0x41 0x21 0x1F 0x00 0xFF 0x00 0x00 0x03 0x99 Static green color
0x66 0x14 0x23 0x41 0x21 0x1F 0x00 0x00 0xFF 0x00 0x03 0x99 Static blue color
0x66 0x14 0x23 0x41 0x21 0x1F 0x5A 0x00 0x9D 0x00 0x03 0x99 Static violet color
0x66 0x14 0x23 0x27 0x21 0x1F 0x00 0x00 0xFF 0x00 0x03 0x99 Built‑in mode 0x27 at speed 0x1F (the slowest possible)
0x66 0x14 0x23 0x34 0x21 0x10 0x00 0x00 0xFF 0x00 0x03 0x99 Built‑in mode 0x34 at speed 0x10 (fast)
0x66 0x14 0x24 0x34 0x21 0x10 0x00 0x00 0xFE 0x00 0x03 0x99 Turned off built‑in mode 0x34 at speed 0x10 (fast)

Power

Query for current status

Power status can be known from FFF3 characteristic.

Request

Type Direct read
Read from FFF3
Read result 1. 0x3B when the bulb is off
2. 0xFF when the bulb is on

Set current status

Power status can be set via FFF1 and FFF2 characteristics. It's a two step process: first you write 0x04 in FFF1 and then you set power status in FFF2. The requests are done with 200ms interval.

Requests

Type Write
Write to FFF1
Payload 0x04

…wait 200ms…

Type Write
Write to FFF2
Payload 1. 0x00 turn off
2. 0x3F turn on

Example

Request Action
gatttool -b B4:99:4C:2A:0E:4A --char-write-req -a 0x0017 -n 04 &&
sleep 0.2s &&
gatttool -b B4:99:4C:2A:0E:4A --char-write-req -a 0x001a -n 00
				
Turn the bulb off
gatttool -b B4:99:4C:2A:0E:4A --char-write-req -a 0x0017 -n 04 &&
sleep 0.2s &&
gatttool -b B4:99:4C:2A:0E:4A --char-write-req -a 0x001a -n FF
				
Turn the bulb on

Static color mode

Static color mode is set via write request to FFE9 characteristic.

Request

Type Write
Write to FFE9
Payload See below

Payload description

Payload must be 7 bytes long.

  1. payload[0] must be equal to magic constant 0x56
  2. payload[1]: red color component
  3. payload[2]: green color component
  4. payload[3]: blue color component
  5. payload[4] must be equal to magic constant 0x00
  6. payload[5] must be equal to magic constant 0xF0
  7. payload[6] must be equal to magic constant 0xAA

Examples

Magic R G B Magic Magic Magic Description
0x56 0xFF 0x00 0x00 0x00 0xF0 0xAA Static red color
0x56 0x00 0xFF 0x00 0x00 0xF0 0xAA Static green color
0x56 0x00 0x00 0xFF 0x00 0xF0 0xAA Static blue color
0x56 0x5A 0x00 0x9D 0x00 0xF0 0xAA Static violet color

Built-in mode

Built-in mode is set via write request to FFE9 characteristic.

Request

Type Write
Write to FFE9
Payload See below

Payload description

Payload must be 4 bytes long.

  1. payload[0] must be equal to magic constant 0xBB
  2. payload[1]: build-in mode
  3. payload[2]: speed
  4. payload[3] must be equal to magic constant 0x44

Examples

Magic Mode Speed Magic Description
0xBB 0x27 0x1F 0x44 Built‑in mode 0x27 at speed 0x1F (the slowest possible)
0xBB 0x34 0x10 0x44 Built‑in mode 0x34 at speed 0x10 (fast)

Clock

Query for current clock value

Current clock can be read from FE01 characteristic. Epoch start for the bulb is 2000-01-01 00:00:00; every time you turn the electricity off (on a hardware level, not like described above) the clock is reset to that value.

Request

Type Direct read
Read from FE01
Read result See below

Response

The response is 7 bytes long.

  1. result[0]: seconds
  2. result[1]: minutes
  3. result[2]: hours (24 hours format)
  4. result[3]: day of month, starting from 1
  5. result[4]: month (1 is Jan., 2 is Feb., etc)
  6. result[5]: lower byte of the year
  7. result[6]: upper byte of the year

Example

gatttool -b B4:99:4C:2A:0E:4A --char-read -a 0x0086
Characteristic value/descriptor: 08 36 01 01 01 df 07
Seconds Minutes Hours Date Month Lower year Upper year Description
0x08 0x36 0x01 0x01 0x01 0xDF 0x07 01/01/2015 01:54:08

Set clock value

Current clock can be set by writing FE01 characteristic (the same that is used to query clock).

Request

Type Write
Write to FE01
Payload See below

Payload description

Payload must be 7 bytes long.

  1. result[0]: seconds
  2. result[1]: minutes
  3. result[2]: hours (24 hours format)
  4. result[3]: day of month, starting from 1
  5. result[4]: month (1 is Jan., 2 is Feb., etc)
  6. result[5]: lower byte of the year
  7. result[6]: upper byte of the year

Example

gatttool -b B4:99:4C:2A:0E:4A --char-write -a 0x0086 -n 3b1f011e01df07
Seconds Minutes Hours Date Month Lower year Upper year Description
0x3b 0x1F 0x01 0x1E 0x01 0xDF 0x07 01/30/2015 01:31:59

Magic constants

Built-in modes

  1. 0x25: Seven color cross fade
  2. 0x26: Red gradual change
  3. 0x27: Green gradual change
  4. 0x28: Blue gradual change
  5. 0x29: Yellow gradual change
  6. 0x2a: Cyan gradual change
  7. 0x2b: Purple gradual change
  8. 0x2c: White gradual change
  9. 0x2d: Red, Green cross fade
  10. 0x2e: Red blue cross fade
  11. 0x2f: Green blue cross fade
  12. 0x30: Seven color stobe flash
  13. 0x31: Red strobe flash
  14. 0x32: Green strobe flash
  15. 0x33: Blue strobe flash
  16. 0x34: Yellow strobe flash
  17. 0x35: Cyan strobe flash
  18. 0x36: Purple strobe flash
  19. 0x37: White strobe flash
  20. 0x38: Seven color jumping change

Speed

Some operational modes take a speed parameter that controls how fast the colors are changed. 0x01 is the fastest, 0x1F is the slowest.