Skip to content

Commit 2ecc53b

Browse files
UDP Signal color correction (wled#1902)
* added ui changes for saturation in sync * added setters/getters for hsv settings * added color correction logic * faster algorithm for color conversion * added save/load config to fs * adjusted value scale * move color functions to colors.cpp * remove unchecked file * Various small changes Moved settings location in sync settings Changed wording from hyperion to live Moved code into setRealtimePixel(), reducing duplication and enabling the functionality for DMX streams Co-authored-by: Christian Schwinne <[email protected]>
1 parent 3eb1fe0 commit 2ecc53b

File tree

9 files changed

+114
-10
lines changed

9 files changed

+114
-10
lines changed

wled00/cfg.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,10 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
271271
CJSON(arlsDisableGammaCorrection, if_live[F("no-gc")]); // false
272272
CJSON(arlsOffset, if_live[F("offset")]); // 0
273273

274+
CJSON(liveHSVCorrection, if_live[F("corr")]);
275+
CJSON(liveHSVSaturation, if_live[F("hsvsat")]);
276+
CJSON(liveHSVValue, if_live[F("hsvval")]);
277+
274278
CJSON(alexaEnabled, interfaces["va"][F("alexa")]); // false
275279

276280
CJSON(macroAlexaOn, interfaces["va"]["macros"][0]);
@@ -608,10 +612,14 @@ void serializeConfig() {
608612
if_live_dmx[F("seqskip")] = e131SkipOutOfSequence;
609613
if_live_dmx[F("addr")] = DMXAddress;
610614
if_live_dmx[F("mode")] = DMXMode;
615+
611616
if_live[F("timeout")] = realtimeTimeoutMs / 100;
612617
if_live[F("maxbri")] = arlsForceMaxBri;
613618
if_live[F("no-gc")] = arlsDisableGammaCorrection;
614619
if_live[F("offset")] = arlsOffset;
620+
if_live[F("corr")] = liveHSVCorrection;
621+
if_live[F("hsvsat")] = liveHSVSaturation;
622+
if_live[F("hsvval")] = liveHSVValue;
615623

616624
JsonObject if_va = interfaces.createNestedObject("va");
617625
if_va[F("alexa")] = alexaEnabled;

wled00/colors.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,77 @@ void relativeChangeWhite(int8_t amount, byte lowerBoundary)
4747
col[3] = new_val;
4848
}
4949

50+
void colorHSVtoRGB(float hue, float saturation, float value, byte& red, byte& green, byte& blue)
51+
{
52+
float r, g, b;
53+
54+
auto i = static_cast<int>(hue * 6);
55+
auto f = hue * 6 - i;
56+
auto p = value * (1 - saturation);
57+
auto q = value * (1 - f * saturation);
58+
auto t = value * (1 - (1 - f) * saturation);
59+
60+
switch (i % 6)
61+
{
62+
case 0: r = value, g = t, b = p;
63+
break;
64+
case 1: r = q, g = value, b = p;
65+
break;
66+
case 2: r = p, g = value, b = t;
67+
break;
68+
case 3: r = p, g = q, b = value;
69+
break;
70+
case 4: r = t, g = p, b = value;
71+
break;
72+
case 5: r = value, g = p, b = q;
73+
break;
74+
}
75+
76+
red = static_cast<uint8_t>(r * 255);
77+
green = static_cast<uint8_t>(g * 255);
78+
blue = static_cast<uint8_t>(b * 255);
79+
}
80+
81+
void colorRGBtoHSV(byte red, byte green, byte blue, float& hue, float& saturation, float& value)
82+
{
83+
auto rd = static_cast<float>(red) / 255;
84+
auto gd = static_cast<float>(green) / 255;
85+
auto bd = static_cast<float>(blue) / 255;
86+
auto max = std::max({ rd, gd, bd }), min = std::min({ rd, gd, bd });
87+
88+
value = max;
89+
90+
auto d = max - min;
91+
saturation = max == 0 ? 0 : d / max;
92+
93+
hue = 0;
94+
if (max != min)
95+
{
96+
if (max == rd) hue = (gd - bd) / d + (gd < bd ? 6 : 0);
97+
else if (max == gd) hue = (bd - rd) / d + 2;
98+
else if (max == bd) hue = (rd - gd) / d + 4;
99+
hue /= 6;
100+
}
101+
}
102+
103+
#define SATURATION_THRESHOLD 0.1
104+
#define MAX_HSV_VALUE 1
105+
#define MAX_HSV_SATURATION 1
106+
107+
//corrects the realtime colors. 10 is the unchanged saturation/value
108+
//this feature might cause slowdowns with large LED counts
109+
void correctColors(byte r, byte g, byte b, byte* rgb) {
110+
float hsv[3] = { 0,0,0 };
111+
colorRGBtoHSV(r, g,b , hsv[0], hsv[1], hsv[2]);
112+
float saturated = hsv[1] > SATURATION_THRESHOLD ?
113+
hsv[1] * ((float)liveHSVSaturation / 10) : hsv[1];
114+
float saturation = saturated < MAX_HSV_SATURATION ? saturated : MAX_HSV_SATURATION;
115+
116+
float valued = hsv[2] * ((float)liveHSVValue/10);
117+
float value = valued < MAX_HSV_VALUE ? valued : MAX_HSV_VALUE;
118+
colorHSVtoRGB(hsv[0], saturation, value, rgb[0], rgb[1], rgb[2]);
119+
}
120+
50121
void colorHStoRGB(uint16_t hue, byte sat, byte* rgb) //hue, sat to rgb
51122
{
52123
float h = ((float)hue)/65535.0;

wled00/data/settings_sync.htm

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ <h3>WLED Broadcast</h3>
2828
<i>Reboot required to apply changes. </i>
2929
<h3>Instance List</h3>
3030
Enable instance list: <input type="checkbox" name="NL"><br>
31-
Make this instance discoverable: <input type="checkbox" name="NB"><br>
31+
Make this instance discoverable: <input type="checkbox" name="NB">
3232
<h3>Realtime</h3>
3333
Receive UDP realtime: <input type="checkbox" name="RD"><br><br>
3434
<i>Network DMX input</i><br>
@@ -59,7 +59,10 @@ <h3>Realtime</h3>
5959
Timeout: <input name="ET" type="number" min="1" max="65000" required> ms<br>
6060
Force max brightness: <input type="checkbox" name="FB"><br>
6161
Disable realtime gamma correction: <input type="checkbox" name="RG"><br>
62-
Realtime LED offset: <input name="WO" type="number" min="-255" max="255" required>
62+
Realtime LED offset: <input name="WO" type="number" min="-255" max="255" required><br><br>
63+
Realtime HSV color correction: <input type="checkbox" name="HX"><br>
64+
Saturation (1-30): <input name="HS" type="number" min="1" max="30" value="1" step="1"><br>
65+
Value (1-60): <input name="HV" type="number" min="1" max="60" value="10" step="1">
6366
<h3>Alexa Voice Assistant</h3>
6467
Emulate Alexa device: <input type="checkbox" name="AL"><br>
6568
Alexa invocation name: <input name="AI" maxlength="32">

wled00/fcn_declare.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ void colorFromUint32(uint32_t in, bool secondary = false);
5858
void colorFromUint24(uint32_t in, bool secondary = false);
5959
uint32_t colorFromRgbw(byte* rgbw);
6060
void relativeChangeWhite(int8_t amount, byte lowerBoundary = 0);
61+
void colorHSVtoRGB(float hue, float saturation, float value, byte& red, byte& green, byte& blue);
62+
void colorRGBtoHSV(byte red, byte green, byte blue, float& hue, float& saturation, float& value);
63+
void correctColors(byte r, byte g, byte b, byte* rgb);
6164
void colorHStoRGB(uint16_t hue, byte sat, byte* rgb); //hue, sat to rgb
6265
void colorKtoRGB(uint16_t kelvin, byte* rgb);
6366
void colorCTtoRGB(uint16_t mired, byte* rgb); //white spectrum to rgb

wled00/html_settings.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -254,8 +254,8 @@ Send Macro notifications: <input type="checkbox" name="SM"><br>
254254
Send notifications twice: <input type="checkbox" name="S2"><br><i>
255255
Reboot required to apply changes.</i><h3>Instance List</h3>
256256
Enable instance list: <input type="checkbox" name="NL"><br>
257-
Make this instance discoverable: <input type="checkbox" name="NB"><br><h3>
258-
Realtime</h3>Receive UDP realtime: <input type="checkbox" name="RD"><br><br><i>
257+
Make this instance discoverable: <input type="checkbox" name="NB"><h3>Realtime
258+
</h3>Receive UDP realtime: <input type="checkbox" name="RD"><br><br><i>
259259
Network DMX input</i><br>Type: <select name="DI" onchange="SP(),adj()"><option
260260
value="5568">E1.31 (sACN)</option><option value="6454">Art-Net</option><option
261261
value="4048">DDP</option><option value="0" selected="selected">Custom port
@@ -275,9 +275,12 @@ E1.31 info</a><br>Timeout: <input name="ET" type="number" min="1" max="65000"
275275
required> ms<br>Force max brightness: <input type="checkbox" name="FB"><br>
276276
Disable realtime gamma correction: <input type="checkbox" name="RG"><br>
277277
Realtime LED offset: <input name="WO" type="number" min="-255" max="255"
278-
required><h3>Alexa Voice Assistant</h3>Emulate Alexa device: <input
279-
type="checkbox" name="AL"><br>Alexa invocation name: <input name="AI"
280-
maxlength="32"><h3>Blynk</h3><b>
278+
required><br><br>Realtime HSV color correction: <input type="checkbox"
279+
name="HX"><br>Saturation (1-30): <input name="HS" type="number" min="1"
280+
max="30" value="1" step="1"><br>Value (1-60): <input name="HV" type="number"
281+
min="1" max="60" value="10" step="1"><h3>Alexa Voice Assistant</h3>
282+
Emulate Alexa device: <input type="checkbox" name="AL"><br>
283+
Alexa invocation name: <input name="AI" maxlength="32"><h3>Blynk</h3><b>
281284
Blynk, MQTT and Hue sync all connect to external hosts!<br>
282285
This may impact the responsiveness of the ESP8266.</b><br>
283286
For best results, only use one of these services at a time.<br>

wled00/set.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,10 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
214214
notifyMacro = request->hasArg(F("SM"));
215215
notifyTwice = request->hasArg(F("S2"));
216216

217+
liveHSVCorrection = request->hasArg(F("HX"));
218+
liveHSVSaturation = request->arg(F("HS")).toInt();
219+
liveHSVValue = request->arg(F("HV")).toInt();
220+
217221
nodeListEnabled = request->hasArg(F("NL"));
218222
if (!nodeListEnabled) Nodes.clear();
219223
nodeBroadcastEnabled = request->hasArg(F("NB"));

wled00/udp.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,6 @@ void handleNotifications()
161161
for (uint16_t i = 0; i < packetSize -2; i += 3)
162162
{
163163
setRealtimePixel(id, lbuf[i], lbuf[i+1], lbuf[i+2], 0);
164-
165164
id++; if (id >= ledCount) break;
166165
}
167166
strip.show();
@@ -385,7 +384,7 @@ void handleNotifications()
385384
uint16_t id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00);
386385
for (uint16_t i = 4; i < packetSize -2; i += 3)
387386
{
388-
if (id >= ledCount) break;
387+
if (id >= ledCount) break;
389388
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
390389
id++;
391390
}
@@ -394,7 +393,7 @@ void handleNotifications()
394393
uint16_t id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00);
395394
for (uint16_t i = 4; i < packetSize -2; i += 4)
396395
{
397-
if (id >= ledCount) break;
396+
if (id >= ledCount) break;
398397
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]);
399398
id++;
400399
}
@@ -424,6 +423,11 @@ void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w)
424423
uint16_t pix = i + arlsOffset;
425424
if (pix < ledCount)
426425
{
426+
if (liveHSVCorrection) {
427+
byte correctedColors[3] = {0,0,0};
428+
correctColors(r, g, b, correctedColors);
429+
r = correctedColors[0]; g = correctedColors[1]; b = correctedColors[2];
430+
}
427431
if (!arlsDisableGammaCorrection && strip.gammaCorrectCol)
428432
{
429433
strip.setPixelColor(pix, strip.gamma8(r), strip.gamma8(g), strip.gamma8(b), strip.gamma8(w));

wled00/wled.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,9 @@ WLED_GLOBAL byte irEnabled _INIT(0); // Infrared receiver
294294
WLED_GLOBAL uint16_t udpPort _INIT(21324); // WLED notifier default port
295295
WLED_GLOBAL uint16_t udpPort2 _INIT(65506); // WLED notifier supplemental port
296296
WLED_GLOBAL uint16_t udpRgbPort _INIT(19446); // Hyperion port
297+
WLED_GLOBAL bool liveHSVCorrection _INIT(false);
298+
WLED_GLOBAL uint16_t liveHSVSaturation _INIT(13);
299+
WLED_GLOBAL uint16_t liveHSVValue _INIT(10);
297300

298301
WLED_GLOBAL bool receiveNotificationBrightness _INIT(true); // apply brightness from incoming notifications
299302
WLED_GLOBAL bool receiveNotificationColor _INIT(true); // apply color

wled00/xml.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,11 @@ void getSettingsJS(byte subPage, char* dest)
396396
{
397397
sappend('v',SET_F("UP"),udpPort);
398398
sappend('v',SET_F("U2"),udpPort2);
399+
400+
sappend('c',SET_F("HX"),liveHSVCorrection);
401+
sappend('v',SET_F("HS"),liveHSVSaturation);
402+
sappend('v',SET_F("HV"),liveHSVValue);
403+
399404
sappend('c',SET_F("RB"),receiveNotificationBrightness);
400405
sappend('c',SET_F("RC"),receiveNotificationColor);
401406
sappend('c',SET_F("RX"),receiveNotificationEffects);

0 commit comments

Comments
 (0)