diff --git a/.gitignore b/.gitignore index 2116e693..d8884449 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ .pioenvs .piolibdeps .vscode +platformio.ini !.vscode/extensions.json /wled00/Release /wled00/extLibs diff --git a/wled00/FX.cpp b/wled00/FX.cpp index e4ee0aab..867ef9f1 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -141,7 +141,7 @@ uint16_t WS2812FX::color_wipe(bool rev, bool useRandomColors) { SEGENV.step = 0; } } - + uint16_t ledIndex = (prog * SEGLEN) >> 15; uint16_t rem = 0; rem = (prog * SEGLEN) * 2; //mod 0xFFFF @@ -2346,6 +2346,29 @@ uint16_t WS2812FX::mode_static_pattern() return FRAMETIME; } +uint16_t WS2812FX::mode_tri_static_pattern() +{ + uint8_t segSize = (SEGMENT.intensity >> 5) +1; + uint8_t currSeg = 0; + uint16_t currSegCount = 0; + + for (uint16_t i = SEGMENT.start; i < SEGMENT.stop; i++) { + if ( currSeg % 3 == 0 ) { + setPixelColor(i, SEGCOLOR(0)); + } else if( currSeg % 3 == 1) { + setPixelColor(i, SEGCOLOR(1)); + } else { + setPixelColor(i, (SEGCOLOR(2) > 0 ? SEGCOLOR(2) : WHITE)); + } + currSegCount += 1; + if (currSegCount >= segSize) { + currSeg +=1; + currSegCount = 0; + } + } + + return FRAMETIME; +} //American Police Light with all LEDs Red and Blue uint16_t WS2812FX::mode_policeall() diff --git a/wled00/FX.h b/wled00/FX.h index 076bc0b9..cb98edfa 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -84,7 +84,7 @@ #define IS_REVERSE ((SEGMENT.options & REVERSE ) == REVERSE ) #define IS_SELECTED ((SEGMENT.options & SELECTED) == SELECTED ) -#define MODE_COUNT 86 +#define MODE_COUNT 87 #define FX_MODE_STATIC 0 #define FX_MODE_BLINK 1 @@ -171,8 +171,9 @@ #define FX_MODE_TWINKLECAT 81 #define FX_MODE_HALLOWEEN_EYES 82 #define FX_MODE_STATIC_PATTERN 83 -#define FX_MODE_POLICE 84 -#define FX_MODE_POLICE_ALL 85 +#define FX_MODE_TRI_STATIC_PATTERN 84 +#define FX_MODE_POLICE 85 +#define FX_MODE_POLICE_ALL 86 class WS2812FX { @@ -312,6 +313,7 @@ class WS2812FX { _mode[FX_MODE_TWINKLECAT] = &WS2812FX::mode_twinklecat; _mode[FX_MODE_HALLOWEEN_EYES] = &WS2812FX::mode_halloween_eyes; _mode[FX_MODE_STATIC_PATTERN] = &WS2812FX::mode_static_pattern; + _mode[FX_MODE_TRI_STATIC_PATTERN] = &WS2812FX::mode_tri_static_pattern; _mode[FX_MODE_POLICE] = &WS2812FX::mode_police; _mode[FX_MODE_POLICE_ALL] = &WS2812FX::mode_policeall; @@ -328,7 +330,7 @@ class WS2812FX { } void - init(bool supportWhite, uint16_t countPixels, bool skipFirs), + init(bool supportWhite, uint16_t countPixels, bool skipFirs, uint8_t disableNLeds), service(void), blur(uint8_t), fade_out(uint8_t r), @@ -370,6 +372,7 @@ class WS2812FX { paletteBlend = 0, colorOrder = 0, milliampsPerLed = 55, + _disableNLeds = 0, getBrightness(void), getMode(void), getSpeed(void), @@ -383,7 +386,8 @@ class WS2812FX { uint16_t ablMilliampsMax, - currentMilliamps; + currentMilliamps, + _usableCount; uint32_t timebase, @@ -491,6 +495,7 @@ class WS2812FX { mode_twinklecat(void), mode_halloween_eyes(void), mode_static_pattern(void), + mode_tri_static_pattern(void), mode_police(void), mode_policeall(void); @@ -563,7 +568,7 @@ const char JSON_mode_names[] PROGMEM = R"=====([ "Out Out","Out In","Circus","Halloween","Tri Chase","Tri Wipe","Tri Fade","Lightning","ICU","Multi Comet", "Dual Scanner","Stream 2","Oscillate","Pride 2015","Juggle","Palette","Fire 2012","Colorwaves","Bpm","Fill Noise", "Noise 1","Noise 2","Noise 3","Noise 4","Colortwinkles","Lake","Meteor","Smooth Meteor","Railway","Ripple", -"Twinklefox","Twinklecat","Halloween Eyes","Solid Pattern","Police","Police All" +"Twinklefox","Twinklecat","Halloween Eyes","Solid Pattern","Tri Color Pattern", "Police","Police All" ])====="; diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 2fcca1ec..9d521571 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -30,25 +30,40 @@ #define LED_SKIP_AMOUNT 1 #define MIN_SHOW_DELAY 15 -void WS2812FX::init(bool supportWhite, uint16_t countPixels, bool skipFirst) +void WS2812FX::init(bool supportWhite, uint16_t countPixels, bool skipFirst, uint8_t disableNLeds) { - if (supportWhite == _rgbwMode && countPixels == _length && _locked != NULL) return; + if (supportWhite == _rgbwMode && countPixels == _length && _locked != NULL && disableNLeds == _disableNLeds) return; RESET_RUNTIME; _rgbwMode = supportWhite; _skipFirstMode = skipFirst; _length = countPixels; - + + if (disableNLeds > 0) { + uint16_t groupCount = disableNLeds +1; + //since 1st led is lit, even partial group has a led lit, whereas int division truncates decimal. + bool hasExtraLight = _length % groupCount != 0; + _usableCount = _length/groupCount; + _usableCount += hasExtraLight ? 1 : 0; + } else { + _usableCount = _length; + } + + _disableNLeds = disableNLeds; + uint8_t ty = 1; if (supportWhite) ty =2; uint16_t lengthRaw = _length; - if (_skipFirstMode) lengthRaw += LED_SKIP_AMOUNT; + if (_skipFirstMode) { + lengthRaw += LED_SKIP_AMOUNT; + } + bus->Begin((NeoPixelType)ty, lengthRaw); delete[] _locked; _locked = new byte[_length]; _segments[0].start = 0; - _segments[0].stop = _length; + _segments[0].stop = _usableCount; unlockAll(); setBrightness(_brightness); @@ -99,8 +114,9 @@ void WS2812FX::setPixelColor(uint16_t n, uint32_t c) { void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w) { + uint16_t actualPixelLocation = i * (_disableNLeds+1); if (_locked[i] && !_modeUsesLock) return; - if (IS_REVERSE) i = SEGMENT.stop -1 -i + SEGMENT.start; //reverse just individual segment + if (IS_REVERSE) i = SEGMENT.stop -1 -actualPixelLocation + SEGMENT.start; //reverse just individual segment byte tmpg = g; switch (colorOrder) //0 = Grb, default { @@ -111,14 +127,18 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w) } if (!_cronixieMode) { - if (reverseMode) i = _length -1 -i; + if (reverseMode) i = _usableCount -1 -i; if (_skipFirstMode) { if (i < LED_SKIP_AMOUNT) bus->SetPixelColor(i, RgbwColor(0,0,0,0)); i += LED_SKIP_AMOUNT; } - - bus->SetPixelColor(i, RgbwColor(r,g,b,w)); + bus->SetPixelColor(actualPixelLocation, RgbwColor(r,g,b,w)); + if (_disableNLeds > 0) { + for(uint16_t offCount=0; offCount < _disableNLeds; offCount++) { + bus->SetPixelColor((actualPixelLocation+offCount+1), RgbwColor(0,0,0,0)); + } + } } else { if(i>6)return; byte o = 10*i; diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index 6c4203bc..ac36c6c9 100644 Binary files a/wled00/data/settings_leds.htm and b/wled00/data/settings_leds.htm differ diff --git a/wled00/html_settings.h b/wled00/html_settings.h index f688c56d..b16d2293 100644 --- a/wled00/html_settings.h +++ b/wled00/html_settings.h @@ -187,7 +187,8 @@ Palette blending:
Reverse LED order (rotate 180):
-Skip first LED:
+Skip first LED:
+Disable repeating N LED: (Spaces out patterns by turning off leds between colors)
)====="; diff --git a/wled00/wled00.ino b/wled00/wled00.ino index d59f11bf..07403d5e 100644 --- a/wled00/wled00.ino +++ b/wled00/wled00.ino @@ -155,6 +155,7 @@ uint16_t transitionDelay = 750; //default crossfade duration in ms //bool strip.reverseMode = false; //flip entire LED strip (reverses all effect directions) --> edit in WS2812FX.h bool skipFirstLed = false; //ignore first LED in strip (useful if you need the LED as signal repeater) +uint8_t disableNLeds = 0; //disables N LEDs between active nodes. (Useful for spacing out lights for more traditional christmas light look) byte briMultiplier = 100; //% of brightness to set (to limit power, if you set it to 50 and set bri to 255, actual brightness will be 127) diff --git a/wled00/wled01_eeprom.ino b/wled00/wled01_eeprom.ino index 486b3f1f..fe766239 100644 --- a/wled00/wled01_eeprom.ino +++ b/wled00/wled01_eeprom.ino @@ -244,6 +244,8 @@ void saveSettingsToEEPROM() saveCurrPresetCycConf = false; } + EEPROM.write(2213, disableNLeds); + writeStringToEEPROM(2220, blynkApiKey, 35); for (int i = 0; i < 8; ++i) @@ -515,6 +517,8 @@ void loadSettingsFromEEPROM(bool first) presetApplyFx = EEPROM.read(2212); } + disableNLeds = EEPROM.read(2213); + bootPreset = EEPROM.read(389); wifiLock = EEPROM.read(393); utcOffsetSecs = EEPROM.read(394) + ((EEPROM.read(395) << 8) & 0xFF00); diff --git a/wled00/wled02_xml.ino b/wled00/wled02_xml.ino index e0546f0a..f2e11cab 100644 --- a/wled00/wled02_xml.ino +++ b/wled00/wled02_xml.ino @@ -272,6 +272,7 @@ void getSettingsJS(byte subPage, char* dest) sappend('i',"PB",strip.paletteBlend); sappend('c',"RV",strip.reverseMode); sappend('c',"SL",skipFirstLed); + sappend('v',"DL",disableNLeds); } if (subPage == 3) diff --git a/wled00/wled03_set.ino b/wled00/wled03_set.ino index 0bd3fa1c..e56e5ebf 100644 --- a/wled00/wled03_set.ino +++ b/wled00/wled03_set.ino @@ -85,10 +85,10 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) colS[0] = request->arg("CR").toInt(); colS[1] = request->arg("CG").toInt(); colS[2] = request->arg("CB").toInt(); + colS[3] = request->arg("CW").toInt(); colSecS[0] = request->arg("SR").toInt(); colSecS[1] = request->arg("SG").toInt(); colSecS[2] = request->arg("SB").toInt(); - colS[3] = request->arg("CW").toInt(); colSecS[3] = request->arg("SW").toInt(); briS = request->arg("CA").toInt(); effectDefault = request->arg("FX").toInt(); @@ -120,6 +120,9 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) if (t >= 0 && t < 4) strip.paletteBlend = t; strip.reverseMode = request->hasArg("RV"); skipFirstLed = request->hasArg("SL"); + + disableNLeds = request->arg("DL").toInt(); + t = request->arg("BF").toInt(); if (t > 0) briMultiplier = t; } @@ -310,7 +313,9 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) } } if (subPage != 6 || !doReboot) saveSettingsToEEPROM(); //do not save if factory reset - if (subPage == 2) strip.init(useRGBW,ledCount,skipFirstLed); + if (subPage == 2) { + strip.init(useRGBW,ledCount,skipFirstLed,disableNLeds); + } if (subPage == 4) alexaInit(); } diff --git a/wled00/wled05_init.ino b/wled00/wled05_init.ino index 6ed76aec..4939b629 100644 --- a/wled00/wled05_init.ino +++ b/wled00/wled05_init.ino @@ -7,6 +7,11 @@ void wledInit() EEPROM.begin(EEPSIZE); ledCount = EEPROM.read(229) + ((EEPROM.read(398) << 8) & 0xFF00); if (ledCount > MAX_LEDS || ledCount == 0) ledCount = 30; + + disableNLeds = EEPROM.read(2213); + //this was reading 255 after inital flash causing bootloop. Don't know why. + disableNLeds = disableNLeds != 255 ? disableNLeds : 0; + #ifdef ESP8266 #if LEDPIN == 3 if (ledCount > MAX_LEDS_DMA) ledCount = MAX_LEDS_DMA; //DMA method uses too much ram @@ -25,7 +30,7 @@ void wledInit() DEBUG_PRINT("heap "); DEBUG_PRINTLN(ESP.getFreeHeap()); - strip.init(EEPROM.read(372),ledCount,EEPROM.read(2204)); //init LEDs quickly + strip.init(EEPROM.read(372),ledCount,EEPROM.read(2204),disableNLeds); //init LEDs quickly strip.setBrightness(0); DEBUG_PRINT("LEDs inited. heap usage ~");