Skip to content

Commit f2aef24

Browse files
Fefedu973CalcProgrammer1
authored andcommitted
Fixed govee direct mode control
1 parent f019320 commit f2aef24

2 files changed

Lines changed: 95 additions & 19 deletions

File tree

Controllers/GoveeController/GoveeController.cpp

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
| SPDX-License-Identifier: GPL-2.0-only |
1010
\*---------------------------------------------------------*/
1111

12+
#include <algorithm>
1213
#include <nlohmann/json.hpp>
1314
#include "base64.hpp"
1415
#include "GoveeController.h"
@@ -182,22 +183,48 @@ void GoveeController::SetColor(unsigned char red, unsigned char green, unsigned
182183

183184
void GoveeController::SendRazerData(RGBColor* colors, unsigned int size)
184185
{
185-
std::vector<base64::byte> pkt = { 0xBB, 0x00, 0x00, 0xB0, 0x00, 0x00 };
186-
json command;
186+
/*-----------------------------------------------------*\
187+
| Do not send an empty frame (this was producing |
188+
| length=2, count=0) |
189+
\*-----------------------------------------------------*/
190+
if(size == 0)
191+
{
192+
return;
193+
}
194+
195+
/*-----------------------------------------------------*\
196+
| PT payload: BB [len_hi] [len_lo] B0 [gradient_off=1] |
197+
| [led_count] (RGB * N) [xor] |
198+
| length = 2 + 3*N (bytes after 0xB0: gradient_off + |
199+
| led_count + RGB*count) |
200+
\*-----------------------------------------------------*/
201+
const unsigned int count = std::min(size, 255u);
202+
const unsigned int payload_len = 2 + (3 * count);
203+
204+
/*-----------------------------------------------------*\
205+
| Create buffer with fixed size and fill sequentially |
206+
\*-----------------------------------------------------*/
187207

188-
pkt[2] = 2 + (3 * size);
189-
pkt[5] = size;
190-
pkt.resize(6 + (3 * size));
208+
std::vector<base64::byte> pkt;
209+
pkt.reserve(7 + (3 * count));
191210

192-
for(std::size_t led_idx = 0; led_idx < size; led_idx++)
211+
pkt.push_back(0xBB);
212+
pkt.push_back(static_cast<base64::byte>((payload_len >> 8) & 0xFF)); /* len_hi */
213+
pkt.push_back(static_cast<base64::byte>(payload_len & 0xFF)); /* len_lo */
214+
pkt.push_back(0xB0); /* subcommand */
215+
pkt.push_back(0x01); /* gradient_off = 1 */
216+
pkt.push_back(static_cast<base64::byte>(count)); /* led_count */
217+
218+
for(std::size_t led_idx = 0; led_idx < count; led_idx++)
193219
{
194-
pkt[6 + (led_idx * 3)] = RGBGetRValue(colors[led_idx]);
195-
pkt[7 + (led_idx * 3)] = RGBGetGValue(colors[led_idx]);
196-
pkt[8 + (led_idx * 3)] = RGBGetBValue(colors[led_idx]);
220+
pkt.push_back(RGBGetRValue(colors[led_idx]));
221+
pkt.push_back(RGBGetGValue(colors[led_idx]));
222+
pkt.push_back(RGBGetBValue(colors[led_idx]));
197223
}
198224

199225
pkt.push_back(CalculateXorChecksum(pkt));
200226

227+
json command;
201228
command["msg"]["cmd"] = "razer";
202229
command["msg"]["data"]["pt"] = base64::encode(pkt);
203230

@@ -246,7 +273,11 @@ void GoveeController::SendScan()
246273
json command;
247274

248275
command["msg"]["cmd"] = "scan";
249-
command["msg"]["data"]["account_topic"] = "GA/123456789";
276+
/*-----------------------------------------------------*\
277+
| Matches what Govee devices commonly accept for LAN |
278+
| scan |
279+
\*-----------------------------------------------------*/
280+
command["msg"]["data"]["account_topic"] = "reserve";
250281

251282
/*-----------------------------------------------------*\
252283
| Convert the JSON object to a string and write it |

Controllers/GoveeController/RGBController_Govee.cpp

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
| SPDX-License-Identifier: GPL-2.0-only |
1010
\*---------------------------------------------------------*/
1111

12+
#include <algorithm>
1213
#include <map>
14+
#include <string>
1315
#include "RGBController_Govee.h"
1416

1517
using namespace std::chrono_literals;
@@ -65,32 +67,72 @@ RGBController_Govee::~RGBController_Govee()
6567

6668
void RGBController_Govee::SetupZones()
6769
{
68-
unsigned int led_count = govee_led_counts[controller->GetSku()];
70+
unsigned int led_count = 0;
71+
std::map<std::string, unsigned int>::iterator it = govee_led_counts.find(controller->GetSku());
72+
if(it != govee_led_counts.end())
73+
{
74+
led_count = it->second;
75+
}
76+
/*-----------------------------------------------------*\
77+
| Fallback so Direct mode is usable even if SKU isn't |
78+
| in the table |
79+
\*-----------------------------------------------------*/
80+
if(led_count == 0)
81+
{
82+
led_count = 20; /* safe default; user can resize in UI */
83+
}
6984

7085
zone strip;
7186
strip.name = "Govee Strip";
7287
strip.type = ZONE_TYPE_LINEAR;
7388
strip.leds_count = led_count;
74-
strip.leds_min = led_count;
75-
strip.leds_max = led_count;
89+
/*-----------------------------------------------------*\
90+
| Only make resizable for unknown SKUs |
91+
\*-----------------------------------------------------*/
92+
if(govee_led_counts.find(controller->GetSku()) == govee_led_counts.end())
93+
{
94+
strip.leds_min = 1;
95+
strip.leds_max = 255;
96+
}
97+
else
98+
{
99+
strip.leds_min = led_count;
100+
strip.leds_max = led_count;
101+
}
76102
strip.matrix_map = NULL;
77103
zones.push_back(strip);
78104

79105
for(std::size_t led_idx = 0; led_idx < strip.leds_count; led_idx++)
80106
{
81107
led strip_led;
82-
strip_led.name = "Govee LED";
108+
strip_led.name = "Govee LED " + std::to_string(led_idx);
83109
leds.push_back(strip_led);
84110
}
85111

86112
SetupColors();
87113
}
88114

89-
void RGBController_Govee::ResizeZone(int /*zone*/, int /*new_size*/)
115+
void RGBController_Govee::ResizeZone(int zone, int new_size)
90116
{
91-
/*---------------------------------------------------------*\
92-
| This device does not support resizing zones |
93-
\*---------------------------------------------------------*/
117+
if(zone < 0 || zone >= (int)zones.size() || new_size <= 0)
118+
{
119+
return;
120+
}
121+
122+
new_size = std::max(1, std::min(255, new_size));
123+
zones[zone].leds_count = new_size;
124+
zones[zone].leds_min = 1;
125+
zones[zone].leds_max = 255;
126+
127+
leds.clear();
128+
leds.resize(new_size);
129+
for(int i = 0; i < new_size; ++i)
130+
{
131+
leds[i].name = "Govee LED " + std::to_string(i);
132+
}
133+
134+
SetupColors(); /* re-sync color buffers with LED count */
135+
DeviceUpdateLEDs(); /* push an updated frame */
94136
}
95137

96138
void RGBController_Govee::DeviceUpdateLEDs()
@@ -99,7 +141,10 @@ void RGBController_Govee::DeviceUpdateLEDs()
99141

100142
if(modes[active_mode].color_mode == MODE_COLORS_PER_LED)
101143
{
102-
controller->SendRazerData(&colors[0], (unsigned int)colors.size());
144+
if(!colors.empty())
145+
{
146+
controller->SendRazerData(&colors[0], (unsigned int)colors.size());
147+
}
103148
}
104149
}
105150

0 commit comments

Comments
 (0)