egold555 / Govee-Reverse-Engineering

A central place to document reverse engineering Govee Products.
124 stars 22 forks source link

FYI: Computing Scene Codes #11

Open wez opened 8 months ago

wez commented 8 months ago

I've been poking at things and found something that I think you may find useful, and may be worth documenting here.

You can download a catalog of pre-defined scenes for a given sku; you need to pass the AppVersion header for it to return anything:

$ curl "https://app2.govee.com/appsku/v1/light-effect-libraries?sku=H6072" -H 'AppVersion: 5.6.01' -s

Which produces data like the following abbreviated excerpt:

{
  "message": "success",
  "status": 200,
  "data": {
    "categories": [
{
  "sceneId": 7691,
  "iconUrls": [
    "https://d1f2504ijhdyjw.cloudfront.net/deals-img/c1068ace12a82ee32333f5c35bbc154e-new_light_btn_scenes_four_color%403x.png",
    "https://d1f2504ijhdyjw.cloudfront.net/deals-img/9215bf8e3df86bd03eb32b93fd3f5b3b-new_light_btn_scenes_four_color_press%403x.png",
    "https://d1f2504ijhdyjw.cloudfront.net/deals-img/6b7e891d014ba5742fbbc02368e077e9-new_light_btn_scenes_four_color_dark%403x.png"
  ],
  "sceneName": "rainbow B",
  "analyticName": "rainbow B",
  "sceneType": 2,
  "sceneCode": 0,
  "scenceCategoryId": 0,
  "popUpPrompt": 0,
  "scenesHint": "",
  "rule": {
    "maxSoftVersion": "",
    "minSoftVersion": "",
    "maxHardVersion": "",
    "minHardVersion": "",
    "maxWifiSoftVersion": "",
    "minWifiSoftVersion": "",
    "maxWifiHardVersion": "",
    "minWifiHardVersion": ""
  },
  "lightEffects": [
    {
      "scenceParamId": 11837,
      "scenceName": "",
      "scenceParam": "ASkAAAAHAgH/gQD5FBQD+RQG/wAA/38A//8AAP8AAP//AAD/EADyAACAAA==",
      "sceneCode": 10191,
      "specialEffect": [],
      "cmdVersion": 1,
      "sceneType": 2,
      "diyEffectCode": [],
      "diyEffectStr": "",
      "rules": [],
      "speedInfo": {
        "config": "",
        "speedIndex": 0,
        "supSpeed": false
      }
    }
  ],
  "voiceUrl": "",
  "createTime": 0
},

],
"supportSpeed": 1
  }
}

The part of interest is the sceneCode in the lightEffects list; for the Rainbow above, ignore its direct sceneCode: 0 and look inside its lightEffects list for its sceneCode: 10191

Using some jq, we can produce a simpler list:

$ curl "https://app2.govee.com/appsku/v1/light-effect-libraries?sku=H6072" -H 'AppVersion: 5.6.01' -s | \
   jq '[.data.categories[].scenes[] | {name: .sceneName, code: .lightEffects[0].sceneCode}]'

outputs something like this excerpt:

[
  {
    "name": "Sunrise",
    "code": 2099
  },
  {
    "name": "rainbow B",
    "code": 10191
  },
]

Armed with that you can now construct a BLE packet that will activate a scene if you know its name. Taking that rainbow B example, its scene code is 10191 in decimal. Convert to hex to produce: 0x27cf which you can break into two bytes and swap around, adding on to a scene mode packet, similar to the others discussed in this repo:

0x33 0x05 0x04 0xcf 0x27

then zero-pad out to 19 bytes + checksum and voila, you have a packet that you can send either via BLE or via the LAN ptReal command that will activate that scene.

I figured this out by following https://github.com/bwp91/homebridge-govee/wiki/Scene%2C-Music%2C-DIY-Modes which suggests saving a short-cut for a scene in the govee app, and then plucks the corresponding base64 encoded version of the packet out of some data returned from another govee URL.

$ echo MwUEzycAAAAAAAAAAAAAAAAAANo= | base64 -d | xxd
00000000: 3305 04cf 2700 0000 0000 0000 0000 0000  3...'...........
00000010: 0000 00da                                ....

Staring at some other data from the new HTTP platform API that returns scene codes (https://developer.govee.com/reference/get-light-scene), I realized that the code was embedded in that packet.

LAN Protocol and ptReal

The Govee LAN Protocol doesn't document this, but you can send BLE packets to the device via the LAN protocol by encoding them as base64 packets and sending data like this to UDP port 4003 on the target device:

{
  "msg":{
    "cmd":"ptReal",
    "data":{
      "command": ["MwUEzycAAAAAAAAAAAAAAAAAANo="]
    }
  }
}
$ echo '{"msg":{"cmd":"ptReal","data":{"command":["MwUEzycAAAAAAAAAAAAAAAAAANo="]}}}' | \
    nc -u 192.168.1.100 4003
jstnkndll commented 8 months ago

Very Useful Thank You, for taking the time to document this and explain this.

wez commented 8 months ago

FWIW, it doesn't seem to work reliably for scene codes larger than 0xff, so this isn't 100%, but it does give a way to map from the list of known codes to data you can send to the device.

AlgoClaw commented 8 months ago

I am not able to get any codes to work on my H61A8 -- even if less than 0xff (255).

For the H61A8, "Sunrise" is 128, which yields a command of MwUEgAAAAAAAAAAAAAAAAAAAALI= (feel free to check me on that).

But, every time I push that command (or any other valid command), the scene pattern restarts. It does not change the scene to the one I set, it simply restarts the current scene. Further, if the command is invalid, nothing happens. So, I am pretty sure I am pushing the right command, it just doesn't change it.

Is this the only way to control scenes via LAN (that is publicly known)? Most scene codes for the H61A8 are larger than 255.

egold555 commented 4 months ago

This is awesome, thanks for this documentation!

Unsure if you think we should leave this as a open issue (Maybe we pin it) or is it worth adding a file / folder for documentation like this to the repo?

I am open to any and all ideas

loebi-ch commented 3 months ago

Hi @wez!

Yesterday I've got some Govee Floor Lamps Basic on my birthday and wanted to integrate them into my Home Assistant. Unfortunately it didn't work as easy as I expected. These are my first Govee devices. I encountered your name and your posts at different places and obviousley you're the man that knows the most about the propriatary Govee solutions. I integrated the lamps into HA with different addons and I also tried your Govee2MQTT addon which runs quite well, but faces some problems when it comes to setting colors onto single segments. Mainly it works, but since it's using the cloud, the reaction time is very bad, when setting segments 0..7 one by one. I'm a programmer and I quickly setup my own UDP server to check the local LAN API. It was no problem to discover the lamps and setting color and brightness, but no word about setting single segments in the manual. I nearly gave up and then discovered this post and the "ptReal" command. But I didn't get how to discover the payload for this command.

You write Convert to hex to produce: 0x27cf which you can break into two bytes and swap around, adding on to a scene mode packet, similar to the others discussed in this repo I understand how to find the appropriate scene code, but wrapping the hex code of this scene code around WHAT? How do I build the correct scene mode packet and calculate the checksum? Can you give me some hints?

My intention actually is to use my Govee Floor Lamps not with the predefined scenes, but just some static gradients. I don't like the animations. Maybe for a party, but in my everyday life I just want the lamps to shine in different static gradients. Do you think this will be possible localy without using the Govee app? Will these be anyhow possible with the LAN API?

Besides, thank you very much for all your efforts that you are putting in for the community!

Best regards Andy