From a9bcc75733118402fbaae1c3700c772596f75d46 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sat, 27 Jan 2024 15:16:59 +0100 Subject: [PATCH 01/10] added function to generate random palette based on harmonic color theory --- wled00/FX_fcn.cpp | 6 +-- wled00/colors.cpp | 100 +++++++++++++++++++++++++++++++++++++++++++ wled00/fcn_declare.h | 2 + 3 files changed, 103 insertions(+), 5 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index eeaa2c1e1b..c7fb7815d9 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -224,11 +224,7 @@ CRGBPalette16 IRAM_ATTR &Segment::loadPalette(CRGBPalette16 &targetPalette, uint unsigned long timeSinceLastChange = millis() - _lastPaletteChange; if (timeSinceLastChange > randomPaletteChangeTime * 1000U) { _randomPalette = _newRandomPalette; - _newRandomPalette = CRGBPalette16( - CHSV(random8(), random8(160, 255), random8(128, 255)), - CHSV(random8(), random8(160, 255), random8(128, 255)), - CHSV(random8(), random8(160, 255), random8(128, 255)), - CHSV(random8(), random8(160, 255), random8(128, 255))); + _newRandomPalette = generateRandomPalette(&_randomPalette); _lastPaletteChange = millis(); handleRandomPalette(); // do a 1st pass of blend } diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 21c27d651c..8dcc735c3c 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -91,6 +91,106 @@ void setRandomColor(byte* rgb) colorHStoRGB(lastRandomIndex*256,255,rgb); } +/* + *generates a random palette based on color theory + */ + +CRGBPalette16 generateRandomPalette(CRGBPalette16* basepalette) +{ + CHSV palettecolors[4]; //array of colors for the new palette + uint8_t keepcolorposition = random8(4); //color position of current random palette to keep + palettecolors[keepcolorposition] = rgb2hsv_approximate(basepalette->entries[keepcolorposition*5]); //read one of the base colors of the current palette + palettecolors[keepcolorposition].hue += random8(20)-10; // +/- 10 randomness + //generate 4 saturation and brightness value numbers + //only one saturation is allowed to be below 200 creating mostly vibrant colors + //only one brigthness value number is allowed to below 200, creating mostly bright palettes + + for (int i = 0; i<3; i++) { //generate three high values + palettecolors[i].saturation = random8(180,255); + palettecolors[i].value = random8(180,255); + } + //allow one to be lower + palettecolors[3].saturation = random8(80,255); + palettecolors[3].value = random8(50,255); + + //shuffle the arrays using Fisher-Yates algorithm + for (int i = 3; i > 0; i--) { + uint8_t j = random8(0, i + 1); + //swap [i] and [j] + uint8_t temp = palettecolors[i].saturation; + palettecolors[i].saturation = palettecolors[j].saturation; + palettecolors[j].saturation = temp; + } + + for (int i = 3; i > 0; i--) { + uint8_t j = random8(0, i + 1); + //swap [i] and [j] + uint8_t temp = palettecolors[i].value; + palettecolors[i].value = palettecolors[j].value; + palettecolors[j].value = temp; + } + + //now generate three new hues based off of the hue of the chosen current color + uint8_t basehue = palettecolors[keepcolorposition].hue; + uint8_t harmonics[3]; //hues that are harmonic but still a littl random + uint8_t type = random8(5); //choose a harmony type + + switch (type) { + case 0: // analogous + harmonics[0] = basehue + random8(30, 50); + harmonics[1] = basehue + random8(10, 30); + harmonics[2] = basehue - random8(10, 30); + break; + + case 1: // triadic + harmonics[0] = basehue + 110 + random8(20); + harmonics[1] = basehue + 230 + random8(20); + harmonics[2] = basehue + random8(30)-15; + break; + + case 2: // split-complementary + harmonics[0] = basehue + 140 + random8(20); + harmonics[1] = basehue + 200 + random8(20); + harmonics[2] = basehue + random8(30)-15; + break; + + case 3: // tetradic + harmonics[0] = basehue + 80 + random8(20); + harmonics[1] = basehue + 170 + random8(20); + harmonics[2] = basehue + random8(30)-15; + break; + + case 4: // square + harmonics[0] = basehue + 80 + random8(20); + harmonics[1] = basehue + 170 + random8(20); + harmonics[2] = basehue + 260 + random8(20); + break; + } + + //shuffle the hues: + for (int i = 2; i > 0; i--) { + uint8_t j = random8(0, i + 1); + //swap [i] and [j] + uint8_t temp = harmonics[i]; + harmonics[i] = harmonics[j]; + harmonics[j] = temp; + } + + //now set the hues + int j=0; + for (int i = 0; i<4; i++) { + if(i==keepcolorposition) continue; //skip the base color + palettecolors[i].hue = harmonics[j]; + j++; + } + + return CRGBPalette16( palettecolors[0], + palettecolors[1], + palettecolors[2], + palettecolors[3]); + +} + void colorHStoRGB(uint16_t hue, byte sat, byte* rgb) //hue, sat to rgb { float h = ((float)hue)/65535.0f; diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index e256ceb5f0..3eda4ff82b 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -1,6 +1,7 @@ #ifndef WLED_FCN_DECLARE_H #define WLED_FCN_DECLARE_H +#include "FastLED.h" /* * All globally accessible functions are declared here */ @@ -65,6 +66,7 @@ class NeoGammaWLEDMethod { uint32_t color_blend(uint32_t,uint32_t,uint16_t,bool b16=false); uint32_t color_add(uint32_t,uint32_t, bool fast=false); uint32_t color_fade(uint32_t c1, uint8_t amount, bool video=false); +CRGBPalette16 generateRandomPalette(CRGBPalette16* basepalette); inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); } void colorHStoRGB(uint16_t hue, byte sat, byte* rgb); //hue, sat to rgb void colorKtoRGB(uint16_t kelvin, byte* rgb); From bccc97d25f3bab3bddc853c7b59b8252ef93aa77 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sat, 27 Jan 2024 20:36:59 +0100 Subject: [PATCH 02/10] fixed include, bugfix in random palette handling --- wled00/FX_fcn.cpp | 2 +- wled00/fcn_declare.h | 1 - wled00/wled.h | 1 + 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index c7fb7815d9..4cfe17f48d 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -223,7 +223,7 @@ CRGBPalette16 IRAM_ATTR &Segment::loadPalette(CRGBPalette16 &targetPalette, uint case 1: {//periodically replace palette with a random one unsigned long timeSinceLastChange = millis() - _lastPaletteChange; if (timeSinceLastChange > randomPaletteChangeTime * 1000U) { - _randomPalette = _newRandomPalette; + //_randomPalette = _newRandomPalette; _newRandomPalette = generateRandomPalette(&_randomPalette); _lastPaletteChange = millis(); handleRandomPalette(); // do a 1st pass of blend diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 3eda4ff82b..ac68a6f8c6 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -1,7 +1,6 @@ #ifndef WLED_FCN_DECLARE_H #define WLED_FCN_DECLARE_H -#include "FastLED.h" /* * All globally accessible functions are declared here */ diff --git a/wled00/wled.h b/wled00/wled.h index 23cd43636d..a7023c6d8e 100755 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -177,6 +177,7 @@ using PSRAMDynamicJsonDocument = BasicJsonDocument; #define PSRAMDynamicJsonDocument DynamicJsonDocument #endif +#include "FastLED.h" #include "const.h" #include "fcn_declare.h" #include "NodeStruct.h" From 12e2116acb02d1f077085919dbf732ae63d6199d Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sat, 27 Jan 2024 21:07:11 +0100 Subject: [PATCH 03/10] bugfix, need to initialize the random palette to something useful --- wled00/FX_fcn.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 4cfe17f48d..87f8b71a6f 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -77,7 +77,7 @@ uint16_t Segment::_usedSegmentData = 0U; // amount of RAM all segments use for t uint16_t Segment::maxWidth = DEFAULT_LED_COUNT; uint16_t Segment::maxHeight = 1; -CRGBPalette16 Segment::_randomPalette = CRGBPalette16(DEFAULT_COLOR); +CRGBPalette16 Segment::_randomPalette = generateRandomPalette(&_randomPalette); CRGBPalette16 Segment::_newRandomPalette = CRGBPalette16(DEFAULT_COLOR); unsigned long Segment::_lastPaletteChange = 0; // perhaps it should be per segment From e114b842ba217524cde6ea2c686eb0397b7a6334 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sat, 27 Jan 2024 22:03:29 +0100 Subject: [PATCH 04/10] fixed initialisation or random palette --- wled00/FX_fcn.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 87f8b71a6f..079ce7a86e 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -78,7 +78,7 @@ uint16_t Segment::maxWidth = DEFAULT_LED_COUNT; uint16_t Segment::maxHeight = 1; CRGBPalette16 Segment::_randomPalette = generateRandomPalette(&_randomPalette); -CRGBPalette16 Segment::_newRandomPalette = CRGBPalette16(DEFAULT_COLOR); +CRGBPalette16 Segment::_newRandomPalette = generateRandomPalette(&_randomPalette); unsigned long Segment::_lastPaletteChange = 0; // perhaps it should be per segment #ifndef WLED_DISABLE_MODE_BLEND @@ -223,7 +223,6 @@ CRGBPalette16 IRAM_ATTR &Segment::loadPalette(CRGBPalette16 &targetPalette, uint case 1: {//periodically replace palette with a random one unsigned long timeSinceLastChange = millis() - _lastPaletteChange; if (timeSinceLastChange > randomPaletteChangeTime * 1000U) { - //_randomPalette = _newRandomPalette; _newRandomPalette = generateRandomPalette(&_randomPalette); _lastPaletteChange = millis(); handleRandomPalette(); // do a 1st pass of blend From f5ed757780fe9e17042af69d73d23cf5028f1575 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sun, 28 Jan 2024 14:19:46 +0100 Subject: [PATCH 05/10] added some minor fixes -fastled flags -gamma correction -pass by reference instead of pointer --- wled00/FX_fcn.cpp | 6 +++--- wled00/colors.cpp | 19 +++++++++++++------ wled00/fcn_declare.h | 2 +- wled00/wled.h | 2 ++ 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 079ce7a86e..d06a7baab5 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -77,8 +77,8 @@ uint16_t Segment::_usedSegmentData = 0U; // amount of RAM all segments use for t uint16_t Segment::maxWidth = DEFAULT_LED_COUNT; uint16_t Segment::maxHeight = 1; -CRGBPalette16 Segment::_randomPalette = generateRandomPalette(&_randomPalette); -CRGBPalette16 Segment::_newRandomPalette = generateRandomPalette(&_randomPalette); +CRGBPalette16 Segment::_randomPalette = generateRandomPalette(_randomPalette); +CRGBPalette16 Segment::_newRandomPalette = generateRandomPalette(_randomPalette); unsigned long Segment::_lastPaletteChange = 0; // perhaps it should be per segment #ifndef WLED_DISABLE_MODE_BLEND @@ -223,7 +223,7 @@ CRGBPalette16 IRAM_ATTR &Segment::loadPalette(CRGBPalette16 &targetPalette, uint case 1: {//periodically replace palette with a random one unsigned long timeSinceLastChange = millis() - _lastPaletteChange; if (timeSinceLastChange > randomPaletteChangeTime * 1000U) { - _newRandomPalette = generateRandomPalette(&_randomPalette); + _newRandomPalette = generateRandomPalette(_randomPalette); _lastPaletteChange = millis(); handleRandomPalette(); // do a 1st pass of blend } diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 8dcc735c3c..49ae071d5a 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -95,11 +95,11 @@ void setRandomColor(byte* rgb) *generates a random palette based on color theory */ -CRGBPalette16 generateRandomPalette(CRGBPalette16* basepalette) +CRGBPalette16 generateRandomPalette(CRGBPalette16 &basepalette) { CHSV palettecolors[4]; //array of colors for the new palette uint8_t keepcolorposition = random8(4); //color position of current random palette to keep - palettecolors[keepcolorposition] = rgb2hsv_approximate(basepalette->entries[keepcolorposition*5]); //read one of the base colors of the current palette + palettecolors[keepcolorposition] = rgb2hsv_approximate(basepalette.entries[keepcolorposition*5]); //read one of the base colors of the current palette palettecolors[keepcolorposition].hue += random8(20)-10; // +/- 10 randomness //generate 4 saturation and brightness value numbers //only one saturation is allowed to be below 200 creating mostly vibrant colors @@ -184,10 +184,17 @@ CRGBPalette16 generateRandomPalette(CRGBPalette16* basepalette) j++; } - return CRGBPalette16( palettecolors[0], - palettecolors[1], - palettecolors[2], - palettecolors[3]); + //apply gamma correction + CRGB RGBpalettecolors[4]; + for (int i = 0; i<4; i++) { + RGBpalettecolors[i] = (CRGB)palettecolors[i]; //convert to RGB + RGBpalettecolors[i] = gamma32((uint32_t)RGBpalettecolors[i]); + } + + return CRGBPalette16( RGBpalettecolors[0], + RGBpalettecolors[1], + RGBpalettecolors[2], + RGBpalettecolors[3]); } diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index ac68a6f8c6..ff37184617 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -65,7 +65,7 @@ class NeoGammaWLEDMethod { uint32_t color_blend(uint32_t,uint32_t,uint16_t,bool b16=false); uint32_t color_add(uint32_t,uint32_t, bool fast=false); uint32_t color_fade(uint32_t c1, uint8_t amount, bool video=false); -CRGBPalette16 generateRandomPalette(CRGBPalette16* basepalette); +CRGBPalette16 generateRandomPalette(CRGBPalette16 &basepalette); inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); } void colorHStoRGB(uint16_t hue, byte sat, byte* rgb); //hue, sat to rgb void colorKtoRGB(uint16_t kelvin, byte* rgb); diff --git a/wled00/wled.h b/wled00/wled.h index a7023c6d8e..5ac675757a 100755 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -177,6 +177,8 @@ using PSRAMDynamicJsonDocument = BasicJsonDocument; #define PSRAMDynamicJsonDocument DynamicJsonDocument #endif +#define FASTLED_INTERNAL //remove annoying pragma messages +#define USE_GET_MILLISECOND_TIMER #include "FastLED.h" #include "const.h" #include "fcn_declare.h" From 2659055c311c8928523931cd429c3560bc38b49d Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Sun, 28 Jan 2024 19:22:36 +0100 Subject: [PATCH 06/10] fixed typos --- wled00/colors.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 49ae071d5a..9f16d1290d 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -103,7 +103,7 @@ CRGBPalette16 generateRandomPalette(CRGBPalette16 &basepalette) palettecolors[keepcolorposition].hue += random8(20)-10; // +/- 10 randomness //generate 4 saturation and brightness value numbers //only one saturation is allowed to be below 200 creating mostly vibrant colors - //only one brigthness value number is allowed to below 200, creating mostly bright palettes + //only one brightness value number is allowed below 200, creating mostly bright palettes for (int i = 0; i<3; i++) { //generate three high values palettecolors[i].saturation = random8(180,255); @@ -132,7 +132,7 @@ CRGBPalette16 generateRandomPalette(CRGBPalette16 &basepalette) //now generate three new hues based off of the hue of the chosen current color uint8_t basehue = palettecolors[keepcolorposition].hue; - uint8_t harmonics[3]; //hues that are harmonic but still a littl random + uint8_t harmonics[3]; //hues that are harmonic but still a little random uint8_t type = random8(5); //choose a harmony type switch (type) { From ef6fe43251f4cb111c77c9c603660118f1aa67f6 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Mon, 29 Jan 2024 22:14:26 +0100 Subject: [PATCH 07/10] random palette transitions with set transition time --- wled00/FX.h | 3 ++- wled00/FX_fcn.cpp | 20 +++++++++++++++----- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index abf33f9976..b29a8008eb 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -420,7 +420,8 @@ typedef struct Segment { // perhaps this should be per segment, not static static CRGBPalette16 _randomPalette; // actual random palette static CRGBPalette16 _newRandomPalette; // target random palette - static unsigned long _lastPaletteChange; // last random palette change time in millis() + static uint16_t _lastPaletteChange; // last random palette change time in millis()/1000 + static uint16_t _lastPaletteBlend; // blend palette according to set Transition Delay in millis()%0xFFFF #ifndef WLED_DISABLE_MODE_BLEND static bool _modeBlend; // mode/effect blending semaphore #endif diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index d06a7baab5..1b8c09aaa6 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -79,7 +79,8 @@ uint16_t Segment::maxHeight = 1; CRGBPalette16 Segment::_randomPalette = generateRandomPalette(_randomPalette); CRGBPalette16 Segment::_newRandomPalette = generateRandomPalette(_randomPalette); -unsigned long Segment::_lastPaletteChange = 0; // perhaps it should be per segment +uint16_t Segment::_lastPaletteChange = 0; // perhaps it should be per segment +uint16_t Segment::_lastPaletteBlend = 0; //in millis (lowest 16 bits only) #ifndef WLED_DISABLE_MODE_BLEND bool Segment::_modeBlend = false; @@ -220,11 +221,11 @@ CRGBPalette16 IRAM_ATTR &Segment::loadPalette(CRGBPalette16 &targetPalette, uint switch (pal) { case 0: //default palette. Exceptions for specific effects above targetPalette = PartyColors_p; break; - case 1: {//periodically replace palette with a random one - unsigned long timeSinceLastChange = millis() - _lastPaletteChange; - if (timeSinceLastChange > randomPaletteChangeTime * 1000U) { + case 1: {//periodically replace palette with a random one + if ((millis()/1000U) - _lastPaletteChange > randomPaletteChangeTime) { _newRandomPalette = generateRandomPalette(_randomPalette); - _lastPaletteChange = millis(); + _lastPaletteChange = millis()/1000U; + _lastPaletteBlend = (uint16_t)(millis()&0xFFFF)-512; //starts blending immediately handleRandomPalette(); // do a 1st pass of blend } targetPalette = _randomPalette; @@ -461,6 +462,15 @@ CRGBPalette16 IRAM_ATTR &Segment::currentPalette(CRGBPalette16 &targetPalette, u void Segment::handleRandomPalette() { // just do a blend; if the palettes are identical it will just compare 48 bytes (same as _randomPalette == _newRandomPalette) // this will slowly blend _newRandomPalette into _randomPalette every 15ms or 8ms (depending on MIN_SHOW_DELAY) + // if palette transitions is enabled, blend it according to Transition Time (if longer than minimum given by service calls) + if(strip.paletteFade) + { + if((millis()&0xFFFF) - _lastPaletteBlend < strip.getTransition()>>7) //assumes that 128 updates are needed to blend a palette, so shift by 7 (can be more, can be less) + { + return; //not time to fade yet + } + _lastPaletteBlend = millis(); + } nblendPaletteTowardPalette(_randomPalette, _newRandomPalette, 48); } From ca05aa84ff0d94851c688493f1d9d74f699a9b6f Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Tue, 30 Jan 2024 22:28:40 +0100 Subject: [PATCH 08/10] changed randomness and added optimizations -added fully random palette function ('the old way', currently just used for initialization) -changed randomness values to make it a little less random -added 10% chance for pastel color palette -now using swap() from std library for shuffeling -changed function name -moved update check from loadPalette() to handleRandomPalette() saving CPU cycles --- wled00/FX_fcn.cpp | 26 +++++------ wled00/colors.cpp | 101 +++++++++++++++++++++++-------------------- wled00/fcn_declare.h | 3 +- 3 files changed, 70 insertions(+), 60 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 1b8c09aaa6..bb260bf2e9 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -77,8 +77,8 @@ uint16_t Segment::_usedSegmentData = 0U; // amount of RAM all segments use for t uint16_t Segment::maxWidth = DEFAULT_LED_COUNT; uint16_t Segment::maxHeight = 1; -CRGBPalette16 Segment::_randomPalette = generateRandomPalette(_randomPalette); -CRGBPalette16 Segment::_newRandomPalette = generateRandomPalette(_randomPalette); +CRGBPalette16 Segment::_randomPalette = generateRandomPalette(); +CRGBPalette16 Segment::_newRandomPalette = generateRandomPalette(); uint16_t Segment::_lastPaletteChange = 0; // perhaps it should be per segment uint16_t Segment::_lastPaletteBlend = 0; //in millis (lowest 16 bits only) @@ -222,13 +222,7 @@ CRGBPalette16 IRAM_ATTR &Segment::loadPalette(CRGBPalette16 &targetPalette, uint case 0: //default palette. Exceptions for specific effects above targetPalette = PartyColors_p; break; case 1: {//periodically replace palette with a random one - if ((millis()/1000U) - _lastPaletteChange > randomPaletteChangeTime) { - _newRandomPalette = generateRandomPalette(_randomPalette); - _lastPaletteChange = millis()/1000U; - _lastPaletteBlend = (uint16_t)(millis()&0xFFFF)-512; //starts blending immediately - handleRandomPalette(); // do a 1st pass of blend - } - targetPalette = _randomPalette; + targetPalette = _randomPalette; //random palette is generated at intervals in handleRandomPalette() break;} case 2: {//primary color only CRGB prim = gamma32(colors[0]); @@ -463,11 +457,17 @@ void Segment::handleRandomPalette() { // just do a blend; if the palettes are identical it will just compare 48 bytes (same as _randomPalette == _newRandomPalette) // this will slowly blend _newRandomPalette into _randomPalette every 15ms or 8ms (depending on MIN_SHOW_DELAY) // if palette transitions is enabled, blend it according to Transition Time (if longer than minimum given by service calls) - if(strip.paletteFade) + + if ((millis()/1000U) - _lastPaletteChange > randomPaletteChangeTime) { + _newRandomPalette = generateHarmonicRandomPalette(_randomPalette); + _lastPaletteChange = millis()/1000U; + _lastPaletteBlend = (uint16_t)(millis()&0xFFFF)-512; //starts blending immediately + } + + if (strip.paletteFade) { - if((millis()&0xFFFF) - _lastPaletteBlend < strip.getTransition()>>7) //assumes that 128 updates are needed to blend a palette, so shift by 7 (can be more, can be less) - { - return; //not time to fade yet + if ((millis() & 0xFFFF) - _lastPaletteBlend < strip.getTransition() >> 7) {//assumes that 128 updates are needed to blend a palette, so shift by 7 (can be more, can be less) + return; //not time to fade yet, delay the update } _lastPaletteBlend = millis(); } diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 9f16d1290d..5daeb1f285 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -92,42 +92,33 @@ void setRandomColor(byte* rgb) } /* - *generates a random palette based on color theory + *generates a random palette based on harmonic color theory + *takes a base palette as the input, it will choose one color of the base palette and keep it */ -CRGBPalette16 generateRandomPalette(CRGBPalette16 &basepalette) +CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette) { CHSV palettecolors[4]; //array of colors for the new palette uint8_t keepcolorposition = random8(4); //color position of current random palette to keep palettecolors[keepcolorposition] = rgb2hsv_approximate(basepalette.entries[keepcolorposition*5]); //read one of the base colors of the current palette - palettecolors[keepcolorposition].hue += random8(20)-10; // +/- 10 randomness + palettecolors[keepcolorposition].hue += random8(10)-5; // +/- 5 randomness of base color //generate 4 saturation and brightness value numbers //only one saturation is allowed to be below 200 creating mostly vibrant colors //only one brightness value number is allowed below 200, creating mostly bright palettes - for (int i = 0; i<3; i++) { //generate three high values - palettecolors[i].saturation = random8(180,255); - palettecolors[i].value = random8(180,255); + for (int i = 0; i < 3; i++) { //generate three high values + palettecolors[i].saturation = random8(200,255); + palettecolors[i].value = random8(220,255); } //allow one to be lower palettecolors[3].saturation = random8(80,255); - palettecolors[3].value = random8(50,255); + palettecolors[3].value = random8(80,255); - //shuffle the arrays using Fisher-Yates algorithm - for (int i = 3; i > 0; i--) { - uint8_t j = random8(0, i + 1); - //swap [i] and [j] - uint8_t temp = palettecolors[i].saturation; - palettecolors[i].saturation = palettecolors[j].saturation; - palettecolors[j].saturation = temp; - } + //shuffle the arrays for (int i = 3; i > 0; i--) { - uint8_t j = random8(0, i + 1); - //swap [i] and [j] - uint8_t temp = palettecolors[i].value; - palettecolors[i].value = palettecolors[j].value; - palettecolors[j].value = temp; + std::swap(palettecolors[i].saturation, palettecolors[random8(i + 1)].saturation); + std::swap(palettecolors[i].value, palettecolors[random8(i + 1)].value); } //now generate three new hues based off of the hue of the chosen current color @@ -143,50 +134,58 @@ CRGBPalette16 generateRandomPalette(CRGBPalette16 &basepalette) break; case 1: // triadic - harmonics[0] = basehue + 110 + random8(20); - harmonics[1] = basehue + 230 + random8(20); - harmonics[2] = basehue + random8(30)-15; + harmonics[0] = basehue + 113 + random8(15); + harmonics[1] = basehue + 233 + random8(15); + harmonics[2] = basehue -7 + random8(15); break; case 2: // split-complementary - harmonics[0] = basehue + 140 + random8(20); - harmonics[1] = basehue + 200 + random8(20); - harmonics[2] = basehue + random8(30)-15; + harmonics[0] = basehue + 145 + random8(10); + harmonics[1] = basehue + 205 + random8(10); + harmonics[2] = basehue - 5 + random8(10); break; - - case 3: // tetradic + + case 3: // square + harmonics[0] = basehue + 85 + random8(10); + harmonics[1] = basehue + 175 + random8(10); + harmonics[2] = basehue + 265 + random8(10); + break; + + case 4: // tetradic harmonics[0] = basehue + 80 + random8(20); harmonics[1] = basehue + 170 + random8(20); harmonics[2] = basehue + random8(30)-15; - break; - - case 4: // square - harmonics[0] = basehue + 80 + random8(20); - harmonics[1] = basehue + 170 + random8(20); - harmonics[2] = basehue + 260 + random8(20); - break; + break; } - //shuffle the hues: - for (int i = 2; i > 0; i--) { - uint8_t j = random8(0, i + 1); - //swap [i] and [j] - uint8_t temp = harmonics[i]; - harmonics[i] = harmonics[j]; - harmonics[j] = temp; + + if (random8() < 128) //50:50 chance of shuffeling hues or keep the color order + { + //shuffle the hues: + for (int i = 2; i > 0; i--) { + std::swap(harmonics[i], harmonics[random8(i + 1)]); + } } //now set the hues - int j=0; - for (int i = 0; i<4; i++) { + int j = 0; + for (int i = 0; i < 4; i++) { if(i==keepcolorposition) continue; //skip the base color palettecolors[i].hue = harmonics[j]; j++; } - //apply gamma correction + bool makepastelpalette = false; + if (random8() < 25) {//~10% chance of desaturated 'pastel' colors + makepastelpalette = true; + } + + //apply saturation & gamma correction CRGB RGBpalettecolors[4]; - for (int i = 0; i<4; i++) { + for (int i = 0; i < 4; i++) { + if(makepastelpalette && palettecolors[i].saturation > 180) { + palettecolors[i].saturation -= 160; //desaturate all four colors + } RGBpalettecolors[i] = (CRGB)palettecolors[i]; //convert to RGB RGBpalettecolors[i] = gamma32((uint32_t)RGBpalettecolors[i]); } @@ -195,7 +194,17 @@ CRGBPalette16 generateRandomPalette(CRGBPalette16 &basepalette) RGBpalettecolors[1], RGBpalettecolors[2], RGBpalettecolors[3]); +} + +CRGBPalette16 generateRandomPalette(void) //generate fully random palette +{ + CRGBPalette16 random = CRGBPalette16( + CHSV(random8(), random8(160, 255), random8(128, 255)), + CHSV(random8(), random8(160, 255), random8(128, 255)), + CHSV(random8(), random8(160, 255), random8(128, 255)), + CHSV(random8(), random8(160, 255), random8(128, 255))); + return generateHarmonicRandomPalette(random); } void colorHStoRGB(uint16_t hue, byte sat, byte* rgb) //hue, sat to rgb diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index ff37184617..e664e17065 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -65,7 +65,8 @@ class NeoGammaWLEDMethod { uint32_t color_blend(uint32_t,uint32_t,uint16_t,bool b16=false); uint32_t color_add(uint32_t,uint32_t, bool fast=false); uint32_t color_fade(uint32_t c1, uint8_t amount, bool video=false); -CRGBPalette16 generateRandomPalette(CRGBPalette16 &basepalette); +CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette); +CRGBPalette16 generateRandomPalette(void); inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); } void colorHStoRGB(uint16_t hue, byte sat, byte* rgb); //hue, sat to rgb void colorKtoRGB(uint16_t kelvin, byte* rgb); From e0f89beebbbf453135d10565d188c69487d5be71 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Thu, 1 Feb 2024 20:06:48 +0100 Subject: [PATCH 09/10] slight change to color parameters added more white, changed function return value of fully random palette function --- wled00/colors.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 5daeb1f285..2b24c718d5 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -111,7 +111,7 @@ CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette) palettecolors[i].value = random8(220,255); } //allow one to be lower - palettecolors[3].saturation = random8(80,255); + palettecolors[3].saturation = random8(20,255); palettecolors[3].value = random8(80,255); @@ -198,13 +198,11 @@ CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette) CRGBPalette16 generateRandomPalette(void) //generate fully random palette { - CRGBPalette16 random = CRGBPalette16( - CHSV(random8(), random8(160, 255), random8(128, 255)), - CHSV(random8(), random8(160, 255), random8(128, 255)), - CHSV(random8(), random8(160, 255), random8(128, 255)), - CHSV(random8(), random8(160, 255), random8(128, 255))); - - return generateHarmonicRandomPalette(random); + return CRGBPalette16( + CHSV(random8(), random8(160, 255), random8(128, 255)), + CHSV(random8(), random8(160, 255), random8(128, 255)), + CHSV(random8(), random8(160, 255), random8(128, 255)), + CHSV(random8(), random8(160, 255), random8(128, 255))); } void colorHStoRGB(uint16_t hue, byte sat, byte* rgb) //hue, sat to rgb From 41e51bbeb5776081eb94adff90164f9e5a6531df Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Tue, 6 Feb 2024 11:06:23 +0100 Subject: [PATCH 10/10] Configuration item for harmonic palettes Comment cleanup --- wled00/FX.h | 4 ++-- wled00/FX_fcn.cpp | 35 +++++++++++++-------------- wled00/cfg.cpp | 2 ++ wled00/colors.cpp | 45 ++++++++++++++++------------------- wled00/data/settings_leds.htm | 1 + wled00/set.cpp | 1 + wled00/wled.h | 17 ++++++------- wled00/xml.cpp | 1 + 8 files changed, 52 insertions(+), 54 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index b29a8008eb..703191ea91 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -420,8 +420,8 @@ typedef struct Segment { // perhaps this should be per segment, not static static CRGBPalette16 _randomPalette; // actual random palette static CRGBPalette16 _newRandomPalette; // target random palette - static uint16_t _lastPaletteChange; // last random palette change time in millis()/1000 - static uint16_t _lastPaletteBlend; // blend palette according to set Transition Delay in millis()%0xFFFF + static uint16_t _lastPaletteChange; // last random palette change time in millis()/1000 + static uint16_t _lastPaletteBlend; // blend palette according to set Transition Delay in millis()%0xFFFF #ifndef WLED_DISABLE_MODE_BLEND static bool _modeBlend; // mode/effect blending semaphore #endif diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index bb260bf2e9..617558ffa2 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -77,10 +77,10 @@ uint16_t Segment::_usedSegmentData = 0U; // amount of RAM all segments use for t uint16_t Segment::maxWidth = DEFAULT_LED_COUNT; uint16_t Segment::maxHeight = 1; -CRGBPalette16 Segment::_randomPalette = generateRandomPalette(); -CRGBPalette16 Segment::_newRandomPalette = generateRandomPalette(); -uint16_t Segment::_lastPaletteChange = 0; // perhaps it should be per segment -uint16_t Segment::_lastPaletteBlend = 0; //in millis (lowest 16 bits only) +CRGBPalette16 Segment::_randomPalette = generateRandomPalette(); // was CRGBPalette16(DEFAULT_COLOR); +CRGBPalette16 Segment::_newRandomPalette = generateRandomPalette(); // was CRGBPalette16(DEFAULT_COLOR); +uint16_t Segment::_lastPaletteChange = 0; // perhaps it should be per segment +uint16_t Segment::_lastPaletteBlend = 0; //in millis (lowest 16 bits only) #ifndef WLED_DISABLE_MODE_BLEND bool Segment::_modeBlend = false; @@ -221,9 +221,9 @@ CRGBPalette16 IRAM_ATTR &Segment::loadPalette(CRGBPalette16 &targetPalette, uint switch (pal) { case 0: //default palette. Exceptions for specific effects above targetPalette = PartyColors_p; break; - case 1: {//periodically replace palette with a random one + case 1: //randomly generated palette targetPalette = _randomPalette; //random palette is generated at intervals in handleRandomPalette() - break;} + break; case 2: {//primary color only CRGB prim = gamma32(colors[0]); targetPalette = CRGBPalette16(prim); break;} @@ -452,24 +452,21 @@ CRGBPalette16 IRAM_ATTR &Segment::currentPalette(CRGBPalette16 &targetPalette, u return targetPalette; } -// relies on WS2812FX::service() to call it max every 8ms or more (MIN_SHOW_DELAY) +// relies on WS2812FX::service() to call it for each frame void Segment::handleRandomPalette() { - // just do a blend; if the palettes are identical it will just compare 48 bytes (same as _randomPalette == _newRandomPalette) - // this will slowly blend _newRandomPalette into _randomPalette every 15ms or 8ms (depending on MIN_SHOW_DELAY) - // if palette transitions is enabled, blend it according to Transition Time (if longer than minimum given by service calls) - + // is it time to generate a new palette? if ((millis()/1000U) - _lastPaletteChange > randomPaletteChangeTime) { - _newRandomPalette = generateHarmonicRandomPalette(_randomPalette); + _newRandomPalette = useHarmonicRandomPalette ? generateHarmonicRandomPalette(_randomPalette) : generateRandomPalette(); _lastPaletteChange = millis()/1000U; - _lastPaletteBlend = (uint16_t)(millis()&0xFFFF)-512; //starts blending immediately + _lastPaletteBlend = (uint16_t)(millis() & 0xFFFF)-512; // starts blending immediately } - if (strip.paletteFade) - { - if ((millis() & 0xFFFF) - _lastPaletteBlend < strip.getTransition() >> 7) {//assumes that 128 updates are needed to blend a palette, so shift by 7 (can be more, can be less) - return; //not time to fade yet, delay the update - } - _lastPaletteBlend = millis(); + // if palette transitions is enabled, blend it according to Transition Time (if longer than minimum given by service calls) + if (strip.paletteFade) { + // assumes that 128 updates are sufficient to blend a palette, so shift by 7 (can be more, can be less) + // in reality there need to be 255 blends to fully blend two entirely different palettes + if ((millis() & 0xFFFF) - _lastPaletteBlend < strip.getTransition() >> 7) return; // not yet time to fade, delay the update + _lastPaletteBlend = millis(); } nblendPaletteTowardPalette(_randomPalette, _newRandomPalette, 48); } diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 53c0d5290b..89b0d10b00 100755 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -395,6 +395,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { strip.setTransition(fadeTransition ? transitionDelayDefault : 0); CJSON(strip.paletteFade, light_tr["pal"]); CJSON(randomPaletteChangeTime, light_tr[F("rpc")]); + CJSON(useHarmonicRandomPalette, light_tr[F("hrp")]); JsonObject light_nl = light["nl"]; CJSON(nightlightMode, light_nl["mode"]); @@ -872,6 +873,7 @@ void serializeConfig() { light_tr["dur"] = transitionDelayDefault / 100; light_tr["pal"] = strip.paletteFade; light_tr[F("rpc")] = randomPaletteChangeTime; + light_tr[F("hrp")] = useHarmonicRandomPalette; JsonObject light_nl = light.createNestedObject("nl"); light_nl["mode"] = nightlightMode; diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 2b24c718d5..3ed54d9594 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -91,12 +91,11 @@ void setRandomColor(byte* rgb) colorHStoRGB(lastRandomIndex*256,255,rgb); } -/* - *generates a random palette based on harmonic color theory - *takes a base palette as the input, it will choose one color of the base palette and keep it +/* + * generates a random palette based on harmonic color theory + * takes a base palette as the input, it will choose one color of the base palette and keep it */ - -CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette) +CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette) { CHSV palettecolors[4]; //array of colors for the new palette uint8_t keepcolorposition = random8(4); //color position of current random palette to keep @@ -104,7 +103,7 @@ CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette) palettecolors[keepcolorposition].hue += random8(10)-5; // +/- 5 randomness of base color //generate 4 saturation and brightness value numbers //only one saturation is allowed to be below 200 creating mostly vibrant colors - //only one brightness value number is allowed below 200, creating mostly bright palettes + //only one brightness value number is allowed below 200, creating mostly bright palettes for (int i = 0; i < 3; i++) { //generate three high values palettecolors[i].saturation = random8(200,255); @@ -114,8 +113,7 @@ CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette) palettecolors[3].saturation = random8(20,255); palettecolors[3].value = random8(80,255); - - //shuffle the arrays + //shuffle the arrays for (int i = 3; i > 0; i--) { std::swap(palettecolors[i].saturation, palettecolors[random8(i + 1)].saturation); std::swap(palettecolors[i].value, palettecolors[random8(i + 1)].value); @@ -151,17 +149,15 @@ CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette) harmonics[2] = basehue + 265 + random8(10); break; - case 4: // tetradic + case 4: // tetradic harmonics[0] = basehue + 80 + random8(20); harmonics[1] = basehue + 170 + random8(20); harmonics[2] = basehue + random8(30)-15; break; } - - if (random8() < 128) //50:50 chance of shuffeling hues or keep the color order - { - //shuffle the hues: + if (random8() < 128) { + //50:50 chance of shuffling hues or keep the color order for (int i = 2; i > 0; i--) { std::swap(harmonics[i], harmonics[random8(i + 1)]); } @@ -170,36 +166,35 @@ CRGBPalette16 generateHarmonicRandomPalette(CRGBPalette16 &basepalette) //now set the hues int j = 0; for (int i = 0; i < 4; i++) { - if(i==keepcolorposition) continue; //skip the base color + if (i==keepcolorposition) continue; //skip the base color palettecolors[i].hue = harmonics[j]; j++; - } + } bool makepastelpalette = false; - if (random8() < 25) {//~10% chance of desaturated 'pastel' colors - makepastelpalette = true; + if (random8() < 25) { //~10% chance of desaturated 'pastel' colors + makepastelpalette = true; } //apply saturation & gamma correction CRGB RGBpalettecolors[4]; for (int i = 0; i < 4; i++) { - if(makepastelpalette && palettecolors[i].saturation > 180) { + if (makepastelpalette && palettecolors[i].saturation > 180) { palettecolors[i].saturation -= 160; //desaturate all four colors } RGBpalettecolors[i] = (CRGB)palettecolors[i]; //convert to RGB - RGBpalettecolors[i] = gamma32((uint32_t)RGBpalettecolors[i]); + RGBpalettecolors[i] = gamma32(((uint32_t)RGBpalettecolors[i]) & 0x00FFFFFFU); //strip alpha from CRGB } - return CRGBPalette16( RGBpalettecolors[0], - RGBpalettecolors[1], - RGBpalettecolors[2], - RGBpalettecolors[3]); + return CRGBPalette16(RGBpalettecolors[0], + RGBpalettecolors[1], + RGBpalettecolors[2], + RGBpalettecolors[3]); } CRGBPalette16 generateRandomPalette(void) //generate fully random palette { - return CRGBPalette16( - CHSV(random8(), random8(160, 255), random8(128, 255)), + return CRGBPalette16(CHSV(random8(), random8(160, 255), random8(128, 255)), CHSV(random8(), random8(160, 255), random8(128, 255)), CHSV(random8(), random8(160, 255), random8(128, 255)), CHSV(random8(), random8(160, 255), random8(128, 255))); diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index e80cad7414..b7992660ec 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -848,6 +848,7 @@

Transitions

Palette transitions:
Random Cycle Palette Time: s
+ Use harmonic Random Cycle Palette:

Timed light

Default Duration: min
Default Target brightness:
diff --git a/wled00/set.cpp b/wled00/set.cpp index 49a54ab253..3be2fc38f6 100755 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -302,6 +302,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) strip.paletteFade = request->hasArg(F("PF")); t = request->arg(F("TP")).toInt(); randomPaletteChangeTime = MIN(255,MAX(1,t)); + useHarmonicRandomPalette = request->hasArg(F("TH")); nightlightTargetBri = request->arg(F("TB")).toInt(); t = request->arg(F("TL")).toInt(); diff --git a/wled00/wled.h b/wled00/wled.h index b2f20c15f0..3af970e0cb 100755 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -542,15 +542,16 @@ WLED_GLOBAL bool wasConnected _INIT(false); WLED_GLOBAL byte lastRandomIndex _INIT(0); // used to save last random color so the new one is not the same // transitions -WLED_GLOBAL bool fadeTransition _INIT(true); // enable crossfading brightness/color -WLED_GLOBAL bool modeBlending _INIT(true); // enable effect blending -WLED_GLOBAL bool transitionActive _INIT(false); -WLED_GLOBAL uint16_t transitionDelay _INIT(750); // global transition duration -WLED_GLOBAL uint16_t transitionDelayDefault _INIT(750); // default transition time (stored in cfg.json) +WLED_GLOBAL bool fadeTransition _INIT(true); // enable crossfading brightness/color +WLED_GLOBAL bool modeBlending _INIT(true); // enable effect blending +WLED_GLOBAL bool transitionActive _INIT(false); +WLED_GLOBAL uint16_t transitionDelay _INIT(750); // global transition duration +WLED_GLOBAL uint16_t transitionDelayDefault _INIT(750); // default transition time (stored in cfg.json) WLED_GLOBAL unsigned long transitionStartTime; -WLED_GLOBAL float tperLast _INIT(0.0f); // crossfade transition progress, 0.0f - 1.0f -WLED_GLOBAL bool jsonTransitionOnce _INIT(false); // flag to override transitionDelay (playlist, JSON API: "live" & "seg":{"i"} & "tt") -WLED_GLOBAL uint8_t randomPaletteChangeTime _INIT(5); // amount of time [s] between random palette changes (min: 1s, max: 255s) +WLED_GLOBAL float tperLast _INIT(0.0f); // crossfade transition progress, 0.0f - 1.0f +WLED_GLOBAL bool jsonTransitionOnce _INIT(false); // flag to override transitionDelay (playlist, JSON API: "live" & "seg":{"i"} & "tt") +WLED_GLOBAL uint8_t randomPaletteChangeTime _INIT(5); // amount of time [s] between random palette changes (min: 1s, max: 255s) +WLED_GLOBAL bool useHarmonicRandomPalette _INIT(true); // use *harmonic* random palette generation (nicer looking) or truly random // nightlight WLED_GLOBAL bool nightlightActive _INIT(false); diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 3c7ebd2c38..a24d76fb20 100755 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -453,6 +453,7 @@ void getSettingsJS(byte subPage, char* dest) sappend('v',SET_F("TD"),transitionDelayDefault); sappend('c',SET_F("PF"),strip.paletteFade); sappend('v',SET_F("TP"),randomPaletteChangeTime); + sappend('c',SET_F("TH"),useHarmonicRandomPalette); sappend('v',SET_F("BF"),briMultiplier); sappend('v',SET_F("TB"),nightlightTargetBri); sappend('v',SET_F("TL"),nightlightDelayMinsDefault);