diff --git a/readme.md b/readme.md index 08a325b7..7eaffcdd 100644 --- a/readme.md +++ b/readme.md @@ -1,11 +1,11 @@ ![WLED logo](https://raw.githubusercontent.com/Aircoookie/WLED/development/wled_logo.png) -## Welcome to my project WLED! (v0.8.0) +## Welcome to my project WLED! (v0.8.1) A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control NeoPixel (WS2812B) LEDs! ### Features: -- WS2812FX library integrated for over 70 special effects +- WS2812FX library integrated for 75 special effects - FastLED noise effects and palettes - Customizable Mobile and desktop UI with color and effect controls - Settings page - configuration over network diff --git a/wled00/NpbWrapper.h b/wled00/NpbWrapper.h index 5912966a..9ea3c980 100644 --- a/wled00/NpbWrapper.h +++ b/wled00/NpbWrapper.h @@ -2,25 +2,32 @@ #ifndef NpbWrapper_h #define NpbWrapper_h -//#define WORKAROUND_ESP32_BITBANG +#define WORKAROUND_ESP32_BITBANG //see https://github.com/Aircoookie/WLED/issues/2 for flicker free ESP32 support -#define LEDPIN 2 //strip pin. Only effective for ESP32, ESP8266 must use gpio2 +#define LEDPIN 2 //strip pin. Any for ESP32, gpio2 is recommended for ESP8266 //uncomment this if red and green are swapped //#define SWAPRG //automatically uses the right driver method for each platform #ifdef ARDUINO_ARCH_ESP32 -#ifdef WORKAROUND_ESP32_BITBANG -#define PIXELMETHOD NeoEsp32BitBangWs2813Method -#else -#define PIXELMETHOD NeoEsp32RmtWS2813_V3Method -#endif + #ifdef WORKAROUND_ESP32_BITBANG + #define PIXELMETHOD NeoEsp32BitBangWs2813Method + #pragma message "Software BitBang is used because of your NeoPixelBus version. Look in NpbWrapper.h for instructions on how to mitigate flickering." + #else + #define PIXELMETHOD NeoEsp32RmtWS2813_V3Method + #endif #else //esp8266 -//you may change to DMA method on pin GPIO3 here -#define PIXELMETHOD NeoEsp8266Uart800KbpsMethod -//#define PIXELMETHOD NeoEsp8266Dma800KbpsMethod + //autoselect the right method depending on strip pin + #if LEDPIN == 2 + #define PIXELMETHOD NeoEsp8266Uart800KbpsMethod + #elif LEDPIN == 3 + #define PIXELMETHOD NeoEsp8266Dma800KbpsMethod + #else + #define PIXELMETHOD NeoEsp8266BitBang800KbpsMethod + #pragma message "Software BitBang will be used because of your selected LED pin. This may cause flicker. Use GPIO 2 or 3 for best results." + #endif #endif //handle swapping Red and Green automatically diff --git a/wled00/WS2812FX.cpp b/wled00/WS2812FX.cpp index 8f4af282..84f3bea4 100644 --- a/wled00/WS2812FX.cpp +++ b/wled00/WS2812FX.cpp @@ -40,8 +40,7 @@ #include "WS2812FX.h" -#include "FastLED.h" -#include "palettes.h"; +#include "palettes.h" void WS2812FX::init(bool supportWhite, uint16_t countPixels, bool skipFirst) { @@ -72,6 +71,7 @@ void WS2812FX::service() { _segment_index = i; if(now > SEGMENT_RUNTIME.next_time || _triggered) { doShow = true; + handle_palette(); uint16_t delay = (this->*_mode[SEGMENT.mode])(); SEGMENT_RUNTIME.next_time = now + max(delay, 5); SEGMENT_RUNTIME.counter_mode_call++; @@ -89,6 +89,12 @@ void WS2812FX::clear() bus->ClearTo(RgbColor(0)); } +bool WS2812FX::modeUsesLock(uint8_t m) +{ + if (m == FX_MODE_FIRE_2012 || m == FX_MODE_COLORTWINKLE) return true; + return false; +} + void WS2812FX::setPixelColor(uint16_t n, uint32_t c) { uint8_t w = (c >> 24) & 0xFF; uint8_t r = (c >> 16) & 0xFF; @@ -99,8 +105,8 @@ void WS2812FX::setPixelColor(uint16_t n, uint32_t c) { void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w) { + if (_locked[i] && !modeUsesLock(SEGMENT.mode)) return; if (_reverseMode) i = _length - 1 -i; - if (_locked[i] && SEGMENT.mode != FX_MODE_FIRE_2012) return; if (IS_REVERSE) i = SEGMENT.stop - (i - SEGMENT.start); //reverse just individual segment if (!_cronixieMode) { @@ -176,7 +182,7 @@ void WS2812FX::trigger() { void WS2812FX::setMode(uint8_t m) { RESET_RUNTIME; - bool ua = _segments[0].mode == FX_MODE_FIRE_2012 && m != FX_MODE_FIRE_2012; + bool ua = modeUsesLock(_segments[0].mode) && !modeUsesLock(m); _segments[0].mode = constrain(m, 0, MODE_COUNT - 1); if (ua) unlockAll(); setBrightness(_brightness); @@ -317,7 +323,7 @@ void WS2812FX::resetSegments() { void WS2812FX::setIndividual(uint16_t i, uint32_t col) { - if (SEGMENT.mode == FX_MODE_FIRE_2012) return; + if (modeUsesLock(SEGMENT.mode)) return; if (i >= 0 && i < _length) { _locked[i] = false; @@ -339,13 +345,13 @@ void WS2812FX::setRange(uint16_t i, uint16_t i2, uint32_t col) void WS2812FX::lock(uint16_t i) { - if (SEGMENT.mode == FX_MODE_FIRE_2012) return; + if (modeUsesLock(SEGMENT.mode)) return; if (i >= 0 && i < _length) _locked[i] = true; } void WS2812FX::lockRange(uint16_t i, uint16_t i2) { - if (SEGMENT.mode == FX_MODE_FIRE_2012) return; + if (modeUsesLock(SEGMENT.mode)) return; for (uint16_t x = i; x <= i2; x++) { if (i >= 0 && i < _length) _locked[i] = true; @@ -354,13 +360,13 @@ void WS2812FX::lockRange(uint16_t i, uint16_t i2) void WS2812FX::unlock(uint16_t i) { - if (SEGMENT.mode == FX_MODE_FIRE_2012) return; + if (modeUsesLock(SEGMENT.mode)) return; if (i >= 0 && i < _length) _locked[i] = false; } void WS2812FX::unlockRange(uint16_t i, uint16_t i2) { - if (SEGMENT.mode == FX_MODE_FIRE_2012) return; + if (modeUsesLock(SEGMENT.mode)) return; for (uint16_t x = i; x < i2; x++) { if (x >= 0 && x < _length) _locked[x] = false; @@ -376,7 +382,7 @@ void WS2812FX::setTransitionMode(bool t) { SEGMENT_RUNTIME.trans_act = (t) ? 1:2; if (!t) return; - unsigned long waitMax = millis() + 20; //refresh after 20 seconds if transition enabled + unsigned long waitMax = millis() + 20; //refresh after 20 ms if transition enabled if (SEGMENT.mode == FX_MODE_STATIC && SEGMENT_RUNTIME.next_time > waitMax) SEGMENT_RUNTIME.next_time = waitMax; } @@ -454,6 +460,7 @@ void WS2812FX::strip_off() { * Inspired by the Adafruit examples. */ uint32_t WS2812FX::color_wheel(uint8_t pos) { + if (SEGMENT.palette) return color_from_palette(pos, false, true, 0); pos = 255 - pos; if(pos < 85) { return ((uint32_t)(255 - pos * 3) << 16) | ((uint32_t)(0) << 8) | (pos * 3); @@ -497,17 +504,24 @@ uint16_t WS2812FX::mode_static(void) { return (SEGMENT_RUNTIME.trans_act == 1) ? 20 : 500; } +#define PALETTE_SOLID_WRAP (paletteBlend == 1 || paletteBlend == 3) /* * Blink/strobe function * Alternate between color1 and color2 * if(strobe == true) then create a strobe effect */ -uint16_t WS2812FX::blink(uint32_t color1, uint32_t color2, bool strobe) { +uint16_t WS2812FX::blink(uint32_t color1, uint32_t color2, bool strobe, bool do_palette) { uint32_t color = ((SEGMENT_RUNTIME.counter_mode_call & 1) == 0) ? color1 : color2; - if(IS_REVERSE) color = (color == color1) ? color2 : color1; - for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { - setPixelColor(i, color); + if (color == color1 && do_palette) + { + for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { + setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); + } + } else { + for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { + setPixelColor(i, color); + } } if((SEGMENT_RUNTIME.counter_mode_call & 1) == 0) { @@ -522,7 +536,7 @@ uint16_t WS2812FX::blink(uint32_t color1, uint32_t color2, bool strobe) { * Normal blinking. 50% on/off time. */ uint16_t WS2812FX::mode_blink(void) { - return blink(SEGMENT.colors[0], SEGMENT.colors[1], false); + return blink(SEGMENT.colors[0], SEGMENT.colors[1], false, true); } @@ -530,7 +544,7 @@ uint16_t WS2812FX::mode_blink(void) { * Classic Blink effect. Cycling through the rainbow. */ uint16_t WS2812FX::mode_blink_rainbow(void) { - return blink(color_wheel(SEGMENT_RUNTIME.counter_mode_call & 0xFF), SEGMENT.colors[1], false); + return blink(color_wheel(SEGMENT_RUNTIME.counter_mode_call & 0xFF), SEGMENT.colors[1], false, false); } @@ -538,7 +552,7 @@ uint16_t WS2812FX::mode_blink_rainbow(void) { * Classic Strobe effect. */ uint16_t WS2812FX::mode_strobe(void) { - return blink(SEGMENT.colors[0], SEGMENT.colors[1], true); + return blink(SEGMENT.colors[0], SEGMENT.colors[1], true, true); } @@ -546,7 +560,7 @@ uint16_t WS2812FX::mode_strobe(void) { * Classic Strobe effect. Cycling through the rainbow. */ uint16_t WS2812FX::mode_strobe_rainbow(void) { - return blink(color_wheel(SEGMENT_RUNTIME.counter_mode_call & 0xFF), SEGMENT.colors[1], true); + return blink(color_wheel(SEGMENT_RUNTIME.counter_mode_call & 0xFF), SEGMENT.colors[1], true, false); } @@ -555,10 +569,11 @@ uint16_t WS2812FX::mode_strobe_rainbow(void) { * LEDs are turned on (color1) in sequence, then turned off (color2) in sequence. * if (bool rev == true) then LEDs are turned off in reverse order */ -uint16_t WS2812FX::color_wipe(uint32_t color1, uint32_t color2, bool rev) { +uint16_t WS2812FX::color_wipe(uint32_t color1, uint32_t color2, bool rev, bool dopalette) { if(SEGMENT_RUNTIME.counter_mode_step < SEGMENT_LENGTH) { uint32_t led_offset = SEGMENT_RUNTIME.counter_mode_step; - setPixelColor(SEGMENT.start + led_offset, color1); + uint16_t i = SEGMENT.start + led_offset; + setPixelColor(i, dopalette ? color_from_palette(i, true, PALETTE_SOLID_WRAP, 0) : color1); } else { uint32_t led_offset = SEGMENT_RUNTIME.counter_mode_step - SEGMENT_LENGTH; if(rev) { @@ -577,14 +592,14 @@ uint16_t WS2812FX::color_wipe(uint32_t color1, uint32_t color2, bool rev) { * Lights all LEDs one after another. */ uint16_t WS2812FX::mode_color_wipe(void) { - return color_wipe(SEGMENT.colors[0], SEGMENT.colors[1], false); + return color_wipe(SEGMENT.colors[0], SEGMENT.colors[1], false, true); } /* * Lights all LEDs one after another. Turns off opposite */ uint16_t WS2812FX::mode_color_sweep(void) { - return color_wipe(SEGMENT.colors[0], SEGMENT.colors[1], true); + return color_wipe(SEGMENT.colors[0], SEGMENT.colors[1], true, true); } @@ -597,7 +612,7 @@ uint16_t WS2812FX::mode_color_wipe_random(void) { SEGMENT_RUNTIME.aux_param = get_random_wheel_index(SEGMENT_RUNTIME.aux_param); } uint32_t color = color_wheel(SEGMENT_RUNTIME.aux_param); - return color_wipe(color, color, false); + return color_wipe(color, color, false, false); } @@ -609,7 +624,7 @@ uint16_t WS2812FX::mode_color_sweep_random(void) { SEGMENT_RUNTIME.aux_param = get_random_wheel_index(SEGMENT_RUNTIME.aux_param); } uint32_t color = color_wheel(SEGMENT_RUNTIME.aux_param); - return color_wipe(color, color, true); + return color_wipe(color, color, true, false); } @@ -652,27 +667,35 @@ uint16_t WS2812FX::mode_breath(void) { if(lum > 255) lum = 511 - lum; // lum = 15 -> 255 -> 15 uint16_t delay; - if(lum == 15) delay = 970; // 970 pause before each breath - else if(lum <= 25) delay = 38; // 19 - else if(lum <= 50) delay = 36; // 18 - else if(lum <= 75) delay = 28; // 14 - else if(lum <= 100) delay = 20; // 10 - else if(lum <= 125) delay = 14; // 7 - else if(lum <= 150) delay = 11; // 5 - else delay = 10; // 4 + if(lum == 15) delay = 465; // 970 pause before each breath + else if(lum <= 25) delay = 19; // 19 + else if(lum <= 50) delay = 18; // 18 + else if(lum <= 75) delay = 14; // 14 + else if(lum <= 100) delay = 10; // 10 + else if(lum <= 125) delay = 7; // 7 + else if(lum <= 150) delay = 5; // 5 + else delay = 4; // 4 - uint32_t color = SEGMENT.colors[0]; - uint8_t w = (color >> 24 & 0xFF) * lum / 256; - uint8_t r = (color >> 16 & 0xFF) * lum / 256; - uint8_t g = (color >> 8 & 0xFF) * lum / 256; - uint8_t b = (color & 0xFF) * lum / 256; - for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { - setPixelColor(i, r, g, b, w); + if (SEGMENT.palette == 0) + { + uint32_t color = SEGMENT.colors[0]; + uint8_t w = (color >> 24 & 0xFF) * lum / 256; + uint8_t r = (color >> 16 & 0xFF) * lum / 256; + uint8_t g = (color >> 8 & 0xFF) * lum / 256; + uint8_t b = (color & 0xFF) * lum / 256; + for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { + setPixelColor(i, r, g, b, w); + } + } else + { + for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { + setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0, lum)); + } } SEGMENT_RUNTIME.counter_mode_step += 2; if(SEGMENT_RUNTIME.counter_mode_step > (512-15)) SEGMENT_RUNTIME.counter_mode_step = 15; - return delay; + return delay * (((256 - SEGMENT.speed)/64) +1); } @@ -683,9 +706,8 @@ uint16_t WS2812FX::mode_fade(void) { int lum = SEGMENT_RUNTIME.counter_mode_step; if(lum > 255) lum = 511 - lum; // lum = 0 -> 255 -> 0 - uint32_t color = color_blend(SEGMENT.colors[0], SEGMENT.colors[1], lum); for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { - setPixelColor(i, color); + setPixelColor(i, color_blend(color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), SEGMENT.colors[1], lum)); } SEGMENT_RUNTIME.counter_mode_step += 4; @@ -694,11 +716,11 @@ uint16_t WS2812FX::mode_fade(void) { } -//TODO add intensity (more than 1 pixel lit) /* - * Runs a single pixel back and forth. + * Scan mode parent function */ -uint16_t WS2812FX::mode_scan(void) { +uint16_t WS2812FX::scan(bool dual) +{ if(SEGMENT_RUNTIME.counter_mode_step > (SEGMENT_LENGTH * 2) - 3) { SEGMENT_RUNTIME.counter_mode_step = 0; } @@ -708,34 +730,35 @@ uint16_t WS2812FX::mode_scan(void) { } int led_offset = SEGMENT_RUNTIME.counter_mode_step - (SEGMENT_LENGTH - 1); - led_offset = abs(led_offset); - setPixelColor(SEGMENT.start + led_offset, SEGMENT.colors[0]); + led_offset = abs(led_offset); + + uint16_t i = SEGMENT.start + led_offset; + setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); + + if (dual) { + uint16_t i2 = SEGMENT.start + SEGMENT_LENGTH - led_offset - 1; + setPixelColor(i2, color_from_palette(i2, true, PALETTE_SOLID_WRAP, 0)); + } SEGMENT_RUNTIME.counter_mode_step++; return SPEED_FORMULA_L; } +//TODO add intensity (more than 1 pixel lit) +/* + * Runs a single pixel back and forth. + */ +uint16_t WS2812FX::mode_scan(void) { + return scan(false); +} + + /* * Runs two pixel back and forth in opposite directions. */ uint16_t WS2812FX::mode_dual_scan(void) { - if(SEGMENT_RUNTIME.counter_mode_step > (SEGMENT_LENGTH * 2) - 3) { - SEGMENT_RUNTIME.counter_mode_step = 0; - } - - for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { - setPixelColor(i, BLACK); - } - - int led_offset = SEGMENT_RUNTIME.counter_mode_step - (SEGMENT_LENGTH - 1); - led_offset = abs(led_offset); - - setPixelColor(SEGMENT.start + led_offset, SEGMENT.colors[0]); - setPixelColor(SEGMENT.start + SEGMENT_LENGTH - led_offset - 1, SEGMENT.colors[0]); - - SEGMENT_RUNTIME.counter_mode_step++; - return SPEED_FORMULA_L; + return scan(true); } @@ -770,11 +793,16 @@ uint16_t WS2812FX::mode_rainbow_cycle(void) { /* * theater chase function */ -uint16_t WS2812FX::theater_chase(uint32_t color1, uint32_t color2) { +uint16_t WS2812FX::theater_chase(uint32_t color1, uint32_t color2, bool dopalette) { SEGMENT_RUNTIME.counter_mode_call = SEGMENT_RUNTIME.counter_mode_call % 3; for(uint16_t i=0; i < SEGMENT_LENGTH; i++) { if((i % 3) == SEGMENT_RUNTIME.counter_mode_call) { - setPixelColor(SEGMENT.start + i, color1); + if (dopalette) + { + setPixelColor(SEGMENT.start + i, color_from_palette(SEGMENT.start + i, true, PALETTE_SOLID_WRAP, 0)); + } else { + setPixelColor(SEGMENT.start + i, color1); + } } else { setPixelColor(SEGMENT.start + i, color2); } @@ -788,7 +816,7 @@ uint16_t WS2812FX::theater_chase(uint32_t color1, uint32_t color2) { * Inspired by the Adafruit examples. */ uint16_t WS2812FX::mode_theater_chase(void) { - return theater_chase(SEGMENT.colors[0], SEGMENT.colors[1]); + return theater_chase(SEGMENT.colors[0], SEGMENT.colors[1], true); } @@ -798,7 +826,7 @@ uint16_t WS2812FX::mode_theater_chase(void) { */ uint16_t WS2812FX::mode_theater_chase_rainbow(void) { SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) & 0xFF; - return theater_chase(color_wheel(SEGMENT_RUNTIME.counter_mode_step), SEGMENT.colors[1]); + return theater_chase(color_wheel(SEGMENT_RUNTIME.counter_mode_step), SEGMENT.colors[1], false); } @@ -813,7 +841,12 @@ uint16_t WS2812FX::mode_running_lights(void) { for(uint16_t i=0; i < SEGMENT_LENGTH; i++) { int s = (sin(i+SEGMENT_RUNTIME.counter_mode_call) * 127) + 128; - setPixelColor(SEGMENT.start + i, (((uint32_t)(r * s)) / 255), (((uint32_t)(g * s)) / 255), (((uint32_t)(b * s)) / 255), (((uint32_t)(w * s)) / 255)); + if (SEGMENT.palette == 0) + { + setPixelColor(SEGMENT.start + i, (((uint32_t)(r * s)) / 255), (((uint32_t)(g * s)) / 255), (((uint32_t)(b * s)) / 255), (((uint32_t)(w * s)) / 255)); + } else { + setPixelColor(SEGMENT.start + i, color_from_palette(SEGMENT.start + i, true, PALETTE_SOLID_WRAP, 0, s)); + } } return 10 + (uint16_t)(255 - SEGMENT.speed); @@ -833,7 +866,13 @@ uint16_t WS2812FX::twinkle(uint32_t color) { SEGMENT_RUNTIME.counter_mode_step = random(min_leds, max_leds); } - setPixelColor(SEGMENT.start + random(SEGMENT_LENGTH), color); + uint16_t i = SEGMENT.start + random(SEGMENT_LENGTH); + if (color == SEGMENT.colors[0]) + { + setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); + } else { + setPixelColor(i, color); + } SEGMENT_RUNTIME.counter_mode_step--; return 50 + (8 * (uint16_t)(255 - SEGMENT.speed)); @@ -905,8 +944,15 @@ uint16_t WS2812FX::twinkle_fade(uint32_t color) { fade_out((255-SEGMENT.intensity) / 32); if(random8(3) == 0) { - setPixelColor(SEGMENT.start + random(SEGMENT_LENGTH), color); + uint16_t i = SEGMENT.start + random(SEGMENT_LENGTH); + if (color == SEGMENT.colors[0]) + { + setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); + } else { + setPixelColor(i, color); + } } + return 100 + ((uint32_t)(255 - SEGMENT.speed)) / 3; } @@ -932,7 +978,9 @@ uint16_t WS2812FX::mode_twinkle_fade_random(void) { * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ */ uint16_t WS2812FX::mode_sparkle(void) { - setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.aux_param, SEGMENT.colors[1]); + for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { + setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 1)); + } SEGMENT_RUNTIME.aux_param = random(SEGMENT_LENGTH); // aux_param stores the random led index setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.aux_param, SEGMENT.colors[0]); return 10 + (uint16_t)(255 - SEGMENT.speed); @@ -946,11 +994,12 @@ uint16_t WS2812FX::mode_sparkle(void) { uint16_t WS2812FX::mode_flash_sparkle(void) { if(SEGMENT_RUNTIME.counter_mode_call == 0) { for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { - setPixelColor(i, SEGMENT.colors[0]); + setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); } } - setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.aux_param, SEGMENT.colors[0]); + uint16_t i = SEGMENT.start + SEGMENT_RUNTIME.aux_param; + setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); if(random8(5) == 0) { SEGMENT_RUNTIME.aux_param = random(SEGMENT_LENGTH); // aux_param stores the random led index @@ -967,7 +1016,7 @@ uint16_t WS2812FX::mode_flash_sparkle(void) { */ uint16_t WS2812FX::mode_hyper_sparkle(void) { for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { - setPixelColor(i, SEGMENT.colors[0]); + setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); } if(random8(5) < 2) { @@ -985,7 +1034,7 @@ uint16_t WS2812FX::mode_hyper_sparkle(void) { */ uint16_t WS2812FX::mode_multi_strobe(void) { for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { - setPixelColor(i, SEGMENT.colors[1]); + setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 1)); } uint16_t delay = 50 + 20*(uint16_t)(255-SEGMENT.speed); @@ -1015,7 +1064,7 @@ uint16_t WS2812FX::mode_android(void) { } for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { - setPixelColor(i, SEGMENT.colors[1]); + setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 1)); } if (SEGMENT_RUNTIME.aux_param2 > ((float)SEGMENT.intensity/255.0)*(float)SEGMENT_LENGTH) @@ -1064,10 +1113,19 @@ uint16_t WS2812FX::mode_android(void) { * color1 = background color * color2 and color3 = colors of two adjacent leds */ -uint16_t WS2812FX::chase(uint32_t color1, uint32_t color2, uint32_t color3) { +uint16_t WS2812FX::chase(uint32_t color1, uint32_t color2, uint32_t color3, uint8_t dopalette) { uint16_t a = SEGMENT_RUNTIME.counter_mode_step; uint16_t b = (a + 1) % SEGMENT_LENGTH; uint16_t c = (b + 1) % SEGMENT_LENGTH; + + switch (dopalette) + { + case 0: break; + case 1: color1 = color_from_palette(SEGMENT.start + a, true, PALETTE_SOLID_WRAP, 1); break; + case 2: color2 = color_from_palette(SEGMENT.start + b, true, PALETTE_SOLID_WRAP, 1); break; + case 3: color3 = color_from_palette(SEGMENT.start + c, true, PALETTE_SOLID_WRAP, 1); break; + } + setPixelColor(SEGMENT.start + a, color1); setPixelColor(SEGMENT.start + b, color2); setPixelColor(SEGMENT.start + c, color3); @@ -1076,20 +1134,15 @@ uint16_t WS2812FX::chase(uint32_t color1, uint32_t color2, uint32_t color3) { return SPEED_FORMULA_L; } -/* - * Tricolor chase mode - */ -uint16_t WS2812FX::mode_tricolor_chase(void) { - return chase(SEGMENT.colors[0], SEGMENT.colors[1], SEGMENT.colors[2]); -} /* * Bicolor chase, more primary color. */ uint16_t WS2812FX::mode_chase_color(void) { - return chase(SEGMENT.colors[1], SEGMENT.colors[0], SEGMENT.colors[0]); + return chase(SEGMENT.colors[1], SEGMENT.colors[0], SEGMENT.colors[0], 1); } + /* * Primary running followed by random color. */ @@ -1097,7 +1150,7 @@ uint16_t WS2812FX::mode_chase_random(void) { if(SEGMENT_RUNTIME.counter_mode_step == 0) { SEGMENT_RUNTIME.aux_param = get_random_wheel_index(SEGMENT_RUNTIME.aux_param); } - return chase(color_wheel(SEGMENT_RUNTIME.aux_param), SEGMENT.colors[0], SEGMENT.colors[0]); + return chase(color_wheel(SEGMENT_RUNTIME.aux_param), SEGMENT.colors[0], SEGMENT.colors[0], 0); } @@ -1110,7 +1163,7 @@ uint16_t WS2812FX::mode_chase_rainbow_white(void) { uint32_t color2 = color_wheel(((n * 256 / SEGMENT_LENGTH) + (SEGMENT_RUNTIME.counter_mode_call & 0xFF)) & 0xFF); uint32_t color3 = color_wheel(((m * 256 / SEGMENT_LENGTH) + (SEGMENT_RUNTIME.counter_mode_call & 0xFF)) & 0xFF); - return chase(SEGMENT.colors[0], color2, color3); + return chase(SEGMENT.colors[0], color2, color3, 0); } @@ -1161,7 +1214,8 @@ uint16_t WS2812FX::mode_colorful(void) { * Emulates a traffic light. */ uint16_t WS2812FX::mode_traffic_light(void) { - for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) setPixelColor(i, SEGMENT.colors[1]); + for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) + setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 1)); uint32_t mdelay = 500; for (int i = SEGMENT.start; i < SEGMENT.stop-1 ; i+=3) { @@ -1188,7 +1242,7 @@ uint16_t WS2812FX::mode_chase_rainbow(void) { uint8_t color_index = SEGMENT_RUNTIME.counter_mode_call & 0xFF; uint32_t color = color_wheel(((SEGMENT_RUNTIME.counter_mode_step * color_sep) + color_index) & 0xFF); - return chase(color, SEGMENT.colors[0],SEGMENT.colors[1]); + return chase(color, SEGMENT.colors[0], SEGMENT.colors[1], 0); } @@ -1200,7 +1254,7 @@ uint16_t WS2812FX::mode_chase_flash(void) { uint8_t flash_step = SEGMENT_RUNTIME.counter_mode_call % ((flash_count * 2) + 1); for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { - setPixelColor(i, SEGMENT.colors[0]); + setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); } uint16_t delay = 10 + ((30 * (uint16_t)(255 - SEGMENT.speed)) / SEGMENT_LENGTH); @@ -1262,21 +1316,27 @@ uint16_t WS2812FX::mode_chase_flash_random(void) { uint16_t WS2812FX::running(uint32_t color1, uint32_t color2) { for(uint16_t i=0; i < SEGMENT_LENGTH; i++) { if((i + SEGMENT_RUNTIME.counter_mode_step) % 4 < 2) { - setPixelColor(SEGMENT.stop - i, color1); + if (color1 == SEGMENT.colors[0]) + { + setPixelColor(SEGMENT.stop - i, color_from_palette(SEGMENT.stop - i, true, PALETTE_SOLID_WRAP, 0)); + } else + { + setPixelColor(SEGMENT.stop - i, color1); + } } else { setPixelColor(SEGMENT.stop - i, color2); } } - SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) & 0x3; + if (SEGMENT.speed != 0) SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) & 0x3; return 35 + ((350 * (uint32_t)(255 - SEGMENT.speed)) / 255); } /* - * Alternating color/white pixels running. + * Alternating color/sec pixels running. */ uint16_t WS2812FX::mode_running_color(void) { - return running(SEGMENT.colors[0], WHITE); + return running(SEGMENT.colors[0], SEGMENT.colors[1]); } @@ -1327,11 +1387,13 @@ uint16_t WS2812FX::mode_running_random(void) { uint16_t WS2812FX::mode_larson_scanner(void) { fade_out((255-SEGMENT.intensity) / 32); + uint16_t index = 0; if(SEGMENT_RUNTIME.counter_mode_step < SEGMENT_LENGTH) { - setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[0]); + index = SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step; } else { - setPixelColor(SEGMENT.start + ((SEGMENT_LENGTH * 2) - SEGMENT_RUNTIME.counter_mode_step) - 2, SEGMENT.colors[0]); + index = SEGMENT.start + ((SEGMENT_LENGTH * 2) - SEGMENT_RUNTIME.counter_mode_step) - 2; } + setPixelColor(index, color_from_palette(index, true, PALETTE_SOLID_WRAP, 0)); SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % ((SEGMENT_LENGTH * 2) - 2); return SPEED_FORMULA_L; @@ -1344,11 +1406,8 @@ uint16_t WS2812FX::mode_larson_scanner(void) { uint16_t WS2812FX::mode_comet(void) { fade_out((255-SEGMENT.intensity) / 32); - if(IS_REVERSE) { - setPixelColor(SEGMENT.stop - SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[0]); - } else { - setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[0]); - } + uint16_t index = SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step; + setPixelColor(index, color_from_palette(index, true, PALETTE_SOLID_WRAP, 0)); SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % SEGMENT_LENGTH; return SPEED_FORMULA_L; @@ -1361,7 +1420,7 @@ uint16_t WS2812FX::mode_comet(void) { uint16_t WS2812FX::fireworks(uint32_t color) { uint32_t prevLed, thisLed, nextLed; - fade_out((255-SEGMENT.intensity) / 32); + fade_out(3); // set brightness(i) = ((brightness(i-1)/4 + brightness(i+1))/4) + brightness(i) for(uint16_t i=SEGMENT.start + 1; i > 16) & 0xFF; byte g = (SEGMENT.colors[0] >> 8) & 0xFF; byte b = (SEGMENT.colors[0] & 0xFF); - byte lum = max(w, max(r, max(g, b)))/(((256-SEGMENT.intensity)/16)+1); + byte lum = (SEGMENT.palette == 0) ? max(w, max(r, max(g, b))) : 255; + lum /= (((256-SEGMENT.intensity)/16)+1); for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { - int flicker = random8(lum); - setPixelColor(i, max(r - flicker, 0), max(g - flicker, 0), max(b - flicker, 0), max(w - flicker, 0)); + byte flicker = random8(lum); + if (SEGMENT.palette == 0) { + setPixelColor(i, max(r - flicker, 0), max(g - flicker, 0), max(b - flicker, 0), max(w - flicker, 0)); + } else { + setPixelColor(i, color_from_palette(i, true, PALETTE_SOLID_WRAP, 0, 255 - flicker)); + } } return 10 + (2 * (uint16_t)(255 - SEGMENT.speed)); } @@ -1508,18 +1574,21 @@ uint16_t WS2812FX::mode_dual_color_wipe_in_out(void) { int end = SEGMENT_LENGTH - SEGMENT_RUNTIME.counter_mode_step - 1; bool odd = (SEGMENT_LENGTH % 2) == 1; int mid = odd ? ((SEGMENT_LENGTH / 2) + 1) : (SEGMENT_LENGTH / 2); - if (SEGMENT_RUNTIME.counter_mode_step < mid) { - setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[0]); - setPixelColor(SEGMENT.start + end, SEGMENT.colors[0]); + if (SEGMENT_RUNTIME.counter_mode_step < mid) { + byte pindex = map(SEGMENT_RUNTIME.counter_mode_step, 0, mid -1, 0, 255); + uint32_t col = color_from_palette(pindex, false, false, 0); + + setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step, col); + setPixelColor(SEGMENT.start + end, col); } else { if (odd) { // If odd, we need to 'double count' the center LED (once to turn it on, // once to turn it off). So trail one behind after the middle LED. - setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step - 1, 0); - setPixelColor(SEGMENT.start + end + 1, 0); + setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step - 1, SEGMENT.colors[1]); + setPixelColor(SEGMENT.start + end + 1, SEGMENT.colors[1]); } else { - setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step, 0); - setPixelColor(SEGMENT.start + end, 0); + setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[1]); + setPixelColor(SEGMENT.start + end, SEGMENT.colors[1]); } } SEGMENT_RUNTIME.counter_mode_step++; @@ -1542,24 +1611,31 @@ uint16_t WS2812FX::mode_dual_color_wipe_in_out(void) { */ uint16_t WS2812FX::mode_dual_color_wipe_in_in(void) { bool odd = (SEGMENT_LENGTH % 2) == 1; - int mid = SEGMENT_LENGTH / 2; + int mid = SEGMENT_LENGTH / 2; + byte pindex = 0; + uint32_t col = 0; + if (SEGMENT_RUNTIME.counter_mode_step <= mid) + { + pindex = map(SEGMENT_RUNTIME.counter_mode_step, 0, mid, 0, 255); + col = color_from_palette(pindex, false, false, 0); + } if (odd) { if (SEGMENT_RUNTIME.counter_mode_step <= mid) { - setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[0]); - setPixelColor(SEGMENT.start + SEGMENT_LENGTH - SEGMENT_RUNTIME.counter_mode_step - 1, SEGMENT.colors[0]); + setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step, col); + setPixelColor(SEGMENT.start + SEGMENT_LENGTH - SEGMENT_RUNTIME.counter_mode_step - 1, col); } else { int i = SEGMENT_RUNTIME.counter_mode_step - mid; - setPixelColor(SEGMENT.start + i - 1, 0); - setPixelColor(SEGMENT.start + SEGMENT_LENGTH - i, 0); + setPixelColor(SEGMENT.start + i - 1, SEGMENT.colors[1]); + setPixelColor(SEGMENT.start + SEGMENT_LENGTH - i, SEGMENT.colors[1]); } } else { if (SEGMENT_RUNTIME.counter_mode_step < mid) { - setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[0]); - setPixelColor(SEGMENT.start + SEGMENT_LENGTH - SEGMENT_RUNTIME.counter_mode_step - 1, SEGMENT.colors[0]); + setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step, col); + setPixelColor(SEGMENT.start + SEGMENT_LENGTH - SEGMENT_RUNTIME.counter_mode_step - 1, col); } else { int i = SEGMENT_RUNTIME.counter_mode_step - mid; - setPixelColor(SEGMENT.start + i, 0); - setPixelColor(SEGMENT.start + SEGMENT_LENGTH - i - 1, 0); + setPixelColor(SEGMENT.start + i, SEGMENT.colors[1]); + setPixelColor(SEGMENT.start + SEGMENT_LENGTH - i - 1, SEGMENT.colors[1]); } } SEGMENT_RUNTIME.counter_mode_step++; @@ -1583,22 +1659,29 @@ uint16_t WS2812FX::mode_dual_color_wipe_in_in(void) { uint16_t WS2812FX::mode_dual_color_wipe_out_out(void) { int end = SEGMENT_LENGTH - SEGMENT_RUNTIME.counter_mode_step - 1; bool odd = (SEGMENT_LENGTH % 2) == 1; - int mid = SEGMENT_LENGTH / 2; - if (odd) { + int mid = SEGMENT_LENGTH / 2; + byte pindex = 0; + uint32_t col = 0; + if (SEGMENT_RUNTIME.counter_mode_step <= mid) + { + pindex = map(SEGMENT_RUNTIME.counter_mode_step, 0, mid, 255, 0); + col = color_from_palette(pindex, false, false, 0); + } + if (odd) { if (SEGMENT_RUNTIME.counter_mode_step <= mid) { - setPixelColor(SEGMENT.start + mid + SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[0]); - setPixelColor(SEGMENT.start + mid - SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[0]); + setPixelColor(SEGMENT.start + mid + SEGMENT_RUNTIME.counter_mode_step, col); + setPixelColor(SEGMENT.start + mid - SEGMENT_RUNTIME.counter_mode_step, col); } else { - setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step - 1, 0); - setPixelColor(SEGMENT.start + end + 1, 0); + setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step - 1, SEGMENT.colors[1]); + setPixelColor(SEGMENT.start + end + 1, SEGMENT.colors[1]); } } else { if (SEGMENT_RUNTIME.counter_mode_step < mid) { - setPixelColor(SEGMENT.start + mid - SEGMENT_RUNTIME.counter_mode_step - 1, SEGMENT.colors[0]); - setPixelColor(SEGMENT.start + mid + SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[0]); + setPixelColor(SEGMENT.start + mid - SEGMENT_RUNTIME.counter_mode_step - 1, col); + setPixelColor(SEGMENT.start + mid + SEGMENT_RUNTIME.counter_mode_step, col); } else { - setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step, 0); - setPixelColor(SEGMENT.start + end, 0); + setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[1]); + setPixelColor(SEGMENT.start + end, SEGMENT.colors[1]); } } SEGMENT_RUNTIME.counter_mode_step++; @@ -1621,24 +1704,31 @@ uint16_t WS2812FX::mode_dual_color_wipe_out_out(void) { */ uint16_t WS2812FX::mode_dual_color_wipe_out_in(void) { bool odd = (SEGMENT_LENGTH % 2) == 1; - int mid = SEGMENT_LENGTH / 2; + int mid = SEGMENT_LENGTH / 2; + byte pindex = 0; + uint32_t col = 0; + if (SEGMENT_RUNTIME.counter_mode_step <= mid) + { + pindex = map(SEGMENT_RUNTIME.counter_mode_step, 0, mid, 255, 0); + col = color_from_palette(pindex, false, false, 0); + } if (odd) { if (SEGMENT_RUNTIME.counter_mode_step <= mid) { - setPixelColor(SEGMENT.start + mid + SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[0]); - setPixelColor(SEGMENT.start + mid - SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[0]); + setPixelColor(SEGMENT.start + mid + SEGMENT_RUNTIME.counter_mode_step, col); + setPixelColor(SEGMENT.start + mid - SEGMENT_RUNTIME.counter_mode_step, col); } else { int i = SEGMENT_RUNTIME.counter_mode_step - mid; - setPixelColor(SEGMENT.start + i - 1, 0); - setPixelColor(SEGMENT.start + SEGMENT_LENGTH - i, 0); + setPixelColor(SEGMENT.start + i - 1, SEGMENT.colors[1]); + setPixelColor(SEGMENT.start + SEGMENT_LENGTH - i, SEGMENT.colors[1]); } } else { if (SEGMENT_RUNTIME.counter_mode_step < mid) { - setPixelColor(SEGMENT.start + mid - SEGMENT_RUNTIME.counter_mode_step - 1, SEGMENT.colors[0]); - setPixelColor(SEGMENT.start + mid + SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[0]); + setPixelColor(SEGMENT.start + mid - SEGMENT_RUNTIME.counter_mode_step - 1, col); + setPixelColor(SEGMENT.start + mid + SEGMENT_RUNTIME.counter_mode_step, col); } else { int i = SEGMENT_RUNTIME.counter_mode_step - mid; - setPixelColor(SEGMENT.start + i, 0); - setPixelColor(SEGMENT.start + SEGMENT_LENGTH - i - 1, 0); + setPixelColor(SEGMENT.start + i, SEGMENT.colors[1]); + setPixelColor(SEGMENT.start + SEGMENT_LENGTH - i - 1, SEGMENT.colors[1]); } } SEGMENT_RUNTIME.counter_mode_step++; @@ -1656,10 +1746,38 @@ uint16_t WS2812FX::mode_dual_color_wipe_out_in(void) { /* - * Alternating white/red/black pixels running. + * Tricolor chase function + */ +uint16_t WS2812FX::tricolor_chase(uint32_t color1, uint32_t color2, uint32_t color3) { + uint16_t index = SEGMENT_RUNTIME.counter_mode_step % 6; + for(uint16_t i=0; i < SEGMENT_LENGTH; i++, index++) { + if(index > 5) index = 0; + + uint32_t color = color1; + if(index > 3) color = color_from_palette(i, true, PALETTE_SOLID_WRAP, 2); + else if(index > 1) color = color2; + + setPixelColor(SEGMENT.stop - i, color); + } + + SEGMENT_RUNTIME.counter_mode_step++; + return 35 + ((350 * (uint32_t)(255 - SEGMENT.speed)) / 255); +} + + +/* + * Alternating white/red/black pixels running. PLACEHOLDER */ uint16_t WS2812FX::mode_circus_combustus(void) { - return chase(RED, WHITE, BLACK); + return tricolor_chase(RED, WHITE, BLACK); +} + + +/* + * Tricolor chase mode + */ +uint16_t WS2812FX::mode_tricolor_chase(void) { + return tricolor_chase(SEGMENT.colors[1], SEGMENT.colors[0], SEGMENT.colors[2]); } @@ -1673,23 +1791,23 @@ uint16_t WS2812FX::mode_icu(void) { { setPixelColor(i, SEGMENT.colors[1]); } + + byte pindex = map(dest, 0, SEGMENT_LENGTH/2, 0, 255); + uint32_t col = color_from_palette(pindex, false, false, 0); - setPixelColor(SEGMENT.start + dest, SEGMENT.colors[0]); - setPixelColor(SEGMENT.start + dest + SEGMENT_LENGTH/2, SEGMENT.colors[0]); + setPixelColor(SEGMENT.start + dest, col); + setPixelColor(SEGMENT.start + dest + SEGMENT_LENGTH/2, col); if(SEGMENT_RUNTIME.aux_param == dest) { // pause between eye movements if(random8(6) == 0) { // blink once in a while - setPixelColor(SEGMENT.start + dest, BLACK); - setPixelColor(SEGMENT.start + dest + SEGMENT_LENGTH/2, BLACK); + setPixelColor(SEGMENT.start + dest, SEGMENT.colors[1]); + setPixelColor(SEGMENT.start + dest + SEGMENT_LENGTH/2, SEGMENT.colors[1]); return 200; } SEGMENT_RUNTIME.aux_param = random(SEGMENT_LENGTH/2); return 1000 + random(2000); } - setPixelColor(SEGMENT.start + dest, BLACK); - setPixelColor(SEGMENT.start + dest + SEGMENT_LENGTH/2, BLACK); - if(SEGMENT_RUNTIME.aux_param > SEGMENT_RUNTIME.counter_mode_step) { SEGMENT_RUNTIME.counter_mode_step++; dest++; @@ -1698,8 +1816,8 @@ uint16_t WS2812FX::mode_icu(void) { dest--; } - setPixelColor(SEGMENT.start + dest, SEGMENT.colors[0]); - setPixelColor(SEGMENT.start + dest + SEGMENT_LENGTH/2, SEGMENT.colors[0]); + setPixelColor(SEGMENT.start + dest, col); + setPixelColor(SEGMENT.start + dest + SEGMENT_LENGTH/2, col); return SPEED_FORMULA_L; } @@ -1719,7 +1837,7 @@ uint16_t WS2812FX::mode_tricolor_wipe(void) } else { uint32_t led_offset = SEGMENT_RUNTIME.counter_mode_step - SEGMENT_LENGTH*2; - setPixelColor(SEGMENT.start + led_offset, SEGMENT.colors[2]); + setPixelColor(SEGMENT.start + led_offset, color_from_palette(SEGMENT.start + led_offset, true, PALETTE_SOLID_WRAP, 2)); } SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % (SEGMENT_LENGTH * 3); @@ -1734,21 +1852,33 @@ uint16_t WS2812FX::mode_tricolor_wipe(void) */ uint16_t WS2812FX::mode_tricolor_fade(void) { - static uint32_t color1 = 0, color2 = 0; + uint32_t color1 = 0, color2 = 0; + byte stage = 0; - if(SEGMENT_RUNTIME.counter_mode_step == 0) { + if(SEGMENT_RUNTIME.counter_mode_step < 256) { color1 = SEGMENT.colors[0]; color2 = SEGMENT.colors[1]; - } else if(SEGMENT_RUNTIME.counter_mode_step == 256) { + stage = 0; + } else if(SEGMENT_RUNTIME.counter_mode_step < 512) { color1 = SEGMENT.colors[1]; color2 = SEGMENT.colors[2]; - } else if(SEGMENT_RUNTIME.counter_mode_step == 512) { + stage = 1; + } else { color1 = SEGMENT.colors[2]; color2 = SEGMENT.colors[0]; + stage = 2; } - uint32_t color = color_blend(color1, color2, SEGMENT_RUNTIME.counter_mode_step % 256); + byte stp = SEGMENT_RUNTIME.counter_mode_step % 256; + uint32_t color = 0; for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { + if (stage == 2) { + color = color_blend(color_from_palette(i, true, PALETTE_SOLID_WRAP, 2), color2, stp); + } else if (stage == 1) { + color = color_blend(color1, color_from_palette(i, true, PALETTE_SOLID_WRAP, 2), stp); + } else { + color = color_blend(color1, color2, stp); + } setPixelColor(i, color); } @@ -1771,12 +1901,13 @@ uint16_t WS2812FX::mode_multi_comet(void) for(uint8_t i=0; i < 6; i++) { if(comets[i] < SEGMENT_LENGTH) { - if (SEGMENT.colors[2] != SEGMENT.colors[1]) + uint16_t index = SEGMENT.start + comets[i]; + if (SEGMENT.colors[2] != 0) { - setPixelColor(SEGMENT.start + comets[i], i % 2 ? SEGMENT.colors[0] : SEGMENT.colors[2]); + setPixelColor(index, i % 2 ? color_from_palette(index, true, PALETTE_SOLID_WRAP, 0) : SEGMENT.colors[2]); } else { - setPixelColor(SEGMENT.start + comets[i], SEGMENT.colors[0]); + setPixelColor(index, color_from_palette(index, true, PALETTE_SOLID_WRAP, 0)); } comets[i]++; } else { @@ -1804,13 +1935,15 @@ uint16_t WS2812FX::mode_dual_larson_scanner(void){ fade_out((255-SEGMENT.intensity) / 32); - setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[0]); - if (SEGMENT.colors[2] != SEGMENT.colors[1]) + uint16_t index = SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step; + setPixelColor(index, color_from_palette(index, true, PALETTE_SOLID_WRAP, 0)); + index = SEGMENT.stop - SEGMENT_RUNTIME.counter_mode_step; + if (SEGMENT.colors[2] != 0) { - setPixelColor(SEGMENT.stop - SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[2]); + setPixelColor(index, SEGMENT.colors[2]); } else { - setPixelColor(SEGMENT.stop - SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[0]); + setPixelColor(index, color_from_palette(index, true, PALETTE_SOLID_WRAP, 0)); } if(SEGMENT_RUNTIME.counter_mode_step >= (SEGMENT.stop - SEGMENT.start) || SEGMENT_RUNTIME.counter_mode_step <= 0) @@ -1835,7 +1968,7 @@ uint16_t WS2812FX::mode_random_chase(void) int b = random(6) != 0 ? (color & 0xFF) : random(256); setPixelColor(SEGMENT.start, r, g, b); - return 15 + 2*(uint16_t)(255 - SEGMENT.speed); + return 10 + (uint16_t)(255 - SEGMENT.speed); } typedef struct Oscillator { @@ -1901,7 +2034,12 @@ uint16_t WS2812FX::mode_lightning(void) if (SEGMENT_RUNTIME.aux_param2) { for (int i = ledstart; i < ledstart + ledlen; i++) { - setPixelColor(i,bri,bri,bri,bri); + if (SEGMENT.palette == 0) + { + setPixelColor(i,bri,bri,bri,bri); + } else { + setPixelColor(i,color_from_palette(i, true, PALETTE_SOLID_WRAP, 0, bri)); + } } SEGMENT_RUNTIME.aux_param2 = 0; SEGMENT_RUNTIME.counter_mode_step++; @@ -1918,6 +2056,15 @@ uint16_t WS2812FX::mode_lightning(void) } +CRGB WS2812FX::fastled_from_col(uint32_t color) +{ + CRGB fastled_col; + fastled_col.red = (color >> 16 & 0xFF); + fastled_col.green = (color >> 8 & 0xFF); + fastled_col.blue = (color & 0xFF); + return fastled_col; +} + // Pride2015 // Animated, ever-changing rainbows. // by Mark Kriegsman: https://gist.github.com/kriegsman/964de772d64c502760e5 @@ -1952,11 +2099,7 @@ uint16_t WS2812FX::mode_pride_2015(void) bri8 += (255 - brightdepth); CRGB newcolor = CHSV( hue8, sat8, bri8); - - uint32_t color = getPixelColor(i); - fastled_col.red = (color >> 16 & 0xFF); - fastled_col.green = (color >> 8 & 0xFF); - fastled_col.blue = (color & 0xFF); + fastled_col = fastled_from_col(getPixelColor(i)); nblend( fastled_col, newcolor, 64); setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue); @@ -1974,10 +2117,7 @@ uint16_t WS2812FX::mode_juggle(void){ byte dothue = 0; for ( byte i = 0; i < 8; i++) { uint16_t index = SEGMENT.start + beatsin16(i + 7, 0, SEGMENT_LENGTH -1); - uint32_t color = getPixelColor(index); - fastled_col.red = (color >> 16 & 0xFF); - fastled_col.green = (color >> 8 & 0xFF); - fastled_col.blue = (color & 0xFF); + fastled_col = fastled_from_col(getPixelColor(index)); fastled_col |= CHSV(dothue, 220, 255); setPixelColor(index, fastled_col.red, fastled_col.green, fastled_col.blue); dothue += 32; @@ -2028,17 +2168,11 @@ void WS2812FX::handle_palette(void) _lastPaletteChange = millis(); } break;} case 2: {//primary color only - CRGB prim; - prim.red = (SEGMENT.colors[0] >> 16 & 0xFF); - prim.green = (SEGMENT.colors[0] >> 8 & 0xFF); - prim.blue = (SEGMENT.colors[0] & 0xFF); + CRGB prim = fastled_from_col(SEGMENT.colors[0]); targetPalette = CRGBPalette16(prim); break;} case 3: {//based on primary //considering performance implications - CRGB prim; - prim.red = (SEGMENT.colors[0] >> 16 & 0xFF); - prim.green = (SEGMENT.colors[0] >> 8 & 0xFF); - prim.blue = (SEGMENT.colors[0] & 0xFF); + CRGB prim = fastled_from_col(SEGMENT.colors[0]); CHSV prim_hsv = rgb2hsv_approximate(prim); targetPalette = CRGBPalette16( CHSV(prim_hsv.h, prim_hsv.s, prim_hsv.v), //color itself @@ -2047,24 +2181,12 @@ void WS2812FX::handle_palette(void) CHSV(prim_hsv.h, prim_hsv.s, prim_hsv.v)); //color itself break;} case 4: {//primary + secondary - CRGB prim; - prim.red = (SEGMENT.colors[0] >> 16 & 0xFF); - prim.green = (SEGMENT.colors[0] >> 8 & 0xFF); - prim.blue = (SEGMENT.colors[0] & 0xFF); - CRGB sec; - sec.red = (SEGMENT.colors[1] >> 16 & 0xFF); - sec.green = (SEGMENT.colors[1] >> 8 & 0xFF); - sec.blue = (SEGMENT.colors[1] & 0xFF); + CRGB prim = fastled_from_col(SEGMENT.colors[0]); + CRGB sec = fastled_from_col(SEGMENT.colors[1]); targetPalette = CRGBPalette16(sec,prim); break;} case 5: {//based on primary + secondary - CRGB prim; - prim.red = (SEGMENT.colors[0] >> 16 & 0xFF); - prim.green = (SEGMENT.colors[0] >> 8 & 0xFF); - prim.blue = (SEGMENT.colors[0] & 0xFF); - CRGB sec; - sec.red = (SEGMENT.colors[1] >> 16 & 0xFF); - sec.green = (SEGMENT.colors[1] >> 8 & 0xFF); - sec.blue = (SEGMENT.colors[1] & 0xFF); + CRGB prim = fastled_from_col(SEGMENT.colors[0]); + CRGB sec = fastled_from_col(SEGMENT.colors[1]); targetPalette = CRGBPalette16(sec,prim,CRGB::White); break;} case 6: //Party colors targetPalette = PartyColors_p; break; @@ -2093,11 +2215,20 @@ void WS2812FX::handle_palette(void) } } +uint32_t WS2812FX::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri) +{ + if (SEGMENT.palette == 0 && mcol < 3) return SEGMENT.colors[mcol]; //WS2812FX default + uint8_t paletteIndex = i; + if (mapping) paletteIndex = map(i,SEGMENT.start,SEGMENT.stop,0,255); + if (!wrap) paletteIndex = map(paletteIndex, 0, 255, 0, 240); //cut off blend at palette "end" + CRGB fastled_col; + fastled_col = ColorFromPalette( currentPalette, paletteIndex, pbri, (paletteBlend == 3)? NOBLEND:LINEARBLEND); + return fastled_col.r*65536 + fastled_col.g*256 + fastled_col.b; +} + uint16_t WS2812FX::mode_palette(void) { - handle_palette(); - CRGB fastled_col; bool noWrap = (paletteBlend == 2 || (paletteBlend == 0 && SEGMENT.speed == 0)); for (uint16_t i = SEGMENT.start; i <= SEGMENT.stop; i++) { @@ -2105,8 +2236,7 @@ uint16_t WS2812FX::mode_palette(void) if (noWrap) colorIndex = map(colorIndex, 0, 255, 0, 240); //cut off blend at palette "end" - fastled_col = ColorFromPalette( currentPalette, colorIndex, 255, (paletteBlend == 3)? NOBLEND:LINEARBLEND); - setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue); + setPixelColor(i, color_from_palette(colorIndex, false, true, 255)); } SEGMENT_RUNTIME.counter_mode_step += SEGMENT.speed *2; if (SEGMENT.speed == 0) SEGMENT_RUNTIME.counter_mode_step = 0; @@ -2150,7 +2280,6 @@ uint16_t WS2812FX::mode_palette(void) uint16_t WS2812FX::mode_fire_2012(void) { - handle_palette(); // Step 1. Cool down every cell a little for( int i = SEGMENT.start; i <= SEGMENT.stop; i++) { _locked[i] = qsub8(_locked[i], random8(0, ((COOLING * 10) / SEGMENT_LENGTH) + 2)); @@ -2181,7 +2310,6 @@ uint16_t WS2812FX::mode_fire_2012(void) // widely-varying set of parameters, using a color palette. uint16_t WS2812FX::mode_colorwaves(void) { - handle_palette(); uint16_t duration = 10 + SEGMENT.speed; uint16_t sPseudotime = SEGMENT_RUNTIME.counter_mode_step; uint16_t sHue16 = SEGMENT_RUNTIME.aux_param; @@ -2220,11 +2348,7 @@ uint16_t WS2812FX::mode_colorwaves(void) index = scale8( index, 240); CRGB newcolor = ColorFromPalette(currentPalette, index, bri8); - - uint32_t color = getPixelColor(i); - fastled_col.red = (color >> 16 & 0xFF); - fastled_col.green = (color >> 8 & 0xFF); - fastled_col.blue = (color & 0xFF); + fastled_col = fastled_from_col(getPixelColor(i)); nblend(fastled_col, newcolor, 128); setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue); @@ -2238,7 +2362,6 @@ uint16_t WS2812FX::mode_colorwaves(void) // colored stripes pulsing at a defined Beats-Per-Minute (BPM) uint16_t WS2812FX::mode_bpm(void) { - handle_palette(); CRGB fastled_col; uint8_t beat = beatsin8(SEGMENT.speed, 64, 255); for (uint16_t i = SEGMENT.start; i <= SEGMENT.stop; i++) { @@ -2254,7 +2377,6 @@ uint16_t WS2812FX::mode_bpm(void) uint16_t WS2812FX::mode_fillnoise8(void) { if (SEGMENT_RUNTIME.counter_mode_call == 0) SEGMENT_RUNTIME.counter_mode_step = random(12345); - handle_palette(); CRGB fastled_col; for (uint16_t i = SEGMENT.start; i <= SEGMENT.stop; i++) { uint8_t index = inoise8(i * SEGMENT_LENGTH, SEGMENT_RUNTIME.counter_mode_step + i * SEGMENT_LENGTH) % 255; @@ -2269,7 +2391,6 @@ uint16_t WS2812FX::mode_fillnoise8(void) uint16_t WS2812FX::mode_noise16_1(void) { uint16_t scale = 320; // the "zoom factor" for the noise - handle_palette(); CRGB fastled_col; SEGMENT_RUNTIME.counter_mode_step += (1 + SEGMENT.speed/16); @@ -2298,7 +2419,6 @@ uint16_t WS2812FX::mode_noise16_1(void) uint16_t WS2812FX::mode_noise16_2(void) { uint16_t scale = 1000; // the "zoom factor" for the noise - handle_palette(); CRGB fastled_col; SEGMENT_RUNTIME.counter_mode_step += (1 + SEGMENT.speed); @@ -2326,7 +2446,6 @@ uint16_t WS2812FX::mode_noise16_2(void) uint16_t WS2812FX::mode_noise16_3(void) { uint16_t scale = 800; // the "zoom factor" for the noise - handle_palette(); CRGB fastled_col; SEGMENT_RUNTIME.counter_mode_step += (1 + SEGMENT.speed); @@ -2354,7 +2473,6 @@ uint16_t WS2812FX::mode_noise16_3(void) //https://github.com/aykevl/ledstrip-spark/blob/master/ledstrip.ino uint16_t WS2812FX::mode_noise16_4(void) { - handle_palette(); CRGB fastled_col; SEGMENT_RUNTIME.counter_mode_step += SEGMENT.speed; for (uint16_t i = SEGMENT.start; i <= SEGMENT.stop; i++) { @@ -2366,3 +2484,65 @@ uint16_t WS2812FX::mode_noise16_4(void) } +//based on https://gist.github.com/kriegsman/5408ecd397744ba0393e +uint16_t WS2812FX::mode_colortwinkle() +{ + CRGB fastled_col, prev; + fract8 fadeUpAmount = 8 + (SEGMENT.speed/4), fadeDownAmount = 5 + (SEGMENT.speed/7); + for( uint16_t i = SEGMENT.start; i <= SEGMENT.stop; i++) { + fastled_col = fastled_from_col(getPixelColor(i)); + prev = fastled_col; + if(_locked[i]) { + CRGB incrementalColor = fastled_col; + incrementalColor.nscale8_video( fadeUpAmount); + fastled_col += incrementalColor; + + if( fastled_col.red == 255 || fastled_col.green == 255 || fastled_col.blue == 255) { + _locked[i] = false; + } + setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue); + + if (fastled_from_col(getPixelColor(i)) == prev) //fix "stuck" pixels + { + fastled_col += fastled_col; + setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue); + } + } else { + fastled_col.nscale8( 255 - fadeDownAmount); + setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue); + } + } + + if( random8() <= SEGMENT.intensity ) { + for (uint8_t times = 0; times < 5; times++) //attempt to spawn a new pixel 5 times + { + int i = SEGMENT.start + random16(SEGMENT_LENGTH); + if(getPixelColor(i) == 0) { + fastled_col = ColorFromPalette(currentPalette, random8(), 64, NOBLEND); + _locked[i] = true; + setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue); + return 20; //only spawn 1 new pixel per frame + } + } + } + return 20; +} + + +//Calm effect, like a lake at night +uint16_t WS2812FX::mode_lake() { + uint8_t sp = SEGMENT.speed/10; + int wave1 = beatsin8(sp +2, -64,64); + int wave2 = beatsin8(sp +1, -64,64); + uint8_t wave3 = beatsin8(sp +2, 0,80); + CRGB fastled_col; + + for (uint16_t i = SEGMENT.start; i <= SEGMENT.stop; i++) + { + int index = cos8((i*15)+ wave1)/2 + cubicwave8((i*23)+ wave2)/2; + uint8_t lum = (index > wave3) ? index - wave3 : 0; + fastled_col = ColorFromPalette(currentPalette, map(index,0,255,0,240), lum, LINEARBLEND); + setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue); + } + return 33; +} diff --git a/wled00/WS2812FX.h b/wled00/WS2812FX.h index d074bbf7..281fdbd3 100644 --- a/wled00/WS2812FX.h +++ b/wled00/WS2812FX.h @@ -40,6 +40,7 @@ #define WS2812FX_h #include "NpbWrapper.h" +#include "FastLED.h" #define DEFAULT_BRIGHTNESS (uint8_t)50 #define DEFAULT_MODE (uint8_t)0 @@ -82,7 +83,7 @@ #define REVERSE (uint8_t)0x80 #define IS_REVERSE ((SEGMENT.options & REVERSE) == REVERSE) -#define MODE_COUNT 74 +#define MODE_COUNT 76 #define FX_MODE_STATIC 0 #define FX_MODE_BLINK 1 @@ -159,6 +160,8 @@ #define FX_MODE_NOISE16_2 71 #define FX_MODE_NOISE16_3 72 #define FX_MODE_NOISE16_4 73 +#define FX_MODE_COLORTWINKLE 74 +#define FX_MODE_LAKE 75 class WS2812FX { typedef uint16_t (WS2812FX::*mode_ptr)(void); @@ -261,6 +264,8 @@ class WS2812FX { _mode[FX_MODE_NOISE16_2] = &WS2812FX::mode_noise16_2; _mode[FX_MODE_NOISE16_3] = &WS2812FX::mode_noise16_3; _mode[FX_MODE_NOISE16_4] = &WS2812FX::mode_noise16_4; + _mode[FX_MODE_COLORTWINKLE] = &WS2812FX::mode_colortwinkle; + _mode[FX_MODE_LAKE] = &WS2812FX::mode_lake; _brightness = DEFAULT_BRIGHTNESS; _running = false; @@ -327,6 +332,7 @@ class WS2812FX { uint32_t color_wheel(uint8_t), + color_from_palette(uint16_t, bool, bool, uint8_t, uint8_t pbri = 255), color_blend(uint32_t,uint32_t,uint8_t), getPixelColor(uint16_t), getColor(void); @@ -346,12 +352,13 @@ class WS2812FX { // mode helper functions uint16_t - blink(uint32_t, uint32_t, bool strobe), - color_wipe(uint32_t, uint32_t, bool), - theater_chase(uint32_t, uint32_t), + blink(uint32_t, uint32_t, bool strobe, bool), + color_wipe(uint32_t, uint32_t, bool , bool), + scan(bool), + theater_chase(uint32_t, uint32_t, bool), twinkle(uint32_t), twinkle_fade(uint32_t), - chase(uint32_t, uint32_t, uint32_t), + chase(uint32_t, uint32_t, uint32_t, uint8_t), running(uint32_t, uint32_t), fireworks(uint32_t), tricolor_chase(uint32_t, uint32_t, uint32_t); @@ -432,16 +439,21 @@ class WS2812FX { mode_noise16_2(void), mode_noise16_3(void), mode_noise16_4(void), + mode_colortwinkle(void), + mode_lake(void), mode_lightning(void); private: NeoPixelWrapper *bus; + + CRGB fastled_from_col(uint32_t); uint16_t _length; uint16_t _rand16seed; uint8_t _brightness; void handle_palette(void); + bool modeUsesLock(uint8_t); double _cronixieSecMultiplier; diff --git a/wled00/data/index.htm b/wled00/data/index.htm index d35ee2b9..954c1901 100644 --- a/wled00/data/index.htm +++ b/wled00/data/index.htm @@ -2,7 +2,7 @@ - WLED 0.8.0 + WLED 0.8.1 +WLED 0.8.1 + )====="; //head1 (css) @@ -123,7 +123,7 @@ Effect Panel



-

Set secondary color to @@ -133,7 +133,7 @@ Set secondary color to or

FastLED Palette

-
diff --git a/wled00/htmls01.h b/wled00/htmls01.h index b015bf58..36ced6af 100644 --- a/wled00/htmls01.h +++ b/wled00/htmls01.h @@ -237,7 +237,7 @@ Send notifications twice:
Receive UDP realtime:

E1.31 (sACN)
Use E1.31 multicast:
-E1.31 universe:
+E1.31 start universe:
Reboot required. Check out LedFx!

Timeout: ms
Force max brightness:
@@ -411,7 +411,7 @@ HTTP traffic is unencrypted. An attacker in the same network can intercept form
Enable ArduinoOTA:

About

-WLED version 0.8.0

+WLED version 0.8.1

Contributors:
StormPie (Mobile HTML UI)

Thank you so much!

diff --git a/wled00/htmls02.h b/wled00/htmls02.h index 4a706c10..45f6b54e 100644 --- a/wled00/htmls02.h +++ b/wled00/htmls02.h @@ -24,7 +24,7 @@ button{background:var(--bCol);color:var(--tCol);font-family:var(--cFn),sans-seri //new user welcome page -#ifndef WLED_FLASH_512K_MODE +#ifndef WLED_DISABLE_MOBILE_UI const char PAGE_welcome0[] PROGMEM = R"=====( diff --git a/wled00/palettes.h b/wled00/palettes.h index 942f2f4b..881acd08 100644 --- a/wled00/palettes.h +++ b/wled00/palettes.h @@ -500,6 +500,42 @@ DEFINE_GRADIENT_PALETTE( Orange_Teal_gp ) { 200, 255, 72, 0, 255, 255, 72, 0}; +//Custom palette by Aircoookie + +DEFINE_GRADIENT_PALETTE( Tiamat_gp ) { + 0, 1, 2, 14, //gc + 33, 2, 5, 35, //gc from 47, 61,126 + 100, 13,135, 92, //gc from 88,242,247 + 120, 43,255,193, //gc from 135,255,253 + 140, 247, 7,249, //gc from 252, 69,253 + 160, 193, 17,208, //gc from 231, 96,237 + 180, 39,255,154, //gc from 130, 77,213 + 200, 4,213,236, //gc from 57,122,248 + 220, 39,252,135, //gc from 177,254,255 + 240, 193,213,253, //gc from 203,239,253 + 255, 255,249,255}; + +//Custom palette by Aircoookie + +DEFINE_GRADIENT_PALETTE( April_Night_gp ) { + 0, 1, 5, 45, //deep blue + 10, 1, 5, 45, + 25, 5,169,175, //light blue + 40, 1, 5, 45, + 61, 1, 5, 45, + 76, 45,175, 31, //green + 91, 1, 5, 45, + 112, 1, 5, 45, + 127, 249,150, 5, //yellow + 143, 1, 5, 45, + 162, 1, 5, 45, + 178, 255,92, 0, //pastel orange + 193, 1, 5, 45, + 214, 1, 5, 45, + 229, 223, 45, 72, //pink + 244, 1, 5, 45, + 255, 1, 5, 45}; + // Single array of defined cpt-city color palettes. // This will let us programmatically choose one based on @@ -543,8 +579,10 @@ const TProgmemRGBGradientPalettePtr gGradientPalettes[] = { BlacK_Magenta_Red_gp, //41-28 Magred BlacK_Red_Magenta_Yellow_gp, //42-29 Yelmag Blue_Cyan_Yellow_gp, //43-30 Yelblu - Orange_Teal_gp //44-31 Orange & Teal - }; + Orange_Teal_gp, //44-31 Orange & Teal + Tiamat_gp, //45-32 Tiamat + April_Night_gp //46-33 April Night +}; // Count of how many cpt-city gradients are defined: @@ -552,4 +590,3 @@ const uint8_t gGradientPaletteCount = sizeof( gGradientPalettes) / sizeof( TProgmemRGBGradientPalettePtr ); #endif - diff --git a/wled00/wled00.ino b/wled00/wled00.ino index 1f587a5b..2bf62730 100644 --- a/wled00/wled00.ino +++ b/wled00/wled00.ino @@ -3,15 +3,29 @@ */ /* * @title WLED project sketch - * @version 0.8.0 + * @version 0.8.1 * @author Christian Schwinne */ -//ESP8266-01 got too little storage space to work with all features of WLED. To use it, you must use ESP8266 Arduino Core v2.3.0 and the setting 512K(64K SPIFFS). -//Uncomment the following line to disable some features (currently Mobile UI, welcome page and single digit + cronixie overlays) to compile for ESP8266-01 -//#define WLED_FLASH_512K_MODE -//CURRENTLY NOT WORKING +//ESP8266-01 (blue) got too little storage space to work with all features of WLED. To use it, you must use ESP8266 Arduino Core v2.3.0 and the setting 512K(64K SPIFFS). + +//ESP8266-01 (black) has 1MB flash and can thus fit the whole program. Use 1M(64K SPIFFS). +//If you want the OTA update function though, you need to make sure the sketch is smaller than 479kB. +//Uncomment some of the following lines to disable features to compile for ESP8266-01 (max flash size 434kB): + +//You are required to disable these two features: +//#define WLED_DISABLE_MOBILE_UI +//#define WLED_DISABLE_OTA + +//You need to choose 1-2 of these features to disable: +//#define WLED_DISABLE_ALEXA +//#define WLED_DISABLE_BLYNK +//#define WLED_DISABLE_CRONIXIE +//#define WLED_DISABLE_HUESYNC + +//to toggle usb serial debug (un)comment following line(s) +//#define DEBUG //library inclusions #include @@ -28,14 +42,18 @@ #endif #include -#include #include #include +#ifndef WLED_DISABLE_OTA +#include #include "src/dependencies/webserver/ESP8266HTTPUpdateServer.h" +#endif #include "src/dependencies/time/Time.h" #include "src/dependencies/time/TimeLib.h" #include "src/dependencies/timezone/Timezone.h" +#ifndef WLED_DISABLE_BLYNK #include "src/dependencies/blynk/BlynkSimpleEsp.h" +#endif #include "src/dependencies/e131/E131.h" #include "src/dependencies/pubsubclient/PubSubClient.h" #include "htmls00.h" @@ -45,8 +63,8 @@ //version code in format yymmddb (b = daily build) -#define VERSION 1810151 -char versionString[] = "0.8.0"; +#define VERSION 1811071 +char versionString[] = "0.8.1"; //AP and OTA default passwords (for maximum change them!) @@ -54,10 +72,6 @@ char apPass[65] = "wled1234"; char otaPass[33] = "wledota"; -//to toggle usb serial debug (un)comment following line(s) -//#define DEBUG - - //spiffs FS only useful for debug (only ESP8266) //#define USEFS @@ -375,7 +389,9 @@ HTTPClient* hueClient = NULL; WiFiClient* mqttTCPClient = NULL; PubSubClient* mqtt = NULL; +#ifndef WLED_DISABLE_OTA ESP8266HTTPUpdateServer httpUpdater; +#endif //udp interface objects WiFiUDP notifierUdp, rgbUdp; @@ -491,7 +507,9 @@ void loop() { if (!realtimeActive) //block stuff if WARLS/Adalight is enabled { if (dnsActive) dnsServer.processNextRequest(); + #ifndef WLED_DISABLE_OTA if (aOtaEnabled) ArduinoOTA.handle(); + #endif handleNightlight(); if (!onlyAP) { handleHue(); @@ -521,5 +539,3 @@ void loop() { } #endif } - - diff --git a/wled00/wled01_eeprom.ino b/wled00/wled01_eeprom.ino index 44260017..197c9fd5 100644 --- a/wled00/wled01_eeprom.ino +++ b/wled00/wled01_eeprom.ino @@ -446,7 +446,7 @@ void loadSettingsFromEEPROM(bool first) enableRealtimeUI = EEPROM.read(2201); uiConfiguration = EEPROM.read(2202); - #ifdef WLED_FLASH_512K_MODE + #ifdef WLED_DISABLE_MOBILE_UI uiConfiguration = 1; //force default UI since mobile is unavailable #endif @@ -567,7 +567,6 @@ String loadMacro(byte index) if (EEPROM.read(i) == 0) break; m += char(EEPROM.read(i)); } - if (m.charAt(0) < 65 || m.charAt(0) > 90) return ""; //do simple check if macro is valid (capital first letter) return m; } @@ -600,4 +599,3 @@ void saveMacro(byte index, String mc, bool sing=true) //only commit on single sa } if (sing) EEPROM.commit(); } - diff --git a/wled00/wled03_set.ino b/wled00/wled03_set.ino index dc048301..cf319b21 100644 --- a/wled00/wled03_set.ino +++ b/wled00/wled03_set.ino @@ -213,6 +213,7 @@ void handleSettingsSet(byte subPage) if (server.hasArg("OL")){ overlayDefault = server.arg("OL").toInt(); + if (overlayCurrent != overlayDefault) strip.unlockAll(); overlayCurrent = overlayDefault; } diff --git a/wled00/wled05_init.ino b/wled00/wled05_init.ino index a5f9f66a..dd53e8ee 100644 --- a/wled00/wled05_init.ino +++ b/wled00/wled05_init.ino @@ -86,6 +86,7 @@ void wledInit() //init ArduinoOTA if (!onlyAP) { + #ifndef WLED_DISABLE_OTA if (aOtaEnabled) { ArduinoOTA.onStart([]() { @@ -97,6 +98,7 @@ void wledInit() if (strlen(cmDNS) > 0) ArduinoOTA.setHostname(cmDNS); ArduinoOTA.begin(); } + #endif if (!initLedsLast) strip.service(); // Set up mDNS responder: @@ -138,6 +140,7 @@ void initStrip() if (bootPreset>0) applyPreset(bootPreset, turnOnAtBoot, true, true); colorUpdated(0); if(digitalRead(buttonPin) == LOW) buttonEnabled = false; //disable button if it is "pressed" unintentionally + } void initAP(){ @@ -224,6 +227,25 @@ void getBuildInfo() oappendi(VERSION); oappend("\r\neepver: "); oappendi(EEPVER); + oappend("\r\nopt: "); + #ifndef WLED_DISABLE_ALEXA + oappend("alexa "); + #endif + #ifndef WLED_DISABLE_BLYNK + oappend("blynk "); + #endif + #ifndef WLED_DISABLE_CRONIXIE + oappend("cronixie "); + #endif + #ifndef WLED_DISABLE_HUESYNC + oappend("huesync "); + #endif + #ifndef WLED_DISABLE_MOBILE_UI + oappend("mobile-ui "); + #endif + #ifndef WLED_DISABLE_OTA + oappend("ota"); + #endif #ifdef USEFS oappend("\r\nspiffs: true\r\n"); #else @@ -236,13 +258,9 @@ void getBuildInfo() #endif oappend("button-pin: gpio"); oappendi(buttonPin); - oappend("\r\n"); - #ifdef ARDUINO_ARCH_ESP32 - oappend("strip-pin: gpio"); + oappend("\r\nstrip-pin: gpio"); oappendi(LEDPIN); - #else - oappend("strip-pin: gpio2"); - #endif + oappend("\r\nbrand: wled\r\n"); oappend("\r\nbuild-type: src\r\n"); } @@ -255,6 +273,3 @@ bool checkClientIsMobile(String useragent) if (useragent.indexOf("iPod") >= 0) return true; return false; } - - - diff --git a/wled00/wled07_notify.ino b/wled00/wled07_notify.ino index d77f5bba..1a3e7614 100644 --- a/wled00/wled07_notify.ino +++ b/wled00/wled07_notify.ino @@ -3,6 +3,7 @@ */ #define WLEDPACKETSIZE 24 +#define UDP_IN_MAXSIZE 1472 void notify(byte callMode, bool followUp=false) { @@ -76,6 +77,27 @@ void initE131(){ } } +void handleE131(){ + //E1.31 protocol support + if(e131Enabled) { + uint16_t len = e131->parsePacket(); + if (!len || e131->universe < e131Universe || e131->universe > e131Universe +4) return; + len /= 3; //one LED is 3 DMX channels + + uint16_t multipacketOffset = (e131->universe - e131Universe)*170; //if more than 170 LEDs (510 channels), client will send in next higher universe + if (ledCount <= multipacketOffset) return; + + arlsLock(realtimeTimeoutMs); + if (len + multipacketOffset > ledCount) len = ledCount - multipacketOffset; + + for (uint16_t i = 0; i < len; i++) { + int j = i * 3; + setRealtimePixel(i + multipacketOffset, e131->data[j], e131->data[j+1], e131->data[j+2], 0); + } + strip.show(); + } +} + void handleNotifications() { //send second notification if enabled @@ -83,20 +105,7 @@ void handleNotifications() notify(notificationSentCallMode,true); } - //E1.31 protocol support - if(e131Enabled) { - uint16_t len = e131->parsePacket(); - if (len && e131->universe == e131Universe) { - arlsLock(realtimeTimeoutMs); - if (len > ledCount) len = ledCount; - for (uint16_t i = 0; i < len; i++) { - int j = i * 3; - - setRealtimePixel(i, e131->data[j], e131->data[j+1], e131->data[j+2], 0); - } - strip.show(); - } - } + handleE131(); //unlock strip when realtime UDP times out if (realtimeActive && millis() > realtimeTimeout) @@ -116,16 +125,16 @@ void handleNotifications() if (!packetSize && udpRgbConnected) { packetSize = rgbUdp.parsePacket(); if (!receiveDirect) return; - if (packetSize > 1026 || packetSize < 3) return; + if (packetSize > UDP_IN_MAXSIZE || packetSize < 3) return; realtimeIP = rgbUdp.remoteIP(); DEBUG_PRINTLN(rgbUdp.remoteIP()); - byte udpIn[packetSize]; - rgbUdp.read(udpIn, packetSize); + olen = 0; + rgbUdp.read(obuf, packetSize); arlsLock(realtimeTimeoutMs); uint16_t id = 0; for (uint16_t i = 0; i < packetSize -2; i += 3) { - setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0); + setRealtimePixel(id, obuf[i], obuf[i+1], obuf[i+2], 0); id++; if (id >= ledCount) break; } @@ -133,11 +142,13 @@ void handleNotifications() return; } - if (packetSize > 1026) return; + if (packetSize > UDP_IN_MAXSIZE) return; if(packetSize && notifierUdp.remoteIP() != WiFi.localIP()) //don't process broadcasts we send ourselves { - byte udpIn[packetSize]; - notifierUdp.read(udpIn, packetSize); + olen = 0; + notifierUdp.read(obuf, packetSize); + char* udpIn = obuf; + if (udpIn[0] == 0 && !realtimeActive && receiveNotifications) //wled notifier, block if realtime packets active { if (receiveNotificationColor) @@ -195,6 +206,7 @@ void handleNotifications() if (udpIn[1] == 0) { realtimeActive = false; + return; } else { arlsLock(udpIn[1]*1000); } @@ -222,6 +234,15 @@ void handleNotifications() id++; if (id >= ledCount) break; } + } else if (udpIn[0] == 4) //dnrgb + { + uint16_t id = ((udpIn[3] << 0) & 0xFF) + ((udpIn[2] << 8) & 0xFF00); + for (uint16_t i = 4; i < packetSize -2; i += 3) + { + if (id >= ledCount) break; + setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], udpIn[i+3]); + id++; + } } strip.show(); } @@ -243,5 +264,3 @@ void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w) } } } - - diff --git a/wled00/wled11_ol.ino b/wled00/wled11_ol.ino index a3ac6d16..f0b8bb84 100644 --- a/wled00/wled11_ol.ino +++ b/wled00/wled11_ol.ino @@ -171,9 +171,9 @@ void _overlayAnalogClock() int pix; for (int i = 0; i <= 12; i++) { - pix = overlayMin + analogClock12pixel + (overlaySize/12)*i; - if (pix > overlayMax) pix = pix - overlayMax; - strip.setIndividual(pix,0x00FFAA); + pix = analogClock12pixel + round((overlaySize / 12.0) *i); + if (pix > overlayMax) pix -= overlaySize; + strip.setIndividual(pix, 0x00FFAA); } } if (!analogClockSecondsTrail) strip.setIndividual(secondPixel, 0xFF0000); @@ -184,7 +184,7 @@ void _overlayAnalogClock() void _overlayNixieClock() { - #ifdef WLED_FLASH_512K_MODE + #ifdef WLED_DISABLE_CRONIXIE if (countdownMode) checkCountdown(); #else diff --git a/wled00/wled12_alexa.ino b/wled00/wled12_alexa.ino index 05f3ebbf..cfee39ec 100644 --- a/wled00/wled12_alexa.ino +++ b/wled00/wled12_alexa.ino @@ -5,7 +5,13 @@ * https://github.com/kakopappa/arduino-esp8266-alexa-wemo-switch * https://github.com/probonopd/ESP8266HueEmulator */ +void prepareIds() { + escapedMac = WiFi.macAddress(); + escapedMac.replace(":", ""); + escapedMac.toLowerCase(); +} +#ifndef WLED_DISABLE_ALEXA void alexaInit() { if (alexaEnabled && WiFi.status() == WL_CONNECTED) @@ -87,12 +93,6 @@ void alexaDim(byte briL) handleSet(ct); } -void prepareIds() { - escapedMac = WiFi.macAddress(); - escapedMac.replace(":", ""); - escapedMac.toLowerCase(); -} - void respondToSearch() { DEBUG_PRINTLN(""); DEBUG_PRINT("Send resp to "); @@ -288,3 +288,9 @@ bool connectUDP(){ return state; } +#else +void alexaInit(){} +void handleAlexa(){} +void alexaInitPages(){} +bool handleAlexaApiCall(String req, String body){return false;} +#endif diff --git a/wled00/wled13_cronixie.ino b/wled00/wled13_cronixie.ino index 845aaf69..2043b153 100644 --- a/wled00/wled13_cronixie.ino +++ b/wled00/wled13_cronixie.ino @@ -19,7 +19,7 @@ byte getSameCodeLength(char code, int index, char const cronixieDisplay[]) void setCronixie() { - #ifndef WLED_FLASH_512K_MODE + #ifndef WLED_DISABLE_CRONIXIE /* * digit purpose index * 0-9 | 0-9 (incl. random) @@ -146,7 +146,7 @@ void setCronixie() void _overlayCronixie() { if (countdownMode) checkCountdown(); - #ifndef WLED_FLASH_512K_MODE + #ifndef WLED_DISABLE_CRONIXIE byte h = hour(local); byte h0 = h; @@ -214,4 +214,3 @@ void _overlayCronixie() //strip.trigger(); //this has a drawback, no effects slower than RefreshMs. advantage: Quick update, not dependant on effect time #endif } - diff --git a/wled00/wled14_colors.ino b/wled00/wled14_colors.ino index ed008a84..47b6216a 100644 --- a/wled00/wled14_colors.ino +++ b/wled00/wled14_colors.ino @@ -1,6 +1,27 @@ /* * Color conversion methods */ + +void colorHStoRGB(uint16_t hue, byte sat, byte* rgb) //hue, sat to rgb +{ + float h = ((float)hue)/65535.0; + float s = ((float)sat)/255.0; + byte i = floor(h*6); + float f = h * 6-i; + float p = 255 * (1-s); + float q = 255 * (1-f*s); + float t = 255 * (1-(1-f)*s); + switch (i%6) { + case 0: rgb[0]=255,rgb[1]=t,rgb[2]=p;break; + case 1: rgb[0]=q,rgb[1]=255,rgb[2]=p;break; + case 2: rgb[0]=p,rgb[1]=255,rgb[2]=t;break; + case 3: rgb[0]=p,rgb[1]=q,rgb[2]=255;break; + case 4: rgb[0]=t,rgb[1]=p,rgb[2]=255;break; + case 5: rgb[0]=255,rgb[1]=p,rgb[2]=q; + } +} + +#ifndef WLED_DISABLE_HUESYNC void colorCTtoRGB(uint16_t mired, byte* rgb) //white spectrum to rgb { //this is only an approximation using WS2812B with gamma correction enabled @@ -31,25 +52,6 @@ void colorCTtoRGB(uint16_t mired, byte* rgb) //white spectrum to rgb } } -void colorHStoRGB(uint16_t hue, byte sat, byte* rgb) //hue, sat to rgb -{ - float h = ((float)hue)/65535.0; - float s = ((float)sat)/255.0; - byte i = floor(h*6); - float f = h * 6-i; - float p = 255 * (1-s); - float q = 255 * (1-f*s); - float t = 255 * (1-(1-f)*s); - switch (i%6) { - case 0: rgb[0]=255,rgb[1]=t,rgb[2]=p;break; - case 1: rgb[0]=q,rgb[1]=255,rgb[2]=p;break; - case 2: rgb[0]=p,rgb[1]=255,rgb[2]=t;break; - case 3: rgb[0]=p,rgb[1]=q,rgb[2]=255;break; - case 4: rgb[0]=t,rgb[1]=p,rgb[2]=255;break; - case 5: rgb[0]=255,rgb[1]=p,rgb[2]=q; - } -} - void colorXYtoRGB(float x, float y, byte* rgb) //coordinates to rgb (https://www.developers.meethue.com/documentation/color-conversions-rgb-xy) { float z = 1.0f - x - y; @@ -106,6 +108,16 @@ void colorXYtoRGB(float x, float y, byte* rgb) //coordinates to rgb (https://www rgb[2] = 255.0*b; } +void colorRGBtoXY(byte* rgb, float* xy) //rgb to coordinates (https://www.developers.meethue.com/documentation/color-conversions-rgb-xy) +{ + float X = rgb[0] * 0.664511f + rgb[1] * 0.154324f + rgb[2] * 0.162028f; + float Y = rgb[0] * 0.283881f + rgb[1] * 0.668433f + rgb[2] * 0.047685f; + float Z = rgb[0] * 0.000088f + rgb[1] * 0.072310f + rgb[2] * 0.986039f; + xy[0] = X / (X + Y + Z); + xy[1] = Y / (X + Y + Z); +} +#endif + void colorFromDecOrHexString(byte* rgb, byte* wht, char* in) { if (in[0] == 0) return; @@ -126,15 +138,6 @@ void colorFromDecOrHexString(byte* rgb, byte* wht, char* in) rgb[2] = c & 0xFF; } -void colorRGBtoXY(byte* rgb, float* xy) //rgb to coordinates (https://www.developers.meethue.com/documentation/color-conversions-rgb-xy) -{ - float X = rgb[0] * 0.664511f + rgb[1] * 0.154324f + rgb[2] * 0.162028f; - float Y = rgb[0] * 0.283881f + rgb[1] * 0.668433f + rgb[2] * 0.047685f; - float Z = rgb[0] * 0.000088f + rgb[1] * 0.072310f + rgb[2] * 0.986039f; - xy[0] = X / (X + Y + Z); - xy[1] = Y / (X + Y + Z); -} - float minf (float v, float w) { if (w > v) return v; @@ -155,4 +158,3 @@ void colorRGBtoRGBW(byte* rgb, byte* wht) //rgb to rgbw (http://codewelt.com/rgb float sat = 255.0f * ((high - low) / high); *wht = (byte)((255.0f - sat) / 255.0f * (rgb[0] + rgb[1] + rgb[2]) / 3); } - diff --git a/wled00/wled15_hue.ino b/wled00/wled15_hue.ino index dbc9f73a..f8ce9206 100644 --- a/wled00/wled15_hue.ino +++ b/wled00/wled15_hue.ino @@ -1,7 +1,7 @@ /* * Sync to Philips hue lights */ - +#ifndef WLED_DISABLE_HUESYNC void handleHue() { if (huePollingEnabled && WiFi.status() == WL_CONNECTED && hueClient != NULL) @@ -206,4 +206,7 @@ String getJsonValue(String* req, String key) } return ""; } - +#else +void handleHue(){} +bool setupHue(){return false;} +#endif diff --git a/wled00/wled16_blynk.ino b/wled00/wled16_blynk.ino index b6193105..8fd3ba57 100644 --- a/wled00/wled16_blynk.ino +++ b/wled00/wled16_blynk.ino @@ -7,19 +7,24 @@ byte blSat = 255; void initBlynk(const char* auth) { + #ifndef WLED_DISABLE_BLYNK if (WiFi.status() != WL_CONNECTED) return; blynkEnabled = (auth[0] != 0); if (blynkEnabled) Blynk.config(auth); + #endif } void handleBlynk() { + #ifndef WLED_DISABLE_BLYNK if (WiFi.status() == WL_CONNECTED && blynkEnabled) Blynk.run(); + #endif } void updateBlynk() { + #ifndef WLED_DISABLE_BLYNK if (onlyAP) return; Blynk.virtualWrite(V0, bri); //we need a RGB -> HSB convert here @@ -29,8 +34,10 @@ void updateBlynk() Blynk.virtualWrite(V6, effectIntensity); Blynk.virtualWrite(V7, nightlightActive); Blynk.virtualWrite(V8, notifyDirect); + #endif } +#ifndef WLED_DISABLE_BLYNK BLYNK_WRITE(V0) { bri = param.asInt();//bri @@ -86,4 +93,4 @@ BLYNK_WRITE(V8) { notifyDirect = (param.asInt()>0); //send notifications } - +#endif diff --git a/wled00/wled17_mqtt.ino b/wled00/wled17_mqtt.ino index 5b69ee51..63ddb0a0 100644 --- a/wled00/wled17_mqtt.ino +++ b/wled00/wled17_mqtt.ino @@ -93,6 +93,8 @@ bool reconnectMQTT() strcat(subuf, "/api"); mqtt->subscribe(subuf); } + + publishMQTT(); } return mqtt->connected(); } diff --git a/wled00/wled18_server.ino b/wled00/wled18_server.ino index 2415184b..fa6582cd 100644 --- a/wled00/wled18_server.ino +++ b/wled00/wled18_server.ino @@ -132,7 +132,13 @@ void initServer() server.on("/list", HTTP_GET, handleFileList); #endif //init ota page + #ifndef WLED_DISABLE_OTA httpUpdater.setup(&server); + #else + server.on("/update", HTTP_GET, [](){ + serveMessage(500, "Not implemented", "OTA updates are not supported in this build.", 254); + }); + #endif } else { server.on("/edit", HTTP_GET, [](){ @@ -311,7 +317,7 @@ void serveSettings(byte subPage) //0: menu 1: wifi 2: leds 3: ui 4: sync 5: time 6: sec 255: welcomepage if (!realtimeActive || enableRealtimeUI) //do not serve while receiving realtime { - #ifdef WLED_FLASH_512K_MODE //disable welcome page if not enough storage + #ifdef WLED_DISABLE_MOBILE_UI //disable welcome page if not enough storage if (subPage == 255) {serveIndex(); return;} #endif @@ -363,4 +369,3 @@ void serveSettings(byte subPage) serveRealtimeError(true); } } -