From f2aef24b8a2d039ae45823fda65f65b28e8905fb Mon Sep 17 00:00:00 2001 From: Fefedu973 Date: Wed, 10 Sep 2025 05:36:04 +0000 Subject: [PATCH] Fixed govee direct mode control --- .../GoveeController/GoveeController.cpp | 55 ++++++++++++---- .../GoveeController/RGBController_Govee.cpp | 63 ++++++++++++++++--- 2 files changed, 97 insertions(+), 21 deletions(-) diff --git a/Controllers/GoveeController/GoveeController.cpp b/Controllers/GoveeController/GoveeController.cpp index 287da302e..ef252fff9 100644 --- a/Controllers/GoveeController/GoveeController.cpp +++ b/Controllers/GoveeController/GoveeController.cpp @@ -9,6 +9,7 @@ | SPDX-License-Identifier: GPL-2.0-only | \*---------------------------------------------------------*/ +#include #include #include "base64.hpp" #include "GoveeController.h" @@ -182,22 +183,48 @@ void GoveeController::SetColor(unsigned char red, unsigned char green, unsigned void GoveeController::SendRazerData(RGBColor* colors, unsigned int size) { - std::vector pkt = { 0xBB, 0x00, 0x00, 0xB0, 0x00, 0x00 }; - json command; - - pkt[2] = 2 + (3 * size); - pkt[5] = size; - pkt.resize(6 + (3 * size)); - - for(std::size_t led_idx = 0; led_idx < size; led_idx++) + /*-----------------------------------------------------*\ + | Do not send an empty frame (this was producing | + | length=2, count=0) | + \*-----------------------------------------------------*/ + if(size == 0) { - pkt[6 + (led_idx * 3)] = RGBGetRValue(colors[led_idx]); - pkt[7 + (led_idx * 3)] = RGBGetGValue(colors[led_idx]); - pkt[8 + (led_idx * 3)] = RGBGetBValue(colors[led_idx]); + return; + } + + /*-----------------------------------------------------*\ + | PT payload: BB [len_hi] [len_lo] B0 [gradient_off=1] | + | [led_count] (RGB * N) [xor] | + | length = 2 + 3*N (bytes after 0xB0: gradient_off + | + | led_count + RGB*count) | + \*-----------------------------------------------------*/ + const unsigned int count = std::min(size, 255u); + const unsigned int payload_len = 2 + (3 * count); + + /*-----------------------------------------------------*\ + | Create buffer with fixed size and fill sequentially | + \*-----------------------------------------------------*/ + + std::vector pkt; + pkt.reserve(7 + (3 * count)); + + pkt.push_back(0xBB); + pkt.push_back(static_cast((payload_len >> 8) & 0xFF)); /* len_hi */ + pkt.push_back(static_cast(payload_len & 0xFF)); /* len_lo */ + pkt.push_back(0xB0); /* subcommand */ + pkt.push_back(0x01); /* gradient_off = 1 */ + pkt.push_back(static_cast(count)); /* led_count */ + + for(std::size_t led_idx = 0; led_idx < count; led_idx++) + { + pkt.push_back(RGBGetRValue(colors[led_idx])); + pkt.push_back(RGBGetGValue(colors[led_idx])); + pkt.push_back(RGBGetBValue(colors[led_idx])); } pkt.push_back(CalculateXorChecksum(pkt)); + json command; command["msg"]["cmd"] = "razer"; command["msg"]["data"]["pt"] = base64::encode(pkt); @@ -246,7 +273,11 @@ void GoveeController::SendScan() json command; command["msg"]["cmd"] = "scan"; - command["msg"]["data"]["account_topic"] = "GA/123456789"; + /*-----------------------------------------------------*\ + | Matches what Govee devices commonly accept for LAN | + | scan | + \*-----------------------------------------------------*/ + command["msg"]["data"]["account_topic"] = "reserve"; /*-----------------------------------------------------*\ | Convert the JSON object to a string and write it | diff --git a/Controllers/GoveeController/RGBController_Govee.cpp b/Controllers/GoveeController/RGBController_Govee.cpp index 0ab0456a7..50a8009a6 100644 --- a/Controllers/GoveeController/RGBController_Govee.cpp +++ b/Controllers/GoveeController/RGBController_Govee.cpp @@ -9,7 +9,9 @@ | SPDX-License-Identifier: GPL-2.0-only | \*---------------------------------------------------------*/ +#include #include +#include #include "RGBController_Govee.h" using namespace std::chrono_literals; @@ -65,32 +67,72 @@ RGBController_Govee::~RGBController_Govee() void RGBController_Govee::SetupZones() { - unsigned int led_count = govee_led_counts[controller->GetSku()]; + unsigned int led_count = 0; + std::map::iterator it = govee_led_counts.find(controller->GetSku()); + if(it != govee_led_counts.end()) + { + led_count = it->second; + } + /*-----------------------------------------------------*\ + | Fallback so Direct mode is usable even if SKU isn't | + | in the table | + \*-----------------------------------------------------*/ + if(led_count == 0) + { + led_count = 20; /* safe default; user can resize in UI */ + } zone strip; strip.name = "Govee Strip"; strip.type = ZONE_TYPE_LINEAR; strip.leds_count = led_count; - strip.leds_min = led_count; - strip.leds_max = led_count; + /*-----------------------------------------------------*\ + | Only make resizable for unknown SKUs | + \*-----------------------------------------------------*/ + if(govee_led_counts.find(controller->GetSku()) == govee_led_counts.end()) + { + strip.leds_min = 1; + strip.leds_max = 255; + } + else + { + strip.leds_min = led_count; + strip.leds_max = led_count; + } strip.matrix_map = NULL; zones.push_back(strip); for(std::size_t led_idx = 0; led_idx < strip.leds_count; led_idx++) { led strip_led; - strip_led.name = "Govee LED"; + strip_led.name = "Govee LED " + std::to_string(led_idx); leds.push_back(strip_led); } SetupColors(); } -void RGBController_Govee::ResizeZone(int /*zone*/, int /*new_size*/) +void RGBController_Govee::ResizeZone(int zone, int new_size) { - /*---------------------------------------------------------*\ - | This device does not support resizing zones | - \*---------------------------------------------------------*/ + if(zone < 0 || zone >= (int)zones.size() || new_size <= 0) + { + return; + } + + new_size = std::max(1, std::min(255, new_size)); + zones[zone].leds_count = new_size; + zones[zone].leds_min = 1; + zones[zone].leds_max = 255; + + leds.clear(); + leds.resize(new_size); + for(int i = 0; i < new_size; ++i) + { + leds[i].name = "Govee LED " + std::to_string(i); + } + + SetupColors(); /* re-sync color buffers with LED count */ + DeviceUpdateLEDs(); /* push an updated frame */ } void RGBController_Govee::DeviceUpdateLEDs() @@ -99,7 +141,10 @@ void RGBController_Govee::DeviceUpdateLEDs() if(modes[active_mode].color_mode == MODE_COLORS_PER_LED) { - controller->SendRazerData(&colors[0], (unsigned int)colors.size()); + if(!colors.empty()) + { + controller->SendRazerData(&colors[0], (unsigned int)colors.size()); + } } }