Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FYI: Computing Scene Codes #11

Open
wez opened this issue Dec 31, 2023 · 50 comments
Open

FYI: Computing Scene Codes #11

wez opened this issue Dec 31, 2023 · 50 comments
Labels
Enhancement New information regarding a product

Comments

@wez
Copy link

wez commented Dec 31, 2023

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
Copy link

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

@wez
Copy link
Author

wez commented Jan 12, 2024

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.

@egold555
Copy link
Owner

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

@egold555 egold555 added the Enhancement New information regarding a product label May 15, 2024
@loebi-ch
Copy link

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

@egold555 egold555 pinned this issue May 22, 2024
@Hauty9
Copy link

Hauty9 commented Nov 5, 2024

Hello @wez !

I have the same question as @loebi-ch about how to calculate the scene code. Are you able to give us a step by step of what you mean when you say:

Convert to hex to produce: 0x27cf which you can break into two bytes and swap around, adding on to a scene mode packet then zero-pad out to 19 bytes + checksum.

I understand how to convert decimal to hex but get lost when you say to break into two bytes and swap around. I also do not understand the zero-pad out to 19bytes + checksum.

I would love to use this for my Govee permanent lights via the LAN API which has very little control to it.

Please let me know if you can give further instructions on how to calculate the scene codes.

Thanks!

Braden

@AlgoClaw
Copy link

AlgoClaw commented Nov 14, 2024

@Hauty9 Here are notes I took when I figured this out. Hope it helps.

Using the example of the scene "Forest"

Scene = Forest
Cloud API = 130
Offset = Cloud API - 128 = 2
Hex Offset = hex(Offset) = 0002
Hex Scene Prefix = 33 05 04
Hex Command = Hex Scene Prefix + Hex Offset(3,2) + Hex Offset(1,2) = 33 05 04 02 00
Checksum = XORchecksum(Hex Command) = 30
Pad = 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Combined = Hex Command + Pad + Checksum = 33 05 04 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 30
Combined_No_Space = 3305040200000000000000000000000000000030
BT Command = base64(Combined_No_Space) = MwUEAgAAAAAAAAAAAAAAAAAAADA=

At the step "Hex command", you take the offset (0002), break it into 2 parts (00) and (02), then switch them around (0200). I think that is the part you are stuck at.

Calculate the XORChecksum of "Hex Command" here: https://tinkererway.dev/the_dev_calc/xor_crc_calc https://www.scadacore.com/tools/programming-calculators/online-checksum-calculator/

Calculate the base64 of the hex "Combined_No_Space" here: https://base64.guru/converter/encode/hex

@Hauty9
Copy link

Hauty9 commented Nov 16, 2024

@AlgoClaw Thanks for the explanation, however I think I'm still a bit lost on some parts.

Where do you get the Hex Scene Prefix from? Does this number change per scene or is it always the same.

For the Cloud API, is the number the scene ID or ParamID?

I'm pulling the scene information my Govee permanent outdoor lights.

My "forest" scene has an id of 10745 and ParamID of 17950

Thank you for your help!

@AlgoClaw
Copy link

AlgoClaw commented Nov 18, 2024

@Hauty9

  1. The scene prefix code is the same for any "scene". There are different prefixes if you are setting the mode to "color", "music", "DIY", etc. I have no idea what those other prefixes are. But, if you are setting a predefined "scene", the scene code prefix is always "33 05 04". That is my understanding, at least.

  2. Ehh, for the cloud API, I don't really remember... I don't think it ever lined up properly. My use of the term "cloud API" may not be correct (sorry). I was grabbing the number by pulling the data from Govee.

I have several H61A8, so I can pull the data using:

