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: %%

Touch threshold:
@@ -539,7 +539,7 @@ ${i+1}:

Use Gamma correction for color: (strongly recommended)
Use Gamma correction for brightness: (not recommended)

- Brightness factor: % + Brightness factor: %%

Transitions

Crossfade:
Transition Time: ms
diff --git a/wled00/html_settings.h b/wled00/html_settings.h index 1bc13bc4..22b47c51 100644 --- a/wled00/html_settings.h +++ b/wled00/html_settings.h @@ -119,7 +119,8 @@ style="width:260px">Make a segment for each output:
Custom bus start indices:
White Balance correction:
Calculate CCT from RGB:
CCT blending mode: TODO

+name="CR">
CCT additive blending: %%

Touch threshold:
IR GPIO: (not recommended)

Brightness factor: %

Transitions

Crossfade: %%

Transitions

Crossfade:
Transition Time: ms
Enable Palette transitions:

Timed light

Default Duration: hasArg(F("MS")); correctWB = request->hasArg(F("CCT")); cctFromRgb = request->hasArg(F("CR")); + strip.cctBlending = request->arg(F("CB")).toInt(); + Bus::setCCTBlend(strip.cctBlending); for (uint8_t s = 0; s < WLED_MAX_BUSSES; s++) { char lp[4] = "L0"; lp[2] = 48+s; lp[3] = 0; //ascii 0-9 //strip data pin diff --git a/wled00/wled.h b/wled00/wled.h index 2127622e..03a9928f 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -269,8 +269,8 @@ WLED_GLOBAL byte bootPreset _INIT(0); // save preset to load //if false, only one segment spanning the total LEDs is created, //but not on LED settings save if there is more than one segment currently WLED_GLOBAL bool autoSegments _INIT(false); -WLED_GLOBAL bool correctWB _INIT(false); //CCT color correction of RGB color -WLED_GLOBAL bool cctFromRgb _INIT(true); //CCT is calculated from RGB instead of using seg.cct +WLED_GLOBAL bool correctWB _INIT(false); //CCT color correction of RGB color +WLED_GLOBAL bool cctFromRgb _INIT(true); //CCT is calculated from RGB instead of using seg.cct WLED_GLOBAL byte col[] _INIT_N(({ 255, 160, 0, 0 })); // current RGB(W) primary color. col[] should be updated if you want to change the color. WLED_GLOBAL byte colSec[] _INIT_N(({ 0, 0, 0, 0 })); // current RGB(W) secondary color diff --git a/wled00/xml.cpp b/wled00/xml.cpp index ba0767be..ee3b9368 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -372,6 +372,7 @@ void getSettingsJS(byte subPage, char* dest) sappend('c',SET_F("MS"),autoSegments); sappend('c',SET_F("CCT"),correctWB); sappend('c',SET_F("CR"),cctFromRgb); + sappend('v',SET_F("CB"),strip.cctBlending); for (uint8_t s=0; s < busses.getNumBusses(); s++) { Bus* bus = busses.getBus(s);