Reverse Engineering Govee Smart Lights

Reverse Engineering Govee Smart Lights
Photo by Zishan khan / Unsplash

Getting started

First we need to enable bluetooth logging on the smartphone, for me it was in

Settings > Developer options > Enable Bluetooth HCI snoop log

Now we activate bluetooth and use the govee app. I also started a screen recording to make debugging easier later on!

Exporting the log

Now to find out where the log is generated we can use adb:

adb shell cat /etc/bluetooth/bt_stack.conf

and search for BtSnoopFileName=/data/log/bt/btsnoop_hci.log which reveils the folder, but its not generated as a single file, there are multiple logs suffixed with timestamps, so we simply download the whole folder

adb pull /data/log/bt

Now we load the hci log into Wireshark and filter for the device to make things easier:

We can now see the data of the packets but to make debugging easier I exported the packets as json

because that way I can build a little "log debugger" tool that helps me to see which packets are sent at what time in the screen recording:

First contact

Before we start looking at the actual data transfer we need to find out some BLE (bluetooth low energy) ids. I'm using nodejs with @abandonware/noble.

We simply start scanning for bluetooth devices and it shows up:

Now we connect to the device and ask for the available services and characteristics. The trick is to wait a at least 100 ms after connecting, otherwise we receive an empty array.

We receive a whole lot of services and characteristics:

service 1800
characteristic 2a00 (Device Name)
characteristic 2a01 (Appearance)
characteristic 2a04 (Peripheral Preferred Connection Parameters)
characteristic 2ac9 (null)

service 1801
characteristic 2a05 (Service Changed)

service 000102030405060708090a0b0c0d1910
characteristic 000102030405060708090a0b0c0d2b10
characteristic 000102030405060708090a0b0c0d2b11

service 02f0000000000000000000000000fe00
characteristic 02f0000000000000000000000000ff03
characteristic 02f0000000000000000000000000ff02
characteristic 02f0000000000000000000000000ff01
characteristic 02f0000000000000000000000000ff00

If we take a look at a write request we know which service and characteristics are the ones we need:

service 000102030405060708090a0b0c0d1910
write characteristic: 000102030405060708090a0b0c0d2b11
read characteristic: 000102030405060708090a0b0c0d2b10

Analyzing the traffic

The first thing that is quite noticeable are lots packages which are send at a constant interval:

HUAWEI Mate 20 lite -> Govee_H6054_1146
0200001b0017000400521400aa33000000000000000000000000000000000099
Govee_H6054_1146 -> HUAWEI Mate 20 lite
0200201b00170004001b1000aa33000000000000000000000000000000000099

This is a keepalive loop, but to make the log less confusing we hide them for now.

Next noticeable pattern is that package data always starts with OxAA, 0x33 or 0xA3

Let's take a look at the packet that is send when we turn on the lights:

3333110000000000000000000000000000000001
33     -> the packet type "power"
  33   -> the command "power"
    1  -> turn on light nr. 1
     1 -> turn on light nr. 2

Packets are always padded to a total length of 20 bytes, where the last byte is a checksum. By taking a few different packages and trying around a bit I found out that the checksum is calculated by taking all bytes and performing an XOR operation:

function hexify(x) {
    let toReturn = x.toString(16)
    return toReturn.length < 2 ? '0' + toReturn : toReturn
}

function prepareMsg(bytes) {
    while (bytes.length < 19) bytes.push(0);

    let checksum = Number(bytes[0]);
    bytes.slice(1).forEach(byte => {
        checksum ^= Number(byte);
    });

    return Buffer.from([...bytes, checksum].map(hexify).join(""), "hex");
}

Packet types

By looking at the video and the corresponding packets I could extract the following packet types:

33 33
xx state (0x10, 0x01 or 0x11)
Toggle power
33 04
xx brightness (0 - 100)
Global brightness
 33 05 04 xx           
          |            
          +--- scene id
Switch scene
 33 05 0a xx             
          |              
          +--- diy group?
DIY mode
 33 05 13 xx xx            
          |  -             
          |  +- mode       
          +---- sensitivity
Music mode
 33 05 15 01 xx xx xx 0000000000 xx xx               
             |  |  |  |          |  |                
             |  |  |  |          |  +- segment info 1
             |  |  |  |          +-----segment info 2
             |  |  |  +----------------padding       
             |  |  +-------------------b             
             |  +----------------------g             
             +-------------------------r             
Set rgb color of segments
 33 05 15 02 xx xx xx                 
             |  |  |                  
             |  |  +- brightness 0-100
             |  +---- segment info 1  
             +------- segment info 2  
Set brightness of segments
 33 05 15 033 xx ... xx                               
              |      |                                
              |      +- brightness 0-100 of segment 1 
              +-------- brightness 0-100 of segment 12
Set brightness of segments
a300010a020426500000010001ff0000801414a7 
a30102e21405ff0000ff7f00ff9107ff7f00ff3a
...
a3ff1700fc000080000000000000000000000037

 packet 1                                                      
 a3 00 01 xx ... xx                                            
    |  |  |  |   |                                             
    |  |  |  |   +- checksum                                   
    |  |  |  +----- data of first packet                       
    |  |  +-------- amount of packets including start and end  
    |  +----------- write start                                
    +-------------- packet number 0                            
                                                               
 packet 2                                                      
 a3 01 ... xx                                                  
    |  |   |                                                   
    |  |   +------- checksum                                   
    |  +----------- data of second packet                      
    +-------------- packet number 1                            
                                                               
 packet 3                                                      
 a3 ff ... xx                                                  
    |  |   |                                                   
    |  |   +------- checksum                                   
    |  +----------- data of last packet                        
    +-------------- write end                                  
multi packet write
  04 xx xx xx xx xx xx xx ...                                         
  |  |  |  |  |  |        |                                           
  |  |  |  |  |  |        +-- other colors                            
  |  |  |  |  |  +----------- color 1 (r, g, b)                       
  |  |  |  |  +-------------- color bytes length (one color = 3 bytes)
  |  |  |  +----------------- speed                                   
  |  |  +-------------------- style mode                              
  |  +------------------------style                                   
  +-------------------------- diy                                     

this is then sent in a multi packet write
diy data
04 diy
ff combo style
xx style mode
xx speed
xx color bytes length
xx xx xx ... colors

04 = diy
xx = first diy style
xx = first diy mode
xx = second diy style
xx = second diy mode

this is then sent in a multi packet write
diy combo data

It is available as npm package:

govee-lightbar
Govee H6054 bluetooth toolkit. Latest version: 1.0.1, last published: 2 minutes ago. Start using govee-lightbar in your project by running `npm i govee-lightbar`. There are no other projects in the npm registry using govee-lightbar.