diff --git a/wled00/FX.h b/wled00/FX.h
index c75e730b..6bb7afc1 100644
--- a/wled00/FX.h
+++ b/wled00/FX.h
@@ -673,6 +673,7 @@ class WS2812FX {
paletteFade = 0,
paletteBlend = 0,
milliampsPerLed = 55,
+ cctBlending = 0,
getBrightness(void),
getMode(void),
getSpeed(void),
diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp
index a6a407f0..7c82bf68 100644
--- a/wled00/FX_fcn.cpp
+++ b/wled00/FX_fcn.cpp
@@ -1152,4 +1152,5 @@ uint32_t WS2812FX::gamma32(uint32_t color)
}
WS2812FX* WS2812FX::instance = nullptr;
-int16_t Bus::_cct = -1;
\ No newline at end of file
+int16_t Bus::_cct = -1;
+uint8_t Bus::_cctBlend = 0;
\ No newline at end of file
diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h
index 6adce933..4863014d 100644
--- a/wled00/bus_manager.h
+++ b/wled00/bus_manager.h
@@ -113,6 +113,14 @@ class Bus {
static void setCCT(uint16_t cct) {
_cct = cct;
}
+ static void setCCTBlend(uint8_t b) {
+ if (b > 100) b = 100;
+ _cctBlend = (b * 127) / 100;
+ //compile-time limiter for hardware that can't power both white channels at max
+ #ifdef WLED_MAX_CCT_BLEND
+ if (_cctBlend > WLED_MAX_CCT_BLEND) _cctBlend = WLED_MAX_CCT_BLEND;
+ #endif
+ }
bool reversed = false;
@@ -125,6 +133,7 @@ class Bus {
bool _needsRefresh = false;
uint8_t _autoWhiteMode = 0;
static int16_t _cct;
+ static uint8_t _cctBlend;
uint32_t autoWhiteCalc(uint32_t c) {
if (_autoWhiteMode == RGBW_MODE_MANUAL_ONLY) return c;
@@ -300,19 +309,29 @@ class BusPwm : public Bus {
cct = (approximateKelvinFromRGB(c) - 1900) >> 5;
}
+ //0 - linear (CCT 127 = 50% warm, 50% cold), 127 - additive CCT blending (CCT 127 = 100% warm, 100% cold)
+ uint8_t ww, cw;
+ if (cct < _cctBlend) ww = 255;
+ else ww = ((255-cct) * 255) / (255 - _cctBlend);
+
+ if ((255-cct) < _cctBlend) cw = 255;
+ else cw = (cct * 255) / (255 - _cctBlend);
+
+ ww = (w * ww) / 255; //brightness scaling
+ cw = (w * cw) / 255;
+
switch (_type) {
case TYPE_ANALOG_1CH: //one channel (white), relies on auto white calculation
_data[0] = w;
break;
case TYPE_ANALOG_2CH: //warm white + cold white
- // perhaps a non-linear adjustment would be in order. need to test
- _data[1] = (w * cct) / 255;
- _data[0] = (w * (255-cct)) / 255;
+ _data[1] = cw;
+ _data[0] = ww;
break;
case TYPE_ANALOG_5CH: //RGB + warm white + cold white
// perhaps a non-linear adjustment would be in order. need to test
- _data[4] = (w * cct) / 255;
- w = (w * (255-cct)) / 255;
+ _data[4] = cw;
+ w = ww;
case TYPE_ANALOG_4CH: //RGBW
_data[3] = w;
case TYPE_ANALOG_3CH: //standard dumb RGB
diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp
index faeab4db..b3067406 100644
--- a/wled00/cfg.cpp
+++ b/wled00/cfg.cpp
@@ -82,6 +82,8 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
uint8_t rgbwMode = hw_led[F("rgbwm")] | RGBW_MODE_DUAL; // use global setting (legacy)
CJSON(correctWB, hw_led["cct"]);
CJSON(cctFromRgb, hw_led[F("cr")]);
+ CJSON(strip.cctBlending, hw_led[F("cb")]);
+ Bus::setCCTBlend(strip.cctBlending);
JsonArray ins = hw_led["ins"];
@@ -523,6 +525,7 @@ void serializeConfig() {
hw_led[F("ledma")] = strip.milliampsPerLed;
hw_led["cct"] = correctWB;
hw_led[F("cr")] = cctFromRgb;
+ hw_led[F("cb")] = strip.cctBlending;
JsonArray hw_led_ins = hw_led.createNestedArray("ins");
diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm
index 582a4aef..6060f7db 100644
--- a/wled00/data/settings_leds.htm
+++ b/wled00/data/settings_leds.htm
@@ -512,7 +512,7 @@ ${i+1}:
Custom bus start indices:
White Balance correction:
Calculate CCT from RGB:
- CCT blending mode: TODO
+ CCT additive blending: %%