Fixed govee direct mode control

This commit is contained in:
Fefedu973
2025-09-10 05:36:04 +00:00
committed by Adam Honse
parent f019320df1
commit f2aef24b8a
2 changed files with 97 additions and 21 deletions

View File

@@ -9,6 +9,7 @@
| SPDX-License-Identifier: GPL-2.0-only |
\*---------------------------------------------------------*/
#include <algorithm>
#include <nlohmann/json.hpp>
#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<base64::byte> 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<base64::byte> pkt;
pkt.reserve(7 + (3 * count));
pkt.push_back(0xBB);
pkt.push_back(static_cast<base64::byte>((payload_len >> 8) & 0xFF)); /* len_hi */
pkt.push_back(static_cast<base64::byte>(payload_len & 0xFF)); /* len_lo */
pkt.push_back(0xB0); /* subcommand */
pkt.push_back(0x01); /* gradient_off = 1 */
pkt.push_back(static_cast<base64::byte>(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 |

View File

@@ -9,7 +9,9 @@
| SPDX-License-Identifier: GPL-2.0-only |
\*---------------------------------------------------------*/
#include <algorithm>
#include <map>
#include <string>
#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<std::string, unsigned int>::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());
}
}
}