`curl "https://app2.govee.com/appsku/v1/light-effect-libraries?sku=H61A8" -H 'AppVersion: 5.9.20' -s > govee_H61A8.json'

or, if you want to filter for just the "sceneName" and "sceneId", use:

'curl "https://app2.govee.com/appsku/v1/light-effect-libraries?sku=H61A8" -H 'AppVersion: 5.9.20' -s | jq '[.data.categories[].scenes[] | {name: .sceneName, sceneId: .sceneId}]' > govee_H61A8_scenes.json'

For the H61A8, the "Forest" scene has "sceneId" 130, and dozens of different "scenceParamId". I think sceneId is the critical one. If I remember correctly, the scene codes only translated properly a few times. If you figure that part out, please post here to let me (and everyone else) know.

I was keeping track of my H61A8 stuff here (https://docs.google.com/spreadsheets/d/1FokCgrgi34qqEEiy1-_AeeroNMDFz-83XSapXxNVXFI/edit?usp=sharing), but I got bored and moved on after a while.

Post the model number of your lights and I can pull the data for it and see if I can help.

@Hauty9
Copy link

Hauty9 commented Nov 18, 2024

@AlgoClaw

Thank you for all the explanations! I used postman to pull the information about the scenes from Govee. I did:
POST https://openapi.api.govee.com/router/api/v1/device/scenes
{
"requestId": "uuid",
"payload": {
"sku": "H805A",
"device": "Device_ID"
}
}

That returned all the scene information for my lights. For mine, the "forest" scene returns like this:
{
"name": "Forest",
"value": {
"id": 10745,
"paramId": 17950
}

However, Any of my DIY Scenes come back with a a 8 number value and not an ID or paramId.

I have the Permanent Outdoor Elite series. H805A

Do all your scenes only have a 3 number value?

Thanks!

@AlgoClaw
Copy link

@Hauty9

Do all your scenes only have a 3 number value?

Most have 3 digits, but not all. A dozen-or-so have 4 and 5 digits. For example, the newly added "Thanksgiving" has sceneId 15332. Other examples "Dreamlike":7610 "Undersea King":8400 "ARRAKIS":10067.

my DIY Scenes come back with a 8 number value and not an ID or paramId.

How are you getting info for DIY scenes? The public API should not have anything specific to your setup. Also note, "DIY" scenes may have a different prefix.

We are nearing the end of my knowledge about this stuff. Most of what I know is from reading @wez 's comments and posts on the subject and then a little trial-and-error from trying to do it myself.


At this point, you are probably just going to have to go through each number individually to see what the output is. For H61A8, only "Sunrise", "Sunset", and "Forest" worked as expected. The 100+ I tried after did not line up.

Govee is not making it easy. The "WLAN Guide" they released provides only top-level generic information (https://app-h5.govee.com/user-manual/wlan-guide). However, I was playing in the app last night and found some additional stuff that might bring insight.

It seems "Razer Chroma" is now able to control Govee lights through LAN communication. If you go to -- Govee app > "Home" tab > human silhouette in bottom-right > "Local Services" -- it will open a "User Guide" for how to interact with Razer Chroma. It also certainly uses LAN connections, as the guide specifies that the "LAN Control" option must be enabled for each device and Razer Chroma must be running on the same network.

I have no idea what Razer Chroma is, but this may provide a much easier way to interact.

@Hauty9
Copy link

Hauty9 commented Dec 3, 2024

@AlgoClaw

This is all very interesting. I use Postman to pull all the scenes from the API. The POST command looks like this:

https://openapi.api.govee.com/router/api/v1/device/scenes

In the body of my POST command is:
{
"requestId": "uuid",
"payload": {
"sku": "H805A",
"device": "Device ID I found in the Govee App"
}
}

That POST request will return all the scene information.
I have yet to see a scene ID with less than 5 digits. I am able to trigger these scenes via the cloud API with the 5 digit ID and paraID but would rather have the control be local

My Thanksgiving scene outputs like this:

"name": "Thanksgiving",
"value": {
"id": 10775,
"paramId": 17980

For my DIY scenes I use the same POST as above but I replace "scenes" with diy-scenes" and I get a list of all my DIY scenes that are associated with that device.

I got all my information on how to get the scene information from this link: https://developer.govee.com/reference/get-light-scene

How are you pulling information for each scene?

I don't much about Razor Chroma but sounds very interesting if it uses local control!

@AlgoClaw
Copy link

AlgoClaw commented Dec 5, 2024

@Hauty9

API

Ah, I see you are using Govee's official API with your own API key. Hence, you are able to pull info about your account and your configuration (and your custom made DIY scenes).

The info I get is simply by using the no-key-required public API that @wez posts at the very top of this thread. You can pull the info at https://reqbin.com/post-online if you do not have a CLI to work with. For example, you can enter the command:

curl "https://app2.govee.com/appsku/v1/light-effect-libraries?sku=H805A" -H 'AppVersion: 999999'

This specifies the model number "H805A" (as a parameter) and the "AppVersion" "999999" (as a header). If you do not specify an "AppVersion", the return message is simply "service is busy please try again later". So, I tried with an arbitrarily high number "999999". I also tried with "0" to see if the results were different, and they were.

So you don't have to do this yourself, I posted the results for 3 models (H61A8, H7039, H805A), with AppVersion 0 and 999999 here https://github.com/AlgoClaw/Govee/tree/main.

In the 999999 AppVersion for the H805A (https://github.com/AlgoClaw/Govee/blob/main/H805A_2024-12-04_AppVer999999), the code for "Thanksgiving" is the following (lines 1728-1767):

{
                "sceneId": 10775,
                "iconUrls": ["https://d1f2504ijhdyjw.cloudfront.net/img/5d449e7ad3e54350b9ab9e6a242efcd3-new_light_btn_scenes_thanks_giving%403x.png", "https://d1f2504ijhdyjw.cloudfront.net/img/7d5682af58f3e8c4f53f78e42dfc7e76-new_light_btn_scenes_thanks_giving_press%403x.png", "https://d1f2504ijhdyjw.cloudfront.net/img/2970975f8989fce8e1970624c207cb08-new_light_btn_scenes_thanks_giving_dark%403x.png"],
                "sceneName": "Thanksgiving",
                "analyticName": "Thanksgiving",
                "sceneType": 2,
                "sceneCode": 0,
                "scenceCategoryId": 0,
                "popUpPrompt": 0,
                "scenesHint": "",
                "rule": {
                    "maxSoftVersion": "",
                    "minSoftVersion": "",
                    "maxHardVersion": "",
                    "minHardVersion": "",
                    "maxWifiSoftVersion": "",
                    "minWifiSoftVersion": "",
                    "maxWifiHardVersion": "",
                    "minWifiHardVersion": ""
                },
                "lightEffects": [{
                    "scenceParamId": 17980,
                    "scenceName": "",
                    "scenceParam": "BSAyAAADAgH/AAP3FBQD/BQD/5AH/3gH/zoHFAD5AACAASA1AAADAgH/AAP3FBQD/BQD/5AH/3gH/zoHFgD5AACAASlQAAABAgH/AAP3FBQD8hQG/wAA//8AAP8AAP//AAD/iwD/EgD5AAD8ASAAAAABAgH/GQH0FBQA8hQD/10H/5EH//8AAACAAACAASlVAAABAgH/AAP3FBQD8hQG/wAA//8AAP8AAP//AAD/iwD/EAD5AAD8AQ==",
                    "sceneCode": 11286,
                    "specialEffect": [],
                    "cmdVersion": 1,
                    "sceneType": 2,
                    "diyEffectCode": [],
                    "diyEffectStr": "",
                    "rules": [],
                    "speedInfo": {
                        "config": "",
                        "speedIndex": 0,
                        "supSpeed": false
                    }
                }],
                "voiceUrl": "",
                "createTime": 1712114992028
            }

LAN Commands (H61A8)

I went back through my attempt to organize the working LAN commands for the H61A8 (https://docs.google.com/spreadsheets/d/1FokCgrgi34qqEEiy1-_AeeroNMDFz-83XSapXxNVXFI). It seems through firmware updates Govee removed nearly all commands that I identified for a scene. Previously, I identified about 45 commands that would start a scene. Now, I can only identify 13. So, even if this was a good to send LAN commands, Govee forces updates that remove them (or change them).

Separately, I previously linked the incorrect website to calculate the checksum. The site you want to use is https://www.scadacore.com/tools/programming-calculators/online-checksum-calculator/. This is the only site I can find that gives the correct result.

Looking back at the UI I made in NodeRed, I can control power, brightness, and color using LAN commands with the (very) basic info Govee provides in their guide (https://app-h5.govee.com/user-manual/wlan-guide).


LAN Commands (Generally)

Based on Craig K's (@Mavrrick) comment here https://developer.govee.com/discuss/660c7e59aa38b40025f0cf53, it seems multiple of these commands are required to be sent in a single message in order to initiate a scene.

He seems to be much more active in the development and understanding of the LAN commands.
See:

I think the H805A is here (he does not use model numbers):

@Hauty9
Copy link

Hauty9 commented Dec 13, 2024

@AlgoClaw

Thank you for all the detailed examples and descriptions! I find it kind of strange that you can pull scene ids with two different APIs. Maybe this is par for the course for other APIs but kind of wish Govee would spell it out more and make a more robust local API. Or if there was a way to pass the scenes to a Matter controller, that would solve alot of issues. I have mine integrated into SmartThings but it only has basic control and I have not found a way to trigger any scenes within SmartThings.

I will have to check out some of the links you provided and see how much time I want to put into this if Govee updates kill off some scene IDs. I have it working pretty good right now with the cloud API but I'm a fan of local control and would love to have it all locally done.

I do wish the cloud API had the ability to trigger "tap to run" scenes or groups as well. I have two sets of permanent outdoor lights to cover my house that I would love to trigger at the same time via the API but have not found a way to do that. I'm not a fan of sending the same scene to one controller then another controller with a second or two delay. The lights look mildly out of sync depending on the scene.

@AlgoClaw
Copy link

@Hauty9 @wez

SOLVED?

Okay, I think I figured it all out and completely reverse engineered the scene codes. Given just the publicly available API (no key required), you can calculate the required commands to send for any given scene.

Here is an explanation of how to do it: https://github.com/AlgoClaw/Govee/blob/main/decoded/explanation

Here is a bash script to generate a JSON for any given model: https://github.com/AlgoClaw/Govee/blob/main/decoded/govee_decoded.sh
(Let me apologize in advance -- this is some of the sloppiest coding I have ever done).

I pre-made jsons for three models.
H61A8: https://github.com/AlgoClaw/Govee/blob/main/decoded/govee_H61A8_scenes_with_commands.json
H7039: https://github.com/AlgoClaw/Govee/blob/main/decoded/govee_H7039_scenes_with_commands.json
H805A: https://github.com/AlgoClaw/Govee/blob/main/decoded/govee_H805A_scenes_with_commands.json

Now, I just need @wez to integrate this into https://github.com/wez/govee2mqtt

Let me know if anyone else has success with these.

@loebi-ch
Copy link

Wow @AlgoClaw, it seems as you've found the holy grail :-) Congratulations for solving the Govee puzzle.
I don't unterstand why developers make it so tricky for others... The history showed us that OpenSource has great potential and I don't understand why companies are doing proprietary stuff as this. They would sell much more of their physical devices if they had a more straightforward local API...

@AlgoClaw
Copy link

@loebi-ch You're preaching to the choir. I spent most of my winter break on this. They could have saved hundreds of hours (between all of us) if they just released the documentation on how to use their devices.

I recently bought another TP-Link smart dimmer switch (I have ~40 TP-Link smart devices already). Apparently TP-Link devices now require cloud authentication credentials to control the devices locally. Needless to say, I will be returning the new switch and I blocked Internet access to my existing switches. I spent a few hours looking for good alternatives, but came up short.

It seems we are moving backwards when it comes to user ownership and local control. This battle may be won, but the war is not looking good. C'est la vie, we fight on nonetheless.

@egold555
Copy link
Owner

This is amazing. Thank you all for all the work on this!

Happy to add/merge any of this documentation into this repo if you think it benefits the community.

@AlgoClaw
Copy link

@egold555 I hereby waive all rights in the linked documents and code. Please copy/modify/reuse whatever you'd like.

@Hauty9
Copy link

Hauty9 commented Dec 30, 2024

@AlgoClaw,

Nice work!! I appreciate you spending the time to figure this out!

I do have a question about how you are sending the commands. I was looking a the Christmas scene for the H805A:

"name": "Christmas",
"code": 11271,
"params_b64": "AykAAhQFAgH/GQAAAAAC+jIG/zgA/38AAP8AAAAAAP///wAAFADvAAAAACMAAhQFAAH/GQHmMjIB9DIE8QAdAP8AAP//////FgDyEgDdACAAAAABAgH/cAPbFBQA9xQD/wAAAAAAAP8AEQCAAAAAAA==",
"hex_cmd": [
"a3000107020329000214050201ff19000000007b",
"a30102fa3206ff3800ff7f0000ff0000000000d6",
"a302ffffff00001400ef00000000230002140595",
"a3030001ff1901e6323201f43204f1001d00ff70",
"a3040000ffffffffff1600f21200dd0020000053",
"a30500010201ff7003db141400f71403ff0000ec",
"a3ff00000000ff00110080000000000000000032",
"330504072c000000000000000000000000000019"
],
"b64_cmd": [
"owABBwIDKQACFAUCAf8ZAAAAAHs=",
"owEC+jIG/zgA/38AAP8AAAAAANY=",
"owL///8AABQA7wAAAAAjAAIUBZU=",
"owMAAf8ZAeYyMgH0MgTxAB0A/3A=",
"owQAAP//////FgDyEgDdACAAAFM=",
"owUAAQIB/3AD2xQUAPcUA/8AAOw=",
"o/8AAAAA/wARAIAAAAAAAAAAADI=",
"MwUEBywAAAAAAAAAAAAAAAAAABk="
]
},
{

What are you sending to the controller from this and how are you sending it? I have yet to get any kind of scene commands to trigger locally. I can get standard on/off from the documented local API to work but keep failing with the local scene control. I can send the lights this command to turn on and it works great:

{"msg":{"cmd":"turn","data":{"value":1}}}

But when I try a scene commands like this:

{"msg":{"cmd":"ptReal","data":{"command":["AixQAAAFAgL/fgPMKBTMTAHMFBQCABQFL6r/ntr+/6U0/38A/wAAAAAAAAAAACxVAAAFAgL/fgPMKBTMTAHMFBQCABQF/wAA/38A/6U0ntr+L6r/AAAAAAAAAA=="]}}}

I get nothing. Any suggestions?

@AlgoClaw
Copy link

@Hauty9

You want to use the "b64_cmd" data (from the JSON I generated) for the command field. For Christmas, try the "b64_cmd" data you posted, like this:

{"msg":	{"cmd":"ptReal","data":	{"command": ["owABBwIDKQACFAUCAf8ZAAAAAHs=","owECjIG/zgA/38AAP8AAAAAANY=","owL///8AABQA7wAAAAAjAAIUBZU=","owMAAf8ZAeYyMgH0MgTxAB0A/3A=","owQAAP//////FgDyEgDdACAAAFM=","owUAAQIB/3AD2xQUAPcUA/8AAOw=","o/8AAAAA/wARAIAAAAAAAAAAADI=","MwUEBywAAAAAAAAAAAAAAAAAABk="]}}}

I personally use a docker instance of Node-Red for the bulk of my home automation. There are a bunch of UI nodes that pull data and format it and send it to a "UDP out" node -- it is messy.

But, I send the scene commands the same way as I send power, brightness, and color commands. So, if you have those functions working, you are doing it right. It just seems the command you are sending is not correct.

wez added a commit to wez/govee2mqtt that referenced this issue Dec 30, 2024
This commit adopts the excellent reverse engineering work
carried out by @AlgoClaw in egold555/Govee-Reverse-Engineering#11 (comment)
as the way that we apply scenes.

This should result in fewer weird glitches and more accurate
application of the defined scenes.

My testing of this has been light; there is a unit test that
verifies the example from the walkthrough of the process,
and I used the CLI interface to apply a couple of scenes:

```console
./target/debug/govee lan-control --ip 192.168.1.201 scene Breathe
Loading environment overrides from "/home/wez/wez-personal/govee-rs/.env"
Computed ["o/8BAQIAAAAAAAAAAAAAAAAAAF4=", "MwUECgAAAAAAAAAAAAAAAAAAADg="]
```
@wez
Copy link
Author

wez commented Dec 30, 2024

@AlgoClaw this is great, thank you! I've pushed a version of this in govee2mqtt: wez/govee2mqtt@5de5b50

It seems to work when used via the CLI interface. I haven't tested it beyond that at this time, so I haven't made a release with these bits yet.

@wez
Copy link
Author

wez commented Dec 31, 2024

The most recent govee2mqtt release now prefers to use the LAN API with this technique

@loebi-ch
Copy link

Thank you @AlgoClaw for solving the puzzle and thank you @wez for integrating it so fast. It works like a charm. The scenes now change without any delay thanx to using the local API.

I'm wondering if we could find the corresponding local API commands for changing the single segments and setting DIY scenes and snapshots.

@Hauty9
Copy link

Hauty9 commented Dec 31, 2024

@AlgoClaw

Thank you for the explanation! It works great now! I'm really excited to bring local control to the lights as the cloud seems unreliable. This is a game changer for my setup!

To push this a bit further....have you found a way to trigger any "tap to run" scenes or turn a group on and off? I have two sets of H805a lights on my house that I want them paired together but have not found a way to do so outside of the Govee app. When I send a command to one string then the other string they are out of sync. If I use the app with the "tap to run" scenes or turn the group on and off they are closer in sync but have yet to figure out a way to do it via the API.

@AlgoClaw
Copy link

AlgoClaw commented Dec 31, 2024

@Hauty9

Glad to hear it. It is nice to know this works on different models too.

For groups, I have not found a way to access a "group" defined in the app. Instead, I define my own groups locally on my sever (in Node-Red).

As far as syncing goes, I send the command to all my devices (or a subset of devices) simultaneously. I am not sure if it is precisely simultaneous, but 80% of the time, the lights are synced together. In Node-Red, this is accomplished by linking one input node to multiple outputs ("Govee1", Govee2", etc., see below)
image
My setup is likely not what most people are using.

How are you sending the commands? what language/script type?

Can you make a function/script for setting a scene to device? Example:
setgovee(device, scenename)

Then make a script to call a series of that function for each light ("light1", "light2", "light3")? Example:
setgovee("light1", "Halloween-A")
setgovee("light2", "Halloween-A")
setgovee("light3", "Halloween-A")

@Hauty9
Copy link

Hauty9 commented Dec 31, 2024

@AlgoClaw

I use a home control/automation system called RTI. There is a driver designed to send UDP commands to a specified IP. So for my case I would need two instances of the driver in my system as the driver only has capabilities to send to a single IP for each instance.

What I'm actually just thinking about, that I will need to test, is that since its local control I can use two instances of the driver and send commands to each Govee controller in less than a second. In RTI you build macros with the driver commands you want to use. I'm thinking since its local and two different Govee controllers, the commands might not get lost like they do when I send commands to the cloud API. I found I needed to add a couple second delay when sending commands to cloud API or else the second command was lost.

I gotta do some re-programming and testing but I'm thinking the speed of local control along with two driver instances might be the key to get the devices as close to sync'd up as possible.

@AlgoClaw
Copy link

I did not give proper appreciation and credit before. The techniques I used were based overwhelmingly on the work already performed by @wez and @Mavrrick.

Specifically, @wez 's:

  • Posting of the API to pull scene data (described in the first comment here).
  • Documentation of the Bluetooth commands, formation of the hex codes, conversion to base64, JSON format/wrapping, and UDP communication (described in the first comment here)
  • Excellent Home Assistant integration via https://github.com/wez/govee2mqtt and speedy updates to include local control. (I have actually starting using HA again because of this).

And, @Mavrrick 's

  • Insight that multiple commands are required to set most scenes (based on his code here and posts on Govee's forum)
  • Library of commands (I have limited experience with Hubitat, but relied on those libraries for confirming results)

Initially, I was manually sniffing Bluetooth packets, extracting the payload, converting the hex to base64, then searching github to see if anyone else already posted that exact base64 string. Each time, there would be one-or-two results @Mavrrick included in his libraries. This let me know the conversion was correct -- but also that the number of commands needed for a scene matched the number of Bluetooth packets sent.

After combining what @wez and @Mavrrick provided, I actually considered the problem "solved". However, we would have to manually sniff packets for every scene on every device--and manually re-sniff whenever Govee updated or added new scenes.

The only contribution I really made was to try deciphering the "scenceParam" to see if it matched the Bluetooth hex commands--which it did, with some additional work.

Also, thank you to @Hauty9 . I gave up on this several times but kept coming back because @Hauty9 kept the issue active (bumping it to the top of my inbox).

@loebi-ch
Copy link

loebi-ch commented Jan 1, 2025

@AlgoClaw what Bluetooth sniffer and how have you used it to sniff the packages sent to the Govee device?

@Mavrrick
Copy link

Mavrrick commented Jan 1, 2025

@AlgoClaw This is amazing work, but i have a few questions as i am having some unexpected results using the script output from this process.

First are you familiar with the new ptURL command and does this take any account for that. I have yet to find any way to work with scenes that use the ptURL command at all. This ptURL command is found on a few new devices like the Net Lights, the Curatin Lights 2, and the Christmas Lights Gen 2

Second how many devices were checked. I am running into inconsistencies with what I had already extracted. Simply put when using your script to extract for the H6066 device i get one command string that is fairly different from what i had already extracted. I thought the difference would be related to maybe a speed value, but it doesn't appear to be working.

My process pulls in a command string of

"cmd": "["owABAgQnFR0BAAEFAAIAD57//x0=", "o/9lAAAAAAAAAAAAAAAAAAAAADk=", "MwUEDQoAHQAAAAAAAAAAAAAAACg="]"

Your script pulls in a command string of

"b64_cmd": [
  "owABAgISAAAAACcVHQEAAQUAApg=",
  "o/8AD57//2UAAAAAAAAAAAAAAKg=",
  "MwUEDQoAAAAAAAAAAAAAAAAAADU="
]

The extra \ and " for data handling aside the strings have some significant differences. I am really curious to hear from others on how this works for them.

The way my extract works is by using a call to the AWS service Govee uses with their Phone app. That app set of data when going to the home page and lists various things including Tap-To-Runs. Those tap to runs include in their data a section for iotmsg that includes the entire command. For the most part that has worked well to retrieve working commands, but is a pain. I was really excited to use this method to generate the list in full. The commands though are not matching up. I have tried several different commands now and none of them have matched and they don't appear to work.

Ofcourse my testing so far has been with commands generated by your script. Do you believe the script may have some issues?

@AlgoClaw
Copy link

AlgoClaw commented Jan 2, 2025

@loebi-ch

My Bluetooth sniffing method is very low-tech. I use a setting available in the "Developer options" on Android.

Steps:

  1. Disable Bluetooth (if enabled)
  2. Enable packet capture
    Settings > System > Developer options > Enable Bluetooth HCI snoop log > Enabled
  3. Enable Bluetooth
  4. Perform Bluetooth actions
  5. Disable Bluetooth
  6. Disable packet capture
    Settings > System > Developer options > Enable Bluetooth HCI snoop log > Disabled

After step 6, the log file should be located at:
/data/misc/bluetooth/logs/btsnoop_hci.log

I then copy this to my computer and open it in WireShark.

NOTE 1: When you enable and disable the HCI snoop log, Bluetooth has to be disabled. If Bluetooth is enabled on either side, the log file (likely) will not save.

NOTE 2: A lot of people on various forums on the internet say your phone needs to be rooted to capture Bluetooth data. I don't know if this is true. My phone is rooted, but I don't see why that is required for the above method.

NOTE 3: Make sure you are sending commands to the Govee device via Bluetooth. I wasted so much time accidentally sending commands via the cloud. When you are in the Govee app, controlling a device, there is a Bluetooth or WiFi symbol at the top, make sure you are using Bluetooth. If you want to force Bluetooth, you can disable WiFi and cell data.


@Mavrrick

  1. I have no experience with the ptURL command. In fact, I only add "ptReal" because of @wez 's first comment. The other commands provided by Govee in their documentation are "scan", "turn", "brightness", "devStatus", and "colorwc" -- which are all somewhat descriptive. But, "ptReal" and "ptURL" are not very descriptive. What is "ptURL" used for? Is it used instead of "ptReal" for those newer devices?

  2. I spot checked ~30 scenes on the H61A8 and ~10 on the H7039 (the only two models I own). Further, it seems Hauty9 has had success with the H805A.

  3. For the H6066, does the b64_cmd from my script work? When I convert the commands from your method (from base64 to hex) the results are:

a30001020427151d010001050002000f9effff1d
a3ff650000000000000000000000000000000039
3305040d0a001d00000000000000000000000028

This is interesting. For the last command, there is the same prefix (330504) and converted sceneCode (0d0a). However, there is a "1d" in the following section... This would imply that the fixed padding (28x zeros, 14x hex zeros) is not correct and that some data may be present there (at least sometimes). I add padding per wez's comment above "zero-pad out to 19 bytes" -- but this may not be true in all cases.

"1d" (hex) = "29" (dec) = "HQ==" (base64)

None of those seem to match anything from the raw data. I'll think on it.

  1. Interesting. You are logging the commands via the cloud method. Try logging the "mirage" scene via Bluetooth (as described above) and see if the results are the same? If not, that would be even more interesting.

  2. The script could have many issues. It would not surprise me at all. That being said, the commands work on three different model numbers (that I am aware of, so far).

    After I made the discovery around 6pm on the 30th, I wrote up the explanation document, then stayed up until 4am writing the bash script. As time went on, I cared less and less about readability, cleanliness, and conciseness and just wanted results that made sense. Towards the bottom of the script, in the "Format JSON" section, you can really see how lazy I got... I use a nasty combination of regex find-and-replace commands with a series of "jq" commands (which I have never used before), and needless writing the data to different files -- just to move some characters around.

    I am an amateur/hobbyist programmer and even I am kind of embarrassed by that script. I might try to clean up up in the coming week or so. Please feel free to re-write it in any language of your choice. I can work with any language (except Python) with a preference to work in the Linux CLI (hence my tendency for shell scripts).

    I know at least some commands line up -- this is how I confirmed my results initially. For example, if you search the first base64 command for "Forest" on GitHub (https://github.com/search?q=%22owABBwIDJgABAAoCAf8ZAbQKCtk%3D%22&type=code), there are 4 results for code in your repositories.

@loebi-ch
Copy link

loebi-ch commented Jan 2, 2025

I hope it's okay to post that inside this Github issue...

I invested a few hours to try to set the segments of a Govee light by local API.

My use case: Most of the time I want to set my Govee lights to a static gradient and not to a fancy animated scene.
So far, I created snapshots in the Govee app and used the Cloud API to set the light to the appropriate snapshot. But this is very awkward, because you have to create snapshots for each individual light and there is a big latency when using the cloud API.

My knowledge is based on the very useful and detailed post of @Mavrrick found here: https://www.loxforum.com/forum/faqs-tutorials-howto-s/446672-govee-ble-local-api-segmentsteuerung-szenen that explains in detail how the "Grafiti mode" works. Thank you Mavrrick!

Here is my code in my favourite coding language (C#). It's quite straightforward and easy to translate to other programming languages.

//------------ CONFIGURATION----------------------------------------
string deviceIpAddress = "192.168.1.36";
string[] gradientColors = ["ff8800", "ff0000", "a035ff"]; //sunset
//string[] gradientColors = ["ff0000", "00ff00", "0000ff"]; //rainbow
//string[] gradientColors = ["ff7114"]; //warm white

//------------------------------------------------------------------------

//Define segments depending on specified gradient colors count
int[] segmentSizes;
switch (gradientColors.Length)
{
    case 1:
        segmentSizes = [14];
        break;
    case 2:
        segmentSizes = [7, 7];
        break;
    case 3:
        segmentSizes = [5, 4, 5];
        break;
    case 4:
        segmentSizes = [4, 3, 3, 4];
        break;
    case 5:
        segmentSizes = [3, 3, 3, 3, 2];
        break;
    case 6:
        segmentSizes = [3, 2, 2, 2, 2, 3];
        break;
    case 7:
        segmentSizes = [2, 2, 2, 2, 2, 2, 2];
        break;
    default:
        Console.WriteLine("[ERROR] You have to specify at least 1 and max 7 gradient colors!");
        return;
}

//Reverse gradient colors (as Govee lights start from bottom to top and I want to define it from top to bottom)
gradientColors = gradientColors.Reverse().ToArray();

//Generate Govee LAN API command
string command = "01 pc"; //pc = packet count (will be replaced afterwards when we know how many packets we have)
command += "03"; //Grafiti mode
command += "09"; //Animation direction (0a: Down; 09: Up; 02: Cycle; 13: Fading; 0f: Sparkle; 14: Breathe)
command += 0.ToString("X2"); //speed of animation (0-100)
command += 0.ToString("X2"); //intensity of background (0-100)
command += "000000"; //background color RGB in hex
command += " " + segmentSizes.Length.ToString("X2"); //Segment count
int pixelNumber = 0;
for (int segmentIndex = 0; segmentIndex < gradientColors.Length; segmentIndex++) //for each segment
{
    command += " " + segmentSizes[segmentIndex].ToString("X2"); //Segment size
    command += " " + gradientColors[segmentIndex]; //Segment color RGB in hex
    for (int i = 0; i < segmentSizes[segmentIndex]; i++) //for each pixel in the segment
    {
        command += " " + pixelNumber.ToString("X2"); //Pixel number in hex
        pixelNumber++;
    }
}

//Split Govee LAN API command into packages of 17 bytes (20 bytes - 2 starting bytes - 1 checksum byte)
command = command.Replace(" ", "");
List<string> packages = Enumerable.Range(0, (int)Math.Ceiling((decimal)command.Length / 34)).Select(i => command.Substring(i * 34, Math.Min(34, command.Length - i * 34))).ToList();

//Replace "pc" (packet count) in the first package by the actual count of all packages
packages[0] = packages[0].Replace("pc", packages.Count.ToString("X2"));

List<string> base64Packages = [];
for (int packageIndex = 0; packageIndex < packages.Count; packageIndex++)
{
    string package;
    if (packageIndex < packages.Count - 1)
    {
        //Add "a3" and the number of the package to the beginning of the package
        package = "a3" + packageIndex.ToString("X2") + packages[packageIndex];
    }
    else
    {
        //For the last package we add "a3ff" to the beginning of the package
        package = "a3ff" + packages[packageIndex];
        package = package.PadRight(38, '0');
    }

    //Calculate XOR checksum of the package and add it to the end of the package
    byte xorTotalByte = 0;
    for (int i = 0; i < package.Length; i += 2)
    {
        xorTotalByte ^= byte.Parse(package.Substring(i, 2), NumberStyles.AllowHexSpecifier);
    }
    package += xorTotalByte.ToString("X2");
    package = package.ToLower();

    //Convert package to base64
    List<byte> _bytes = [];
    for (int i = 0; i < package.Length; i += 2)
    {
        _bytes.Add(Convert.ToByte(package.Substring(i, 2), 16));
    }
    base64Packages.Add(Convert.ToBase64String(_bytes.ToArray()));
}

//Last package always has to be "MwUKIAMAAAAAAAAAAAAAAAAAAB8="
base64Packages.Add("MwUKIAMAAAAAAAAAAAAAAAAAAB8=");

// Build payload to send to Govee device
JObject jData = new()
{
    ["msg"] = new JObject
    {
        ["cmd"] = "ptReal",
        ["data"] = new JObject
        {
            ["command"] = new JArray(base64Packages)
        }
    }
};
byte[] bytes = Encoding.ASCII.GetBytes(jData.ToString());
Console.WriteLine("Sending command to Govee light @ " + deviceIpAddress + ":4003\n[" + string.Join(", ", base64Packages.Select(t => "\"" + t + "\"").ToList()) + "]");
UdpClient udpClient = new();
udpClient.Send(bytes, bytes.Length, deviceIpAddress, 4003);

I use the calculated Govee command(s) inside Home Assistant by defining a shell_command in configuration.yaml:

shell_command:
  govee_set_sunset_gradient_in_office: echo '{"msg":{"cmd":"ptReal","data":{"command":["owABAwMJAAAAAAADBaA1/wABAsQ=", "owEDBAT/AAAFBgcIBf+IAAkKCyg=", "o/8MDQAAAAAAAAAAAAAAAAAAAF0=", "MwUKIAMAAAAAAAAAAAAAAAAAAB8="]}}}' | nc -w 2 -u 192.168.1.36 4003

And I call it in an automation like this:

action: shell_command.govee_set_sunset_gradient_in_office

This is a very static approach, because I couldn't use any parameters in the shell_command (for IP address and the gradient colors).

Now I'm thinking about exposing an individual service in Home Assistant that's taking the IP address and the segment colors so that I can call:

action: whatever_service.set_gradient
data:
  ip: 192.168.1.36
  colors:
    - ff8800
    - ff0000
    - a035ff

Maybe that's also interesting for others and I think it would be quite easy for @wez to expose such a service, if this is a need also for others...

What do you think?

@wez
Copy link
Author

wez commented Jan 2, 2025

think it would be quite easy for @wez to expose such a service

I'm not sure if it is possible to expose a home assistant service via mqtt, but it would be doable to expose a REST API endpoint in govee2mqtt that could do the heavy lifting.

@wez
Copy link
Author

wez commented Jan 2, 2025

FWIW, over in wez/govee2mqtt#353 some users are noting that this enhanced scene setting technique doesn't work for every device.

One frustration I have with Govee's control scheme is that there is no direct response on whether any given command did a thing. It would be great if there was a way to determine that a scene had been applied--I think this must be possible (perhaps via BLE or IoT?) because I noticed in the Govee app the other day that it reports the scene name that was applied via ptReal when you first drill down into a device.

@Mavrrick
Copy link

Mavrrick commented Jan 2, 2025

@wez It would be interesting to see what devices do and what devices don't work.

I have a theory on that after taking a look at the devices @AlgoClaw tested with. My theory is that this is about device type as much as it anything else. All of the devices @AlgoClaw appears to have validate with are String/strip type devices. What i mean by that is they all run in a series of pixels with no fancy geometric lighting effects with them. The H6066 device i initially started testing with is a Govee Glide Hexa Pro kit. The H6066 didn't work at all with any of the commands passed.

I just ran the script for one of my H6172 strips and compared it to my existing command list I had extracted a while ago. The spot checking I did indicated everything was matching up exactly. So at the least that LED Strip matches up perfectly.

I feel like i need to go through and test the other types of devices to see how close the commands match up.

@AlgoClaw

The ptURL command was something that I found recently with the help of a user as they were having a problem performing the scene extraction in my integration my process on Hubitat. Simply put when my process calls the AWS endpiont we get back a long string that includes all of the Home page data for the Govee Home app. The integration parses down and find a specific group for Tap-To-Runs. Then each tap to run has each action reviewed for certain criteria that make it a Govee Scene, Snapshot, or DIY. Part of that criteria was looking for the ptReal command. Once that was found it would extract out the iotmsg and parse out the cmd value for further processing and saving in the integration.

After a far amount of back and forth and confirming the user had everything right we dug into the raw data to find the ptURL command was in place of ptReal. The command structure was also very different. Below you can see some examples of what was stored from the extraction process for a H70B5. Even worse is that unlike ptReal, the ptUrl command doesn't seem to work when submitted via the LAN Api

        "1003": {
            "cmdType": "ptReal",
            "name": "Star",
            "cmd": "[\"MwUEJwAAAAAAAAAAAAAAAAAAABU=\"]"
        },
        "1004": {
            "cmdType": "ptReal",
            "name": "Meteor",
            "cmd": "[\"MwUEJgAAAAAAAAAAAAAAAAAAABQ=\"]"
        },
        "1005": {
            "cmdType": "ptUrl",
            "name": "Aurora",
            "cmd": "[\"/xQHAABodHRwOi8vYXBwLmdvdmVlLmNvbS9iZmYtZGV2aWNlL3YxL2VmZmVjdC9iaWctY29tbWFuZD9pZD04MDAy\", \"MwUEkyEAAAAAAAAAAAAAAAAAAIA=\"]"
        },
        "1006": {
            "cmdType": "ptUrl",
            "name": "Reindeer",
            "cmd": "[\"/5QIAABodHRwOi8vYXBwLmdvdmVlLmNvbS9iZmYtZGV2aWNlL3YxL2VmZmVjdC9iaWctY29tbWFuZD9pZD0yNjg4OA==\", \"MwUElCEAAAAAAAAAAAAAAAAAAIc=\"]"
        }

This ptURL command is very new and so far I have only seen it on a few devices that were released in the last few months.

Interestingly your process does create a command for the ptURL scenes, but when i reviewed them they were very , very long. like 80+ commands vs 7-8 of most scenes on other devices.

@loebi-ch I think you maybe giving me credit for something I wasn't associated with, or at least nothing in that link. In anyway i don't think that was me, maybe another Mavvrick :)

@AlgoClaw
Copy link

AlgoClaw commented Jan 2, 2025

@Mavrrick @loebi-ch @wez

In the link provided by @loebi-ch, there is a link to another post worth looking at https://blog.coding.kiwi/reverse-engineering-govee-smart-lights/

Also, @Mavrrick on the loxforum thread, at the bottom (most recent post) there is mention that the prefix is "a4" for the "Govee Christmas tree chain H70C4". I wonder if this change would work for those devices currently not working? Simply changing the prefix to "a4" (instead of "a3"). "a3" works on my devices -- so one of y'all could give it a try.


It's unfortunate it does not work for all models. :/

Regarding device feedback, I have found several quarks/bugs. For any scene requiring multiple commands, if you send only the last command (e.g., "MwUE1AAAAAAAAAAAAAAAAAAAAOY=" for "Forest"), the lights will restart their already-selected scene (but they do not change to "Forest").

Further, if you send only the last command, the app will show the scene changed to "Forest" -- even though it did not actually change (if you have scene selection in the app already open, you have to exit out of the device and re-enter the device's scene selection).

Conversely, if you send all commands except the last command, the scene does successfully change -- but the change is not reflected in the app. Effectively, that last command is optional for control.

If you wanted to be devious, you could mix-and-match. For example, using the H61A8, the first 7 commands below set "Forest" without the last command to change the setting in the app. Then, I add the last command for "Meteor shower". Thus, the scene "Forest" is set on the device, but the app will show the scene "Meteor shower" is selected.

"owABBwIDJgABAAoCAf8ZAbQKCtk=",
"owECyBQF//8AAP//////AP//lBI=",
"owL/ABQBlgAAAAAjAAIPBQIB/wo=",
"owMUAfsAAAH6CgQE/wC0/wBH/7M=",
"owT/4/8AAAAAAAAAABoAAAABAl0=",
"owUB/wUByBQUAu4UAQD/AAAAAJI=",
"o/8AAAAAAAAAAAAAAAAAAAAAAFw=",
"MwUE5AAAAAAAAAAAAAAAAAAAANY="

So, if you really want to gaslight somebody into thinking a scene goes by a different name, this is how to do it :)

Also, I noticed when using the scenes set via cloud integration in govee2mqtt, the app does not show any selected scene. That is, the cloud integration via govee2mqtt is the equivalent of sending all commands except the last command. So, there is no way to tell in the Govee app what has been set.


What does the "devStatus" command return? Node-RED is problematic if I remove the container and need to takeover ports 4002 and 4003 from govee2mqtt. @wez is there some way for me to enable verbose reporting for ports 4002 and 4003 in the container logs?

@wez
Copy link
Author

wez commented Jan 2, 2025

@AlgoClaw:

@wez is there some way for me to enable verbose reporting for ports 4002 and 4003 in the container logs?

You can set the log filter to govee::lan_api=trace:

RUST_LOG=govee::lan_api=trace

(set that in the env for the docker container, or if you're using the hass addon, there is an option for this in the UI)

and look for process_packet for the port 4002 traffic:

https://github.com/wez/govee2mqtt/blob/bb4ba8e99c1e17b2598df74cc5a50028d4435369/src/lan_api.rs#L451-L454

and send_request for the port 4003 traffic:

https://github.com/wez/govee2mqtt/blob/bb4ba8e99c1e17b2598df74cc5a50028d4435369/src/lan_api.rs#L196

@Mavrrick
Copy link

Mavrrick commented Jan 2, 2025

May have found a pattern or at least something for the H6066

I took the command created by the script, and the command i already had for a scene and converted them both back to Hex

Here is the hex code for the script and what i had for scene Mirage

My command:

a30001020427151d010001050002000f9effff1d
a3ff650000000000000000000000000000000039
3305040d0a001d00000000000000000000000028

Script

a300010202120000000027151d01000105000298
a3ff000f9effff650000000000000000000000a8
3305040d0a000000000000000000000000000035

I see three differences on line 1. The first is related to a change from 02 to 04 in positions 9 and 10. I think The procedure indicates that should always be 02 so i suspect this is one error of concern. How do we determine that. Then I noticed in the script output it looks like there is a value from positions 11-10 that is missing from the command I received from the method I use. If those characters are removed then the rest of the command looks like it matches up. Lastly there seems to be a new value in the padded 0's in the final line I am suspicious about it relating to the speed for the scene, but need to further test that.

I validated again with scene Dreamland and saw the same thing happen. The Characters in position 11-20 where slightly different but regardless from the script, but they were missing from my working command. Further testing is needed, but this looks promising

@AlgoClaw
Copy link

AlgoClaw commented Jan 2, 2025

@Mavrrick

Yeah, I wrote about the "1d" in the padding in my reply to you (#11 (comment))

These 2 sites provide good insight into what may be happening in that last command:

(they have good info on how to change sections too @loebi-ch). The first link is effectively the same process I went through.

However, I am 99% sure that the last command is not actually required to set the scene -- it only changes the status in the app (see #11 (comment))

The "Mirage" info for the H6066 has the following "scenceParam":

EgAAAAAnFR0BAAEFAAIAD57//2U=

Converted to Hex, this is:

120000000027151d010001050002000f9effff65

The correct commands (you posted) are:

a30001020427151d010001050002000f9effff1d
a3ff650000000000000000000000000000000039
3305040d0a001d00000000000000000000000028

Thus, most of the first line can be taken from the converted scenceParam:

first line : a300010204 27151d010001050002000f9effff 1d

scenceParam: 1200000000 27151d010001050002000f9effff 65

@Mavrrick
Copy link

Mavrrick commented Jan 2, 2025

@AlgoClaw
Yep that is how i took that.

I just converted some data from the H6079 Floor Lamp Pro to see if it followed these same layout. Ofcourse it doesn't at all.

I reviewed the Aurora scene

Hex from the script is:

    "hex_cmd": [
      "a3000106020a0225000000020201cc5401001407",
      "a3011403f2140326ff9d00000000000000008094",
      "a3020000800000020001ff34000000080201ec0e",
      "a3031b03f9010103ea010807fe6208fe660000aa",
      "a304008b00ff8b00ff0000000012ff0012ff10b7",
      "a3ff00f40000f20000020001ff000000000000a6",
      "3305044115000000000000000000000000000066"
    ],

I then took my command:

            "104": {
                "name": "Aurora",
                "cmd": "["MwEBAAAAAAAAAAAAAAAAAAAAADM=", "owABBgoCJQAAAAICAcxUAQAUFBE=", "owED8hQDJv+dAAAAAAAAAACAAIA=", "owIAgAAAAgAB/zQAAAAIAgHsGxU=", "owMD+QEBA+oBCAf+Ygj+ZgAAALE=", "owSLAP+LAP8AAAAAEv8AEv8QALc=", "o//0AADyAAACAAH/AAAAAAAAAKY=", "MwUEQRUAAgAAAAAAAAAAAAAAAGQ="]"
            },

Reverted back to Hex it looks like this:

3301010000000000000000000000000000000033
a30001060a0225000000020201cc540100141411
a30103f2140326ff9d0000000000000000800080
a30200800000020001ff34000000080201ec1b15
a30303f9010103ea010807fe6208fe66000000b1
a3048b00ff8b00ff0000000012ff0012ff1000b7
a3fff40000f20000020001ff00000000000000a6
3305044115000200000000000000000000000064

So the strange thing with this device is it has a totally different first line. I went back and reviewed all of the scenes in the file for that device and they all start with that command. So that first line will be the same on all of them. The other thing I noticed is that the positions 9 and 10 on the line starting with a300 which the script will put 02 have a0. From what i can tell this time if 02 is just not added and everything shifts a few positions.

This keeps getting more complicated with Govee's lack of consistency.

@AlgoClaw
Copy link

AlgoClaw commented Jan 2, 2025

@Mavrrick

That first line (3301010000000000000000000000000000000033) is just the "on" command and not part of the scene command (https://github.com/BeauJBurroughs/Govee-H6127-Reverse-Engineering).

I think everything can be decoded at this point. It is just a matter of getting enough samples to determine what every byte of the hex code is.

  1. Gather known/working commands from Bluetooth and/or AWS, convert to Hex.

  2. Get "scenceParam" from the raw data for each device, convert to Hex.

  3. Compare (1) and (2) above, and fill in the blanks.

I think we are most of the way there. I opened pull and merge requests to start posting the raw data in this repository so we can easily access the "scenceParam" for each scene of each device.

@AlgoClaw
Copy link

AlgoClaw commented Jan 2, 2025

@Mavrrick

As an example, "Aurora" for the H6079, has the following "scenceParam":

CgIlAAAAAgIBzFQBABQUA/IUAyb/nQAAAAAAAAAAgAAAgAAAAgAB/zQAAAAIAgHsGwP5AQED6gEIB/5iCP5mAAAAiwD/iwD/AAAAABL/ABL/EAD0AADyAAACAAH/

and "sceneCode":

5441

(https://github.com/AlgoClaw/Govee-Reverse-Engineering/blob/master/raw_data/H6079_2025-01-02_scenes_raw.json)


Convert "scenceParam" to Hex:

0a0225000000020201cc540100141403f2140326ff9d0000000000000000800000800000020001ff34000000080201ec1b03f9010103ea010807fe6208fe660000008b00ff8b00ff0000000012ff0012ff1000f40000f20000020001ff

Rearrange this, and you get:

________0a0225000000020201cc5401001414__
____03f2140326ff9d00000000000000008000__
____00800000020001ff34000000080201ec1b__
____03f9010103ea010807fe6208fe66000000__
____8b00ff8b00ff0000000012ff0012ff1000__
____f40000f20000020001ff________________
________________________________________

This exactly matches the commands you posted (I removed the first line because that is simply an "on" command).

The prefix for each line is the same as before:

a300____0a0225000000020201cc5401001414__
a30103f2140326ff9d00000000000000008000__
a30200800000020001ff34000000080201ec1b__
a30403f9010103ea010807fe6208fe66000000__
a3058b00ff8b00ff0000000012ff0012ff1000__
a3fff40000f20000020001ff________________
________________________________________

The second to last line is padded for zeros? (this is a guess, we need more data to confirm)

NOTE: This is where my code goes wrong, I add too many zeros.

The prefix for each line is the same as before:

a300____0a0225000000020201cc5401001414__
a30103f2140326ff9d00000000000000008000__
a30200800000020001ff34000000080201ec1b__
a30403f9010103ea010807fe6208fe66000000__
a3058b00ff8b00ff0000000012ff0012ff1000__
a3fff40000f20000020001ff00000000000000__
________________________________________

The missing segment of the first line is "0106" -- which is the same as before, where "06" is the count of command lines (lines starting with "a").

The "01" is fixed? (this is a guess, we need more data to confirm)

a30001060a0225000000020201cc5401001414__
a30103f2140326ff9d00000000000000008000__
a30200800000020001ff34000000080201ec1b__
a30403f9010103ea010807fe6208fe66000000__
a3058b00ff8b00ff0000000012ff0012ff1000__
a3fff40000f20000020001ff00000000000000__
________________________________________

The last line is the same method as before:

convert the sceneCode to hex (5441 --> 1541), then swap the two bytes to get "4115"

scene
prefix     code     00?    ??     padding?                     checksum
"330504" + "4115" + "00" + "02" + "000000000000000000000000" + "64"

And, add the checksum for everything else too.

So, here is what we know we can calculate now, given just the "scenceParam" and "sceneCode":

a300__060a0225000000020201cc5401001414__
a30103f2140326ff9d0000000000000000800080
a30200800000020001ff34000000080201ec1b15
a30403f9010103ea010807fe6208fe66000000b1
a3058b00ff8b00ff0000000012ff0012ff1000b7
a3fff40000f20000020001ff00000000000000a6
3305044115____000000000000000000000000__

We need to:

  • check if "01" is always in that first line.
  • check if "00" is always in the last line after the scene code.
  • figure out where that "02" in the last line is coming from

@Mavrrick
Copy link

Mavrrick commented Jan 3, 2025

That first line (3301010000000000000000000000000000000033) is just the "on" command and not part of the scene command (https://github.com/BeauJBurroughs/Govee-H6127-Reverse-Engineering).

I understand your logic in just wanting to exclude that, but keep in mind the command i have is a exact extraction from Govee for their Govee Home app from a Tap-To-Run. That tap to run must include a on/off command as the first command to be included. If this string is part of the command I would expect it to be there for a reason.

from your script the first line looks like:
a3000106020a0225000000020201cc5401001407
From my command the second line is:
a30001060a0225000000020201cc540100141411

Something is out of alignment:
a3000106020a0225000000020201cc5401001407

The command parts start two positions earlier in the command I have extracted. It looks like the bold characters above are just removed. that shifts every line two characters.

The final line does have what appears like some differences in the padding. I am going to test a few things today to see if i can validate what the differences are. I am wondering if brightness and/or speed make a differences in those values. I will run some more extractions today and see if i can get any clarity on that.

Feel free to take my LanSceneFiles files to convert working commands and compare. The only files that I wouldn't use are the Net_Lights(Derived from your script), and Curtain_Lights(known to be a problematic device), If you need to reconcile Model to device type in the file name you can look at the method getDevType() in library code the library code file Mavrrick.Govee_LAN_API.groovy

@Mavrrick
Copy link

Mavrrick commented Jan 3, 2025

@AlgoClaw or Wez. If you want to see the commands the way I extract them it can be done as follows. First open the Govee Home app and setup a tap to run with the govee scene, or snapshot you want to capture. These first commands will use your Govee Home app creds.

Windows:
curl -H "Content-Type: application/json" ^
"https://community-api.govee.com/os/v1/login" -d "{^
\"email\": \"email\",^
\"password\": \"password\"^
}"

Linux/Unix/MacOS:

curl --location 'https://community-api.govee.com/os/v1/login' \
--header 'Content-Type: application/json' \
--data '{
"email": "email",
"password": "password"
}'

This will return some data that looks like this.

{"message":"Login successful","status":200,"data":{"token":"eyJhbGciOiJIUzI1NiIsInRxxCI6IkpXVCJ9.eyJkYXRhIjp7ImFjY291bnQiOiJ7XCJhY2NvdW50SWRcIjpxIjxxNjY1NTZcxIixcIxVtYWlsXx6XCJdxYXZycmlja0Bob3RtYWlxLmNvbVwifSJ9LCJpYXQiOjE2ODIzMzk4MzcsImV4cCI6MTY4NDkzMTgzN30.wP7N087FGM5jY2xtAtBwBo3NWYxAbLS_uZeumPu2gws","headerUrl":"[https://d1f2504ijhdyjw.cloudfront.net/img/38e4fb1b508275e0145fb01fa908444f-user_crop.jpg","nickName":"Mavrrick","id":1766556,"expiredAt":1684931837263,"email":"mavrr](https://d1f2504ijhdyjw.cloudfront.net/img/38e4fb1b508275e0145fb01fa908444f-user_crop.jpg%22,%22nickName%22:%22Mavrrick%22,%22id%22:1766556,%22expiredAt%22:1684931837263,%22email%22:%22mavrr)

Take note of your token. And then use a tool like Postman to make a call as shown below

Windows:

curl -H "Authorization: Bearer token" ^
-H "appVersion: 5.6.01" ^
"https://app2.govee.com/bff-app/v1/exec-plat/home"

Linux/Unix/MacOS:

curl --location 'https://app2.govee.com/bff-app/v1/exec-plat/home' \
--header 'Content-Type: application/json' \
--header 'appVersion: 5.6.01' \
--header 'Authorization: Bearer token'

Now you just need to scan through the returned message for the tap-to run section that has the scene configured in the Govee Home app as a tap to run. Look for the part that has the oneclicks. For me it is down toward the bottom. Lastly look at the rule section and there you will find the various commands type it can use for the rule. The iotMsg is what contains the command for the LAN API command data. This ofcourse only works for devices you have, but it is something to help you or others validate the data the scripted conversion is producing.

           {
                "componentId": 11068607,
                "name": "Hubitat",
                "type": 1,
                "canManage": 1,
                "canDisable": 1,
                "oneClicks": [
                    {
                        "componentId": 11068607,
                        "name": "test2",
                        "planType": 0,
                        "siriEngineId": 3260297,
                        "presetId": 0,
                        "groupName": "",
                        "groupId": 0,
                        "desc": "",
                        "presetState": 0,
                        "type": 0,
                        "actionType": 3,
                        "allSort": null,
                        "iotRules": [
                            {
                                "cmdGroup": 0,
                                "deviceObj": {
                                    "name": "Glide Hexa Pro",
                                    "sku": "H6066",
                                    "device": "xxxxxx",
                                    "spec": "",
                                    "topic": "xxxxxx",
                                    "bleName": "xxxx",
                                    "bleAddress": "xxxxxxx",
                                    "versionSoft": "1.01.13",
                                    "versionHard": "3.01.01",
                                    "wifiSoftVersion": "2.05.08",
                                    "wifiHardVersion": "1.02.00",
                                    "goodsType": 96,
                                    "pactType": 1,
                                    "pactCode": 2,
                                    "subDevices": {},
                                    "ic": 6,
                                    "ic_sub_1": 0,
                                    "ic_sub_2": 0,
                                    "subDevice": "",
                                    "settings": null,
                                    "feastId": 0,
                                    "feastName": "",
                                    "feastType": 0,
                                    "isFeast": 0,
                                    "subDeviceNum": 0,
                                    "deviceSplicingStatus": 0,
                                    "deviceInstallCount": 0
                                },
                                "rule": [
                                    {
                                        "cmdType": 0,
                                        "deviceType": 2,
                                        "cmdVal": "{\"open\":1}",
                                        "iotMsg": "{\"msg\":{\"accountTopic\":\"xxxxxx\",\"cmd\":\"turn\",\"cmdVersion\":0,\"data\":{\"val\":1},\"transaction\":\"u_1735919174109\",\"type\":1}}",
                                        "blueMsg":"{\"bleCmd\":\"MwEBAAAAAAAAAAAAAAAAAAAAADM\=\",\"type\":\"switch\"}",
                                        "effect": null
                                    },
                                    {
                                        "cmdType": 3,
                                        "deviceType": 2,
                                        "cmdVal": "{\"scenceId\":0,\"scenceParamId\":0,\"scenesCode\":2573,\"scenesStr\":\"Mirage\"}",
                                        "iotMsg":"{\"msg\":{\"accountTopic\":\"xxxxxxx\",\"cmd\":\"ptReal\",\"cmdVersion\":0,\"data\":{\"command\":[\"owABAgQnFR0BAAEFAAIAD57//x0\=\",\"o/9lAAAAAAAAAAAAAAAAAAAAADk\=\",\"MwUEDQoAHQAAAAAAAAAAAAAAACg\=\"]},\"transaction\":\"u_1735749972342\",\"type\":1}}",
                                        "blueMsg":"{\"bleCmd\":\"owABAgQnFR0BAAEFAAIAD57//x0\=,o/9lAAAAAAAAAAAAAAAAAAAAADk\=\",\"modeCmd\":\"MwUEDQoAHQAAAAAAAAAAAAAAACg\=\",\"type\":\"scene\"}",
                                        "effect": null
                                    }
                                ]
                            }
                        ],
                        "execRules": [],
                        "updateTime": 1735919175420
                    }
                ],

@Mavrrick
Copy link

Mavrrick commented Jan 3, 2025

@AlgoClaw. I have looked at 4 devices now with a couple of scenes each. The one consistent problem seems to be around the first A300 line. Putting the Glide hexa pro to the side for now the discrepancies I am seeing are either in position 9-10 as your script assumes will always be 02, or positions 10 and 12 that seem to either advance the whole value forward or have a new character.

I also just had a new issue creep up with the Table Lamp 2 i tested. It appears that you may have a issue with your script dropping trailing zeros. The example I used was scene "Desert" the command i have extracted has an addtional line. When looking at the data it looks like the script has the last line with 6 years. My guess is they were padding and not what was actually part of the base64 to Hex conversion.

@Mavrrick
Copy link

Mavrrick commented Jan 6, 2025

I have been digging through the devices I have to see if I can make any headway on what how to get this working for more devices.

As @AlgoClaw pointed out above this is generally all about the first and the last line. So this is what I have found and validated with my integration.

In many cases the 02 in position 9 and 10 in the a300 line is replaced with something else for these devices as @AlgoClaw has already pointed out. It seems to be fairly consistent for each device though. So this is what i have derived from the devices I can test or validate with.

For H6078 Cylinder lamps the 02 in position 9 and 10 is replaced with "0c09" and then you start to add to that string from position third charter of the hex string

The H6022 cylinder table lamp is similar to the H6078, but it replaces position 9 and 10 with "585a"

The H6052 Table lamp which is a older version of the H6022 is slightly different as it replaces positions 9 and 10 with "07"

I have also looked at the H6066 Hexa Panel Ultra and H6065 Y Light devices. They are slightly different. They both replace 02 in position 9 and 10 with "04". Then they basically ignore the first 10 characters of the converted hex string and start to add the characters at position 11. This causes all of the parsing to shift 10 characters for the entire set of commands. The final line also has 2 parms it appears. They start right after the hex swapped scene code parm. I am still trying to figure out the first 2 charecters in position 11 and 12, but they don't seem to exactly be required. I suspect they are either related to speed, or direction based on the scene, but for now i default them to '00' which seems to work. The next two seem to be device specific. For the H6066 it is "2d" while for the H6065 "47" seem to be the right value. This is consistent across all of the scenes.

@Hauty9
Copy link

Hauty9 commented Jan 6, 2025

I am just catching up on all this and am super pumped the API is getting picked apart even more after @AlgoClaw breakthrough!!

"I spot checked ~30 scenes on the H61A8 and ~10 on the H7039 (the only two models I own). Further, it seems Hauty9 has had success with the H805A." - Yes I can confirm this works with the H805A. I didn't test every single scene but spot checked about 10 of them. There response time for two different Govee controllers receiving the same scene commands sent 1ms from each other has been very solid. So far its been a ton more reliable than the Cloud API!!

I'm super happy that this local control reflects in the app for each scene change. I still don't understand why the cloud API wouldn't trigger the app change. Very frustrating as that API is publicly documented and one would think the app would follow along when API calls were made.

I still gotta read through the rest of the all the posts. Did I see something about triggering tap to run scenes?!?! Anyways this is a great surprise to see when coming off a Holiday break. Nice work everyone!!

@Hauty9
Copy link

Hauty9 commented Jan 7, 2025

Something that popped into my head as I was reading through this is what models of Govee lights have been tested that work with these local scene commands? I tested the Govee permanent outdoor lights elite. I saw @Mavrrick point out that these local commands work on Net Lights, the Curtain Lights 2, and the Christmas Lights Gen 2 as well. Has anyone gotten any other Govee devices to work? I'm new to govee but the reason I got the Elite outdoor lights is that they support the Matter protocol. I believe the Net Lights Curtain 2 and Christmas lights Gen 2 do as well. Since Matter is local control, could that be the difference between some models working and other not? Could these commands be actually hitting Matter scene clusters or these devices might have a different local protocol than the other devices? Just throwing it out there.

@AlgoClaw
Copy link

AlgoClaw commented Jan 7, 2025

Sorry for the delay. I'm back to work now with very little free time (full time attorney).

--

@Mavrrick

With some effort, I converted all of your Lan_Scene_Files to include the hex version of the commands. Available here: Mavrrick_LAN_Scene_Files_hex

Questions regarding Mavrrick.Govee_LAN_API.groovy

What is the model number for the "Wall_Sconce"?

You have the same model ("H70BC") for "XMAS_Light" and "TV_Light_Bar", which is right? and what is the other supposed to be?

--

I am storing raw downloaded files here (pulled directly from the public API): Govee/raw

And, there are modified version with the parameter in hex form added, here: Govee/raw/withparams

--

This is the important part

Now, the hex parameter (Govee/raw/withparams) can be compared to the extracted commands known to work (Mavrrick_LAN_Scene_Files_hex)

I am still 99% confident a method to create the command can be generalized for all device models. You just need a sufficient number of examples for each model (~5 should work). I started keeping notes over on my website as it is easier to make changes quickly.

(these notes are very rough)

https://disbar.red/note/Govee%20Decoded%202

Basically, for each device model, there are a few constants (hopefully) that need to be looked up, then the commands can be reformulated.

For example, for the H6092 (from the API, from Mavrrick)

  1. Convert the "scenceParam" from base64 to hex.
  2. Remove the leading 1 byte (always "21")
  3. Insert the prefix "02 56 0b" before it (always)
  4. Then, there is no suffix for the H6092
  5. Prefixes for each multi-command lines are needed ("a3 00 01" for the first line, "a3 01" for the second line, etc.)
  6. Padding is needed to complete the command on the last line (starting with "a3 ff")
  7. The final commands (starting with 33 05 04) may not follow the normal pattern, but I have not had time to look into it. I also think the last command is optional anyway.

You may not hear from me for a week or so.

--

Feel free to copy, modify, etc. whatever you want.

@loebi-ch
Copy link

loebi-ch commented Jan 7, 2025

I'm new to govee but the reason I got the Elite outdoor lights is that they support the Matter protocol. I believe the Net Lights Curtain 2 and Christmas lights Gen 2 do as well. Since Matter is local control, could that be the difference between some models working and other not?

@Hauty9 I'm absolutely sure that this has to do with the new Matter standard. I've got some new Nanoleaf device as well that works with Matter now, and also there the Home Assistant Nanoleaf integration doesn't work anymore. I'm in contact with a developer from Nanoleaf and he told me that they had to change the internal API due to Matter and Thread, but they are working hard on it to make it work again with Home Assistant (one thing that I don't see with Govee - here some brave individuals as @AlgoClaw invest their valuable time...).

Somehow it's ridiculous: We have a new standard that should make it easier to integrate with everything and actually the Matter devices mostly can be integrated very easily, BUT ONLY with the simplest functions as turn on/off, set one color and brightness. If you want to use more functionality as effects, palettes, segments and so on, you cannot rely on Matter and have to use proprietary integrations which now don't work anymore possibly due to Matter.

Hard times for Smart Home enthusiasts.

@Mavrrick
Copy link

Mavrrick commented Jan 7, 2025

@AlgoClaw
The wall sconce is H6033 or H6038.

H70BC is a curtain Light. I think you meant H70CB which does appear to be a Xmas Light Gen 1 or simply a string light device. It was duplicated. I will remove it from the bad location. Fortunately, because of its location it is non impactful.

If you check out the main integration app and skip down to the method sceneExtract3() currently on line 578 you can see my code and how I am parsing everything to make it work. The method also uses some variables set between lines 53 and 68 that setup the unique criteria's that vary from your original method.

It is interesting you picked the H6092, or the Galaxy Projector device. That is one I haven't looked at myself yet and it totally slipped my mind.

The final commands (starting with 33 05 04) may not follow the normal pattern, but I have not had time to look into it. I also think the last command is optional anyway.

I can tell you with certainty that the final command is needed for devices that such as the H6066, and the H6065 devices. The scene commands work, but do not display properly without at least one of the extra tags on that last line.

@Hauty9 and @loebi-ch
I really don't believe that this has any relation to Matter. Nanoleaf may have built in some dependencies between Matter and their internal API, but the Govee Lan API appears to be completely independent. If anything, the Lan API we use is another control layer at the same level as Matter control. Matter also doesn't have from what I can tell any accommodations for Scenes/Light Effects. The Matter functionality is essentially the same as the Lan API but using a more standard way to get device updates. In my Govee Matter drivers I reverted back to LAN API for scene controls. It is more of a Hybrid driver.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Enhancement New information regarding a product
Projects
None yet
Development

No branches or pull requests

7 participants