diff --git a/readme.md b/readme.md index 778be9d0..08a325b7 100644 --- a/readme.md +++ b/readme.md @@ -1,30 +1,34 @@ -## Welcome to my project WLED! +![WLED logo](https://raw.githubusercontent.com/Aircoookie/WLED/development/wled_logo.png) -WLED is a fast and (relatively) secure implementation of an ESP8266/ESP32 webserver to control NeoPixel (WS2812B) LEDs! +## Welcome to my project WLED! (v0.8.0) -### Features: (V0.7.1) -- RGB, HSB, and brightness sliders -- All new, mobile-friendly web UI! +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 +- FastLED noise effects and palettes +- Customizable Mobile and desktop UI with color and effect controls - Settings page - configuration over network - Access Point and station mode - automatic failsafe AP -- Support of Blynk IoT cloud -- WS2812FX library integrated for over 50 special effects (+Custom Theater Chase)! -- Secondary color support lets you use even more effect combinations -- Alexa smart home device server (including dimming) -- Beta syncronization to Philips hue lights - Support for RGBW strips -- 25 user presets! Save colors and effects and apply them easily! Supports cycling through them. -- HTTP request API for simple integration +- 25 user presets to save and load colors/effects easily, supports cycling through them. - Macro functions to automatically execute API calls - Nightlight function (gradually dims down) -- Notifier function (multiple ESPs sync color via UDP broadcast) -- Support for power pushbutton -- Support for the Adalight serial ambilight protocol! -- Full OTA software update capability (HTTP and ArduinoOTA) -- Password protected OTA page for added security (OTA lock) -- NTP and configurable analog clock function -- Support for the Cronixie Clock kit by Diamex -- Realtime UDP Packet Control (E1.31, Hyperion, WARLS, DRGB, DRGBW) +- Full OTA software updatability (HTTP + ArduinoOTA), password protectable +- Configurable analog clock + support for the Cronixie kit by Diamex + +### Supported light control interfaces: +- HTTP request API +- Blynk IoT +- MQTT +- E1.31 +- Hyperion +- UDP realtime +- Alexa smart device (including dimming) +- Sync to Philips hue lights +- Adalight (PC ambilight via serial) +- Sync color of multiple WLED devices (UDP notifier) +- Simple timers/schedules (time from NTP, timezones/DST supported) ### Quick start guide and documentation: @@ -32,16 +36,14 @@ See the [wiki](https://github.com/Aircoookie/WLED/wiki)! ### Other -Licensed under the MIT license -Uses libraries: -ESP8266/ESP32 Arduino Core -NeoPixelBus by Makuna -[WS2812FX](https://github.com/kitesurfer1404/WS2812FX) by kitesurfer1404 (Aircoookie fork) -Time library -Timezone library by JChristensen -Alexa code based on arduino-esp8266-alexa-multiple-wemo-switch by kakopappa +Licensed under the MIT license +Credits in About page! -Uses Linearicons by Perxis! (link in settings page) +Uses Linearicons by Perxis! + +Join the Discord [server](https://discord.gg/KuqP7NE) to discuss everything about WLED! +You can also send me mails to [dev.aircoookie@gmail.com](mailto:dev.aircoookie@gmail.com). +If you insist that you just love WLED too much, you can [send me a gift](https://paypal.me/aircoookie)! diff --git a/wled00/NpbWrapper.h b/wled00/NpbWrapper.h index b97ae8e5..5912966a 100644 --- a/wled00/NpbWrapper.h +++ b/wled00/NpbWrapper.h @@ -1,8 +1,12 @@ //this code is a modified version of https://github.com/Makuna/NeoPixelBus/issues/103 +#ifndef NpbWrapper_h +#define NpbWrapper_h //#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 + //uncomment this if red and green are swapped //#define SWAPRG @@ -13,9 +17,12 @@ #else #define PIXELMETHOD NeoEsp32RmtWS2813_V3Method #endif -#else +#else //esp8266 +//you may change to DMA method on pin GPIO3 here #define PIXELMETHOD NeoEsp8266Uart800KbpsMethod +//#define PIXELMETHOD NeoEsp8266Dma800KbpsMethod #endif + //handle swapping Red and Green automatically #ifdef SWAPRG #define PIXELFEATURE3 NeoRgbFeature @@ -52,7 +59,7 @@ public: cleanup(); } - void Begin(NeoPixelType type, uint16_t countPixels, uint8_t pin) + void Begin(NeoPixelType type, uint16_t countPixels) { cleanup(); _type = type; @@ -60,12 +67,12 @@ public: switch (_type) { case NeoPixelType_Grb: - _pGrb = new NeoPixelBrightnessBus(countPixels, pin); + _pGrb = new NeoPixelBrightnessBus(countPixels, LEDPIN); _pGrb->Begin(); break; case NeoPixelType_Grbw: - _pGrbw = new NeoPixelBrightnessBus(countPixels, pin); + _pGrbw = new NeoPixelBrightnessBus(countPixels, LEDPIN); _pGrbw->Begin(); break; } @@ -110,7 +117,7 @@ public: void SetPixelColor(uint16_t indexPixel, RgbwColor color) { switch (_type) { - case NeoPixelType_Grb: _pGrbw->SetPixelColor(indexPixel, color); break; + case NeoPixelType_Grb: _pGrb->SetPixelColor(indexPixel, RgbColor(color.R,color.G,color.B)); break; case NeoPixelType_Grbw: _pGrbw->SetPixelColor(indexPixel, color); break; } } @@ -174,3 +181,4 @@ private: } } }; +#endif diff --git a/wled00/WS2812FX.cpp b/wled00/WS2812FX.cpp index 9b2e0e74..8f4af282 100644 --- a/wled00/WS2812FX.cpp +++ b/wled00/WS2812FX.cpp @@ -4,13 +4,13 @@ www.aldick.org FEATURES * A lot of blinken modes and counting - * WS2812FX can be used as drop-in replacement for Adafruit Neopixel Library + * WS2812FX can be used as drop-in replacement for Adafruit NeoPixel Library NOTES - * Uses the Adafruit Neopixel library. Get it here: + * Uses the Adafruit NeoPixel library. Get it here: https://github.com/adafruit/Adafruit_NeoPixel LICENSE The MIT License (MIT) - Copyright (c) 2016 Harm Aldick + Copyright (c) 2016 Harm Aldick Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights @@ -30,1876 +30,116 @@ 2016-05-28 Initial beta release 2016-06-03 Code cleanup, minor improvements, new modes 2016-06-04 2 new fx, fixed setColor (now also resets _mode_color) + 2017-02-02 added external trigger functionality (e.g. for sound-to-light) + 2017-02-02 removed "blackout" on mode, speed or color-change + 2017-09-26 implemented segment and reverse features + 2017-11-16 changed speed calc, reduced memory footprint + 2018-02-24 added hooks for user created custom effects + Modified for WLED */ -#include "Arduino.h" + #include "WS2812FX.h" +#include "FastLED.h" +#include "palettes.h"; -#define CALL_MODE(n) (this->*_mode[n])(); - -void WS2812FX::init(bool supportWhite, uint16_t countPixels, uint8_t pin,bool skipFirst) { - begin(supportWhite,countPixels,pin,skipFirst); - for (int i=0; i < _led_count; i++) _locked[i] = false; - WS2812FX::setBrightness(_brightness); +void WS2812FX::init(bool supportWhite, uint16_t countPixels, bool skipFirst) +{ + if (supportWhite == _rgbwMode && countPixels == _length && _locked != NULL) return; + RESET_RUNTIME; + _rgbwMode = supportWhite; + _skipFirstMode = skipFirst; + _length = countPixels; + if (_skipFirstMode) _length++; + uint8_t ty = 1; + if (supportWhite) ty =2; + bus->Begin((NeoPixelType)ty, _length); + if (_locked != NULL) delete _locked; + _locked = new byte[_length]; + _segments[0].start = 0; + _segments[0].stop = _length -1; + unlockAll(); + setBrightness(_brightness); show(); + _running = true; } void WS2812FX::service() { if(_running || _triggered) { - unsigned long now = millis(); - - if(now - _mode_last_call_time > _mode_delay || _triggered) { - CALL_MODE(_mode_index); - _counter_mode_call++; - _mode_last_call_time = now; - _triggered = false; - } - } -} - -void WS2812FX::trigger() { - _triggered = true; -} - -void WS2812FX::start() { - _counter_mode_call = 0; - _counter_mode_step = 0; - _mode_last_call_time = 0; - _running = true; - show(); -} - -void WS2812FX::stop() { - _running = false; - strip_off(); -} - -void WS2812FX::setMode(byte m) { - _counter_mode_call = 0; - _counter_mode_step = 0; - _mode_last_call_time = 0; - _mode_index = constrain(m, 0, MODE_COUNT-1); - _mode_color = _color; - _mode_var1 = 0; - setBrightness(_brightness); - strip_off_respectLock(); -} - -void WS2812FX::setSpeed(byte s) { - _mode_last_call_time = 0; - _speed = constrain(s, SPEED_MIN, SPEED_MAX); -} - -void WS2812FX::increaseSpeed(byte s) { - s = constrain(_speed + s, SPEED_MIN, SPEED_MAX); - setSpeed(s); -} - -void WS2812FX::decreaseSpeed(byte s) { - s = constrain(_speed - s, SPEED_MIN, SPEED_MAX); - setSpeed(s); -} - -void WS2812FX::setIntensity(byte in) { - _intensity=in; -} - -void WS2812FX::setColor(byte r, byte g, byte b) { - setColor(((uint32_t)r << 16) | ((uint32_t)g << 8) | b); -} - - -void WS2812FX::setColor(byte r, byte g, byte b, byte w) { - setColor(((uint32_t)w << 24)|((uint32_t)r << 16) | ((uint32_t)g << 8) | b); -} - -void WS2812FX::setSecondaryColor(byte r, byte g, byte b) { - setSecondaryColor(((uint32_t)r << 16) | ((uint32_t)g << 8) | b); -} - - -void WS2812FX::setSecondaryColor(byte r, byte g, byte b, byte w) { - setSecondaryColor(((uint32_t)w << 24)|((uint32_t)r << 16) | ((uint32_t)g << 8) | b); -} - -void WS2812FX::setColor(uint32_t c) { - _color = c; - _mode_color = _color; - setBrightness(_brightness); -} - -void WS2812FX::setSecondaryColor(uint32_t c) { - _color_sec = c; - if (_cronixieMode) _cronixieSecMultiplier = getSafePowerMultiplier(900, 100, c, _brightness); - setBrightness(_brightness); -} - -void WS2812FX::increaseBrightness(byte s) { - s = constrain(_brightness + s, BRIGHTNESS_MIN, BRIGHTNESS_MAX); - setBrightness(s); -} - -void WS2812FX::decreaseBrightness(byte s) { - s = constrain(_brightness - s, BRIGHTNESS_MIN, BRIGHTNESS_MAX); - setBrightness(s); -} - -bool WS2812FX::isRunning() { - return _running; -} - -byte WS2812FX::getMode(void) { - return _mode_index; -} - -byte WS2812FX::getSpeed(void) { - return _speed; -} - -byte WS2812FX::getBrightness(void) { - return _brightness; -} - -byte WS2812FX::getModeCount(void) { - return MODE_COUNT; -} - -uint32_t WS2812FX::getColor(void) { - return _color; -} - -/* ##################################################### -# -# Color and Blinken Functions -# -##################################################### */ - -/* - * Turns everything off. Doh. - */ -void WS2812FX::strip_off() { - clear(); - show(); -} - -void WS2812FX::strip_off_respectLock() { - for(uint16_t i=0; i < _led_count; i++) { - if (!_locked[i]) - setPixelColor(i, 0); - } - show(); -} - - -/* - * Put a value 0 to 255 in to get a color value. - * The colours are a transition r -> g -> b -> back to r - * Inspired by the Adafruit examples. - */ -uint32_t WS2812FX::color_wheel(byte pos) { - pos = 255 - pos; - if(pos < 85) { - return ((uint32_t)(255 - pos * 3) << 16) | ((uint32_t)(0) << 8) | (pos * 3); - } else if(pos < 170) { - pos -= 85; - return ((uint32_t)(0) << 16) | ((uint32_t)(pos * 3) << 8) | (255 - pos * 3); - } else { - pos -= 170; - return ((uint32_t)(pos * 3) << 16) | ((uint32_t)(255 - pos * 3) << 8) | (0); - } -} - - -/* - * Returns a new, random wheel index with a minimum distance of 42 from pos. - */ -byte WS2812FX::get_random_wheel_index(byte pos) { - byte r = 0; - byte x = 0; - byte y = 0; - byte d = 0; - - while(d < 42) { - r = random(256); - x = abs(pos - r); - y = 255 - x; - d = minval(x, y); - } - - return r; -} - - -/* - * No blinking. Just plain old static light. - */ -void WS2812FX::mode_static(void) { - for(uint16_t i=0; i < _led_count; i++) { - if (!_locked[i]) - setPixelColor(i, _color); - } - show(); - _mode_delay = (_fastStandard) ? 25 : 500; -} - - -/* - * Normal blinking. on/off duty time set by FX intensity. - */ -void WS2812FX::mode_blink(void) { - if(_counter_mode_call % 2 == 1) { - for(uint16_t i=0; i < _led_count; i++) { - if (!_locked[i]) - setPixelColor(i, _color); - } - _mode_delay = (100 + ((1986 * (uint32_t)(SPEED_MAX - _speed)) / SPEED_MAX))*(float)(_intensity/128.0); - } else { - for(uint16_t i=0; i < _led_count; i++) { - if (!_locked[i]) - setPixelColor(i, _color_sec); - } - _mode_delay = (100 + ((1986 * (uint32_t)(SPEED_MAX - _speed)) / SPEED_MAX))*(float)(2.0-(_intensity/128.0)); - } - show(); -} - - -/* - * Lights all LEDs after each other up. Then turns them in - * that order off (2nd color). Repeat. - */ -void WS2812FX::mode_color_wipe(void) { - if(_counter_mode_step < _led_count) { - if (!_locked[_counter_mode_step]) - setPixelColor(_counter_mode_step, _color); - } else { - if (!_locked[_counter_mode_step - _led_count]) - setPixelColor(_counter_mode_step - _led_count, _color_sec); - } - show(); - - _counter_mode_step = (_counter_mode_step + 1) % (_led_count * 2); - - _mode_delay = 5 + ((50 * (uint32_t)(SPEED_MAX - _speed)) / _led_count); -} - - -/* - * Turns all LEDs after each other to a random color. - * Then starts over with another color. - */ -void WS2812FX::mode_color_wipe_random(void) { - if(_counter_mode_step == 0) { - _mode_color = get_random_wheel_index(_mode_color); - } - if (!_locked[_counter_mode_step]) - setPixelColor(_counter_mode_step, color_wheel(_mode_color)); - show(); - - _counter_mode_step = (_counter_mode_step + 1) % _led_count; - - _mode_delay = 5 + ((50 * (uint32_t)(SPEED_MAX - _speed)) / _led_count); -} - - -/* - * Lights all LEDs in one random color up. Then switches them - * to the next random color. - */ -void WS2812FX::mode_random_color(void) { - _mode_color = get_random_wheel_index(_mode_color); - - for(uint16_t i=0; i < _led_count; i++) { - if (!_locked[i]) - setPixelColor(i, color_wheel(_mode_color)); - } - - show(); - _mode_delay = 100 + ((5000 * (uint32_t)(SPEED_MAX - _speed)) / SPEED_MAX); -} - - -/* - * Lights some pastel colors - */ -void WS2812FX::mode_easter(void) { - //uint32_t cols[]{0x00F7ECC5,0x00F8D5C7,0x00F9E2E7,0x00BED9D4,0x00F7ECC5,0x00F8D5C7,0x00F9E2E7}; - uint32_t cols[]{0x00FF8040,0x00E5D241,0x0077FF77,0x0077F0F0,0x00FF8040,0x00E5D241,0x0077FF77}; - mode_colorful_internal(cols); -} - - -/* - * Lights multiple random leds in a random color (higher intensity, more updates) - */ -void WS2812FX::mode_dynamic(void) { - if(_counter_mode_call == 0) { - for(uint16_t i=0; i < _led_count; i++) { - if (!_locked[i]) - setPixelColor(i, color_wheel(random(256))); - } - } - if (_intensity > 0) //multi dynamic - { - for(uint16_t i=0; i < _led_count; i++) { - if (!_locked[i] && random(256)<_intensity) - setPixelColor(i, color_wheel(random(256))); - } - } else { //single dynamic - int ran = random(_led_count); - if (!_locked[ran]) - setPixelColor(ran, color_wheel(random(256))); - } - show(); - _mode_delay = 100 + ((5000 * (uint32_t)(SPEED_MAX - _speed)) / SPEED_MAX); -} - - -/* - * Does the "standby-breathing" of well known i-Devices. Fixed Speed. - * Use mode "fade" if you like to have something similar with a different speed. - */ -void WS2812FX::mode_breath(void) { - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // step - uint16_t breath_delay_steps[] = { 7, 9, 13, 15, 16, 17, 18, 930, 19, 18, 15, 13, 9, 7, 4, 5, 10 }; // magic numbers for breathing LED - byte breath_brightness_steps[] = { 150, 125, 100, 75, 50, 25, 16, 15, 16, 25, 50, 75, 100, 125, 150, 220, 255 }; // even more magic numbers! - - if(_counter_mode_call == 0) { - _mode_color = breath_brightness_steps[0] + 1; - } - - byte breath_brightness = _mode_color; // we use _mode_color to store the brightness - - if(_counter_mode_step < 8) { - breath_brightness--; - } else { - breath_brightness++; - } - - // update index of current delay when target brightness is reached, start over after the last step - if(breath_brightness == breath_brightness_steps[_counter_mode_step]) { - _counter_mode_step = (_counter_mode_step + 1) % (sizeof(breath_brightness_steps)/sizeof(byte)); - } - - for(uint16_t i=0; i < _led_count; i++) { - if (!_locked[i]) - setPixelColor(i, _color); // set all LEDs to selected color - } - int b = map(breath_brightness, 0, 255, 0, _brightness); // keep brightness below brightness set by user - bus->SetBrightness(b); // set new brightness to leds - show(); - - _mode_color = breath_brightness; // we use _mode_color to store the brightness - _mode_delay = breath_delay_steps[_counter_mode_step]; -} - - -/* - * Fades the LEDs on and (almost) off again. - */ -void WS2812FX::mode_fade(void) { - - int y = _counter_mode_step - 127; - y = 256 - (abs(y) * 2); - double z = (double)y/256; - byte w = ((_color >> 24) & 0xFF), ws = ((_color_sec >> 24) & 0xFF); - byte r = ((_color >> 16) & 0xFF), rs = ((_color_sec >> 16) & 0xFF); - byte g = ((_color >> 8) & 0xFF), gs = ((_color_sec >> 8) & 0xFF); - byte b = (_color & 0xFF), bs = (_color_sec & 0xFF); - w = w+((ws - w)*z); - r = r+((rs - r)*z); - g = g+((gs - g)*z); - b = b+((bs - b)*z); - for(uint16_t i=0; i < _led_count; i++) { - if (!_locked[i]) - setPixelColor(i, r, g, b, w); - } - show(); - - _counter_mode_step = (_counter_mode_step + 1) % 256; - _mode_delay = 5 + ((15 * (uint32_t)(SPEED_MAX - _speed)) / SPEED_MAX); -} - - -/* - * Runs a single pixel back and forth. - */ -void WS2812FX::mode_scan(void) { - if(_counter_mode_step > (_led_count*2) - 2) { - _counter_mode_step = 0; - } - _counter_mode_step++; - - int i = _counter_mode_step - (_led_count - 1); - i = abs(i); - - for(uint16_t x=0; x < _led_count; x++) { - if (!_locked[x]) - setPixelColor(x, _color_sec); - } - if (!_locked[i]) - setPixelColor(abs(i), _color); - show(); - - _mode_delay = 10 + ((30 * (uint32_t)(SPEED_MAX - _speed)) / _led_count); -} - - -/* - * Runs two pixel back and forth in opposite directions. - */ -void WS2812FX::mode_dual_scan(void) { - if(_counter_mode_step > (_led_count*2) - 2) { - _counter_mode_step = 0; - } - _counter_mode_step++; - - int i = _counter_mode_step - (_led_count - 1); - i = abs(i); - for(uint16_t x=0; x < _led_count; x++) { - if (!_locked[x]) - setPixelColor(x, _color_sec); - } - if (!_locked[i]) - setPixelColor(i, _color); - if (!_locked[_led_count - (i+1)]) - setPixelColor(_led_count - (i+1), _color); - show(); - - _mode_delay = 10 + ((30 * (uint32_t)(SPEED_MAX - _speed)) / _led_count); -} - - -/* - * Cycles all LEDs at once through a rainbow. - */ -void WS2812FX::mode_rainbow(void) { - uint32_t color = color_wheel(_counter_mode_step); - for(uint16_t i=0; i < _led_count; i++) { - if (!_locked[i]) - setPixelColor(i, color); - } - show(); - - _counter_mode_step = (_counter_mode_step + 1) % 256; - - _mode_delay = 1 + ((50 * (uint32_t)(SPEED_MAX - _speed)) / SPEED_MAX); -} - - -/* - * Cycles a rainbow over the entire string of LEDs. - */ -void WS2812FX::mode_rainbow_cycle(void) { - for(uint16_t i=0; i < _led_count; i++) { - if (!_locked[i]) - setPixelColor(i, color_wheel(((i * 256 / ((uint16_t)(_led_count*(float)(_intensity/128.0))+1)) + _counter_mode_step) % 256)); - } - show(); - - _counter_mode_step = (_counter_mode_step + 1) % 256; - - _mode_delay = 1 + ((50 * (uint32_t)(SPEED_MAX - _speed)) / SPEED_MAX); -} - - -/* - * Theatre-style crawling lights. - * Inspired by the Adafruit examples. - */ -void WS2812FX::mode_theater_chase(void) { - byte j = _counter_mode_call % 6; - if(j % 2 == 0) { - for(uint16_t i=0; i < _led_count; i=i+3) { - if (!_locked[i+(j/2)]) - setPixelColor(i+(j/2), _color); - } - show(); - _mode_delay = 50 + ((500 * (uint32_t)(SPEED_MAX - _speed)) / SPEED_MAX); - } else { - for(uint16_t i=0; i < _led_count; i=i+3) { - if (!_locked[i+(j/2)]) - setPixelColor(i+(j/2), _color_sec); - } - _mode_delay = 1; - } -} - - -/* - * Theatre-style crawling lights with rainbow effect. - * Inspired by the Adafruit examples. - */ -void WS2812FX::mode_theater_chase_rainbow(void) { - byte j = _counter_mode_call % 6; - if(j % 2 == 0) { - for(uint16_t i=0; i < _led_count; i=i+3) { - if (!_locked[i+(j/2)]) - setPixelColor(i+(j/2), color_wheel((i+_counter_mode_step) % 256)); - } - show(); - _mode_delay = 50 + ((500 * (uint32_t)(SPEED_MAX - _speed)) / SPEED_MAX); - } else { - for(uint16_t i=0; i < _led_count; i=i+3) { - if (!_locked[i+(j/2)]) - setPixelColor(i+(j/2), _color_sec); - } - _mode_delay = 1; - } - _counter_mode_step = (_counter_mode_step + 1) % 256; -} - - -/* - * Running lights effect with smooth sine transition. - */ -void WS2812FX::mode_running_lights(void) { - byte w = ((_color >> 24) & 0xFF); - byte r = ((_color >> 16) & 0xFF); - byte g = ((_color >> 8) & 0xFF); - byte b = (_color & 0xFF); - - for(uint16_t i=0; i < _led_count; i++) { - int s = (sin(i+_counter_mode_call) * 127) + 128; - if (!_locked[i]) - setPixelColor(i, (((uint32_t)(r * s)) / 255), (((uint32_t)(g * s)) / 255), (((uint32_t)(b * s)) / 255), (((uint32_t)(w * s)) / 255)); - } - - show(); - - _mode_delay = 35 + ((350 * (uint32_t)(SPEED_MAX - _speed)) / SPEED_MAX); -} - - -/* - * Blink several LEDs on, reset, repeat. - * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ - */ -void WS2812FX::mode_twinkle(void) { - if(_counter_mode_step == 0) { - for (int i = 0; i < _led_count; i++) - { - setPixelColor(i, _color_sec); - } - uint16_t min_leds = maxval(1, _led_count/5); // make sure, at least one LED is on - uint16_t max_leds = maxval(1, _led_count/2); // make sure, at least one LED is on - _counter_mode_step = random(min_leds, max_leds); - } - int ran = random(_led_count); - if (!_locked[ran]) - setPixelColor(ran, _mode_color); - show(); - - _counter_mode_step--; - _mode_delay = 50 + ((1986 * (uint32_t)(SPEED_MAX - _speed)) / SPEED_MAX); -} - - -/* - * Blink several LEDs in random colors on, reset, repeat. - * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ - */ -void WS2812FX::mode_twinkle_random(void) { - _mode_color = color_wheel(random(256)); - mode_twinkle(); -} - - -/* - * Blink several LEDs on, fading out. - */ -void WS2812FX::mode_twinkle_fade(void) { - - for(uint16_t i=0; i < _led_count; i++) { - uint32_t px_rgb = getPixelColor(i); - - byte px_w = (px_rgb & 0xFF000000) >> 24; - byte px_r = (px_rgb & 0x00FF0000) >> 16; - byte px_g = (px_rgb & 0x0000FF00) >> 8; - byte px_b = (px_rgb & 0x000000FF) >> 0; - - // fade out (divide by 2) - px_w = px_w >> 1; - px_r = px_r >> 1; - px_g = px_g >> 1; - px_b = px_b >> 1; - if (!_locked[i]) - setPixelColor(i, px_r, px_g, px_b, px_w); - } - - if(random(256) < _intensity) { - int ran = random(_led_count); - if (!_locked[ran]) - setPixelColor(ran, _mode_color); - } - - show(); - - _mode_delay = 100 + ((100 * (uint32_t)(SPEED_MAX - _speed)) / SPEED_MAX); -} - - -/* - * Blink several LEDs in random colors on, fading out. - */ -void WS2812FX::mode_twinkle_fade_random(void) { - _mode_color = color_wheel(random(256)); - mode_twinkle_fade(); -} - - -/* - * Blinks one LED at a time. - * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ - */ -void WS2812FX::mode_sparkle(void) { - for(uint16_t i=0; i < _led_count; i++) { - if (!_locked[i]) - setPixelColor(i, _color_sec); - } - int ran = random(_led_count); - if (!_locked[ran]) - setPixelColor(ran ,_color); - show(); - _mode_delay = 10 + ((200 * (uint32_t)(SPEED_MAX - _speed)) / SPEED_MAX); -} - - -/* - * Lights all LEDs in the _color. Flashes single secondary color pixels randomly. - * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ - */ -void WS2812FX::mode_flash_sparkle(void) { - for(uint16_t i=0; i < _led_count; i++) { - if (!_locked[i]) - setPixelColor(i, _color); - } - - if(random(256) <= _intensity) { - int ran = random(_led_count); - if (!_locked[ran]) - setPixelColor(ran , _color_sec); - _mode_delay = 20; - } else { - _mode_delay = 20 + ((200 * (uint32_t)(SPEED_MAX - _speed)) / SPEED_MAX); - } - - show(); -} - - -/* - * Like flash sparkle. With more flash. - * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ - */ -void WS2812FX::mode_hyper_sparkle(void) { - for(uint16_t i=0; i < _led_count; i++) { - if (!_locked[i]) - setPixelColor(i, _color); - } - - if(random(256) <= _intensity) { - for(uint16_t i=0; i < maxval(1, _led_count/3); i++) { - int ran = random(_led_count); - if (!_locked[ran]) - setPixelColor(ran , _color_sec); - } - _mode_delay = 20; - } else { - _mode_delay = 15 + ((120 * (uint32_t)(SPEED_MAX - _speed)) / SPEED_MAX); - } - show(); -} - - -/* - * Classic Strobe effect. - */ -void WS2812FX::mode_strobe(void) { - if(_counter_mode_call % 2 == 0) { - for(uint16_t i=0; i < _led_count; i++) { - if (!_locked[i]) - setPixelColor(i, _color); - } - _mode_delay = 20; - } else { - for(uint16_t i=0; i < _led_count; i++) { - if (!_locked[i]) - setPixelColor(i, _color_sec); - } - _mode_delay = 50 + ((1986 * (uint32_t)(SPEED_MAX - _speed)) / SPEED_MAX); - } - show(); -} - - -/* - * Strobe effect with different strobe count and pause, controlled by _speed. - */ -void WS2812FX::mode_multi_strobe(void) { - for(uint16_t i=0; i < _led_count; i++) { - if (!_locked[i]) - setPixelColor(i, _color_sec); - } - - if(_counter_mode_step < (2 * ((_speed / 10) + 1))) { - if(_counter_mode_step % 2 == 0) { - for(uint16_t i=0; i < _led_count; i++) { - if (!_locked[i]) - setPixelColor(i, _color); - } - _mode_delay = 20; - } else { - _mode_delay = 50; - } - - } else { - _mode_delay = 100 + ((9 - (_speed % 10)) * 125); - } - - show(); - _counter_mode_step = (_counter_mode_step + 1) % ((2 * ((_speed / 10) + 1)) + 1); -} - - -/* - * Classic Strobe effect. Cycling through the rainbow. - */ -void WS2812FX::mode_strobe_rainbow(void) { - if(_counter_mode_call % 2 == 0) { - for(uint16_t i=0; i < _led_count; i++) { - if (!_locked[i]) - setPixelColor(i, color_wheel(_counter_mode_call % 256)); - } - _mode_delay = 20; - } else { - for(uint16_t i=0; i < _led_count; i++) { - if (!_locked[i]) - setPixelColor(i, _color_sec); - } - _mode_delay = 50 + ((1986 * (uint32_t)(SPEED_MAX - _speed)) / SPEED_MAX); - } - show(); -} - - -/* - * Classic Blink effect. Cycling through the rainbow. - */ -void WS2812FX::mode_blink_rainbow(void) { - if(_counter_mode_call % 2 == 1) { - for(uint16_t i=0; i < _led_count; i++) { - if (!_locked[i]) - setPixelColor(i, color_wheel(_counter_mode_call % 256)); - } - } else { - for(uint16_t i=0; i < _led_count; i++) { - if (!_locked[i]) - setPixelColor(i, _color_sec); - } - } - show(); - _mode_delay = 100 + ((1986 * (uint32_t)(SPEED_MAX - _speed)) / SPEED_MAX); -} - - -/* - * Android loading circle - */ -void WS2812FX::mode_android(void) { - if (_counter_mode_call == 0) _mode_color = 0; //we use modecolor as bool - for(uint16_t i=0; i < _led_count; i++) { - if (!_locked[i]) - setPixelColor(i, _color_sec); - } - - uint16_t a = _counter_mode_step; - if (_mode_var1 > ((float)_intensity/255.0)*(float)_led_count) - { - _mode_color = 1; - } else - { - if (_mode_var1 < 2) _mode_color = 0; - } - - if (_mode_color == 0) - { - if (_counter_mode_call %3 == 1) {a++;} - else {_mode_var1++;} - } else - { - a++; - if (_counter_mode_call %3 != 1) _mode_var1--; - } - - if (a >= _led_count) a = 0; - - if (a +_mode_var1 <= _led_count) - { - for(int i = a; i < a+_mode_var1; i++) { - if (!_locked[i]) - setPixelColor(i, _color); - } - } else - { - for(int i = a; i < _led_count; i++) { - if (!_locked[i]) - setPixelColor(i, _color); - } - for(int i = 0; i < _mode_var1 - (_led_count - a); i++) { - if (!_locked[i]) - setPixelColor(i, _color); - } - } - _counter_mode_step = a; - - show(); - _mode_delay = 3 + ((8 * (uint32_t)(SPEED_MAX - _speed)) / _led_count); -} - - -/* - * _color_sec running on _color. - */ -void WS2812FX::mode_chase_color(void) { - for(uint16_t i=0; i < _led_count; i++) { - if (!_locked[i]) - setPixelColor(i, _color_sec); - } - - uint16_t n = _counter_mode_step; - uint16_t m = (_counter_mode_step + 1) % _led_count; - if (!_locked[n]) - setPixelColor(n, _color); - if (!_locked[m]) - setPixelColor(m, _color); - show(); - - _counter_mode_step = (_counter_mode_step + 1) % _led_count; - _mode_delay = 10 + ((30 * (uint32_t)(SPEED_MAX - _speed)) / _led_count); -} - - -/* - * color_sec running followed by random color. - */ -void WS2812FX::mode_chase_random(void) { - if(_counter_mode_step == 0) { - if (!_locked[_led_count-1]) - setPixelColor(_led_count-1, color_wheel(_mode_color)); - _mode_color = get_random_wheel_index(_mode_color); - } - - for(uint16_t i=0; i < _counter_mode_step; i++) { - if (!_locked[i]) - setPixelColor(i, color_wheel(_mode_color)); - } - - uint16_t n = _counter_mode_step; - uint16_t m = (_counter_mode_step + 1) % _led_count; - if (!_locked[n]) - setPixelColor(n, _color_sec); - if (!_locked[m]) - setPixelColor(m, _color_sec); - - show(); - - _counter_mode_step = (_counter_mode_step + 1) % _led_count; - _mode_delay = 10 + ((30 * (uint32_t)(SPEED_MAX - _speed)) / _led_count); -} - - -/* - * color_sec running on rainbow. - */ -void WS2812FX::mode_chase_rainbow(void) { - for(uint16_t i=0; i < _led_count; i++) { - if (!_locked[i]) - setPixelColor(i, color_wheel(((i * 256 / _led_count) + (_counter_mode_call % 256)) % 256)); - } - - uint16_t n = _counter_mode_step; - uint16_t m = (_counter_mode_step + 1) % _led_count; - if (!_locked[n]) - setPixelColor(n, _color_sec); - if (!_locked[m]) - setPixelColor(m, _color_sec); - show(); - - _counter_mode_step = (_counter_mode_step + 1) % _led_count; - _mode_delay = 10 + ((30 * (uint32_t)(SPEED_MAX - _speed)) / _led_count); -} - - -/* - * _color_sec flashes running on _color. - */ -void WS2812FX::mode_chase_flash(void) { - const static byte flash_count = 4; - byte flash_step = _counter_mode_call % ((flash_count * 2) + 1); - - for(uint16_t i=0; i < _led_count; i++) { - if (!_locked[i]) - setPixelColor(i, _color); - } - - if(flash_step < (flash_count * 2)) { - if(flash_step % 2 == 0) { - uint16_t n = _counter_mode_step; - uint16_t m = (_counter_mode_step + 1) % _led_count; - if (!_locked[n]) - setPixelColor(n, _color_sec); - if (!_locked[m]) - setPixelColor(m, _color_sec); - _mode_delay = 20; - } else { - _mode_delay = 30; - } - } else { - _counter_mode_step = (_counter_mode_step + 1) % _led_count; - _mode_delay = 10 + ((30 * (uint32_t)(SPEED_MAX - _speed)) / _led_count); - } - - show(); -} - - -/* - * _color_sec flashes running, followed by random color. - */ -void WS2812FX::mode_chase_flash_random(void) { - const static byte flash_count = 4; - byte flash_step = _counter_mode_call % ((flash_count * 2) + 1); - - for(uint16_t i=0; i < _counter_mode_step; i++) { - if (!_locked[i]) - setPixelColor(i, color_wheel(_mode_color)); - } - - if(flash_step < (flash_count * 2)) { - uint16_t n = _counter_mode_step; - uint16_t m = (_counter_mode_step + 1) % _led_count; - if(flash_step % 2 == 0) { - if (!_locked[n]) - setPixelColor(n, _color_sec); - if (!_locked[m]) - setPixelColor(m, _color_sec); - _mode_delay = 20; - } else { - if (!_locked[n]) - setPixelColor(n, color_wheel(_mode_color)); - if (!_locked[m]) - setPixelColor(m, 0, 0, 0); - _mode_delay = 30; - } - } else { - _counter_mode_step = (_counter_mode_step + 1) % _led_count; - _mode_delay = 1 + ((10 * (uint32_t)(SPEED_MAX - _speed)) / _led_count); - - if(_counter_mode_step == 0) { - _mode_color = get_random_wheel_index(_mode_color); - } - } - - show(); -} - - -/* - * Rainbow running on _color_sec. - */ -void WS2812FX::mode_chase_rainbow_white(void) { - for(uint16_t i=0; i < _led_count; i++) { - if (!_locked[i]) - setPixelColor(i, _color_sec); - } - - uint16_t n = _counter_mode_step; - uint16_t m = (_counter_mode_step + 1) % _led_count; - if (!_locked[n]) - setPixelColor(n, color_wheel(((n * 256 / _led_count) + (_counter_mode_call % 256)) % 256)); - if (!_locked[m]) - setPixelColor(m, color_wheel(((m * 256 / _led_count) + (_counter_mode_call % 256)) % 256)); - show(); - - _counter_mode_step = (_counter_mode_step + 1) % _led_count; - _mode_delay = 10 + ((30 * (uint32_t)(SPEED_MAX - _speed)) / _led_count); -} - -/* - * Red - Amber - Green - Blue lights running - */ -void WS2812FX::mode_colorful(void) { - uint32_t cols[]{0x00FF0000,0x00EEBB00,0x0000EE00,0x000077CC,0x00FF0000,0x00EEBB00,0x0000EE00}; - mode_colorful_internal(cols); -} - -/* - * Common function for 4-color-running (Colorful, easter) - */ -void WS2812FX::mode_colorful_internal(uint32_t cols[]) { - int i = 0; - for (i; i < _led_count ; i+=4) - { - if(!_locked[i])setPixelColor(i, cols[_counter_mode_step]); - if(!_locked[i+1])setPixelColor(i+1, cols[_counter_mode_step+1]); - if(!_locked[i+2])setPixelColor(i+2, cols[_counter_mode_step+2]); - if(!_locked[i+3])setPixelColor(i+3, cols[_counter_mode_step+3]); - } - i+=4; - if(i < _led_count && !_locked[i]) - { - setPixelColor(i, cols[_counter_mode_step]); - - if(i+1 < _led_count && !_locked[i+1]) - { - setPixelColor(i+1, cols[_counter_mode_step+1]); - - if(i+2 < _led_count && !_locked[i+2]) - { - setPixelColor(i+2, cols[_counter_mode_step+2]); + unsigned long now = millis(); // Be aware, millis() rolls over every 49 days + bool doShow = false; + for(uint8_t i=0; i < _num_segments; i++) { + _segment_index = i; + if(now > SEGMENT_RUNTIME.next_time || _triggered) { + doShow = true; + uint16_t delay = (this->*_mode[SEGMENT.mode])(); + SEGMENT_RUNTIME.next_time = now + max(delay, 5); + SEGMENT_RUNTIME.counter_mode_call++; } } + if(doShow) { + show(); + } + _triggered = false; } - - show(); - if (_speed > SPEED_MIN) _counter_mode_step++; //static if lowest speed - if (_counter_mode_step >3) _counter_mode_step = 0; - _mode_delay = 50 + (15 * (uint32_t)(SPEED_MAX - _speed)); } +void WS2812FX::clear() +{ + bus->ClearTo(RgbColor(0)); +} -/* - * Emulates a traffic light. - */ -void WS2812FX::mode_traffic_light(void) { - for(uint16_t i=0; i < _led_count; i++) { - if (!_locked[i]) - setPixelColor(i, _color_sec); - } - for (int i = 0; i < _led_count-2 ; i+=3) +void WS2812FX::setPixelColor(uint16_t n, uint32_t c) { + uint8_t w = (c >> 24) & 0xFF; + uint8_t r = (c >> 16) & 0xFF; + uint8_t g = (c >> 8) & 0xFF; + uint8_t b = c & 0xFF; + setPixelColor(n, r, g, b, w); +} + +void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w) +{ + 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) { - switch (_counter_mode_step) - { - case 0: if(!_locked[i])setPixelColor(i, 0x00FF0000); _mode_delay = 150 + (100 * (uint32_t)(SPEED_MAX - _speed));break; - case 1: if(!_locked[i])setPixelColor(i, 0x00FF0000); _mode_delay = 150 + (20 * (uint32_t)(SPEED_MAX - _speed)); if(!_locked[i+1])setPixelColor(i+1, 0x00EECC00); break; - case 2: if(!_locked[i+2])setPixelColor(i+2, 0x0000FF00); _mode_delay = 150 + (100 * (uint32_t)(SPEED_MAX - _speed));break; - case 3: if(!_locked[i+1])setPixelColor(i+1, 0x00EECC00); _mode_delay = 150 + (20 * (uint32_t)(SPEED_MAX - _speed));break; - } - } - show(); - _counter_mode_step++; - if (_counter_mode_step >3) _counter_mode_step = 0; -} - - -/* - * Random color intruduced alternating from start and end of strip. - */ -void WS2812FX::mode_color_sweep_random(void) { - if(_counter_mode_step == 0 || _counter_mode_step == _led_count) { - _mode_color = get_random_wheel_index(_mode_color); - } - - if(_counter_mode_step < _led_count) { - if (!_locked[_counter_mode_step]) - setPixelColor(_counter_mode_step, color_wheel(_mode_color)); + if (_skipFirstMode) {i++;if(i==1)bus->SetPixelColor(i, RgbwColor(0,0,0,0));} + bus->SetPixelColor(i, RgbwColor(r,g,b,w)); } else { - if (!_locked[(_led_count * 2) - _counter_mode_step - 1]) - setPixelColor((_led_count * 2) - _counter_mode_step - 1, color_wheel(_mode_color)); - } - show(); - - _counter_mode_step = (_counter_mode_step + 1) % (_led_count * 2); - _mode_delay = 5 + ((50 * (uint32_t)(SPEED_MAX - _speed)) / _led_count); -} - - -/* - * Alternating color/2nd pixels running. - */ -void WS2812FX::mode_running_color(void) { - for(uint16_t i=0; i < _led_count; i++) { - if((i + _counter_mode_step) % 4 < 2) { - if (!_locked[i]) - setPixelColor(i, _mode_color); - } else { - if (!_locked[i]) - setPixelColor(i, _color_sec); - } - } - show(); - - _counter_mode_step = (_counter_mode_step + 1) % 4; - _mode_delay = 10 + ((30 * (uint32_t)(SPEED_MAX - _speed)) / _led_count); -} - - -/* - * Alternating red/blue pixels running. (RED) - */ -void WS2812FX::mode_running_red_blue(void) { - for(uint16_t i=0; i < _led_count; i++) { - if((i + _counter_mode_step) % 4 < 2) { - if (!_locked[i]) - setPixelColor(i, 255, 0, 0); - } else { - if (!_locked[i]) - setPixelColor(i, 0, 0, 255); - } - } - show(); - - _counter_mode_step = (_counter_mode_step + 1) % 4; - _mode_delay = 10 + ((30 * (uint32_t)(SPEED_MAX - _speed)) / _led_count); -} - - -/* - * Random colored pixels running. - */ -void WS2812FX::mode_running_random(void) { - for(uint16_t i=_led_count-1; i > 0; i--) { - if (!_locked[i]) + if(i>6)return; + byte o = 10*i; + if (_cronixieBacklightEnabled && _cronixieDigits[i] <11) { - if (!_locked[i-1]) + byte rCorr = (int)(((double)((_segments[0].colors[1]>>16) & 0xFF))*_cronixieSecMultiplier); + byte gCorr = (int)(((double)((_segments[0].colors[1]>>8) & 0xFF))*_cronixieSecMultiplier); + byte bCorr = (int)(((double)((_segments[0].colors[1]) & 0xFF))*_cronixieSecMultiplier); + byte wCorr = (int)(((double)((_segments[0].colors[1]>>24) & 0xFF))*_cronixieSecMultiplier); + for (int j=o; j< o+19; j++) { - setPixelColor(i, getPixelColor(i-1)); - } else + bus->SetPixelColor((_skipFirstMode)?j+1:j,RgbwColor(rCorr,gCorr,bCorr,wCorr)); + } + } else + { + for (int j=o; j< o+19; j++) { - setPixelColor(i, color_wheel(_mode_color)); + bus->SetPixelColor((_skipFirstMode)?j+1:j,RgbwColor(0,0,0,0)); } } - } - - if(_counter_mode_step == 0) { - _mode_color = get_random_wheel_index(_mode_color); - if (!_locked[0]) - setPixelColor(0, color_wheel(_mode_color)); - } - - show(); - - _counter_mode_step = (_counter_mode_step + 1) % 2; - - _mode_delay = 10 + ((30 * (uint32_t)(SPEED_MAX - _speed)) / _led_count); -} - - -/* - * K.I.T.T. - */ -void WS2812FX::mode_larson_scanner(void) { - - for(uint16_t i=0; i < _led_count; i++) { - uint32_t px_rgb = getPixelColor(i); - - byte px_r = (px_rgb & 0x00FF0000) >> 16; - byte px_g = (px_rgb & 0x0000FF00) >> 8; - byte px_b = (px_rgb & 0x000000FF) >> 0; - - // fade out (divide by 2) - px_r = px_r >> 1; - px_g = px_g >> 1; - px_b = px_b >> 1; - - if (!_locked[i]) - setPixelColor(i, px_r, px_g, px_b); - } - - uint16_t pos = 0; - - if(_counter_mode_step < _led_count) { - pos = _counter_mode_step; - } else { - pos = (_led_count * 2) - _counter_mode_step - 2; - } - - if (!_locked[pos]) - setPixelColor(pos, _color); - show(); - - _counter_mode_step = (_counter_mode_step + 1) % ((_led_count * 2) - 2); - _mode_delay = 10 + ((10 * (uint32_t)(SPEED_MAX - _speed)) / _led_count); -} - - -/* - * Fireing comets from one end. - */ -void WS2812FX::mode_comet(void) { - - for(uint16_t i=0; i < _led_count; i++) { - uint32_t px_rgb = getPixelColor(i); - - byte px_r = (px_rgb & 0x00FF0000) >> 16; - byte px_g = (px_rgb & 0x0000FF00) >> 8; - byte px_b = (px_rgb & 0x000000FF) >> 0; - - // fade out (divide by 2) - px_r = px_r >> 1; - px_g = px_g >> 1; - px_b = px_b >> 1; - - if (!_locked[i]) - setPixelColor(i, px_r, px_g, px_b); - } - - if (!_locked[_counter_mode_step]) - setPixelColor(_counter_mode_step, _color); - show(); - - _counter_mode_step = (_counter_mode_step + 1) % _led_count; - _mode_delay = 10 + ((10 * (uint32_t)(SPEED_MAX - _speed)) / _led_count); -} - - -/* - * Firework sparks. - */ -void WS2812FX::mode_fireworks(void) { - uint32_t px_rgb = 0; - byte px_r = 0; - byte px_g = 0; - byte px_b = 0; - - for(uint16_t i=0; i < _led_count; i++) { - px_rgb = getPixelColor(i); - - px_r = (px_rgb & 0x00FF0000) >> 16; - px_g = (px_rgb & 0x0000FF00) >> 8; - px_b = (px_rgb & 0x000000FF) >> 0; - - // fade out (divide by 2) - px_r = px_r >> 1; - px_g = px_g >> 1; - px_b = px_b >> 1; - - if (!_locked[i]) - setPixelColor(i, px_r, px_g, px_b); - } - - // first LED has only one neighbour - px_r = (((getPixelColor(1) & 0x00FF0000) >> 16) >> 1) + ((getPixelColor(0) & 0x00FF0000) >> 16); - px_g = (((getPixelColor(1) & 0x0000FF00) >> 8) >> 1) + ((getPixelColor(0) & 0x0000FF00) >> 8); - px_b = (((getPixelColor(1) & 0x000000FF) >> 0) >> 1) + ((getPixelColor(0) & 0x000000FF) >> 0); - if (!_locked[0]) - setPixelColor(0, px_r, px_g, px_b); - - // set brightness(i) = ((brightness(i-1)/2 + brightness(i+1)) / 2) + brightness(i) - for(uint16_t i=1; i < _led_count-1; i++) { - px_r = (( - (((getPixelColor(i-1) & 0x00FF0000) >> 16) >> 1) + - (((getPixelColor(i+1) & 0x00FF0000) >> 16) >> 0) ) >> 1) + - (((getPixelColor(i ) & 0x00FF0000) >> 16) >> 0); - - px_g = (( - (((getPixelColor(i-1) & 0x0000FF00) >> 8) >> 1) + - (((getPixelColor(i+1) & 0x0000FF00) >> 8) >> 0) ) >> 1) + - (((getPixelColor(i ) & 0x0000FF00) >> 8) >> 0); - - px_b = (( - (((getPixelColor(i-1) & 0x000000FF) >> 0) >> 1) + - (((getPixelColor(i+1) & 0x000000FF) >> 0) >> 0) ) >> 1) + - (((getPixelColor(i ) & 0x000000FF) >> 0) >> 0); - - if (!_locked[i]) - setPixelColor(i, px_r, px_g, px_b); - } - - // last LED has only one neighbour - px_r = (((getPixelColor(_led_count-2) & 0x00FF0000) >> 16) >> 2) + ((getPixelColor(_led_count-1) & 0x00FF0000) >> 16); - px_g = (((getPixelColor(_led_count-2) & 0x0000FF00) >> 8) >> 2) + ((getPixelColor(_led_count-1) & 0x0000FF00) >> 8); - px_b = (((getPixelColor(_led_count-2) & 0x000000FF) >> 0) >> 2) + ((getPixelColor(_led_count-1) & 0x000000FF) >> 0); - if (!_locked[_led_count-1]) - setPixelColor(_led_count-1, px_r, px_g, px_b); - - for(uint16_t i=0; i> 24; - byte p_r = (_color & 0x00FF0000) >> 16; - byte p_g = (_color & 0x0000FF00) >> 8; - byte p_b = (_color & 0x000000FF) >> 0; - byte flicker_val = maxval(p_r,maxval(p_g, maxval(p_b, p_w)))/(((256-_intensity)/16)+1); - for(uint16_t i=0; i < _led_count; i++) + switch(_cronixieDigits[i]) { - int flicker = random(0,flicker_val); - int r1 = p_r-flicker; - int g1 = p_g-flicker; - int b1 = p_b-flicker; - int w1 = p_w-flicker; - if(g1<0) g1=0; - if(r1<0) r1=0; - if(b1<0) b1=0; - if(w1<0) w1=0; - if (!_locked[i]) - setPixelColor(i,r1,g1,b1,w1); - } - show(); - _mode_delay = 10 + ((400 * (uint32_t)(SPEED_MAX - _speed)) / SPEED_MAX); -} - -/* - * Gradient run - */ -void WS2812FX::mode_gradient(void) { - byte p_w = (_color & 0xFF000000) >> 24; - byte p_r = (_color & 0x00FF0000) >> 16; - byte p_g = (_color & 0x0000FF00) >> 8; - byte p_b = (_color & 0x000000FF) >> 0; - byte p_w2 = (_color_sec & 0xFF000000) >> 24; - byte p_r2 = (_color_sec & 0x00FF0000) >> 16; - byte p_g2 = (_color_sec & 0x0000FF00) >> 8; - byte p_b2 = (_color_sec & 0x000000FF) >> 0; - byte nw,nr,ng,nb; - float per,val; //0.0 = sec 1.0 = pri - float brd = _intensity/2; if (brd <1.0) brd = 1.0; - int pp = _counter_mode_step; - int p1 = pp-_led_count; - int p2 = pp+_led_count; - - for(uint16_t i=0; i < _led_count; i++) - { - if (!_locked[i]) - { - val = minval(abs(pp-i),minval(abs(p1-i),abs(p2-i))); - per = val/brd; - if (per >1.0) per = 1.0; - nw = p_w+((p_w2 - p_w)*per); - nr = p_r+((p_r2 - p_r)*per); - ng = p_g+((p_g2 - p_g)*per); - nb = p_b+((p_b2 - p_b)*per); - setPixelColor(i,nr,ng,nb,nw); - } - } - - show(); - _counter_mode_step++; - if (_counter_mode_step >= _led_count) _counter_mode_step = 0; - if (_speed == 0) _counter_mode_step = _led_count >> 1; - _mode_delay = 7 + ((25 * (uint32_t)(SPEED_MAX - _speed)) / _led_count); -} - -/* - * Gradient run with hard transition - */ -void WS2812FX::mode_loading(void) { - byte p_w = (_color & 0xFF000000) >> 24; - byte p_r = (_color & 0x00FF0000) >> 16; - byte p_g = (_color & 0x0000FF00) >> 8; - byte p_b = (_color & 0x000000FF) >> 0; - byte p_w2 = (_color_sec & 0xFF000000) >> 24; - byte p_r2 = (_color_sec & 0x00FF0000) >> 16; - byte p_g2 = (_color_sec & 0x0000FF00) >> 8; - byte p_b2 = (_color_sec & 0x000000FF) >> 0; - byte nw,nr,ng,nb; - float per,val; //0.0 = sec 1.0 = pri - float brd = _intensity; if (brd <1.0) brd = 1.0; - int pp = _counter_mode_step; - int p1 = pp+_led_count; - - for(uint16_t i=0; i < _led_count; i++) - { - if (!_locked[i]) - { - pp = _counter_mode_step; - if (i > pp) pp+=_led_count; - val = abs(pp-i); - per = val/brd; - if (per >1.0) per = 1.0; - nw = p_w+((p_w2 - p_w)*per); - nr = p_r+((p_r2 - p_r)*per); - ng = p_g+((p_g2 - p_g)*per); - nb = p_b+((p_b2 - p_b)*per); - setPixelColor(i,nr,ng,nb,nw); - } - } - - show(); - _counter_mode_step++; - if (_counter_mode_step >= _led_count) _counter_mode_step = 0; - if (_speed == 0) _counter_mode_step = _led_count -1; - _mode_delay = 7 + ((25 * (uint32_t)(SPEED_MAX - _speed)) / _led_count); -} - -/* - * Lights all LEDs after each other up starting from the outer edges and - * finishing in the middle. Then turns them in reverse order off. Repeat. - */ -void WS2812FX::mode_dual_color_wipe_in_out(void) { - int end = _led_count - _counter_mode_step - 1; - bool odd = (_led_count % 2); - int mid = odd ? ((_led_count / 2) + 1) : (_led_count / 2); - if (_counter_mode_step < mid) { - if (!_locked[_counter_mode_step]) - setPixelColor(_counter_mode_step, _color); - if (!_locked[end]) - setPixelColor(end, _color); - } - 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. - if (!_locked[_counter_mode_step -1]) - setPixelColor(_counter_mode_step - 1, _color_sec); - if (!_locked[end+1]) - setPixelColor(end + 1, _color_sec); - } else { - if (!_locked[_counter_mode_step]) - setPixelColor(_counter_mode_step, _color_sec); - if (!_locked[end]) - setPixelColor(end, _color_sec); + case 0: bus->SetPixelColor((_skipFirstMode)?o+6:o+5,RgbwColor(r,g,b,w)); break; + case 1: bus->SetPixelColor((_skipFirstMode)?o+1:o+0,RgbwColor(r,g,b,w)); break; + case 2: bus->SetPixelColor((_skipFirstMode)?o+7:o+6,RgbwColor(r,g,b,w)); break; + case 3: bus->SetPixelColor((_skipFirstMode)?o+2:o+1,RgbwColor(r,g,b,w)); break; + case 4: bus->SetPixelColor((_skipFirstMode)?o+8:o+7,RgbwColor(r,g,b,w)); break; + case 5: bus->SetPixelColor((_skipFirstMode)?o+3:o+2,RgbwColor(r,g,b,w)); break; + case 6: bus->SetPixelColor((_skipFirstMode)?o+9:o+8,RgbwColor(r,g,b,w)); break; + case 7: bus->SetPixelColor((_skipFirstMode)?o+4:o+3,RgbwColor(r,g,b,w)); break; + case 8: bus->SetPixelColor((_skipFirstMode)?o+10:o+9,RgbwColor(r,g,b,w)); break; + case 9: bus->SetPixelColor((_skipFirstMode)?o+5:o+4,RgbwColor(r,g,b,w)); break; } } - - _counter_mode_step++; - if (odd) { - if (_counter_mode_step > _led_count) { - _counter_mode_step = 0; - } - } else { - if (_counter_mode_step >= _led_count) { - _counter_mode_step = 0; - } - } - - show(); - - _mode_delay = 5 + ((50 * (uint32_t)(SPEED_MAX - _speed)) / _led_count); -} - -/* - * Lights all LEDs after each other up starting from the outer edges and - * finishing in the middle. Then turns them in that order off. Repeat. - */ -void WS2812FX::mode_dual_color_wipe_in_in(void) { - bool odd = (_led_count % 2); - int mid = _led_count / 2; - if (odd) { - if (_counter_mode_step <= mid) { - if (!_locked[_counter_mode_step]) - setPixelColor(_counter_mode_step, _color); - if (!_locked[_led_count - _counter_mode_step - 1]) - setPixelColor(_led_count - _counter_mode_step - 1, _color); - } else { - int i = _counter_mode_step - mid; - if (!_locked[i-1]) - setPixelColor(i - 1, _color_sec); - if (!_locked[_led_count - i]) - setPixelColor(_led_count - i, _color_sec); - } - } else { - if (_counter_mode_step < mid) { - if (!_locked[_counter_mode_step]) - setPixelColor(_counter_mode_step, _color); - if (!_locked[_led_count - _counter_mode_step - 1]) - setPixelColor(_led_count - _counter_mode_step - 1, _color); - } else { - int i = _counter_mode_step - mid; - if (!_locked[i]) - setPixelColor(i, _color_sec); - if (!_locked[_led_count - i -1]) - setPixelColor(_led_count - i - 1, _color_sec); - } - } - - _counter_mode_step++; - if (odd) { - if (_counter_mode_step > _led_count) { - _counter_mode_step = 0; - } - } else { - if (_counter_mode_step >= _led_count) { - _counter_mode_step = 0; - } - } - - show(); - - _mode_delay = 5 + ((50 * (uint32_t)(SPEED_MAX - _speed)) / _led_count); -} - -/* - * Lights all LEDs after each other up starting from the middle and - * finishing at the edges. Then turns them in that order off. Repeat. - */ -void WS2812FX::mode_dual_color_wipe_out_out(void) { - int end = _led_count - _counter_mode_step - 1; - bool odd = (_led_count % 2); - int mid = _led_count / 2; - - if (odd) { - if (_counter_mode_step <= mid) { - if (!_locked[mid + _counter_mode_step]) - setPixelColor(mid + _counter_mode_step, _color); - if (!_locked[mid - _counter_mode_step]) - setPixelColor(mid - _counter_mode_step, _color); - } else { - if (!_locked[_counter_mode_step -1]) - setPixelColor(_counter_mode_step - 1, _color_sec); - if (!_locked[end +1]) - setPixelColor(end + 1, _color_sec); - } - } else { - if (_counter_mode_step < mid) { - if (!_locked[mid - _counter_mode_step -1]) - setPixelColor(mid - _counter_mode_step - 1, _color); - if (!_locked[mid + _counter_mode_step]) - setPixelColor(mid + _counter_mode_step, _color); - } else { - if (!_locked[_counter_mode_step]) - setPixelColor(_counter_mode_step, 0); - if (!_locked[end]) - setPixelColor(end, _color_sec); - } - } - - _counter_mode_step++; - if (odd) { - if (_counter_mode_step > _led_count) { - _counter_mode_step = 0; - } - } else { - if (_counter_mode_step >= _led_count) { - _counter_mode_step = 0; - } - } - - show(); - - _mode_delay = 5 + ((50 * (uint32_t)(SPEED_MAX - _speed)) / _led_count); -} - -/* - * Lights all LEDs after each other up starting from the middle and - * finishing at the edges. Then turns them in reverse order off. Repeat. - */ -void WS2812FX::mode_dual_color_wipe_out_in(void) { - bool odd = (_led_count % 2); - int mid = _led_count / 2; - - if (odd) { - if (_counter_mode_step <= mid) { - if (!_locked[mid + _counter_mode_step]) - setPixelColor(mid + _counter_mode_step, _color); - if (!_locked[mid - _counter_mode_step]) - setPixelColor(mid - _counter_mode_step, _color); - } else { - int i = _counter_mode_step - mid; - if (!_locked[i -1]) - setPixelColor(i - 1, _color_sec); - if (!_locked[_led_count - i]) - setPixelColor(_led_count - i, _color_sec); - } - } else { - if (_counter_mode_step < mid) { - if (!_locked[mid - _counter_mode_step -1]) - setPixelColor(mid - _counter_mode_step - 1, _color); - if (!_locked[mid + _counter_mode_step]) - setPixelColor(mid + _counter_mode_step, _color); - } else { - int i = _counter_mode_step - mid; - if (!_locked[i]) - setPixelColor(i, _color_sec); - if (!_locked[_led_count - i -1]) - setPixelColor(_led_count - i - 1, _color_sec); - } - } - - _counter_mode_step++; - if (odd) { - if (_counter_mode_step > _led_count) { - _counter_mode_step = 0; - } - } else { - if (_counter_mode_step >= _led_count) { - _counter_mode_step = 0; - } - } - - show(); - - _mode_delay = 5 + ((50 * (uint32_t)(SPEED_MAX - _speed)) / _led_count); -} - -/* - * Alternating pri/sec/black pixels running. - */ -void WS2812FX::mode_circus_combustus(void) { - for(uint16_t i=0; i < _led_count; i++) { - if((i + _counter_mode_step) % 6 < 2) { - if (!_locked[i]) - setPixelColor(i, _color); - } else if((i + _color) % 6 < 4){ - if (!_locked[i]) - setPixelColor(i, _color_sec); - } else { - if (!_locked[i]) - setPixelColor(i, 0, 0, 0); - } - } - show(); - - _counter_mode_step = (_counter_mode_step + 1) % 6; - _mode_delay = 100 + ((100 * (uint32_t)(SPEED_MAX - _speed)) / _led_count); -} - -void WS2812FX::mode_cc_core() -{ - for (int k = _cc_i1; k <= _cc_i2; k = k + _cc_num1 + _cc_num2) - { - for (int i = 0; i < _cc_num1; i++) - { - int num = 0; - num = ((k + i + _counter_ccStep) % _cc_i2) +_cc_i1; - if (_cc_fs) setPixelColor(num, _color); - if (_cc_fe) setPixelColor(_cc_i2 - num, _color); - } - } - show(); - _counter_ccStep = (_counter_ccStep + _ccStep) % (_cc_i2 - _cc_i1); - _mode_delay = 10 + ((250 * (uint32_t)(SPEED_MAX - _speed)) / SPEED_MAX); -} - -void WS2812FX::mode_cc_standard() -{ - for(uint16_t i=0; i < _led_count; i++) - { - setPixelColor(i, (_cc_i1 <= i && i <= _cc_i2) ? _color_sec : _color); - } - mode_cc_core(); -} - -void WS2812FX::mode_cc_rainbow() -{ - uint32_t color = color_wheel(_counter_mode_step); - for(uint16_t i=0; i < _led_count; i++) { - if (!_locked[i]) - setPixelColor(i, color); - } - mode_cc_core(); - _counter_mode_step = (_counter_mode_step + 1) % 256; -} - -void WS2812FX::mode_cc_cycle() -{ - for(uint16_t i=0; i < _led_count; i++) { - if (!_locked[i]) - setPixelColor(i, color_wheel(((i * 256 / _led_count) + _counter_mode_step) % 256)); - } - mode_cc_core(); - _counter_mode_step = (_counter_mode_step + 1) % 256; -} - -void WS2812FX::mode_cc_blink() -{ - for(uint16_t i=0; i < _led_count; i++) - { - setPixelColor(i, (_cc_i1 <= i && i <= _cc_i2) ? _color_sec : _color); - } - if (_counter_mode_step) - { - mode_cc_core(); - _counter_mode_step = 0; - } else { - show(); - _counter_mode_step = 1; - _mode_delay = 10 + ((250 * (uint32_t)(SPEED_MAX - _speed)) / SPEED_MAX); - } -} - -void WS2812FX::mode_cc_random() -{ - for(uint16_t i=0; i < _led_count; i++) { - if (!_locked[i]) - setPixelColor(i, color_wheel(random(256))); - } - mode_cc_core(); -} - - -//WLED specific methods - -void WS2812FX::setIndividual(int i) -{ - if (i >= 0 && i < _led_count) - { - setPixelColor(i, _color); - //show(); - _locked[i] = true; - } -} - -void WS2812FX::setIndividual(int i, uint32_t col) -{ - if (i >= 0 && i < _led_count) - { - setPixelColor(i, col); - //show(); - _locked[i] = true; - } -} - -void WS2812FX::setRange(int i, int i2) -{ - if (i2 >= i) - { - for (int x = i; x <= i2; x++) - { - if (x >= 0 && x < _led_count) - { - setPixelColor(x, _color); - _locked[x] = true; - } - } - } else - { - for (int x = i2; x < _led_count; x++) - { - if (x >= 0 && x < _led_count) - { - setPixelColor(x, _color); - _locked[x] = true; - } - } - for (int x = 0; x <= i; x++) - { - if (x >= 0 && x < _led_count) - { - setPixelColor(x, _color); - _locked[x] = true; - } - } - } - //show(); -} - -void WS2812FX::setRange(int i, int i2, uint32_t col) -{ - if (i2 >= i) - { - for (int x = i; x <= i2; x++) - { - if (x >= 0 && x < _led_count) - { - setPixelColor(x, col); - _locked[x] = true; - } - } - } else - { - for (int x = i2; x < _led_count; x++) - { - if (x >= 0 && x < _led_count) - { - setPixelColor(x, col); - _locked[x] = true; - } - } - for (int x = 0; x <= i; x++) - { - if (x >= 0 && x < _led_count) - { - setPixelColor(x, col); - _locked[x] = true; - } - } - } - //show(); -} - -void WS2812FX::lock(int i) -{ - if (i >= 0 && i < _led_count) - _locked[i] = true; -} - -void WS2812FX::lockRange(int i, int i2) -{ - for (int x = i; x < i2; x++) - { - if (x >= 0 && x < _led_count) - _locked[x] = true; - } -} - -void WS2812FX::lockAll() -{ - for (int x = 0; x < _led_count; x++) - _locked[x] = true; -} - -void WS2812FX::unlock(int i) -{ - if (i >= 0 && i < _led_count) - _locked[i] = false; -} - -void WS2812FX::unlockRange(int i, int i2) -{ - for (int x = i; x < i2; x++) - { - if (x >= 0 && x < _led_count) - _locked[x] = false; - } -} - -void WS2812FX::unlockAll() -{ - for (int x = 0; x < _led_count; x++) - _locked[x] = false; -} - -void WS2812FX::setFastUpdateMode(bool y) -{ - _fastStandard = y; - if (_mode_index == 0) _mode_delay = 20; } void WS2812FX::setReverseMode(bool b) @@ -1910,6 +150,7 @@ void WS2812FX::setReverseMode(bool b) void WS2812FX::driverModeCronixie(bool b) { _cronixieMode = b; + _segments[0].stop = (b) ? 5 : _length-1; } void WS2812FX::setCronixieBacklight(bool b) @@ -1925,12 +166,252 @@ void WS2812FX::setCronixieDigits(byte d[]) } } +void WS2812FX::show(void) { + bus->Show(); +} + +void WS2812FX::trigger() { + _triggered = true; +} + +void WS2812FX::setMode(uint8_t m) { + RESET_RUNTIME; + bool ua = _segments[0].mode == FX_MODE_FIRE_2012 && m != FX_MODE_FIRE_2012; + _segments[0].mode = constrain(m, 0, MODE_COUNT - 1); + if (ua) unlockAll(); + setBrightness(_brightness); +} + +//TODO transitions + +void WS2812FX::setSpeed(uint8_t s) { + _segments[0].speed = s; +} + +void WS2812FX::setIntensity(uint8_t in) { + _segments[0].intensity = in; +} + +void WS2812FX::setPalette(uint8_t p) { + _segments[0].palette = p; +} + +void WS2812FX::setColor(uint8_t r, uint8_t g, uint8_t b, uint8_t w) { + setColor(((uint32_t)w << 24) |((uint32_t)r << 16) | ((uint32_t)g << 8) | b); +} + +void WS2812FX::setSecondaryColor(uint8_t r, uint8_t g, uint8_t b, uint8_t w) { + setSecondaryColor(((uint32_t)w << 24) |((uint32_t)r << 16) | ((uint32_t)g << 8) | b); +} + +void WS2812FX::setColor(uint32_t c) { + _segments[0].colors[0] = c; +} + +void WS2812FX::setSecondaryColor(uint32_t c) { + _segments[0].colors[1] = c; + if (_cronixieMode) _cronixieSecMultiplier = getSafePowerMultiplier(900, 100, c, _brightness); +} + +void WS2812FX::setBrightness(uint8_t b) { + _brightness = b; + bus->SetBrightness(_brightness); + show(); +} + +uint8_t WS2812FX::getMode(void) { + return _segments[0].mode; +} + +uint8_t WS2812FX::getSpeed(void) { + return _segments[0].speed; +} + +uint8_t WS2812FX::getBrightness(void) { + return _brightness; +} + +uint8_t WS2812FX::getNumSegments(void) { + return _num_segments; +} + +void WS2812FX::setNumSegments(uint8_t n) { + _num_segments = n; +} + +uint32_t WS2812FX::getColor(void) { + return _segments[0].colors[0]; +} + +uint32_t WS2812FX::getPixelColor(uint16_t i) +{ + if (_reverseMode) i = _length- 1 -i; + if (_skipFirstMode) i++; + if (_cronixieMode) + { + if(i>6)return 0; + byte o = 10*i; + switch(_cronixieDigits[i]) + { + case 0: i=o+5; break; + case 1: i=o+0; break; + case 2: i=o+6; break; + case 3: i=o+1; break; + case 4: i=o+7; break; + case 5: i=o+2; break; + case 6: i=o+8; break; + case 7: i=o+3; break; + case 8: i=o+9; break; + case 9: i=o+4; break; + default: return 0; + } + } + RgbwColor lColor = bus->GetPixelColorRgbw(i); + return lColor.W*16777216 + lColor.R*65536 + lColor.G*256 + lColor.B; +} + +WS2812FX::Segment WS2812FX::getSegment(void) { + return SEGMENT; +} + +WS2812FX::Segment_runtime WS2812FX::getSegmentRuntime(void) { + return SEGMENT_RUNTIME; +} + +WS2812FX::Segment* WS2812FX::getSegments(void) { + return _segments; +} + +void WS2812FX::setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, uint32_t color, uint8_t speed, uint8_t intensity, bool reverse) { + uint32_t colors[] = {color, 0, 0}; + setSegment(n, start, stop, mode, colors, speed, intensity, reverse); +} + +void WS2812FX::setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, const uint32_t colors[], uint8_t speed, uint8_t intensity, bool reverse) { + setSegment(n, start, stop, mode, colors, speed, intensity, (uint8_t)(reverse ? REVERSE : NO_OPTIONS)); +} + +void WS2812FX::setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, const uint32_t colors[], uint8_t speed, uint8_t intensity, uint8_t options) { + if(n < (sizeof(_segments) / sizeof(_segments[0]))) { + if(n + 1 > _num_segments) _num_segments = n + 1; + _segments[n].start = start; + _segments[n].stop = stop; + _segments[n].mode = mode; + _segments[n].speed = speed; + _segments[n].intensity = intensity; + _segments[n].options = options; + + for(uint8_t i=0; i= 0 && i < _length) + { + _locked[i] = false; + setPixelColor(i, col); + _locked[i] = true; + } +} + +void WS2812FX::setRange(uint16_t i, uint16_t i2, uint32_t col) +{ + if (i2 >= i) + { + for (uint16_t x = i; x <= i2; x++) setIndividual(x,col); + } else + { + for (uint16_t x = i2; x <= i; x++) setIndividual(x,col); + } +} + +void WS2812FX::lock(uint16_t i) +{ + if (SEGMENT.mode == FX_MODE_FIRE_2012) 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; + for (uint16_t x = i; x <= i2; x++) + { + if (i >= 0 && i < _length) _locked[i] = true; + } +} + +void WS2812FX::unlock(uint16_t i) +{ + if (SEGMENT.mode == FX_MODE_FIRE_2012) 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; + for (uint16_t x = i; x < i2; x++) + { + if (x >= 0 && x < _length) _locked[x] = false; + } +} + +void WS2812FX::unlockAll() +{ + for (int i=0; i < _length; i++) _locked[i] = false; +} + +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 + if (SEGMENT.mode == FX_MODE_STATIC && SEGMENT_RUNTIME.next_time > waitMax) SEGMENT_RUNTIME.next_time = waitMax; +} + +/* + * color blend function + */ +uint32_t WS2812FX::color_blend(uint32_t color1, uint32_t color2, uint8_t blend) { + if(blend == 0) return color1; + if(blend == 255) return color2; + + int w1 = (color1 >> 24) & 0xff; + int r1 = (color1 >> 16) & 0xff; + int g1 = (color1 >> 8) & 0xff; + int b1 = color1 & 0xff; + + int w2 = (color2 >> 24) & 0xff; + int r2 = (color2 >> 16) & 0xff; + int g2 = (color2 >> 8) & 0xff; + int b2 = color2 & 0xff; + + uint32_t w3 = ((w2 * blend) + (w1 * (255 - blend))) / 256; + uint32_t r3 = ((r2 * blend) + (r1 * (255 - blend))) / 256; + uint32_t g3 = ((g2 * blend) + (g1 * (255 - blend))) / 256; + uint32_t b3 = ((b2 * blend) + (b1 * (255 - blend))) / 256; + + return ((w3 << 24) | (r3 << 16) | (g3 << 8) | (b3)); +} + + double WS2812FX::getPowerEstimate(uint16_t leds, uint32_t c, byte b) { double _mARequired = 100; //ESP power double _mul = (double)b/255; double _sum = ((c & 0xFF000000) >> 24) + ((c & 0x00FF0000) >> 16) + ((c & 0x0000FF00) >> 8) + ((c & 0x000000FF) >> 0); - _sum /= (_rgbwMode)? 1024:768; + _sum /= (_rgbwMode)?1024:768; double _mAPerLed = 50*(_mul*_sum); _mARequired += leds*_mAPerLed; return _mARequired; @@ -1951,215 +432,1937 @@ double WS2812FX::getSafePowerMultiplier(double safeMilliAmps, uint16_t leds, uin return 1.0; } -void WS2812FX::setCCIndex1(byte i1) -{ - if (i1 < _led_count-1) _cc_i1 = i1; - if (_cc_i2 <= i1) _cc_i2 = i1+1; - _counter_ccStep = 0; + +/* ##################################################### +# +# Color and Blinken Functions +# +##################################################### */ + +/* + * Turns everything off. Doh. + */ +void WS2812FX::strip_off() { + clear(); + show(); } -void WS2812FX::setCCIndex2(uint16_t i2) -{ - if (i2 > _cc_i1) _cc_i2 = i2; - if (_cc_i2 >= _led_count) _cc_i2 = _led_count-1; - _counter_ccStep = 0; + +/* + * Put a value 0 to 255 in to get a color value. + * The colours are a transition r -> g -> b -> back to r + * Inspired by the Adafruit examples. + */ +uint32_t WS2812FX::color_wheel(uint8_t pos) { + pos = 255 - pos; + if(pos < 85) { + return ((uint32_t)(255 - pos * 3) << 16) | ((uint32_t)(0) << 8) | (pos * 3); + } else if(pos < 170) { + pos -= 85; + return ((uint32_t)(0) << 16) | ((uint32_t)(pos * 3) << 8) | (255 - pos * 3); + } else { + pos -= 170; + return ((uint32_t)(pos * 3) << 16) | ((uint32_t)(255 - pos * 3) << 8) | (0); + } } -void WS2812FX::setCCStart(byte is) -{ - _cc_is = (is < _cc_i1 || is > _cc_i2) ? _cc_i1 : is; - _counter_ccStep = 0; + +/* + * Returns a new, random wheel index with a minimum distance of 42 from pos. + */ +uint8_t WS2812FX::get_random_wheel_index(uint8_t pos) { + uint8_t r = 0; + uint8_t x = 0; + uint8_t y = 0; + uint8_t d = 0; + + while(d < 42) { + r = random8(); + x = abs(pos - r); + y = 255 - x; + d = min(x, y); + } + + return r; } -void WS2812FX::setCCNum1(byte np) -{ - _cc_num1 = np; - _counter_ccStep = 0; + +/* + * No blinking. Just plain old static light. + */ +uint16_t WS2812FX::mode_static(void) { + for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { + setPixelColor(i, SEGMENT.colors[0]); + } + return (SEGMENT_RUNTIME.trans_act == 1) ? 20 : 500; } -void WS2812FX::setCCNum2(byte ns) -{ - _cc_num2 = ns; - _counter_ccStep = 0; + +/* + * 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) { + 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((SEGMENT_RUNTIME.counter_mode_call & 1) == 0) { + return strobe ? 20 : (100 + ((1986 * (uint32_t)(255 - SEGMENT.speed)) / 255))*(float)(SEGMENT.intensity/128.0); + } else { + return strobe ? 50 + ((1986 * (uint32_t)(255 - SEGMENT.speed)) / 255) : (100 + ((1986 * (uint32_t)(255 - SEGMENT.speed)) / 255))*(float)(2.0-(SEGMENT.intensity/128.0)); + } } -void WS2812FX::setCCStep(byte stp) -{ - _ccStep = stp; - _counter_ccStep = 0; + +/* + * Normal blinking. 50% on/off time. + */ +uint16_t WS2812FX::mode_blink(void) { + return blink(SEGMENT.colors[0], SEGMENT.colors[1], false); } -void WS2812FX::setCCFS(bool fs) -{ - _cc_fs = fs; - _cc_fe = (fs) ? _cc_fe : true; - _counter_ccStep = 0; + +/* + * 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); } -void WS2812FX::setCCFE(bool fe) -{ - _cc_fe = fe; - _cc_fs = (fe) ? _cc_fs : true; - _counter_ccStep = 0; + +/* + * Classic Strobe effect. + */ +uint16_t WS2812FX::mode_strobe(void) { + return blink(SEGMENT.colors[0], SEGMENT.colors[1], true); } -void WS2812FX::setCustomChase(byte i1, uint16_t i2, byte is, byte np, byte ns, byte stp, bool fs, bool fe) -{ - setCCIndex1(i1); - setCCIndex2(i2); - setCCStart(is); - _cc_num1 = np; - _cc_num2 = ns; - _ccStep = stp; - setCCFS(fs); - setCCFE(fe); + +/* + * 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); } -//Added for quick NeoPixelBus compatibility with Adafruit syntax -void WS2812FX::setPixelColorRaw(uint16_t i, byte r, byte g, byte b, byte w) -{ - if (_rgbwMode) + +/* + * Color wipe function + * 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) { + if(SEGMENT_RUNTIME.counter_mode_step < SEGMENT_LENGTH) { + uint32_t led_offset = SEGMENT_RUNTIME.counter_mode_step; + setPixelColor(SEGMENT.start + led_offset, color1); + } else { + uint32_t led_offset = SEGMENT_RUNTIME.counter_mode_step - SEGMENT_LENGTH; + if(rev) { + setPixelColor(SEGMENT.stop - led_offset, color2); + } else { + setPixelColor(SEGMENT.start + led_offset, color2); + } + } + + SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % (SEGMENT_LENGTH * 2); + return SPEED_FORMULA_L; +} + + +/* + * Lights all LEDs one after another. + */ +uint16_t WS2812FX::mode_color_wipe(void) { + return color_wipe(SEGMENT.colors[0], SEGMENT.colors[1], false); +} + +/* + * 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); +} + + +/* + * Turns all LEDs after each other to a random color. + * Then starts over with another color. + */ +uint16_t WS2812FX::mode_color_wipe_random(void) { + if(SEGMENT_RUNTIME.counter_mode_step % SEGMENT_LENGTH == 0) { // aux_param will store our random color wheel index + 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); +} + + +/* + * Random color introduced alternating from start and end of strip. + */ +uint16_t WS2812FX::mode_color_sweep_random(void) { + if(SEGMENT_RUNTIME.counter_mode_step % SEGMENT_LENGTH == 0) { // aux_param will store our random color wheel index + 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); +} + + +/* + * Lights all LEDs in one random color up. Then switches them + * to the next random color. + */ +uint16_t WS2812FX::mode_random_color(void) { + SEGMENT_RUNTIME.aux_param = get_random_wheel_index(SEGMENT_RUNTIME.aux_param); // aux_param will store our random color wheel index + uint32_t color = color_wheel(SEGMENT_RUNTIME.aux_param); + + for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { + setPixelColor(i, color); + } + return 50 + (20 * (uint32_t)(255 - SEGMENT.speed)); +} + + +/* + * Lights every LED in a random color. Changes all LED at the same time + * to new random colors. + */ +uint16_t WS2812FX::mode_dynamic(void) { + if(SEGMENT.intensity > 127 || SEGMENT_RUNTIME.counter_mode_call == 0) { + for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { + setPixelColor(i, color_wheel(random8())); + } + } + setPixelColor(SEGMENT.start + random(SEGMENT_LENGTH), color_wheel(random8())); + return 50 + (15 * (uint32_t)(255 - SEGMENT.speed)); +} + + +/* + * Does the "standby-breathing" of well known i-Devices. Fixed Speed. + * Use mode "fade" if you like to have something similar with a different speed. + */ +uint16_t WS2812FX::mode_breath(void) { + int lum = SEGMENT_RUNTIME.counter_mode_step; + 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 + + 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); + } + + SEGMENT_RUNTIME.counter_mode_step += 2; + if(SEGMENT_RUNTIME.counter_mode_step > (512-15)) SEGMENT_RUNTIME.counter_mode_step = 15; + return delay; +} + + +/* + * Fades the LEDs between two colors + */ +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); + } + + SEGMENT_RUNTIME.counter_mode_step += 4; + if(SEGMENT_RUNTIME.counter_mode_step > 511) SEGMENT_RUNTIME.counter_mode_step = 0; + return 5 + ((15 * (uint32_t)(255 - SEGMENT.speed)) / 255); +} + + +//TODO add intensity (more than 1 pixel lit) +/* + * Runs a single pixel back and forth. + */ +uint16_t WS2812FX::mode_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, SEGMENT.colors[1]); + } + + int led_offset = SEGMENT_RUNTIME.counter_mode_step - (SEGMENT_LENGTH - 1); + led_offset = abs(led_offset); + setPixelColor(SEGMENT.start + led_offset, SEGMENT.colors[0]); + + SEGMENT_RUNTIME.counter_mode_step++; + return SPEED_FORMULA_L; +} + + +/* + * 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; +} + + +/* + * Cycles all LEDs at once through a rainbow. + */ +uint16_t WS2812FX::mode_rainbow(void) { + uint32_t color = color_wheel(SEGMENT_RUNTIME.counter_mode_step); + for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { + setPixelColor(i, color); + } + + SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) & 0xFF; + return 1 + (((uint32_t)(255 - SEGMENT.speed)) / 5); +} + + +/* + * Cycles a rainbow over the entire string of LEDs. + */ +uint16_t WS2812FX::mode_rainbow_cycle(void) { + for(uint16_t i=0; i < SEGMENT_LENGTH; i++) { + uint32_t color = color_wheel(((i * 256 / ((uint16_t)(SEGMENT_LENGTH*(float)(SEGMENT.intensity/128.0))+1)) + SEGMENT_RUNTIME.counter_mode_step) & 0xFF); + setPixelColor(SEGMENT.start + i, color); + } + + SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) & 0xFF; + return 1 + (((uint32_t)(255 - SEGMENT.speed)) / 5); +} + + +/* + * theater chase function + */ +uint16_t WS2812FX::theater_chase(uint32_t color1, uint32_t color2) { + 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); + } else { + setPixelColor(SEGMENT.start + i, color2); + } + } + return 50 + (2 * (uint32_t)(255 - SEGMENT.speed)); +} + + +/* + * Theatre-style crawling lights. + * Inspired by the Adafruit examples. + */ +uint16_t WS2812FX::mode_theater_chase(void) { + return theater_chase(SEGMENT.colors[0], SEGMENT.colors[1]); +} + + +/* + * Theatre-style crawling lights with rainbow effect. + * Inspired by the Adafruit examples. + */ +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]); +} + + +/* + * Running lights effect with smooth sine transition. + */ +uint16_t WS2812FX::mode_running_lights(void) { + uint8_t w = ((SEGMENT.colors[0] >> 24) & 0xFF); + uint8_t r = ((SEGMENT.colors[0] >> 16) & 0xFF); + uint8_t g = ((SEGMENT.colors[0] >> 8) & 0xFF); + uint8_t b = (SEGMENT.colors[0] & 0xFF); + + 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)); + } + + return 10 + (uint16_t)(255 - SEGMENT.speed); +} + + +/* + * twinkle function + */ +uint16_t WS2812FX::twinkle(uint32_t color) { + if(SEGMENT_RUNTIME.counter_mode_step == 0) { + for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { + setPixelColor(i, SEGMENT.colors[1]); + } + uint16_t min_leds = max(1, SEGMENT_LENGTH / 5); // make sure, at least one LED is on + uint16_t max_leds = max(1, SEGMENT_LENGTH / 2); // make sure, at least one LED is on + SEGMENT_RUNTIME.counter_mode_step = random(min_leds, max_leds); + } + + setPixelColor(SEGMENT.start + random(SEGMENT_LENGTH), color); + + SEGMENT_RUNTIME.counter_mode_step--; + return 50 + (8 * (uint16_t)(255 - SEGMENT.speed)); +} + +/* + * Blink several LEDs on, reset, repeat. + * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ + */ +uint16_t WS2812FX::mode_twinkle(void) { + return twinkle(SEGMENT.colors[0]); +} + +/* + * Blink several LEDs in random colors on, reset, repeat. + * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ + */ +uint16_t WS2812FX::mode_twinkle_random(void) { + return twinkle(color_wheel(random8())); +} + + +/* + * fade out function + * fades out the current segment by dividing each pixel's intensity by 2 + */ +void WS2812FX::fade_out(uint8_t rate) { + static const float rateMap[] = {1.1, 1.20, 1.5, 2.0, 4.0, 8.0, 16.0, 64.0}; + if (rate > 7) rate = 7; + float mappedRate = rateMap[rate]; + + uint32_t color = SEGMENT.colors[1]; // target color + int w2 = (color >> 24) & 0xff; + int r2 = (color >> 16) & 0xff; + int g2 = (color >> 8) & 0xff; + int b2 = color & 0xff; + + for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { + color = getPixelColor(i); + if(rate == 0) { // old fade-to-black algorithm + setPixelColor(i, (color >> 1) & 0x7F7F7F7F); + } else { // new fade-to-color algorithm + int w1 = (color >> 24) & 0xff; + int r1 = (color >> 16) & 0xff; + int g1 = (color >> 8) & 0xff; + int b1 = color & 0xff; + + int wdelta = (w2 - w1) / mappedRate; + int rdelta = (r2 - r1) / mappedRate; + int gdelta = (g2 - g1) / mappedRate; + int bdelta = (b2 - b1) / mappedRate; + + // if fade isn't complete, make sure delta is at least 1 (fixes rounding issues) + wdelta += (w2 == w1) ? 0 : (w2 > w1) ? 1 : -1; + rdelta += (r2 == r1) ? 0 : (r2 > r1) ? 1 : -1; + gdelta += (g2 == g1) ? 0 : (g2 > g1) ? 1 : -1; + bdelta += (b2 == b1) ? 0 : (b2 > b1) ? 1 : -1; + + setPixelColor(i, r1 + rdelta, g1 + gdelta, b1 + bdelta, w1 + wdelta); + } + } +} + + +/* + * twinkle_fade function + */ +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); + } + return 100 + ((uint32_t)(255 - SEGMENT.speed)) / 3; +} + + +/* + * Blink several LEDs on, fading out. + */ +uint16_t WS2812FX::mode_twinkle_fade(void) { + return twinkle_fade(SEGMENT.colors[0]); +} + + +/* + * Blink several LEDs in random colors on, fading out. + */ +uint16_t WS2812FX::mode_twinkle_fade_random(void) { + return twinkle_fade(color_wheel(random8())); +} + + +/* + * Blinks one LED at a time. + * 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]); + 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); +} + + +/* + * Lights all LEDs in the color. Flashes single white pixels randomly. + * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ + */ +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(SEGMENT.start + SEGMENT_RUNTIME.aux_param, SEGMENT.colors[0]); + + if(random8(5) == 0) { + SEGMENT_RUNTIME.aux_param = random(SEGMENT_LENGTH); // aux_param stores the random led index + setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.aux_param, SEGMENT.colors[1]); + return 20; + } + return 20 + (uint16_t)(255-SEGMENT.speed); +} + + +/* + * Like flash sparkle. With more flash. + * Inspired by www.tweaking4all.com/hardware/arduino/adruino-led-strip-effects/ + */ +uint16_t WS2812FX::mode_hyper_sparkle(void) { + for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { + setPixelColor(i, SEGMENT.colors[0]); + } + + if(random8(5) < 2) { + for(uint16_t i=0; i < max(1, SEGMENT_LENGTH/3); i++) { + setPixelColor(SEGMENT.start + random(SEGMENT_LENGTH), SEGMENT.colors[1]); + } + return 20; + } + return 20 + (uint16_t)(255-SEGMENT.speed); +} + + +/* + * Strobe effect with different strobe count and pause, controlled by speed. + */ +uint16_t WS2812FX::mode_multi_strobe(void) { + for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { + setPixelColor(i, SEGMENT.colors[1]); + } + + uint16_t delay = 50 + 20*(uint16_t)(255-SEGMENT.speed); + uint16_t count = 2 * ((SEGMENT.speed / 10) + 1); + if(SEGMENT_RUNTIME.counter_mode_step < count) { + if((SEGMENT_RUNTIME.counter_mode_step & 1) == 0) { + for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { + setPixelColor(i, SEGMENT.colors[0]); + } + delay = 20; + } else { + delay = 50; + } + } + SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % (count + 1); + return delay; +} + +/* + * Android loading circle + */ +uint16_t WS2812FX::mode_android(void) { + if (SEGMENT_RUNTIME.counter_mode_call == 0) { - bus->SetPixelColor(i, RgbwColor(r,g,b,w)); + SEGMENT_RUNTIME.aux_param = 0; + SEGMENT_RUNTIME.counter_mode_step = SEGMENT.start; + } + + for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { + setPixelColor(i, SEGMENT.colors[1]); + } + + if (SEGMENT_RUNTIME.aux_param2 > ((float)SEGMENT.intensity/255.0)*(float)SEGMENT_LENGTH) + { + SEGMENT_RUNTIME.aux_param = 1; } else { - bus->SetPixelColor(i, RgbColor(r,g,b)); + if (SEGMENT_RUNTIME.aux_param2 < 2) SEGMENT_RUNTIME.aux_param = 0; } + + uint16_t a = SEGMENT_RUNTIME.counter_mode_step; + + if (SEGMENT_RUNTIME.aux_param == 0) + { + if (SEGMENT_RUNTIME.counter_mode_call %3 == 1) {a++;} + else {SEGMENT_RUNTIME.aux_param2++;} + } else + { + a++; + if (SEGMENT_RUNTIME.counter_mode_call %3 != 1) SEGMENT_RUNTIME.aux_param2--; + } + + if (a > SEGMENT.stop) a = SEGMENT.start; + + if (a + SEGMENT_RUNTIME.aux_param2 <= SEGMENT.stop) + { + for(int i = a; i < a+SEGMENT_RUNTIME.aux_param2; i++) { + setPixelColor(i, SEGMENT.colors[0]); + } + } else + { + for(int i = a; i <= SEGMENT.stop; i++) { + setPixelColor(i, SEGMENT.colors[0]); + } + for(int i = SEGMENT.start; i < SEGMENT_RUNTIME.aux_param2 - (SEGMENT.stop +1 -a); i++) { + setPixelColor(i, SEGMENT.colors[0]); + } + } + SEGMENT_RUNTIME.counter_mode_step = a; + + return 3 + ((8 * (uint32_t)(255 - SEGMENT.speed)) / SEGMENT_LENGTH); } -void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w) -{ - if (_reverseMode) i = _led_count - 1 -i; - if (!_cronixieMode) +/* + * color chase function. + * 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 a = SEGMENT_RUNTIME.counter_mode_step; + uint16_t b = (a + 1) % SEGMENT_LENGTH; + uint16_t c = (b + 1) % SEGMENT_LENGTH; + setPixelColor(SEGMENT.start + a, color1); + setPixelColor(SEGMENT.start + b, color2); + setPixelColor(SEGMENT.start + c, color3); + + SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % SEGMENT_LENGTH; + 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]); +} + +/* + * Primary running followed by random color. + */ +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]); +} + + +/* + * Primary running on rainbow. + */ +uint16_t WS2812FX::mode_chase_rainbow_white(void) { + uint16_t n = SEGMENT_RUNTIME.counter_mode_step; + uint16_t m = (SEGMENT_RUNTIME.counter_mode_step + 1) % SEGMENT_LENGTH; + 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); +} + + +/* + * Red - Amber - Green - Blue lights running + */ +uint16_t WS2812FX::mode_colorful(void) { + uint32_t cols[]{0x00FF0000,0x00EEBB00,0x0000EE00,0x000077CC,0x00FF0000,0x00EEBB00,0x0000EE00}; + if (SEGMENT.intensity < 127) //pastel (easter) colors { - if (_skipFirstMode) {i++;if(i==1)setPixelColorRaw(0,0,0,0,0);} - if (_rgbwMode) + cols[0] = 0x00FF8040; + cols[1] = 0x00E5D241; + cols[2] = 0x0077FF77; + cols[3] = 0x0077F0F0; + for (uint8_t i = 4; i < 7; i++) cols[i] = cols[i-4]; + } + int i = SEGMENT.start; + for (i; i <= SEGMENT.stop ; i+=4) + { + setPixelColor(i, cols[SEGMENT_RUNTIME.counter_mode_step]); + setPixelColor(i+1, cols[SEGMENT_RUNTIME.counter_mode_step+1]); + setPixelColor(i+2, cols[SEGMENT_RUNTIME.counter_mode_step+2]); + setPixelColor(i+3, cols[SEGMENT_RUNTIME.counter_mode_step+3]); + } + i+=4; + if(i <= SEGMENT.stop) + { + setPixelColor(i, cols[SEGMENT_RUNTIME.counter_mode_step]); + + if(i+1 <= SEGMENT.stop) { - bus->SetPixelColor(i, RgbwColor(r,g,b,w)); - } else - { - bus->SetPixelColor(i, RgbColor(r,g,b)); - } - } else { - if(i>6)return; - byte o = 10*i; - if (_cronixieBacklightEnabled && _cronixieDigits[i] <11) - { - byte rCorr = (int)(((double)((_color_sec>>16) & 0xFF))*_cronixieSecMultiplier); - byte gCorr = (int)(((double)((_color_sec>>8) & 0xFF))*_cronixieSecMultiplier); - byte bCorr = (int)(((double)((_color_sec) & 0xFF))*_cronixieSecMultiplier); - byte wCorr = (int)(((double)((_color_sec>>24) & 0xFF))*_cronixieSecMultiplier); - for (int j=o; j< o+19; j++) + setPixelColor(i+1, cols[SEGMENT_RUNTIME.counter_mode_step+1]); + + if(i+2 <= SEGMENT.stop) { - setPixelColorRaw((_skipFirstMode)?j+1:j,rCorr,gCorr,bCorr,wCorr); - } - } else - { - for (int j=o; j< o+19; j++) - { - setPixelColorRaw((_skipFirstMode)?j+1:j,0,0,0,0); + setPixelColor(i+2, cols[SEGMENT_RUNTIME.counter_mode_step+2]); } } - switch(_cronixieDigits[i]) + } + + if (SEGMENT.speed > 0) SEGMENT_RUNTIME.counter_mode_step++; //static if lowest speed + if (SEGMENT_RUNTIME.counter_mode_step >3) SEGMENT_RUNTIME.counter_mode_step = 0; + return 50 + (15 * (uint32_t)(255 - SEGMENT.speed)); +} + + +/* + * 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]); + uint32_t mdelay = 500; + for (int i = SEGMENT.start; i < SEGMENT.stop-1 ; i+=3) + { + switch (SEGMENT_RUNTIME.counter_mode_step) { - case 0: setPixelColorRaw((_skipFirstMode)?o+6:o+5,r,g,b,w); break; - case 1: setPixelColorRaw((_skipFirstMode)?o+1:o+0,r,g,b,w); break; - case 2: setPixelColorRaw((_skipFirstMode)?o+7:o+6,r,g,b,w); break; - case 3: setPixelColorRaw((_skipFirstMode)?o+2:o+1,r,g,b,w); break; - case 4: setPixelColorRaw((_skipFirstMode)?o+8:o+7,r,g,b,w); break; - case 5: setPixelColorRaw((_skipFirstMode)?o+3:o+2,r,g,b,w); break; - case 6: setPixelColorRaw((_skipFirstMode)?o+9:o+8,r,g,b,w); break; - case 7: setPixelColorRaw((_skipFirstMode)?o+4:o+3,r,g,b,w); break; - case 8: setPixelColorRaw((_skipFirstMode)?o+10:o+9,r,g,b,w); break; - case 9: setPixelColorRaw((_skipFirstMode)?o+5:o+4,r,g,b,w); break; - default: break; + case 0: setPixelColor(i, 0x00FF0000); mdelay = 150 + (100 * (uint32_t)(255 - SEGMENT.speed));break; + case 1: setPixelColor(i, 0x00FF0000); mdelay = 150 + (20 * (uint32_t)(255 - SEGMENT.speed)); setPixelColor(i+1, 0x00EECC00); break; + case 2: setPixelColor(i+2, 0x0000FF00); mdelay = 150 + (100 * (uint32_t)(255 - SEGMENT.speed));break; + case 3: setPixelColor(i+1, 0x00EECC00); mdelay = 150 + (20 * (uint32_t)(255 - SEGMENT.speed));break; } } + + SEGMENT_RUNTIME.counter_mode_step++; + if (SEGMENT_RUNTIME.counter_mode_step >3) SEGMENT_RUNTIME.counter_mode_step = 0; + return mdelay; } -void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b) -{ - setPixelColor(i,r,g,b,0); + +/* + * Primary, secondary running on rainbow. + */ +uint16_t WS2812FX::mode_chase_rainbow(void) { + uint8_t color_sep = 256 / SEGMENT_LENGTH; + 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]); } -void WS2812FX::setPixelColor(uint16_t i, uint32_t c) -{ - setPixelColor(i,(c>>16) & 0xFF,(c>>8) & 0xFF,(c) & 0xFF,(c>>24) & 0xFF); -} -uint32_t WS2812FX::getPixelColor(uint16_t i) -{ - if (_cronixieMode) - { - if(i>6)return 0; - byte o = 10*i; - switch(_cronixieDigits[i]) - { - case 0: i=o+5; break; - case 1: i=o+0; break; - case 2: i=o+6; break; - case 3: i=o+1; break; - case 4: i=o+7; break; - case 5: i=o+2; break; - case 6: i=o+8; break; - case 7: i=o+3; break; - case 8: i=o+9; break; - case 9: i=o+4; break; - default: return 0; - } +/* + * Sec flashes running on prim. + */ +uint16_t WS2812FX::mode_chase_flash(void) { + const static uint8_t flash_count = 4; + 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]); } - if (_rgbwMode) - { - RgbwColor lColor = bus->GetPixelColorRgbw(i); - return lColor.W*16777216 + lColor.R*65536 + lColor.G*256 + lColor.B; + + uint16_t delay = 10 + ((30 * (uint16_t)(255 - SEGMENT.speed)) / SEGMENT_LENGTH); + if(flash_step < (flash_count * 2)) { + if(flash_step % 2 == 0) { + uint16_t n = SEGMENT_RUNTIME.counter_mode_step; + uint16_t m = (SEGMENT_RUNTIME.counter_mode_step + 1) % SEGMENT_LENGTH; + setPixelColor(SEGMENT.start + n, SEGMENT.colors[1]); + setPixelColor(SEGMENT.start + m, SEGMENT.colors[1]); + delay = 20; + } else { + delay = 30; + } } else { - RgbColor lColor = bus->GetPixelColor(i); - return lColor.R*65536 + lColor.G*256 + lColor.B; + SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % SEGMENT_LENGTH; + } + return delay; +} + + +/* + * Prim flashes running, followed by random color. + */ +uint16_t WS2812FX::mode_chase_flash_random(void) { + const static uint8_t flash_count = 4; + uint8_t flash_step = SEGMENT_RUNTIME.counter_mode_call % ((flash_count * 2) + 1); + + for(uint16_t i=0; i < SEGMENT_RUNTIME.counter_mode_step; i++) { + setPixelColor(SEGMENT.start + i, color_wheel(SEGMENT_RUNTIME.aux_param)); + } + + uint16_t delay = 1 + ((10 * (uint16_t)(255 - SEGMENT.speed)) / SEGMENT_LENGTH); + if(flash_step < (flash_count * 2)) { + uint16_t n = SEGMENT_RUNTIME.counter_mode_step; + uint16_t m = (SEGMENT_RUNTIME.counter_mode_step + 1) % SEGMENT_LENGTH; + if(flash_step % 2 == 0) { + setPixelColor(SEGMENT.start + n, SEGMENT.colors[0]); + setPixelColor(SEGMENT.start + m, SEGMENT.colors[0]); + delay = 20; + } else { + setPixelColor(SEGMENT.start + n, color_wheel(SEGMENT_RUNTIME.aux_param)); + setPixelColor(SEGMENT.start + m, SEGMENT.colors[1]); + delay = 30; + } + } else { + SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % SEGMENT_LENGTH; + + if(SEGMENT_RUNTIME.counter_mode_step == 0) { + SEGMENT_RUNTIME.aux_param = get_random_wheel_index(SEGMENT_RUNTIME.aux_param); + } + } + return delay; +} + + +/* + * Alternating pixels running function. + */ +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); + } else { + setPixelColor(SEGMENT.stop - i, color2); + } + } + + 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. + */ +uint16_t WS2812FX::mode_running_color(void) { + return running(SEGMENT.colors[0], WHITE); +} + + +/* + * Alternating red/blue pixels running. + */ +uint16_t WS2812FX::mode_running_red_blue(void) { + return running(RED, BLUE); +} + + +/* + * Alternating red/green pixels running. + */ +uint16_t WS2812FX::mode_merry_christmas(void) { + return running(RED, GREEN); +} + +/* + * Alternating orange/purple pixels running. + */ +uint16_t WS2812FX::mode_halloween(void) { + return running(PURPLE, ORANGE); +} + + +/* + * Random colored pixels running. + */ +uint16_t WS2812FX::mode_running_random(void) { + for(uint16_t i=SEGMENT_LENGTH-1; i > 0; i--) { + setPixelColor(SEGMENT.start + i, getPixelColor(SEGMENT.start + i - 1)); + } + + if(SEGMENT_RUNTIME.counter_mode_step == 0) { + SEGMENT_RUNTIME.aux_param = get_random_wheel_index(SEGMENT_RUNTIME.aux_param); + setPixelColor(SEGMENT.start, color_wheel(SEGMENT_RUNTIME.aux_param)); + } + + SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step == 0) ? 1 : 0; + return SPEED_FORMULA_L; +} + + +/* + * K.I.T.T. + */ +uint16_t WS2812FX::mode_larson_scanner(void) { + fade_out((255-SEGMENT.intensity) / 32); + + if(SEGMENT_RUNTIME.counter_mode_step < SEGMENT_LENGTH) { + setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[0]); + } else { + setPixelColor(SEGMENT.start + ((SEGMENT_LENGTH * 2) - SEGMENT_RUNTIME.counter_mode_step) - 2, SEGMENT.colors[0]); + } + + SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % ((SEGMENT_LENGTH * 2) - 2); + return SPEED_FORMULA_L; +} + + +/* + * Firing comets from one end. + */ +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]); + } + + SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % SEGMENT_LENGTH; + return SPEED_FORMULA_L; +} + + +/* + * Fireworks function. + */ +uint16_t WS2812FX::fireworks(uint32_t color) { + uint32_t prevLed, thisLed, nextLed; + + fade_out((255-SEGMENT.intensity) / 32); + + // set brightness(i) = ((brightness(i-1)/4 + brightness(i+1))/4) + brightness(i) + for(uint16_t i=SEGMENT.start + 1; i > 2) & 0x3F3F3F3F; + thisLed = getPixelColor(i); + nextLed = (getPixelColor(i+1) >> 2) & 0x3F3F3F3F; + setPixelColor(i, prevLed + thisLed + nextLed); + } + + if(!_triggered) { + for(uint16_t i=0; i> 24) & 0xFF; + byte r = (SEGMENT.colors[0] >> 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); + 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)); + } + return 10 + (2 * (uint16_t)(255 - SEGMENT.speed)); +} + + +/* + * Gradient run + */ +uint16_t WS2812FX::mode_gradient(void) { + if (SEGMENT_RUNTIME.counter_mode_call == 0) SEGMENT_RUNTIME.counter_mode_step = 0; + byte p_w = (SEGMENT.colors[0] & 0xFF000000) >> 24; + byte p_r = (SEGMENT.colors[0] & 0x00FF0000) >> 16; + byte p_g = (SEGMENT.colors[0] & 0x0000FF00) >> 8; + byte p_b = (SEGMENT.colors[0] & 0x000000FF) >> 0; + byte p_w2 = (SEGMENT.colors[1] & 0xFF000000) >> 24; + byte p_r2 = (SEGMENT.colors[1] & 0x00FF0000) >> 16; + byte p_g2 = (SEGMENT.colors[1] & 0x0000FF00) >> 8; + byte p_b2 = (SEGMENT.colors[1] & 0x000000FF) >> 0; + byte nw,nr,ng,nb; + float per,val; //0.0 = sec 1.0 = pri + float brd = SEGMENT.intensity/2; if (brd <1.0) brd = 1.0; + int pp = SEGMENT_RUNTIME.counter_mode_step; + int p1 = pp-SEGMENT_LENGTH; + int p2 = pp+SEGMENT_LENGTH; + + for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) + { + val = min(abs(pp-i),min(abs(p1-i),abs(p2-i))); + per = val/brd; + if (per >1.0) per = 1.0; + nw = p_w+((p_w2 - p_w)*per); + nr = p_r+((p_r2 - p_r)*per); + ng = p_g+((p_g2 - p_g)*per); + nb = p_b+((p_b2 - p_b)*per); + setPixelColor(i,nr,ng,nb,nw); + } + + SEGMENT_RUNTIME.counter_mode_step++; + if (SEGMENT_RUNTIME.counter_mode_step > SEGMENT.stop) SEGMENT_RUNTIME.counter_mode_step = SEGMENT.start; + if (SEGMENT.speed == 0) SEGMENT_RUNTIME.counter_mode_step = SEGMENT.start + (SEGMENT_LENGTH >> 1); + return SPEED_FORMULA_L; +} + + +/* + * Gradient run with hard transition + */ +uint16_t WS2812FX::mode_loading(void) { + if (SEGMENT_RUNTIME.counter_mode_call == 0) SEGMENT_RUNTIME.counter_mode_step = 0; + byte p_w = (SEGMENT.colors[0] & 0xFF000000) >> 24; + byte p_r = (SEGMENT.colors[0] & 0x00FF0000) >> 16; + byte p_g = (SEGMENT.colors[0] & 0x0000FF00) >> 8; + byte p_b = (SEGMENT.colors[0] & 0x000000FF) >> 0; + byte p_w2 = (SEGMENT.colors[1] & 0xFF000000) >> 24; + byte p_r2 = (SEGMENT.colors[1] & 0x00FF0000) >> 16; + byte p_g2 = (SEGMENT.colors[1] & 0x0000FF00) >> 8; + byte p_b2 = (SEGMENT.colors[1] & 0x000000FF) >> 0; + byte nw,nr,ng,nb; + float per,val; //0.0 = sec 1.0 = pri + float brd = SEGMENT.intensity; if (brd <1.0) brd = 1.0; + int pp = SEGMENT_RUNTIME.counter_mode_step; + int p1 = pp+SEGMENT_LENGTH; + + for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) + { + pp = SEGMENT_RUNTIME.counter_mode_step; + if (i > pp) pp+=SEGMENT_LENGTH; + val = abs(pp-i); + per = val/brd; + if (per >1.0) per = 1.0; + nw = p_w+((p_w2 - p_w)*per); + nr = p_r+((p_r2 - p_r)*per); + ng = p_g+((p_g2 - p_g)*per); + nb = p_b+((p_b2 - p_b)*per); + setPixelColor(i,nr,ng,nb,nw); + } + + SEGMENT_RUNTIME.counter_mode_step++; + if (SEGMENT_RUNTIME.counter_mode_step > SEGMENT.stop) SEGMENT_RUNTIME.counter_mode_step = SEGMENT.start; + if (SEGMENT.speed == 0) SEGMENT_RUNTIME.counter_mode_step = SEGMENT.stop; + return SPEED_FORMULA_L; +} + + +/* + * Lights all LEDs after each other up starting from the outer edges and + * finishing in the middle. Then turns them in reverse order off. Repeat. + */ +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]); + } 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); + } else { + setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step, 0); + setPixelColor(SEGMENT.start + end, 0); + } + } + SEGMENT_RUNTIME.counter_mode_step++; + if (odd) { + if (SEGMENT_RUNTIME.counter_mode_step > SEGMENT_LENGTH) { + SEGMENT_RUNTIME.counter_mode_step = 0; + } + } else { + if (SEGMENT_RUNTIME.counter_mode_step >= SEGMENT_LENGTH) { + SEGMENT_RUNTIME.counter_mode_step = 0; + } + } + return SPEED_FORMULA_L; +} + + + /* + * Lights all LEDs after each other up starting from the outer edges and + * finishing in the middle. Then turns them in that order off. Repeat. + */ +uint16_t WS2812FX::mode_dual_color_wipe_in_in(void) { + bool odd = (SEGMENT_LENGTH % 2) == 1; + int mid = SEGMENT_LENGTH / 2; + 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]); + } else { + int i = SEGMENT_RUNTIME.counter_mode_step - mid; + setPixelColor(SEGMENT.start + i - 1, 0); + setPixelColor(SEGMENT.start + SEGMENT_LENGTH - i, 0); + } + } 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]); + } else { + int i = SEGMENT_RUNTIME.counter_mode_step - mid; + setPixelColor(SEGMENT.start + i, 0); + setPixelColor(SEGMENT.start + SEGMENT_LENGTH - i - 1, 0); + } + } + SEGMENT_RUNTIME.counter_mode_step++; + if (odd) { + if (SEGMENT_RUNTIME.counter_mode_step > SEGMENT_LENGTH) { + SEGMENT_RUNTIME.counter_mode_step = 0; + } + } else { + if (SEGMENT_RUNTIME.counter_mode_step >= SEGMENT_LENGTH) { + SEGMENT_RUNTIME.counter_mode_step = 0; + } + } + return SPEED_FORMULA_L; +} + + + /* + * Lights all LEDs after each other up starting from the middle and + * finishing at the edges. Then turns them off in that order. Repeat. + */ +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) { + 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]); + } else { + setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step - 1, 0); + setPixelColor(SEGMENT.start + end + 1, 0); + } + } 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]); + } else { + setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step, 0); + setPixelColor(SEGMENT.start + end, 0); + } + } + SEGMENT_RUNTIME.counter_mode_step++; + if (odd) { + if (SEGMENT_RUNTIME.counter_mode_step > SEGMENT_LENGTH) { + SEGMENT_RUNTIME.counter_mode_step = 0; + } + } else { + if (SEGMENT_RUNTIME.counter_mode_step >= SEGMENT_LENGTH) { + SEGMENT_RUNTIME.counter_mode_step = 0; + } + } + return SPEED_FORMULA_L; +} + + + /* + * Lights all LEDs after each other up starting from the middle and + * finishing at the edges. Then turns them off in reverse order. Repeat. + */ +uint16_t WS2812FX::mode_dual_color_wipe_out_in(void) { + bool odd = (SEGMENT_LENGTH % 2) == 1; + int mid = SEGMENT_LENGTH / 2; + 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]); + } else { + int i = SEGMENT_RUNTIME.counter_mode_step - mid; + setPixelColor(SEGMENT.start + i - 1, 0); + setPixelColor(SEGMENT.start + SEGMENT_LENGTH - i, 0); + } + } 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]); + } else { + int i = SEGMENT_RUNTIME.counter_mode_step - mid; + setPixelColor(SEGMENT.start + i, 0); + setPixelColor(SEGMENT.start + SEGMENT_LENGTH - i - 1, 0); + } + } + SEGMENT_RUNTIME.counter_mode_step++; + if (odd) { + if (SEGMENT_RUNTIME.counter_mode_step > SEGMENT_LENGTH) { + SEGMENT_RUNTIME.counter_mode_step = 0; + } + } else { + if (SEGMENT_RUNTIME.counter_mode_step >= SEGMENT_LENGTH) { + SEGMENT_RUNTIME.counter_mode_step = 0; + } + } + return SPEED_FORMULA_L; +} + + +/* + * Alternating white/red/black pixels running. + */ +uint16_t WS2812FX::mode_circus_combustus(void) { + return chase(RED, WHITE, BLACK); +} + + +/* + * ICU mode + */ +uint16_t WS2812FX::mode_icu(void) { + uint16_t dest = SEGMENT_RUNTIME.counter_mode_step & 0xFFFF; + + for (uint16_t i = SEGMENT.start; i <= SEGMENT.stop; i++) + { + setPixelColor(i, SEGMENT.colors[1]); + } + + setPixelColor(SEGMENT.start + dest, SEGMENT.colors[0]); + setPixelColor(SEGMENT.start + dest + SEGMENT_LENGTH/2, SEGMENT.colors[0]); + + 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); + 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++; + } else if (SEGMENT_RUNTIME.aux_param < SEGMENT_RUNTIME.counter_mode_step) { + SEGMENT_RUNTIME.counter_mode_step--; + dest--; + } + + setPixelColor(SEGMENT.start + dest, SEGMENT.colors[0]); + setPixelColor(SEGMENT.start + dest + SEGMENT_LENGTH/2, SEGMENT.colors[0]); + + return SPEED_FORMULA_L; +} + + +/* + * Custom mode by Aircoookie. Color Wipe, but with 3 colors + */ +uint16_t WS2812FX::mode_tricolor_wipe(void) +{ + if(SEGMENT_RUNTIME.counter_mode_step < SEGMENT_LENGTH) { + uint32_t led_offset = SEGMENT_RUNTIME.counter_mode_step; + setPixelColor(SEGMENT.start + led_offset, SEGMENT.colors[0]); + } else if (SEGMENT_RUNTIME.counter_mode_step < SEGMENT_LENGTH*2) { + uint32_t led_offset = SEGMENT_RUNTIME.counter_mode_step - SEGMENT_LENGTH; + setPixelColor(SEGMENT.start + led_offset, SEGMENT.colors[1]); + } else + { + uint32_t led_offset = SEGMENT_RUNTIME.counter_mode_step - SEGMENT_LENGTH*2; + setPixelColor(SEGMENT.start + led_offset, SEGMENT.colors[2]); + } + + SEGMENT_RUNTIME.counter_mode_step = (SEGMENT_RUNTIME.counter_mode_step + 1) % (SEGMENT_LENGTH * 3); + return SPEED_FORMULA_L; +} + + +/* + * Fades between 3 colors + * Custom mode by Keith Lord: https://github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/TriFade.h + * Modified by Aircoookie + */ +uint16_t WS2812FX::mode_tricolor_fade(void) +{ + static uint32_t color1 = 0, color2 = 0; + + if(SEGMENT_RUNTIME.counter_mode_step == 0) { + color1 = SEGMENT.colors[0]; + color2 = SEGMENT.colors[1]; + } else if(SEGMENT_RUNTIME.counter_mode_step == 256) { + color1 = SEGMENT.colors[1]; + color2 = SEGMENT.colors[2]; + } else if(SEGMENT_RUNTIME.counter_mode_step == 512) { + color1 = SEGMENT.colors[2]; + color2 = SEGMENT.colors[0]; + } + + uint32_t color = color_blend(color1, color2, SEGMENT_RUNTIME.counter_mode_step % 256); + for(uint16_t i=SEGMENT.start; i <= SEGMENT.stop; i++) { + setPixelColor(i, color); + } + + SEGMENT_RUNTIME.counter_mode_step += 4; + if(SEGMENT_RUNTIME.counter_mode_step >= 768) SEGMENT_RUNTIME.counter_mode_step = 0; + + return 5 + ((uint32_t)(255 - SEGMENT.speed) / 10); +} + + +/* + * Creates random comets + * Custom mode by Keith Lord: https://github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/MultiComet.h + */ +uint16_t WS2812FX::mode_multi_comet(void) +{ + fade_out((255-SEGMENT.intensity) / 32); + + static uint16_t comets[] = {UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX}; + + for(uint8_t i=0; i < 6; i++) { + if(comets[i] < SEGMENT_LENGTH) { + if (SEGMENT.colors[2] != SEGMENT.colors[1]) + { + setPixelColor(SEGMENT.start + comets[i], i % 2 ? SEGMENT.colors[0] : SEGMENT.colors[2]); + } else + { + setPixelColor(SEGMENT.start + comets[i], SEGMENT.colors[0]); + } + comets[i]++; + } else { + if(!random(SEGMENT_LENGTH)) { + comets[i] = 0; + } + } + } + return SPEED_FORMULA_L; +} + + +/* + * Creates two Larson scanners moving in opposite directions + * Custom mode by Keith Lord: https://github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/DualLarson.h + */ +uint16_t WS2812FX::mode_dual_larson_scanner(void){ + if (SEGMENT_RUNTIME.aux_param) + { + SEGMENT_RUNTIME.counter_mode_step--; + } else + { + SEGMENT_RUNTIME.counter_mode_step++; + } + + fade_out((255-SEGMENT.intensity) / 32); + + setPixelColor(SEGMENT.start + SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[0]); + if (SEGMENT.colors[2] != SEGMENT.colors[1]) + { + setPixelColor(SEGMENT.stop - SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[2]); + } else + { + setPixelColor(SEGMENT.stop - SEGMENT_RUNTIME.counter_mode_step, SEGMENT.colors[0]); + } + + if(SEGMENT_RUNTIME.counter_mode_step >= (SEGMENT.stop - SEGMENT.start) || SEGMENT_RUNTIME.counter_mode_step <= 0) + SEGMENT_RUNTIME.aux_param = !SEGMENT_RUNTIME.aux_param; + + return SPEED_FORMULA_L; +} + + +/* + * Running random pixels + * Custom mode by Keith Lord: https://github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/RandomChase.h + */ +uint16_t WS2812FX::mode_random_chase(void) +{ + for(uint16_t i=SEGMENT.stop; i>SEGMENT.start; i--) { + setPixelColor(i, getPixelColor(i-1)); + } + uint32_t color = getPixelColor(SEGMENT.start + 1); + int r = random(6) != 0 ? (color >> 16 & 0xFF) : random(256); + int g = random(6) != 0 ? (color >> 8 & 0xFF) : random(256); + int b = random(6) != 0 ? (color & 0xFF) : random(256); + setPixelColor(SEGMENT.start, r, g, b); + + return 15 + 2*(uint16_t)(255 - SEGMENT.speed); +} + +typedef struct Oscillator { + int16_t pos; + int8_t size; + int8_t dir; + int8_t speed; +} oscillator; + +uint16_t WS2812FX::mode_oscillate(void) +{ + static oscillator oscillators[NUM_COLORS] = { + {SEGMENT_LENGTH/4, SEGMENT_LENGTH/8, 1, 1}, + {SEGMENT_LENGTH/4*2, SEGMENT_LENGTH/8, -1, 1}, + {SEGMENT_LENGTH/4*3, SEGMENT_LENGTH/8, 1, 2} + }; + + for(int8_t i=0; i < sizeof(oscillators)/sizeof(oscillators[0]); i++) { + oscillators[i].pos += oscillators[i].dir * oscillators[i].speed; + if((oscillators[i].dir == -1) && (oscillators[i].pos <= 0)) { + oscillators[i].pos = 0; + oscillators[i].dir = 1; + oscillators[i].speed = random(1, 3); + } + if((oscillators[i].dir == 1) && (oscillators[i].pos >= (SEGMENT_LENGTH - 1))) { + oscillators[i].pos = SEGMENT_LENGTH - 1; + oscillators[i].dir = -1; + oscillators[i].speed = random(1, 3); + } + } + + for(int16_t i=0; i < SEGMENT_LENGTH; i++) { + uint32_t color = BLACK; + for(int8_t j=0; j < sizeof(oscillators)/sizeof(oscillators[0]); j++) { + if(i >= oscillators[j].pos - oscillators[j].size && i <= oscillators[j].pos + oscillators[j].size) { + color = (color == BLACK) ? SEGMENT.colors[j] : color_blend(color, SEGMENT.colors[j], 128); + } + } + setPixelColor(SEGMENT.start + i, color); + } + return 15 + (uint32_t)(255 - SEGMENT.speed); +} + + +uint16_t WS2812FX::mode_lightning(void) +{ + uint16_t ledstart = SEGMENT.start + random8(SEGMENT_LENGTH); // Determine starting location of flash + uint16_t ledlen = random8(SEGMENT.stop - ledstart); // Determine length of flash (not to go beyond NUM_LEDS-1) + uint8_t bri = 255/random8(1, 3); + + if (SEGMENT_RUNTIME.counter_mode_step == 0) + { + SEGMENT_RUNTIME.aux_param = random8(3, 3 + SEGMENT.intensity/20); //number of flashes + bri = 52; + SEGMENT_RUNTIME.aux_param2 = 1; + } + + for (int i = SEGMENT.start; i <= SEGMENT.stop; i++) + { + setPixelColor(i,SEGMENT.colors[1]); + } + + if (SEGMENT_RUNTIME.aux_param2) { + for (int i = ledstart; i < ledstart + ledlen; i++) + { + setPixelColor(i,bri,bri,bri,bri); + } + SEGMENT_RUNTIME.aux_param2 = 0; + SEGMENT_RUNTIME.counter_mode_step++; + return random8(4, 10); // each flash only lasts 4-10 milliseconds + } + + SEGMENT_RUNTIME.aux_param2 = 1; + if (SEGMENT_RUNTIME.counter_mode_step == 1) return (200); // longer delay until next flash after the leader + + if (SEGMENT_RUNTIME.counter_mode_step <= SEGMENT_RUNTIME.aux_param) return (50 + random8(100)); // shorter delay between strokes + + SEGMENT_RUNTIME.counter_mode_step = 0; + return (random8(255 - SEGMENT.speed) * 100); // delay between strikes +} + + +// Pride2015 +// Animated, ever-changing rainbows. +// by Mark Kriegsman: https://gist.github.com/kriegsman/964de772d64c502760e5 +uint16_t WS2812FX::mode_pride_2015(void) +{ + uint16_t duration = 10 + SEGMENT.speed; + uint16_t sPseudotime = SEGMENT_RUNTIME.counter_mode_step; + uint16_t sHue16 = SEGMENT_RUNTIME.aux_param; + + uint8_t sat8 = beatsin88( 87, 220, 250); + uint8_t brightdepth = beatsin88( 341, 96, 224); + uint16_t brightnessthetainc16 = beatsin88( 203, (25 * 256), (40 * 256)); + uint8_t msmultiplier = beatsin88(147, 23, 60); + + uint16_t hue16 = sHue16;//gHue * 256; + uint16_t hueinc16 = beatsin88(113, 1, 3000); + + sPseudotime += duration * msmultiplier; + sHue16 += duration * beatsin88( 400, 5,9); + uint16_t brightnesstheta16 = sPseudotime; + CRGB fastled_col; + + for( uint16_t i = SEGMENT.start ; i <= SEGMENT.stop; i++) { + hue16 += hueinc16; + uint8_t hue8 = hue16 >> 8; + + brightnesstheta16 += brightnessthetainc16; + uint16_t b16 = sin16( brightnesstheta16 ) + 32768; + + uint16_t bri16 = (uint32_t)((uint32_t)b16 * (uint32_t)b16) / 65536; + uint8_t bri8 = (uint32_t)(((uint32_t)bri16) * brightdepth) / 65536; + 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); + + nblend( fastled_col, newcolor, 64); + setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue); + } + SEGMENT_RUNTIME.counter_mode_step = sPseudotime; + SEGMENT_RUNTIME.aux_param = sHue16; + return 20; +} + + +// eight colored dots, weaving in and out of sync with each other +uint16_t WS2812FX::mode_juggle(void){ + fade_out((255-SEGMENT.intensity) / 32); + CRGB fastled_col; + 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 |= CHSV(dothue, 220, 255); + setPixelColor(index, fastled_col.red, fastled_col.green, fastled_col.blue); + dothue += 32; + } + return 10 + (uint16_t)(255 - SEGMENT.speed)/4; +} + + +/* + * FastLED palette modes helper function. Limitation: Due to memory reasons, multiple active segments with FastLED will disable the Palette transitions + */ +CRGBPalette16 currentPalette(CRGB::Black); +CRGBPalette16 targetPalette(CloudColors_p); + +void WS2812FX::handle_palette(void) +{ + bool singleSegmentMode = (_segment_index == _segment_index_palette_last); + _segment_index_palette_last = _segment_index; + + switch (SEGMENT.palette) + { + case 0: {//default palette. Differs depending on effect + switch (SEGMENT.mode) + { + case FX_MODE_FIRE_2012 : targetPalette = gGradientPalettes[22]; break;//heat palette + case FX_MODE_COLORWAVES : targetPalette = gGradientPalettes[13]; break;//landscape 33 + case FX_MODE_FILLNOISE8 : targetPalette = OceanColors_p; break; + case FX_MODE_NOISE16_1 : targetPalette = gGradientPalettes[17]; break;//Drywet + case FX_MODE_NOISE16_2 : targetPalette = gGradientPalettes[30]; break;//Blue cyan yellow + case FX_MODE_NOISE16_3 : targetPalette = gGradientPalettes[22]; break;//heat palette + case FX_MODE_NOISE16_4 : targetPalette = gGradientPalettes[13]; break;//landscape 33 + + default: targetPalette = PartyColors_p; break;//palette, bpm + } + break;} + case 1: {//periodically replace palette with a random one. Doesn't work with multiple FastLED segments + if (!singleSegmentMode) + { + targetPalette = PartyColors_p; break; //fallback + } + if (millis() - _lastPaletteChange > 1000 + ((uint32_t)(255-SEGMENT.intensity))*100) + { + targetPalette = CRGBPalette16( + CHSV(random8(), 255, random8(128, 255)), + CHSV(random8(), 255, random8(128, 255)), + CHSV(random8(), 192, random8(128, 255)), + CHSV(random8(), 255, random8(128, 255))); + _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); + 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); + CHSV prim_hsv = rgb2hsv_approximate(prim); + targetPalette = CRGBPalette16( + CHSV(prim_hsv.h, prim_hsv.s, prim_hsv.v), //color itself + CHSV(prim_hsv.h, max(prim_hsv.s - 50,0), prim_hsv.v), //less saturated + CHSV(prim_hsv.h, prim_hsv.s, max(prim_hsv.v - 50,0)), //darker + 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); + 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); + targetPalette = CRGBPalette16(sec,prim,CRGB::White); break;} + case 6: //Party colors + targetPalette = PartyColors_p; break; + case 7: //Cloud colors + targetPalette = CloudColors_p; break; + case 8: //Lava colors + targetPalette = LavaColors_p; break; + case 9: //Ocean colors + targetPalette = OceanColors_p; break; + case 10: //Forest colors + targetPalette = ForestColors_p; break; + case 11: //Rainbow colors + targetPalette = RainbowColors_p; break; + case 12: //Rainbow stripe colors + targetPalette = RainbowStripeColors_p; break; + default: //progmem palettes + targetPalette = gGradientPalettes[constrain(SEGMENT.palette -13, 0, gGradientPaletteCount -1)]; + } + + if (singleSegmentMode && paletteFade) //only blend if just one segment uses FastLED mode + { + nblendPaletteTowardPalette(currentPalette, targetPalette, 48); + } else + { + currentPalette = targetPalette; } } -void WS2812FX::setBrightness(byte b) + +uint16_t WS2812FX::mode_palette(void) { - _brightness = constrain(b, BRIGHTNESS_MIN, BRIGHTNESS_MAX); - bus->SetBrightness(_brightness); - if (_mode_last_call_time + _mode_delay > millis()+50 || b == 0) show(); //only update right away if long time until next refresh + handle_palette(); + CRGB fastled_col; + bool noWrap = (paletteBlend == 2 || (paletteBlend == 0 && SEGMENT.speed == 0)); + for (uint16_t i = SEGMENT.start; i <= SEGMENT.stop; i++) + { + uint8_t colorIndex = map(i,SEGMENT.start,SEGMENT.stop,0,255) - (SEGMENT_RUNTIME.counter_mode_step >> 6 & 0xFF); + + 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); + } + SEGMENT_RUNTIME.counter_mode_step += SEGMENT.speed *2; + if (SEGMENT.speed == 0) SEGMENT_RUNTIME.counter_mode_step = 0; + return 20; } -void WS2812FX::show() + +// WLED limitation: Analog Clock overlay will NOT work when Fire2012 is active +// Fire2012 by Mark Kriegsman, July 2012 +// as part of "Five Elements" shown here: http://youtu.be/knWiGsmgycY +//// +// This basic one-dimensional 'fire' simulation works roughly as follows: +// There's a underlying array of 'heat' cells, that model the temperature +// at each point along the line. Every cycle through the simulation, +// four steps are performed: +// 1) All cells cool down a little bit, losing heat to the air +// 2) The heat from each cell drifts 'up' and diffuses a little +// 3) Sometimes randomly new 'sparks' of heat are added at the bottom +// 4) The heat from each cell is rendered as a color into the leds array +// The heat-to-color mapping uses a black-body radiation approximation. +// +// Temperature is in arbitrary units from 0 (cold black) to 255 (white hot). +// +// This simulation scales it self a bit depending on NUM_LEDS; it should look +// "OK" on anywhere from 20 to 100 LEDs without too much tweaking. +// +// I recommend running this simulation at anywhere from 30-100 frames per second, +// meaning an interframe delay of about 10-35 milliseconds. +// +// Looks best on a high-density LED setup (60+ pixels/meter). +// +// +// There are two main parameters you can play with to control the look and +// feel of your fire: COOLING (used in step 1 above), and SPARKING (used +// in step 3 above) (Effect Intensity = Sparking). +// +// COOLING: How much does the air cool as it rises? +// Less cooling = taller flames. More cooling = shorter flames. +// Default 50, suggested range 20-100 +#define COOLING 75 + +uint16_t WS2812FX::mode_fire_2012(void) { - bus->Show(); + 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)); + } + + // Step 2. Heat from each cell drifts 'up' and diffuses a little + for( int k= SEGMENT.stop; k >= SEGMENT.start + 2; k--) { + _locked[k] = (_locked[k - 1] + _locked[k - 2] + _locked[k - 2] ) / 3; + } + + // Step 3. Randomly ignite new 'sparks' of heat near the bottom + if( random8() <= SEGMENT.intensity ) { + int y = SEGMENT.start + random8(7); + if (y <= SEGMENT.stop) _locked[y] = qadd8(_locked[y], random8(160,255) ); + } + + // Step 4. Map from heat cells to LED colors + for( int j = SEGMENT.start; j <= SEGMENT.stop; j++) { + CRGB color = ColorFromPalette( currentPalette, min(_locked[j],240), 255, LINEARBLEND); + setPixelColor(j, color.red, color.green, color.blue); + } + return 10 + (uint16_t)(255 - SEGMENT.speed)/6; } -void WS2812FX::clear() + +// ColorWavesWithPalettes by Mark Kriegsman: https://gist.github.com/kriegsman/8281905786e8b2632aeb +// This function draws color waves with an ever-changing, +// widely-varying set of parameters, using a color palette. +uint16_t WS2812FX::mode_colorwaves(void) { - bus->ClearTo(RgbColor(0)); + handle_palette(); + uint16_t duration = 10 + SEGMENT.speed; + uint16_t sPseudotime = SEGMENT_RUNTIME.counter_mode_step; + uint16_t sHue16 = SEGMENT_RUNTIME.aux_param; + + uint8_t brightdepth = beatsin88( 341, 96, 224); + uint16_t brightnessthetainc16 = beatsin88( 203, (25 * 256), (40 * 256)); + uint8_t msmultiplier = beatsin88(147, 23, 60); + + uint16_t hue16 = sHue16;//gHue * 256; + uint16_t hueinc16 = beatsin88(113, 300, 1500); + + sPseudotime += duration * msmultiplier; + sHue16 += duration * beatsin88( 400, 5, 9); + uint16_t brightnesstheta16 = sPseudotime; + CRGB fastled_col; + + for ( uint16_t i = SEGMENT.start ; i <= SEGMENT.stop; i++) { + hue16 += hueinc16; + uint8_t hue8 = hue16 / 256; + uint16_t h16_128 = hue16 >> 7; + if ( h16_128 & 0x100) { + hue8 = 255 - (h16_128 >> 1); + } else { + hue8 = h16_128 >> 1; + } + + brightnesstheta16 += brightnessthetainc16; + uint16_t b16 = sin16( brightnesstheta16 ) + 32768; + + uint16_t bri16 = (uint32_t)((uint32_t)b16 * (uint32_t)b16) / 65536; + uint8_t bri8 = (uint32_t)(((uint32_t)bri16) * brightdepth) / 65536; + bri8 += (255 - brightdepth); + + uint8_t index = hue8; + //index = triwave8( index); + 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); + + nblend(fastled_col, newcolor, 128); + setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue); + } + SEGMENT_RUNTIME.counter_mode_step = sPseudotime; + SEGMENT_RUNTIME.aux_param = sHue16; + return 20; } -void WS2812FX::begin(bool supportWhite, uint16_t countPixels, uint8_t pin, bool skipFirst) + +// colored stripes pulsing at a defined Beats-Per-Minute (BPM) +uint16_t WS2812FX::mode_bpm(void) { - if (supportWhite == _rgbwMode && countPixels == _led_count && _locked != NULL) return; - _rgbwMode = supportWhite; - _skipFirstMode = skipFirst; - _led_count = countPixels; - _cc_i2 = _led_count -1; - if (_skipFirstMode) _led_count++; - uint8_t ty = 1; - if (supportWhite) ty =2; - bus->Begin((NeoPixelType)ty, _led_count, pin); - if (_locked != NULL) delete _locked; - _locked = new bool[_led_count]; + handle_palette(); + CRGB fastled_col; + uint8_t beat = beatsin8(SEGMENT.speed, 64, 255); + for (uint16_t i = SEGMENT.start; i <= SEGMENT.stop; i++) { + fastled_col = ColorFromPalette(currentPalette, SEGMENT_RUNTIME.counter_mode_step + (i * 2), beat - SEGMENT_RUNTIME.counter_mode_step + (i * 10)); + setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue); + } + SEGMENT_RUNTIME.counter_mode_step++; + if (SEGMENT_RUNTIME.counter_mode_step >= 255) SEGMENT_RUNTIME.counter_mode_step = 0; + return 20; } -//For some reason min and max are not declared here -uint16_t WS2812FX::minval (uint16_t v, uint16_t w) +uint16_t WS2812FX::mode_fillnoise8(void) { - if (w > v) return v; - return w; + 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; + fastled_col = ColorFromPalette(currentPalette, index, 255, LINEARBLEND); + setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue); + } + SEGMENT_RUNTIME.counter_mode_step += beatsin8(SEGMENT.speed, 1, 6); //10,1,4 + + return 20; } -uint16_t WS2812FX::maxval (uint16_t v, uint16_t w) +uint16_t WS2812FX::mode_noise16_1(void) { - if (w > v) return w; - return v; + uint16_t scale = 320; // the "zoom factor" for the noise + handle_palette(); + CRGB fastled_col; + SEGMENT_RUNTIME.counter_mode_step += (1 + SEGMENT.speed/16); + + for (uint16_t i = SEGMENT.start; i <= SEGMENT.stop; i++) { + + uint16_t shift_x = beatsin8(11); // the x position of the noise field swings @ 17 bpm + uint16_t shift_y = SEGMENT_RUNTIME.counter_mode_step/42; // the y position becomes slowly incremented + + + uint16_t real_x = (i + shift_x) * scale; // the x position of the noise field swings @ 17 bpm + uint16_t real_y = (i + shift_y) * scale; // the y position becomes slowly incremented + uint32_t real_z = SEGMENT_RUNTIME.counter_mode_step; // the z position becomes quickly incremented + + uint8_t noise = inoise16(real_x, real_y, real_z) >> 8; // get the noise data and scale it down + + uint8_t index = sin8(noise * 3); // map LED color based on noise data + + fastled_col = ColorFromPalette(currentPalette, index, 255, LINEARBLEND); // With that value, look up the 8 bit colour palette value and assign it to the current LED. + setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue); + } + + return 20; } + + +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); + + for (uint16_t i = SEGMENT.start; i <= SEGMENT.stop; i++) { + + uint16_t shift_x = SEGMENT_RUNTIME.counter_mode_step >> 6; // x as a function of time + uint16_t shift_y = SEGMENT_RUNTIME.counter_mode_step/42; + + uint32_t real_x = (i + shift_x) * scale; // calculate the coordinates within the noise field + uint32_t real_y = (i + shift_y) * scale; // based on the precalculated positions + uint32_t real_z = 4223; + + uint8_t noise = inoise16(real_x, 0, 4223) >> 8; // get the noise data and scale it down + + uint8_t index = sin8(noise * 3); // map led color based on noise data + + fastled_col = ColorFromPalette(currentPalette, index, noise, LINEARBLEND); // With that value, look up the 8 bit colour palette value and assign it to the current LED. + setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue); + } + + return 20; +} + + +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); + + for (uint16_t i = SEGMENT.start; i <= SEGMENT.stop; i++) { + + uint16_t shift_x = 4223; // no movement along x and y + uint16_t shift_y = 1234; + + uint32_t real_x = (i + shift_x) * scale; // calculate the coordinates within the noise field + uint32_t real_y = (i + shift_y) * scale; // based on the precalculated positions + uint32_t real_z = SEGMENT_RUNTIME.counter_mode_step*8; + + uint8_t noise = inoise16(real_x, real_y, real_z) >> 8; // get the noise data and scale it down + + uint8_t index = sin8(noise * 3); // map led color based on noise data + + fastled_col = ColorFromPalette(currentPalette, index, noise, LINEARBLEND); // With that value, look up the 8 bit colour palette value and assign it to the current LED. + setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue); + } + + return 20; +} + + +//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++) { + int16_t index = inoise16(uint32_t(i - SEGMENT.start) << 12, SEGMENT_RUNTIME.counter_mode_step/8); + fastled_col = ColorFromPalette(currentPalette, index); + setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue); + } + return 20; +} + + diff --git a/wled00/WS2812FX.h b/wled00/WS2812FX.h index 2ea09e4f..d074bbf7 100644 --- a/wled00/WS2812FX.h +++ b/wled00/WS2812FX.h @@ -2,18 +2,17 @@ /* WS2812FX.h - Library for WS2812 LED effects. - Harm Aldick - 2016 www.aldick.org FEATURES * A lot of blinken modes and counting - * WS2812FX can be used as drop-in replacement for Adafruit Neopixel Library + * WS2812FX can be used as drop-in replacement for Adafruit NeoPixel Library NOTES - * Uses the Adafruit Neopixel library. Get it here: + * Uses the Adafruit NeoPixel library. Get it here: https://github.com/adafruit/Adafruit_NeoPixel LICENSE The MIT License (MIT) - Copyright (c) 2016 Harm Aldick + Copyright (c) 2016 Harm Aldick Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights @@ -29,27 +28,61 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - Heavily modified to work with WLED - differs from Github WS2812FX + CHANGELOG + 2016-05-28 Initial beta release + 2016-06-03 Code cleanup, minor improvements, new modes + 2016-06-04 2 new fx, fixed setColor (now also resets _mode_color) + 2017-02-02 added external trigger functionality (e.g. for sound-to-light) + Modified for WLED */ #ifndef WS2812FX_h #define WS2812FX_h -#include "Arduino.h" #include "NpbWrapper.h" -#define DEFAULT_BRIGHTNESS 50 -#define DEFAULT_MODE 0 -#define DEFAULT_SPEED 150 -#define DEFAULT_COLOR 0xFFAA00 +#define DEFAULT_BRIGHTNESS (uint8_t)50 +#define DEFAULT_MODE (uint8_t)0 +#define DEFAULT_SPEED (uint16_t)1000 +#define DEFAULT_COLOR (uint32_t)0xFF0000 -#define SPEED_MIN 0 -#define SPEED_MAX 255 +#define min(a,b) ((a)<(b)?(a):(b)) +#define max(a,b) ((a)>(b)?(a):(b)) -#define BRIGHTNESS_MIN 0 -#define BRIGHTNESS_MAX 255 +/* each segment uses 38 bytes of SRAM memory, so if you're application fails because of + insufficient memory, decreasing MAX_NUM_SEGMENTS may help */ +#define MAX_NUM_SEGMENTS 10 +#define NUM_COLORS 3 /* number of colors per segment */ +#define SEGMENT _segments[_segment_index] +#define SEGMENT_RUNTIME _segment_runtimes[_segment_index] +#define SEGMENT_LENGTH (SEGMENT.stop - SEGMENT.start + 1) +#define SPEED_FORMULA_L 5 + (50*(255 - SEGMENT.speed))/SEGMENT_LENGTH +#define RESET_RUNTIME memset(_segment_runtimes, 0, sizeof(_segment_runtimes)) -#define MODE_COUNT 58 +// some common colors +#define RED (uint32_t)0xFF0000 +#define GREEN (uint32_t)0x00FF00 +#define BLUE (uint32_t)0x0000FF +#define WHITE (uint32_t)0xFFFFFF +#define BLACK (uint32_t)0x000000 +#define YELLOW (uint32_t)0xFFFF00 +#define CYAN (uint32_t)0x00FFFF +#define MAGENTA (uint32_t)0xFF00FF +#define PURPLE (uint32_t)0x400080 +#define ORANGE (uint32_t)0xFF3000 +#define PINK (uint32_t)0xFF1493 +#define ULTRAWHITE (uint32_t)0xFFFFFFFF + +// options +// bit 8: reverse animation +// bits 5-7: fade rate (0-7) +// bit 4: gamma correction +// bits 1-3: TBD +#define NO_OPTIONS (uint8_t)0x00 +#define REVERSE (uint8_t)0x80 +#define IS_REVERSE ((SEGMENT.options & REVERSE) == REVERSE) + +#define MODE_COUNT 74 #define FX_MODE_STATIC 0 #define FX_MODE_BLINK 1 @@ -57,7 +90,7 @@ #define FX_MODE_COLOR_WIPE 3 #define FX_MODE_COLOR_WIPE_RANDOM 4 #define FX_MODE_RANDOM_COLOR 5 -#define FX_MODE_EASTER 6 +#define FX_MODE_COLOR_SWEEP 6 #define FX_MODE_DYNAMIC 7 #define FX_MODE_RAINBOW 8 #define FX_MODE_RAINBOW_CYCLE 9 @@ -104,193 +137,237 @@ #define FX_MODE_DUAL_COLOR_WIPE_OUT_OUT 50 #define FX_MODE_DUAL_COLOR_WIPE_OUT_IN 51 #define FX_MODE_CIRCUS_COMBUSTUS 52 -#define FX_MODE_CUSTOM_CHASE 53 -#define FX_MODE_CC_ON_RAINBOW 54 -#define FX_MODE_CC_ON_RAINBOW_CYCLE 55 -#define FX_MODE_CC_BLINK 56 -#define FX_MODE_CC_RANDOM 57 - +#define FX_MODE_HALLOWEEN 53 +#define FX_MODE_TRICOLOR_CHASE 54 +#define FX_MODE_TRICOLOR_WIPE 55 +#define FX_MODE_TRICOLOR_FADE 56 +#define FX_MODE_LIGHTNING 57 +#define FX_MODE_ICU 58 +#define FX_MODE_MULTI_COMET 59 +#define FX_MODE_DUAL_LARSON_SCANNER 60 +#define FX_MODE_RANDOM_CHASE 61 +#define FX_MODE_OSCILLATE 62 +//Modes that use FastLED --> +#define FX_MODE_PRIDE_2015 63 +#define FX_MODE_JUGGLE 64 +#define FX_MODE_PALETTE 65 +#define FX_MODE_FIRE_2012 66 +#define FX_MODE_COLORWAVES 67 +#define FX_MODE_BPM 68 +#define FX_MODE_FILLNOISE8 69 +#define FX_MODE_NOISE16_1 70 +#define FX_MODE_NOISE16_2 71 +#define FX_MODE_NOISE16_3 72 +#define FX_MODE_NOISE16_4 73 class WS2812FX { - typedef void (WS2812FX::*mode_ptr)(void); + typedef uint16_t (WS2812FX::*mode_ptr)(void); + + // segment parameters public: - WS2812FX(){ + typedef struct Segment { // 21 bytes + uint16_t start; + uint16_t stop; + uint8_t speed; + uint8_t intensity; + uint8_t palette; + uint8_t mode; + uint8_t options; + uint32_t colors[NUM_COLORS]; + } segment; - _mode[FX_MODE_STATIC] = &WS2812FX::mode_static; - _mode[FX_MODE_BLINK] = &WS2812FX::mode_blink; - _mode[FX_MODE_BREATH] = &WS2812FX::mode_breath; - _mode[FX_MODE_COLOR_WIPE] = &WS2812FX::mode_color_wipe; - _mode[FX_MODE_COLOR_WIPE_RANDOM] = &WS2812FX::mode_color_wipe_random; - _mode[FX_MODE_RANDOM_COLOR] = &WS2812FX::mode_random_color; - _mode[FX_MODE_EASTER] = &WS2812FX::mode_easter; - _mode[FX_MODE_DYNAMIC] = &WS2812FX::mode_dynamic; - _mode[FX_MODE_RAINBOW] = &WS2812FX::mode_rainbow; - _mode[FX_MODE_RAINBOW_CYCLE] = &WS2812FX::mode_rainbow_cycle; - _mode[FX_MODE_SCAN] = &WS2812FX::mode_scan; - _mode[FX_MODE_DUAL_SCAN] = &WS2812FX::mode_dual_scan; - _mode[FX_MODE_FADE] = &WS2812FX::mode_fade; - _mode[FX_MODE_THEATER_CHASE] = &WS2812FX::mode_theater_chase; - _mode[FX_MODE_THEATER_CHASE_RAINBOW] = &WS2812FX::mode_theater_chase_rainbow; - _mode[FX_MODE_RUNNING_LIGHTS] = &WS2812FX::mode_running_lights; - _mode[FX_MODE_TWINKLE] = &WS2812FX::mode_twinkle; - _mode[FX_MODE_TWINKLE_RANDOM] = &WS2812FX::mode_twinkle_random; - _mode[FX_MODE_TWINKLE_FADE] = &WS2812FX::mode_twinkle_fade; - _mode[FX_MODE_TWINKLE_FADE_RANDOM] = &WS2812FX::mode_twinkle_fade_random; - _mode[FX_MODE_SPARKLE] = &WS2812FX::mode_sparkle; - _mode[FX_MODE_FLASH_SPARKLE] = &WS2812FX::mode_flash_sparkle; - _mode[FX_MODE_HYPER_SPARKLE] = &WS2812FX::mode_hyper_sparkle; - _mode[FX_MODE_STROBE] = &WS2812FX::mode_strobe; - _mode[FX_MODE_STROBE_RAINBOW] = &WS2812FX::mode_strobe_rainbow; - _mode[FX_MODE_MULTI_STROBE] = &WS2812FX::mode_multi_strobe; - _mode[FX_MODE_BLINK_RAINBOW] = &WS2812FX::mode_blink_rainbow; - _mode[FX_MODE_ANDROID] = &WS2812FX::mode_android; - _mode[FX_MODE_CHASE_COLOR] = &WS2812FX::mode_chase_color; - _mode[FX_MODE_CHASE_RANDOM] = &WS2812FX::mode_chase_random; - _mode[FX_MODE_CHASE_RAINBOW] = &WS2812FX::mode_chase_rainbow; - _mode[FX_MODE_CHASE_FLASH] = &WS2812FX::mode_chase_flash; - _mode[FX_MODE_CHASE_FLASH_RANDOM] = &WS2812FX::mode_chase_flash_random; - _mode[FX_MODE_CHASE_RAINBOW_WHITE] = &WS2812FX::mode_chase_rainbow_white; - _mode[FX_MODE_COLORFUL] = &WS2812FX::mode_colorful; - _mode[FX_MODE_TRAFFIC_LIGHT] = &WS2812FX::mode_traffic_light; - _mode[FX_MODE_COLOR_SWEEP_RANDOM] = &WS2812FX::mode_color_sweep_random; - _mode[FX_MODE_RUNNING_COLOR] = &WS2812FX::mode_running_color; - _mode[FX_MODE_RUNNING_RED_BLUE] = &WS2812FX::mode_running_red_blue; - _mode[FX_MODE_RUNNING_RANDOM] = &WS2812FX::mode_running_random; - _mode[FX_MODE_LARSON_SCANNER] = &WS2812FX::mode_larson_scanner; - _mode[FX_MODE_COMET] = &WS2812FX::mode_comet; - _mode[FX_MODE_FIREWORKS] = &WS2812FX::mode_fireworks; - _mode[FX_MODE_FIREWORKS_RANDOM] = &WS2812FX::mode_fireworks_random; - _mode[FX_MODE_MERRY_CHRISTMAS] = &WS2812FX::mode_merry_christmas; - _mode[FX_MODE_FIRE_FLICKER] = &WS2812FX::mode_fire_flicker; - _mode[FX_MODE_GRADIENT] = &WS2812FX::mode_gradient; - _mode[FX_MODE_LOADING] = &WS2812FX::mode_loading; + // segment runtime parameters + typedef struct Segment_runtime { // 17 bytes + unsigned long next_time; + uint32_t counter_mode_step; + uint32_t counter_mode_call; + uint16_t aux_param; + uint16_t aux_param2; + uint8_t trans_act; + } segment_runtime; + + WS2812FX() { + _mode[FX_MODE_STATIC] = &WS2812FX::mode_static; + _mode[FX_MODE_BLINK] = &WS2812FX::mode_blink; + _mode[FX_MODE_COLOR_WIPE] = &WS2812FX::mode_color_wipe; + _mode[FX_MODE_COLOR_WIPE_RANDOM] = &WS2812FX::mode_color_wipe_random; + _mode[FX_MODE_RANDOM_COLOR] = &WS2812FX::mode_random_color; + _mode[FX_MODE_COLOR_SWEEP] = &WS2812FX::mode_color_sweep; + _mode[FX_MODE_DYNAMIC] = &WS2812FX::mode_dynamic; + _mode[FX_MODE_RAINBOW] = &WS2812FX::mode_rainbow; + _mode[FX_MODE_RAINBOW_CYCLE] = &WS2812FX::mode_rainbow_cycle; + _mode[FX_MODE_SCAN] = &WS2812FX::mode_scan; + _mode[FX_MODE_DUAL_SCAN] = &WS2812FX::mode_dual_scan; + _mode[FX_MODE_FADE] = &WS2812FX::mode_fade; + _mode[FX_MODE_THEATER_CHASE] = &WS2812FX::mode_theater_chase; + _mode[FX_MODE_THEATER_CHASE_RAINBOW] = &WS2812FX::mode_theater_chase_rainbow; + _mode[FX_MODE_TWINKLE] = &WS2812FX::mode_twinkle; + _mode[FX_MODE_TWINKLE_RANDOM] = &WS2812FX::mode_twinkle_random; + _mode[FX_MODE_TWINKLE_FADE] = &WS2812FX::mode_twinkle_fade; + _mode[FX_MODE_TWINKLE_FADE_RANDOM] = &WS2812FX::mode_twinkle_fade_random; + _mode[FX_MODE_SPARKLE] = &WS2812FX::mode_sparkle; + _mode[FX_MODE_FLASH_SPARKLE] = &WS2812FX::mode_flash_sparkle; + _mode[FX_MODE_HYPER_SPARKLE] = &WS2812FX::mode_hyper_sparkle; + _mode[FX_MODE_STROBE] = &WS2812FX::mode_strobe; + _mode[FX_MODE_STROBE_RAINBOW] = &WS2812FX::mode_strobe_rainbow; + _mode[FX_MODE_MULTI_STROBE] = &WS2812FX::mode_multi_strobe; + _mode[FX_MODE_BLINK_RAINBOW] = &WS2812FX::mode_blink_rainbow; + _mode[FX_MODE_ANDROID] = &WS2812FX::mode_android; + _mode[FX_MODE_CHASE_COLOR] = &WS2812FX::mode_chase_color; + _mode[FX_MODE_CHASE_RANDOM] = &WS2812FX::mode_chase_random; + _mode[FX_MODE_CHASE_RAINBOW] = &WS2812FX::mode_chase_rainbow; + _mode[FX_MODE_CHASE_FLASH] = &WS2812FX::mode_chase_flash; + _mode[FX_MODE_CHASE_FLASH_RANDOM] = &WS2812FX::mode_chase_flash_random; + _mode[FX_MODE_CHASE_RAINBOW_WHITE] = &WS2812FX::mode_chase_rainbow_white; + _mode[FX_MODE_COLORFUL] = &WS2812FX::mode_colorful; + _mode[FX_MODE_TRAFFIC_LIGHT] = &WS2812FX::mode_traffic_light; + _mode[FX_MODE_COLOR_SWEEP_RANDOM] = &WS2812FX::mode_color_sweep_random; + _mode[FX_MODE_RUNNING_COLOR] = &WS2812FX::mode_running_color; + _mode[FX_MODE_RUNNING_RED_BLUE] = &WS2812FX::mode_running_red_blue; + _mode[FX_MODE_RUNNING_RANDOM] = &WS2812FX::mode_running_random; + _mode[FX_MODE_LARSON_SCANNER] = &WS2812FX::mode_larson_scanner; + _mode[FX_MODE_COMET] = &WS2812FX::mode_comet; + _mode[FX_MODE_FIREWORKS] = &WS2812FX::mode_fireworks; + _mode[FX_MODE_FIREWORKS_RANDOM] = &WS2812FX::mode_fireworks_random; + _mode[FX_MODE_MERRY_CHRISTMAS] = &WS2812FX::mode_merry_christmas; + _mode[FX_MODE_FIRE_FLICKER] = &WS2812FX::mode_fire_flicker; + _mode[FX_MODE_GRADIENT] = &WS2812FX::mode_gradient; + _mode[FX_MODE_LOADING] = &WS2812FX::mode_loading; _mode[FX_MODE_DUAL_COLOR_WIPE_IN_OUT] = &WS2812FX::mode_dual_color_wipe_in_out; _mode[FX_MODE_DUAL_COLOR_WIPE_IN_IN] = &WS2812FX::mode_dual_color_wipe_in_in; _mode[FX_MODE_DUAL_COLOR_WIPE_OUT_OUT] = &WS2812FX::mode_dual_color_wipe_out_out; _mode[FX_MODE_DUAL_COLOR_WIPE_OUT_IN] = &WS2812FX::mode_dual_color_wipe_out_in; _mode[FX_MODE_CIRCUS_COMBUSTUS] = &WS2812FX::mode_circus_combustus; - _mode[FX_MODE_CUSTOM_CHASE] = &WS2812FX::mode_cc_standard; - _mode[FX_MODE_CC_ON_RAINBOW] = &WS2812FX::mode_cc_rainbow; - _mode[FX_MODE_CC_ON_RAINBOW_CYCLE] = &WS2812FX::mode_cc_cycle; - _mode[FX_MODE_CC_BLINK] = &WS2812FX::mode_cc_blink; - _mode[FX_MODE_CC_RANDOM] = &WS2812FX::mode_cc_random; + _mode[FX_MODE_HALLOWEEN] = &WS2812FX::mode_halloween; + _mode[FX_MODE_TRICOLOR_CHASE] = &WS2812FX::mode_tricolor_chase; + _mode[FX_MODE_TRICOLOR_WIPE] = &WS2812FX::mode_tricolor_wipe; + _mode[FX_MODE_TRICOLOR_FADE] = &WS2812FX::mode_tricolor_fade; + _mode[FX_MODE_BREATH] = &WS2812FX::mode_breath; + _mode[FX_MODE_RUNNING_LIGHTS] = &WS2812FX::mode_running_lights; + _mode[FX_MODE_LIGHTNING] = &WS2812FX::mode_lightning; + _mode[FX_MODE_ICU] = &WS2812FX::mode_icu; + _mode[FX_MODE_MULTI_COMET] = &WS2812FX::mode_multi_comet; + _mode[FX_MODE_DUAL_LARSON_SCANNER] = &WS2812FX::mode_dual_larson_scanner; + _mode[FX_MODE_RANDOM_CHASE] = &WS2812FX::mode_random_chase; + _mode[FX_MODE_OSCILLATE] = &WS2812FX::mode_oscillate; + _mode[FX_MODE_FIRE_2012] = &WS2812FX::mode_fire_2012; + _mode[FX_MODE_PRIDE_2015] = &WS2812FX::mode_pride_2015; + _mode[FX_MODE_BPM] = &WS2812FX::mode_bpm; + _mode[FX_MODE_JUGGLE] = &WS2812FX::mode_juggle; + _mode[FX_MODE_PALETTE] = &WS2812FX::mode_palette; + _mode[FX_MODE_COLORWAVES] = &WS2812FX::mode_colorwaves; + _mode[FX_MODE_FILLNOISE8] = &WS2812FX::mode_fillnoise8; + _mode[FX_MODE_NOISE16_1] = &WS2812FX::mode_noise16_1; + _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_index = DEFAULT_MODE; - _speed = DEFAULT_SPEED; _brightness = DEFAULT_BRIGHTNESS; _running = false; - _led_count = 255; - _mode_last_call_time = 0; - _mode_delay = 0; - _color = DEFAULT_COLOR; - _mode_color = DEFAULT_COLOR; - _color_sec = 0; - _mode_var1 = 0; - _cc_fs = true; - _cc_fe = false; - _cc_is = 0; - _cc_i1 = 0; - _cc_i2 = 254; - _cc_num1 = 5; - _cc_num2 = 5; - _ccStep = 1; - _counter_mode_call = 0; - _counter_mode_step = 0; - _counter_ccStep = 0; - _fastStandard = false; + _num_segments = 1; + _segments[0].mode = DEFAULT_MODE; + _segments[0].colors[0] = DEFAULT_COLOR; + _segments[0].start = 0; + _segments[0].speed = DEFAULT_SPEED; _reverseMode = false; _skipFirstMode = false; + paletteFade = 0; + paletteBlend = 0; _locked = NULL; _cronixieDigits = new byte[6]; bus = new NeoPixelWrapper(); + RESET_RUNTIME; } void - show(void), - setPixelColor(uint16_t i, byte r, byte g, byte b), - setPixelColor(uint16_t i, byte r, byte g, byte b, byte w), - init(bool supportWhite, uint16_t countPixels, uint8_t pin, bool skipFirst), + init(bool supportWhite, uint16_t countPixels, bool skipFirst), service(void), - start(void), - stop(void), - setMode(byte m), - setCustomChase(byte i1, uint16_t i2, byte is, byte np, byte ns, byte stp, bool fs, bool fe), - setCCIndex1(byte i1), - setCCIndex2(uint16_t i2), - setCCStart(byte is), - setCCNum1(byte np), - setCCNum2(byte ns), - setCCStep(byte stp), - setCCFS(bool fs), - setCCFE(bool fe), - setSpeed(byte s), - setIntensity(byte in), - increaseSpeed(byte s), - decreaseSpeed(byte s), - setColor(byte r, byte g, byte b), - setColor(byte r, byte g, byte b, byte w), + clear(void), + strip_off(void), + fade_out(uint8_t r), + setMode(uint8_t m), + setSpeed(uint8_t s), + setIntensity(uint8_t i), + setPalette(uint8_t p), + setColor(uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0), + setSecondaryColor(uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0), setColor(uint32_t c), - setSecondaryColor(byte r, byte g, byte b), - setSecondaryColor(byte r, byte g, byte b, byte w), setSecondaryColor(uint32_t c), - setBrightness(byte b), - increaseBrightness(byte s), - decreaseBrightness(byte s), + setBrightness(uint8_t b), setReverseMode(bool b), driverModeCronixie(bool b), setCronixieDigits(byte* d), setCronixieBacklight(bool b), - setIndividual(int i), - setIndividual(int i, uint32_t col), - setRange(int i, int i2), - setRange(int i, int i2, uint32_t col), - lock(int i), - lockRange(int i, int i2), - lockAll(void), - unlock(int i), - unlockRange(int i, int i2), + setIndividual(uint16_t i, uint32_t col), + setRange(uint16_t i, uint16_t i2, uint32_t col), + lock(uint16_t i), + lockRange(uint16_t i, uint16_t i2), + unlock(uint16_t i), + unlockRange(uint16_t i, uint16_t i2), unlockAll(void), - setFastUpdateMode(bool b), + setTransitionMode(bool t), trigger(void), - setFade(int sp); + setNumSegments(uint8_t n), + setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, uint32_t color, uint8_t speed, uint8_t intensity, bool reverse), + setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, const uint32_t colors[], uint8_t speed, uint8_t intensity, bool reverse), + setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t mode, const uint32_t colors[], uint8_t speed, uint8_t intensity, uint8_t options), + resetSegments(), + setPixelColor(uint16_t n, uint32_t c), + setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0), + show(void); - bool - isRunning(void), - isLocked(int i); - - byte - get_random_wheel_index(byte), + uint8_t + paletteFade, + paletteBlend, + getBrightness(void), getMode(void), getSpeed(void), - getIntensity(void), - getBrightness(void), - getModeCount(void); + getNumSegments(void), + get_random_wheel_index(uint8_t); uint32_t - color_wheel(byte), + color_wheel(uint8_t), + color_blend(uint32_t,uint32_t,uint8_t), + getPixelColor(uint16_t), getColor(void); double getPowerEstimate(uint16_t leds, uint32_t c, byte b), getSafePowerMultiplier(double safeMilliAmps, uint16_t leds, uint32_t c, byte b); - private: - NeoPixelWrapper *bus; + WS2812FX::Segment + getSegment(void); - void - begin(bool supportWhite, uint16_t countPixels, uint8_t pin, bool skipFirst), - clear(void), - setPixelColor(uint16_t i, uint32_t c), - setPixelColorRaw(uint16_t i, byte r, byte g, byte b, byte w), - dofade(void), - strip_off(void), - strip_off_respectLock(void), + WS2812FX::Segment_runtime + getSegmentRuntime(void); + + WS2812FX::Segment* + getSegments(void); + + // 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), + twinkle(uint32_t), + twinkle_fade(uint32_t), + chase(uint32_t, uint32_t, uint32_t), + running(uint32_t, uint32_t), + fireworks(uint32_t), + tricolor_chase(uint32_t, uint32_t, uint32_t); + + // builtin modes + uint16_t mode_static(void), mode_blink(void), + mode_blink_rainbow(void), + mode_strobe(void), + mode_strobe_rainbow(void), mode_color_wipe(void), + mode_color_sweep(void), mode_color_wipe_random(void), + mode_color_sweep_random(void), mode_random_color(void), - mode_easter(void), mode_dynamic(void), mode_breath(void), mode_fade(void), @@ -308,10 +385,7 @@ class WS2812FX { mode_sparkle(void), mode_flash_sparkle(void), mode_hyper_sparkle(void), - mode_strobe(void), - mode_strobe_rainbow(void), mode_multi_strobe(void), - mode_blink_rainbow(void), mode_android(void), mode_chase_color(void), mode_chase_random(void), @@ -320,9 +394,7 @@ class WS2812FX { mode_chase_flash_random(void), mode_chase_rainbow_white(void), mode_colorful(void), - mode_colorful_internal(uint32_t*), mode_traffic_light(void), - mode_color_sweep_random(void), mode_running_color(void), mode_running_red_blue(void), mode_running_random(void), @@ -331,6 +403,7 @@ class WS2812FX { mode_fireworks(void), mode_fireworks_random(void), mode_merry_christmas(void), + mode_halloween(void), mode_fire_flicker(void), mode_gradient(void), mode_loading(void), @@ -339,67 +412,65 @@ class WS2812FX { mode_dual_color_wipe_out_out(void), mode_dual_color_wipe_out_in(void), mode_circus_combustus(void), - mode_cc_core(void), - mode_cc_standard(void), - mode_cc_rainbow(void), - mode_cc_cycle(void), - mode_cc_blink(void), - mode_cc_random(void); + mode_bicolor_chase(void), + mode_tricolor_chase(void), + mode_tricolor_wipe(void), + mode_tricolor_fade(void), + mode_icu(void), + mode_multi_comet(void), + mode_dual_larson_scanner(void), + mode_random_chase(void), + mode_oscillate(void), + mode_fire_2012(void), + mode_pride_2015(void), + mode_bpm(void), + mode_juggle(void), + mode_palette(void), + mode_colorwaves(void), + mode_fillnoise8(void), + mode_noise16_1(void), + mode_noise16_2(void), + mode_noise16_3(void), + mode_noise16_4(void), + mode_lightning(void); - bool - _triggered, - _rgbwMode, - _skipFirstMode, - _fastStandard, - _reverseMode, - _cronixieMode, - _cronixieBacklightEnabled, - _cc_fs, - _cc_fe, - _running; + private: + NeoPixelWrapper *bus; + + uint16_t _length; + uint16_t _rand16seed; + uint8_t _brightness; - bool* - _locked; - - byte - _mode_index, - _speed, - _intensity, - _cc_i1, - _cc_is, - _cc_num1, - _cc_num2, - _ccStep, - _brightness; - - byte* - _cronixieDigits; - - uint16_t - minval(uint16_t v, uint16_t w), - maxval(uint16_t v, uint16_t w), - _cc_i2, - _led_count; - - uint32_t - getPixelColor(uint16_t i), - _color, - _color_sec, - _counter_mode_call, - _counter_mode_step, - _counter_ccStep, - _mode_var1, - _mode_color, - _mode_delay; + void handle_palette(void); double _cronixieSecMultiplier; - unsigned long - _mode_last_call_time; + boolean + _running, + _rgbwMode, + _reverseMode, + _cronixieMode, + _cronixieBacklightEnabled, + _skipFirstMode, + _triggered; - mode_ptr - _mode[MODE_COUNT]; + byte* _locked; + byte* _cronixieDigits; + + mode_ptr _mode[MODE_COUNT]; // SRAM footprint: 4 bytes per element + + + uint32_t _lastPaletteChange = 0; + + uint8_t _segment_index = 0; + uint8_t _segment_index_palette_last = 99; + uint8_t _num_segments = 1; + segment _segments[MAX_NUM_SEGMENTS] = { // SRAM footprint: 20 bytes per element + // start, stop, speed, intensity, mode, options, color[] + { 0, 7, DEFAULT_SPEED, 128, FX_MODE_STATIC, NO_OPTIONS, {DEFAULT_COLOR}} + }; + segment_runtime _segment_runtimes[MAX_NUM_SEGMENTS]; // SRAM footprint: 17 bytes per element }; #endif diff --git a/wled00/data/index.htm b/wled00/data/index.htm index 1903a027..d35ee2b9 100644 --- a/wled00/data/index.htm +++ b/wled00/data/index.htm @@ -2,7 +2,7 @@ - WLED 0.7.1 + WLED 0.8.0 - + +function ps(psNum){ +if (d.querySelector('.oos-chk-ps').checked == false) { + var url = "/win&PL=" + psNum; + } +if (d.querySelector('.oos-chk-ps').checked == true) { + var url = "/win&PS=" + psNum; + } +EC(url); +} +function getVals(){ +var pr = this.parentNode; +var slides = pr.getElementsByTagName("input"); +var s1 = parseFloat(slides[0].value); +var s2 = parseFloat(slides[1].value); +if(s1>s2){var tmp = s2;s2=s1;s1=tmp;} + +var displayElement = pr.getElementsByClassName("rangeValues")[0]; + displayElement.innerHTML = s1 + " - " + s2; +if(!fs)EC('/win&P1=' + s1 + '&P2=' + s2); +} + \ No newline at end of file diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index ed28871b..0573c494 100644 Binary files a/wled00/data/settings_leds.htm and b/wled00/data/settings_leds.htm differ diff --git a/wled00/data/settings_sec.htm b/wled00/data/settings_sec.htm index 9ae3b3a4..d93f96ac 100644 Binary files a/wled00/data/settings_sec.htm and b/wled00/data/settings_sec.htm differ diff --git a/wled00/data/settings_sync.htm b/wled00/data/settings_sync.htm index 1a6fb48c..9775ed68 100644 Binary files a/wled00/data/settings_sync.htm and b/wled00/data/settings_sync.htm differ diff --git a/wled00/data/settings_time.htm b/wled00/data/settings_time.htm index df02ad53..3c06dff4 100644 Binary files a/wled00/data/settings_time.htm and b/wled00/data/settings_time.htm differ diff --git a/wled00/htmls00.h b/wled00/htmls00.h index c954a10a..78e96b93 100644 --- a/wled00/htmls00.h +++ b/wled00/htmls00.h @@ -3,21 +3,30 @@ */ #ifndef WLED_FLASH_512K_MODE const char PAGE_indexM[] PROGMEM = R"=====( -WLED 0.7.1
Loading WLED UI...

WLED

FX 2nd Color

Sync Lights

White Channel

Master Brightness



 
 
 
 

 
 
 
 

Edit Presets

Presets

1
2
3
4

5
6
7
8

9
10
11
12

13
14
15
16

Cycle Mode

Cycle Range

  • Color
  • Effects
  • Both

Preset Duration

Color Transition

FX Speed

FX Intensity

  • Solid
  • Blink
  • Breathe
  • Wipe
  • Wipe Random
  • Random Colors
  • Easter
  • Multi Colors
  • Rainbow Full
  • Rainbow Cycle
  • Scan
  • Double Scan
  • Fade
  • Chase
  • Chase Rainbow
  • Running
  • Twinkle
  • Twinkle Random
  • Twinkle Fade
  • Twinkle Random Fade
  • Sparkle
  • Dark Sparkle
  • Dark Sparkle+
  • Strobe
  • Strobe Rainbow
  • Double Strobe
  • Blink Rainbow
  • Android
  • Dark Chase
  • Dark Chase Random
  • Dark Chase Rainbow
  • Chase Flash
  • Dark Chase Random
  • Rainbow Runner
  • Colorful
  • Traffic Light
  • Sweep Random
  • Running 2
  • Red & Blue
  • Running 2 Random
  • Scanner
  • Lighthouse
  • Fireworks
  • Fireworks Random
  • Merry Christmas
  • Fire Flicker
  • Gradient
  • Gradient Loading
  • In Out
  • In In
  • Out Out
  • Out In
  • Circus
  •  
  • Go to top
+WLED 0.8.0 + )====="; //head1 (css) @@ -101,92 +109,21 @@ const char PAGE_index3[] PROGMEM = R"=====( - - -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
Effect Panel



-

Set secondary color to @@ -194,43 +131,27 @@ Set secondary color to -or -
-
Custom Theater Chase
-using primary and - secondary color LEDs,
-doing steps per tick, -from start and end. -
-
-
-
-
-
-
+or
+
FastLED Palette

+
+
+
Favorite Presets




-Click checkmark to apply brightness, color and effects.

-Cycle through presets to , keep each for ms:

-
-
+Click checkmark to apply brightness, color and effects.

+Cycle through presets to , keep each for ms:

+
Timed Light



Gradually dim down
-1st slider sets duration (1-255min), 2nd sets target brightness. -
-
-
-
-
-
- -
- - - +1st slider sets duration (1-255min), 2nd sets target brightness.
+
+
+
+ )====="; diff --git a/wled00/htmls01.h b/wled00/htmls01.h index 035dd959..b015bf58 100644 --- a/wled00/htmls01.h +++ b/wled00/htmls01.h @@ -1,10 +1,14 @@ /* * Settings html */ + +//common CSS of settings pages const char PAGE_settingsCss[] PROGMEM = R"=====( body{font-family:var(--cFn),sans-serif;text-align:center;background:var(--cCol);color:var(--tCol);line-height:200%;margin:0;background-attachment:fixed}hr{border-color:var(--dCol);filter:drop-shadow(-5px -5px 5px var(--sCol))}button{background:var(--bCol);color:var(--tCol);font-family:var(--cFn),sans-serif;border:.3ch solid var(--bCol);display:inline-block;filter:drop-shadow(-5px -5px 5px var(--sCol));font-size:20px;margin:8px;margin-top:12px}.helpB{text-align:left;position:absolute;width:60px}input{background:var(--bCol);color:var(--tCol);font-family:var(--cFn),sans-serif;border:.5ch solid var(--bCol);filter:drop-shadow(-5px -5px 5px var(--sCol))}input[type=number]{width:3em}select{background:var(--bCol);color:var(--tCol);font-family:var(--cFn),sans-serif;border:0.5ch solid var(--bCol);filter:drop-shadow( -5px -5px 5px var(--sCol) );} )====="; + +//settings menu const char PAGE_settings0[] PROGMEM = R"=====( WLED Settings @@ -26,11 +30,14 @@ body{text-align:center;background:var(--cCol);height:100%;margin:0;background-at )====="; + +//wifi settings const char PAGE_settings_wifi0[] PROGMEM = R"=====( WiFi Settings )====="; + const char PAGE_msg1[] PROGMEM = R"=====( button{background:var(--bCol);color:var(--tCol);font-family:var(--cFn),sans-serif;border:.3ch solid var(--bCol);display:inline-block;filter:drop-shadow(-5px -5px 5px var(--sCol));font-size:20px;margin:8px;margin-top:12px}body{font-family:var(--cFn),sans-serif;text-align:center;background:var(--cCol);color:var(--tCol);line-height:200%;margin:0;background-attachment:fixed} )====="; + +//new user welcome page +#ifndef WLED_FLASH_512K_MODE const char PAGE_welcome0[] PROGMEM = R"=====( WLED Welcome! )====="; + const char PAGE_welcome1[] PROGMEM = R"=====( body{font-family:var(--cFn),sans-serif;text-align:center;background:linear-gradient(var(--bCol),black);height:100%;margin:0;background-repeat:no-repeat;background-attachment: fixed;color: var(--tCol);}svg {fill: var(--dCol);} @@ -41,6 +50,11 @@ Connect the module to your local WiFi here!

Just trying this out in AP mode? Here are the controls.
)====="; +#else +const char PAGE_welcome0[] PROGMEM = ""; +const char PAGE_welcome1[] PROGMEM = ""; +#endif + /* * SPIFFS editor html @@ -54,6 +68,8 @@ eval(function(p,a,c,k,e,r){e=function(c){return(c_state = MQTT_DISCONNECTED; + this->_client = NULL; + this->stream = NULL; + setCallback(NULL); +} + +PubSubClient::PubSubClient(Client& client) { + this->_state = MQTT_DISCONNECTED; + setClient(client); + this->stream = NULL; +} + +PubSubClient::PubSubClient(IPAddress addr, uint16_t port, Client& client) { + this->_state = MQTT_DISCONNECTED; + setServer(addr, port); + setClient(client); + this->stream = NULL; +} +PubSubClient::PubSubClient(IPAddress addr, uint16_t port, Client& client, Stream& stream) { + this->_state = MQTT_DISCONNECTED; + setServer(addr,port); + setClient(client); + setStream(stream); +} +PubSubClient::PubSubClient(IPAddress addr, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) { + this->_state = MQTT_DISCONNECTED; + setServer(addr, port); + setCallback(callback); + setClient(client); + this->stream = NULL; +} +PubSubClient::PubSubClient(IPAddress addr, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) { + this->_state = MQTT_DISCONNECTED; + setServer(addr,port); + setCallback(callback); + setClient(client); + setStream(stream); +} + +PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, Client& client) { + this->_state = MQTT_DISCONNECTED; + setServer(ip, port); + setClient(client); + this->stream = NULL; +} +PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, Client& client, Stream& stream) { + this->_state = MQTT_DISCONNECTED; + setServer(ip,port); + setClient(client); + setStream(stream); +} +PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) { + this->_state = MQTT_DISCONNECTED; + setServer(ip, port); + setCallback(callback); + setClient(client); + this->stream = NULL; +} +PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) { + this->_state = MQTT_DISCONNECTED; + setServer(ip,port); + setCallback(callback); + setClient(client); + setStream(stream); +} + +PubSubClient::PubSubClient(const char* domain, uint16_t port, Client& client) { + this->_state = MQTT_DISCONNECTED; + setServer(domain,port); + setClient(client); + this->stream = NULL; +} +PubSubClient::PubSubClient(const char* domain, uint16_t port, Client& client, Stream& stream) { + this->_state = MQTT_DISCONNECTED; + setServer(domain,port); + setClient(client); + setStream(stream); +} +PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) { + this->_state = MQTT_DISCONNECTED; + setServer(domain,port); + setCallback(callback); + setClient(client); + this->stream = NULL; +} +PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) { + this->_state = MQTT_DISCONNECTED; + setServer(domain,port); + setCallback(callback); + setClient(client); + setStream(stream); +} + +boolean PubSubClient::connect(const char *id) { + return connect(id,NULL,NULL,0,0,0,0); +} + +boolean PubSubClient::connect(const char *id, const char *user, const char *pass) { + return connect(id,user,pass,0,0,0,0); +} + +boolean PubSubClient::connect(const char *id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) { + return connect(id,NULL,NULL,willTopic,willQos,willRetain,willMessage); +} + +boolean PubSubClient::connect(const char *id, const char *user, const char *pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) { + if (!connected()) { + int result = 0; + + if (domain != NULL) { + result = _client->connect(this->domain, this->port); + } else { + result = _client->connect(this->ip, this->port); + } + if (result == 1) { + nextMsgId = 1; + // Leave room in the buffer for header and variable length field + uint16_t length = 5; + unsigned int j; + +#if MQTT_VERSION == MQTT_VERSION_3_1 + uint8_t d[9] = {0x00,0x06,'M','Q','I','s','d','p', MQTT_VERSION}; +#define MQTT_HEADER_VERSION_LENGTH 9 +#elif MQTT_VERSION == MQTT_VERSION_3_1_1 + uint8_t d[7] = {0x00,0x04,'M','Q','T','T',MQTT_VERSION}; +#define MQTT_HEADER_VERSION_LENGTH 7 +#endif + for (j = 0;j>1); + } + } + + buffer[length++] = v; + + buffer[length++] = ((MQTT_KEEPALIVE) >> 8); + buffer[length++] = ((MQTT_KEEPALIVE) & 0xFF); + length = writeString(id,buffer,length); + if (willTopic) { + length = writeString(willTopic,buffer,length); + length = writeString(willMessage,buffer,length); + } + + if(user != NULL) { + length = writeString(user,buffer,length); + if(pass != NULL) { + length = writeString(pass,buffer,length); + } + } + + write(MQTTCONNECT,buffer,length-5); + + lastInActivity = lastOutActivity = millis(); + + while (!_client->available()) { + unsigned long t = millis(); + if (t-lastInActivity >= ((int32_t) MQTT_SOCKET_TIMEOUT*1000UL)) { + _state = MQTT_CONNECTION_TIMEOUT; + _client->stop(); + return false; + } + } + uint8_t llen; + uint16_t len = readPacket(&llen); + + if (len == 4) { + if (buffer[3] == 0) { + lastInActivity = millis(); + pingOutstanding = false; + _state = MQTT_CONNECTED; + return true; + } else { + _state = buffer[3]; + } + } + _client->stop(); + } else { + _state = MQTT_CONNECT_FAILED; + } + return false; + } + return true; +} + +// reads a byte into result +boolean PubSubClient::readByte(uint8_t * result) { + uint32_t previousMillis = millis(); + while(!_client->available()) { + uint32_t currentMillis = millis(); + if(currentMillis - previousMillis >= ((int32_t) MQTT_SOCKET_TIMEOUT * 1000)){ + return false; + } + } + *result = _client->read(); + return true; +} + +// reads a byte into result[*index] and increments index +boolean PubSubClient::readByte(uint8_t * result, uint16_t * index){ + uint16_t current_index = *index; + uint8_t * write_address = &(result[current_index]); + if(readByte(write_address)){ + *index = current_index + 1; + return true; + } + return false; +} + +uint16_t PubSubClient::readPacket(uint8_t* lengthLength) { + uint16_t len = 0; + if(!readByte(buffer, &len)) return 0; + bool isPublish = (buffer[0]&0xF0) == MQTTPUBLISH; + uint32_t multiplier = 1; + uint16_t length = 0; + uint8_t digit = 0; + uint16_t skip = 0; + uint8_t start = 0; + + do { + if (len == 6) { + // Invalid remaining length encoding - kill the connection + _state = MQTT_DISCONNECTED; + _client->stop(); + return 0; + } + if(!readByte(&digit)) return 0; + buffer[len++] = digit; + length += (digit & 127) * multiplier; + multiplier *= 128; + } while ((digit & 128) != 0); + *lengthLength = len-1; + + if (isPublish) { + // Read in topic length to calculate bytes to skip over for Stream writing + if(!readByte(buffer, &len)) return 0; + if(!readByte(buffer, &len)) return 0; + skip = (buffer[*lengthLength+1]<<8)+buffer[*lengthLength+2]; + start = 2; + if (buffer[0]&MQTTQOS1) { + // skip message id + skip += 2; + } + } + + for (uint16_t i = start;istream) { + if (isPublish && len-*lengthLength-2>skip) { + this->stream->write(digit); + } + } + if (len < MQTT_MAX_PACKET_SIZE) { + buffer[len] = digit; + } + len++; + } + + if (!this->stream && len > MQTT_MAX_PACKET_SIZE) { + len = 0; // This will cause the packet to be ignored. + } + + return len; +} + +boolean PubSubClient::loop() { + if (connected()) { + unsigned long t = millis(); + if ((t - lastInActivity > MQTT_KEEPALIVE*1000UL) || (t - lastOutActivity > MQTT_KEEPALIVE*1000UL)) { + if (pingOutstanding) { + this->_state = MQTT_CONNECTION_TIMEOUT; + _client->stop(); + return false; + } else { + buffer[0] = MQTTPINGREQ; + buffer[1] = 0; + _client->write(buffer,2); + lastOutActivity = t; + lastInActivity = t; + pingOutstanding = true; + } + } + if (_client->available()) { + uint8_t llen; + uint16_t len = readPacket(&llen); + uint16_t msgId = 0; + uint8_t *payload; + if (len > 0) { + lastInActivity = t; + uint8_t type = buffer[0]&0xF0; + if (type == MQTTPUBLISH) { + if (callback) { + uint16_t tl = (buffer[llen+1]<<8)+buffer[llen+2]; /* topic length in bytes */ + memmove(buffer+llen+2,buffer+llen+3,tl); /* move topic inside buffer 1 byte to front */ + buffer[llen+2+tl] = 0; /* end the topic as a 'C' string with \x00 */ + char *topic = (char*) buffer+llen+2; + + // make sure payload can be interpreted as 'C' string + buffer[(len < MQTT_MAX_PACKET_SIZE) ? len : MQTT_MAX_PACKET_SIZE -1] = 0; + + // msgId only present for QOS>0 + if ((buffer[0]&0x06) == MQTTQOS1) { + msgId = (buffer[llen+3+tl]<<8)+buffer[llen+3+tl+1]; + payload = buffer+llen+3+tl+2; + callback(topic,payload,len-llen-3-tl-2); + + buffer[0] = MQTTPUBACK; + buffer[1] = 2; + buffer[2] = (msgId >> 8); + buffer[3] = (msgId & 0xFF); + _client->write(buffer,4); + lastOutActivity = t; + + } else { + payload = buffer+llen+3+tl; + callback(topic,payload,len-llen-3-tl); + } + } + } else if (type == MQTTPINGREQ) { + buffer[0] = MQTTPINGRESP; + buffer[1] = 0; + _client->write(buffer,2); + } else if (type == MQTTPINGRESP) { + pingOutstanding = false; + } + } else if (!connected()) { + // readPacket has closed the connection + return false; + } + } + return true; + } + return false; +} + +boolean PubSubClient::publish(const char* topic, const char* payload) { + return publish(topic,(const uint8_t*)payload,strlen(payload),false); +} + +boolean PubSubClient::publish(const char* topic, const char* payload, boolean retained) { + return publish(topic,(const uint8_t*)payload,strlen(payload),retained); +} + +boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength) { + return publish(topic, payload, plength, false); +} + +boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength, boolean retained) { + if (connected()) { + if (MQTT_MAX_PACKET_SIZE < 5 + 2+strlen(topic) + plength) { + // Too long + return false; + } + // Leave room in the buffer for header and variable length field + uint16_t length = 5; + length = writeString(topic,buffer,length); + uint16_t i; + for (i=0;i 0) { + digit |= 0x80; + } + buffer[pos++] = digit; + llen++; + } while(len>0); + + pos = writeString(topic,buffer,pos); + + rc += _client->write(buffer,pos); + + for (i=0;iwrite((char)pgm_read_byte_near(payload + i)); + } + + lastOutActivity = millis(); + + return rc == tlen + 4 + plength; +} + +boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) { + uint8_t lenBuf[4]; + uint8_t llen = 0; + uint8_t digit; + uint8_t pos = 0; + uint16_t rc; + uint16_t len = length; + do { + digit = len % 128; + len = len / 128; + if (len > 0) { + digit |= 0x80; + } + lenBuf[pos++] = digit; + llen++; + } while(len>0); + + buf[4-llen] = header; + for (int i=0;i 0) && result) { + bytesToWrite = (bytesRemaining > MQTT_MAX_TRANSFER_SIZE)?MQTT_MAX_TRANSFER_SIZE:bytesRemaining; + rc = _client->write(writeBuf,bytesToWrite); + result = (rc == bytesToWrite); + bytesRemaining -= rc; + writeBuf += rc; + } + return result; +#else + rc = _client->write(buf+(4-llen),length+1+llen); + lastOutActivity = millis(); + return (rc == 1+llen+length); +#endif +} + +boolean PubSubClient::subscribe(const char* topic) { + return subscribe(topic, 0); +} + +boolean PubSubClient::subscribe(const char* topic, uint8_t qos) { + if (qos > 1) { + return false; + } + if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) { + // Too long + return false; + } + if (connected()) { + // Leave room in the buffer for header and variable length field + uint16_t length = 5; + nextMsgId++; + if (nextMsgId == 0) { + nextMsgId = 1; + } + buffer[length++] = (nextMsgId >> 8); + buffer[length++] = (nextMsgId & 0xFF); + length = writeString((char*)topic, buffer,length); + buffer[length++] = qos; + return write(MQTTSUBSCRIBE|MQTTQOS1,buffer,length-5); + } + return false; +} + +boolean PubSubClient::unsubscribe(const char* topic) { + if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) { + // Too long + return false; + } + if (connected()) { + uint16_t length = 5; + nextMsgId++; + if (nextMsgId == 0) { + nextMsgId = 1; + } + buffer[length++] = (nextMsgId >> 8); + buffer[length++] = (nextMsgId & 0xFF); + length = writeString(topic, buffer,length); + return write(MQTTUNSUBSCRIBE|MQTTQOS1,buffer,length-5); + } + return false; +} + +void PubSubClient::disconnect() { + buffer[0] = MQTTDISCONNECT; + buffer[1] = 0; + _client->write(buffer,2); + _state = MQTT_DISCONNECTED; + _client->stop(); + lastInActivity = lastOutActivity = millis(); +} + +uint16_t PubSubClient::writeString(const char* string, uint8_t* buf, uint16_t pos) { + const char* idp = string; + uint16_t i = 0; + pos += 2; + while (*idp) { + buf[pos++] = *idp++; + i++; + } + buf[pos-i-2] = (i >> 8); + buf[pos-i-1] = (i & 0xFF); + return pos; +} + + +boolean PubSubClient::connected() { + boolean rc; + if (_client == NULL ) { + rc = false; + } else { + rc = (int)_client->connected(); + if (!rc) { + if (this->_state == MQTT_CONNECTED) { + this->_state = MQTT_CONNECTION_LOST; + _client->flush(); + _client->stop(); + } + } + } + return rc; +} + +PubSubClient& PubSubClient::setServer(uint8_t * ip, uint16_t port) { + IPAddress addr(ip[0],ip[1],ip[2],ip[3]); + return setServer(addr,port); +} + +PubSubClient& PubSubClient::setServer(IPAddress ip, uint16_t port) { + this->ip = ip; + this->port = port; + this->domain = NULL; + return *this; +} + +PubSubClient& PubSubClient::setServer(const char * domain, uint16_t port) { + this->domain = domain; + this->port = port; + return *this; +} + +PubSubClient& PubSubClient::setCallback(MQTT_CALLBACK_SIGNATURE) { + this->callback = callback; + return *this; +} + +PubSubClient& PubSubClient::setClient(Client& client){ + this->_client = &client; + return *this; +} + +PubSubClient& PubSubClient::setStream(Stream& stream){ + this->stream = &stream; + return *this; +} + +int PubSubClient::state() { + return this->_state; +} diff --git a/wled00/src/dependencies/pubsubclient/PubSubClient.h b/wled00/src/dependencies/pubsubclient/PubSubClient.h new file mode 100644 index 00000000..9eaa3296 --- /dev/null +++ b/wled00/src/dependencies/pubsubclient/PubSubClient.h @@ -0,0 +1,144 @@ +/* + PubSubClient.h - A simple client for MQTT. + Nick O'Leary + http://knolleary.net +*/ + +#ifndef PubSubClient_h +#define PubSubClient_h + +#include +#include "IPAddress.h" +#include "Client.h" +#include "Stream.h" + +#define MQTT_VERSION_3_1 3 +#define MQTT_VERSION_3_1_1 4 + +// MQTT_VERSION : Pick the version +//#define MQTT_VERSION MQTT_VERSION_3_1 +#ifndef MQTT_VERSION +#define MQTT_VERSION MQTT_VERSION_3_1_1 +#endif + +// MQTT_MAX_PACKET_SIZE : Maximum packet size +#ifndef MQTT_MAX_PACKET_SIZE +#define MQTT_MAX_PACKET_SIZE 128 +#endif + +// MQTT_KEEPALIVE : keepAlive interval in Seconds +#ifndef MQTT_KEEPALIVE +#define MQTT_KEEPALIVE 60 +#endif + +// MQTT_SOCKET_TIMEOUT: socket timeout interval in Seconds +#ifndef MQTT_SOCKET_TIMEOUT +#define MQTT_SOCKET_TIMEOUT 62 +#endif + +// MQTT_MAX_TRANSFER_SIZE : limit how much data is passed to the network client +// in each write call. Needed for the Arduino Wifi Shield. Leave undefined to +// pass the entire MQTT packet in each write call. +//#define MQTT_MAX_TRANSFER_SIZE 80 + +// Possible values for client.state() +#define MQTT_CONNECTION_TIMEOUT -4 +#define MQTT_CONNECTION_LOST -3 +#define MQTT_CONNECT_FAILED -2 +#define MQTT_DISCONNECTED -1 +#define MQTT_CONNECTED 0 +#define MQTT_CONNECT_BAD_PROTOCOL 1 +#define MQTT_CONNECT_BAD_CLIENT_ID 2 +#define MQTT_CONNECT_UNAVAILABLE 3 +#define MQTT_CONNECT_BAD_CREDENTIALS 4 +#define MQTT_CONNECT_UNAUTHORIZED 5 + +#define MQTTCONNECT 1 << 4 // Client request to connect to Server +#define MQTTCONNACK 2 << 4 // Connect Acknowledgment +#define MQTTPUBLISH 3 << 4 // Publish message +#define MQTTPUBACK 4 << 4 // Publish Acknowledgment +#define MQTTPUBREC 5 << 4 // Publish Received (assured delivery part 1) +#define MQTTPUBREL 6 << 4 // Publish Release (assured delivery part 2) +#define MQTTPUBCOMP 7 << 4 // Publish Complete (assured delivery part 3) +#define MQTTSUBSCRIBE 8 << 4 // Client Subscribe request +#define MQTTSUBACK 9 << 4 // Subscribe Acknowledgment +#define MQTTUNSUBSCRIBE 10 << 4 // Client Unsubscribe request +#define MQTTUNSUBACK 11 << 4 // Unsubscribe Acknowledgment +#define MQTTPINGREQ 12 << 4 // PING Request +#define MQTTPINGRESP 13 << 4 // PING Response +#define MQTTDISCONNECT 14 << 4 // Client is Disconnecting +#define MQTTReserved 15 << 4 // Reserved + +#define MQTTQOS0 (0 << 1) +#define MQTTQOS1 (1 << 1) +#define MQTTQOS2 (2 << 1) + +#ifdef ESP8266 +#include +#define MQTT_CALLBACK_SIGNATURE std::function callback +#else +#define MQTT_CALLBACK_SIGNATURE void (*callback)(char*, uint8_t*, unsigned int) +#endif + +class PubSubClient { +private: + Client* _client; + uint8_t buffer[MQTT_MAX_PACKET_SIZE]; + uint16_t nextMsgId; + unsigned long lastOutActivity; + unsigned long lastInActivity; + bool pingOutstanding; + MQTT_CALLBACK_SIGNATURE; + uint16_t readPacket(uint8_t*); + boolean readByte(uint8_t * result); + boolean readByte(uint8_t * result, uint16_t * index); + boolean write(uint8_t header, uint8_t* buf, uint16_t length); + uint16_t writeString(const char* string, uint8_t* buf, uint16_t pos); + IPAddress ip; + const char* domain; + uint16_t port; + Stream* stream; + int _state; +public: + PubSubClient(); + PubSubClient(Client& client); + PubSubClient(IPAddress, uint16_t, Client& client); + PubSubClient(IPAddress, uint16_t, Client& client, Stream&); + PubSubClient(IPAddress, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client); + PubSubClient(IPAddress, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, Stream&); + PubSubClient(uint8_t *, uint16_t, Client& client); + PubSubClient(uint8_t *, uint16_t, Client& client, Stream&); + PubSubClient(uint8_t *, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client); + PubSubClient(uint8_t *, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, Stream&); + PubSubClient(const char*, uint16_t, Client& client); + PubSubClient(const char*, uint16_t, Client& client, Stream&); + PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client); + PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, Stream&); + + PubSubClient& setServer(IPAddress ip, uint16_t port); + PubSubClient& setServer(uint8_t * ip, uint16_t port); + PubSubClient& setServer(const char * domain, uint16_t port); + PubSubClient& setCallback(MQTT_CALLBACK_SIGNATURE); + PubSubClient& setClient(Client& client); + PubSubClient& setStream(Stream& stream); + + boolean connect(const char* id); + boolean connect(const char* id, const char* user, const char* pass); + boolean connect(const char* id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage); + boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage); + void disconnect(); + boolean publish(const char* topic, const char* payload); + boolean publish(const char* topic, const char* payload, boolean retained); + boolean publish(const char* topic, const uint8_t * payload, unsigned int plength); + boolean publish(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained); + boolean publish_P(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained); + boolean subscribe(const char* topic); + boolean subscribe(const char* topic, uint8_t qos); + boolean unsubscribe(const char* topic); + boolean loop(); + boolean connected(); + int state(); +}; + + +#endif diff --git a/wled00/wled00.ino b/wled00/wled00.ino index 2ca91399..1f587a5b 100644 --- a/wled00/wled00.ino +++ b/wled00/wled00.ino @@ -1,16 +1,19 @@ /* - * Main sketch + * Main sketch, global variable declarations */ /* * @title WLED project sketch - * @version 0.7.1 + * @version 0.8.0 * @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) to compile for ESP8266-01 +//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 + +//library inclusions #include #ifdef ARDUINO_ARCH_ESP32 #include @@ -23,6 +26,7 @@ #include #include #endif + #include #include #include @@ -31,155 +35,246 @@ #include "src/dependencies/time/Time.h" #include "src/dependencies/time/TimeLib.h" #include "src/dependencies/timezone/Timezone.h" +#include "src/dependencies/blynk/BlynkSimpleEsp.h" +#include "src/dependencies/e131/E131.h" +#include "src/dependencies/pubsubclient/PubSubClient.h" #include "htmls00.h" #include "htmls01.h" #include "htmls02.h" #include "WS2812FX.h" -#include "src/dependencies/blynk/BlynkSimpleEsp.h" -#include "src/dependencies/e131/E131.h" -//version in format yymmddb (b = daily build) -#define VERSION 1808311 -char versionString[] = "0.7.1"; -//AP and OTA default passwords (change them!) +//version code in format yymmddb (b = daily build) +#define VERSION 1810151 +char versionString[] = "0.8.0"; + + +//AP and OTA default passwords (for maximum change them!) char apPass[65] = "wled1234"; char otaPass[33] = "wledota"; -//spiffs FS only useful for debug (only ESP8266) -//#define USEFS //to toggle usb serial debug (un)comment following line(s) //#define DEBUG -//Hardware-settings (only changeble via code) -#define PIN 2 //strip pin. Only change for ESP32 -byte buttonPin = 0; //needs pull-up -byte auxPin = 15; //use e.g. for external relay -byte auxDefaultState = 0; //0: input 1: high 2: low -byte auxTriggeredState = 0; //0: input 1: high 2: low -//Default CONFIG -char serverDescription[33] = "WLED Light"; -byte currentTheme = 0; -byte uiConfiguration = 0; //0: auto 1: classic 2: mobile +//spiffs FS only useful for debug (only ESP8266) +//#define USEFS + + +//Hardware CONFIG (only changeble HERE, not at runtime) +//LED strip pin changeable in NpbWrapper.h. Only change for ESP32 +byte buttonPin = 0; //needs pull-up +byte auxPin = 15; //debug feature, use e.g. for external relay with API call AX= +byte auxDefaultState = 0; //0: input 1: high 2: low +byte auxTriggeredState = 0; //0: input 1: high 2: low +char ntpServerName[] = "0.wled.pool.ntp.org"; //NTP server to use + + +//WiFi CONFIG (all these can be changed via web UI, no need to set them here) char clientSSID[33] = "Your_Network"; char clientPass[65] = ""; -char cmDNS[33] = "led"; -uint16_t ledCount = 10; //lowered to prevent accidental overcurrent -char apSSID[65] = ""; //AP off by default (unless setup) -byte apChannel = 1; -byte apHide = 0; -byte apWaitTimeSecs = 32; -bool recoveryAPDisabled = false; -IPAddress staticIP(0, 0, 0, 0); -IPAddress staticGateway(0, 0, 0, 0); -IPAddress staticSubnet(255, 255, 255, 0); -IPAddress staticDNS(8, 8, 8, 8); //only for NTP -bool useHSB = true, useHSBDefault = true, useRGBW = false, autoRGBtoRGBW = false; -bool turnOnAtBoot = true; -bool initLedsLast = false, skipFirstLed = false; -byte bootPreset = 0; -byte colS[]{255, 159, 0}; -byte colSecS[]{0, 0, 0}; -byte whiteS = 0; -byte whiteSecS = 0; -byte briS = 127; -byte nightlightTargetBri = 0; -bool fadeTransition = true; -bool sweepTransition = false, sweepDirection = true; -bool disableSecTransition = true; -uint16_t transitionDelay = 1200, transitionDelayDefault = transitionDelay; -bool reverseMode = false; -bool otaLock = false, wifiLock = false; -bool aOtaEnabled = true; -bool buttonEnabled = true; -bool notifyDirect = true, notifyButton = true, notifyDirectDefault = true, alexaNotify = false, macroNotify = false, notifyTwice = false; -bool receiveNotifications = true, receiveNotificationBrightness = true, receiveNotificationColor = true, receiveNotificationEffects = true; -byte briMultiplier = 100; -byte nightlightDelayMins = 60; -bool nightlightFade = true; -uint16_t udpPort = 21324, udpRgbPort = 19446; -byte effectDefault = 0; +char cmDNS[33] = "led"; //mDNS address (x.local), only for Apple and Windows, if Bonjour installed +char apSSID[65] = ""; //AP off by default (unless setup) +byte apChannel = 1; //2.4GHz WiFi AP channel (1-13) +byte apHide = 0; //hidden AP SSID +byte apWaitTimeSecs = 32; //time to wait for connection before opening AP +bool recoveryAPDisabled = false; //never open AP (not recommended) +IPAddress staticIP(0, 0, 0, 0); //static IP of ESP +IPAddress staticGateway(0, 0, 0, 0); //gateway (router) IP +IPAddress staticSubnet(255, 255, 255, 0); //most common subnet in home networks +IPAddress staticDNS(8, 8, 8, 8); //only for NTP, google DNS server + + +//LED CONFIG +uint16_t ledCount = 10; //lowered to prevent accidental overcurrent +bool useRGBW = false; //SK6812 strips can contain an extra White channel +bool autoRGBtoRGBW = false; //if RGBW enabled, calculate White channel from RGB +bool turnOnAtBoot = true; //turn on LEDs at power-up +byte bootPreset = 0; //save preset to load after power-up + +byte colS[]{255, 159, 0}; //default RGB color +byte colSecS[]{0, 0, 0}; //default RGB secondary color +byte whiteS = 0; //default White channel +byte whiteSecS = 0; //default secondary White channel +byte briS = 127; //default brightness +byte effectDefault = 0; byte effectSpeedDefault = 75; -byte effectIntensityDefault = 128; -//NTP stuff -bool ntpEnabled = false; -char ntpServerName[] = "0.wled.pool.ntp.org"; -//custom chase -byte ccNumPrimary = 2; -byte ccNumSecondary = 4; -byte ccIndex1 = 0; -uint16_t ccIndex2 = ledCount -1; -bool ccFromStart = true, ccFromEnd = false; -byte ccStep = 1; -byte ccStart = 0; +byte effectIntensityDefault = 128; //intensity is supported on some effects as an additional parameter (e.g. for blink you can change the duty cycle) +byte effectPaletteDefault = 0; //palette is supported on the FastLED effects, otherwise it has no effect -//alexa -bool alexaEnabled = true; -char alexaInvocationName[33] = "Light"; +bool useGammaCorrectionBri = false; //gamma correct brightness (not recommended) +bool useGammaCorrectionRGB = true; //gamma correct colors (strongly recommended) -byte macroBoot = 0, macroNl = 0; +byte nightlightTargetBri = 0; //brightness after nightlight is over +byte nightlightDelayMins = 60; +bool nightlightFade = true; //if enabled, light will gradually dim towards the target bri. Otherwise, it will instantly set after delay over +bool fadeTransition = true; //enable crossfading color transition +bool enableSecTransition = true; //also enable transition for secondary color +uint16_t transitionDelay = 900; //default crossfade duration in ms + +bool reverseMode = false; //flip entire LED strip (reverses all effect directions) +bool initLedsLast = false; //turn on LEDs only after WiFi connected/AP open +bool skipFirstLed = false; //ignore first LED in strip (useful if you need the LED as signal repeater) +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) + + +//User Interface CONFIG +char serverDescription[33] = "WLED Light"; //Name of module +byte currentTheme = 0; //UI theme index for settings and classic UI +byte uiConfiguration = 0; //0: automatic (depends on user-agent) 1: classic UI 2: mobile UI +bool useHSB = true; //classic UI: use HSB sliders instead of RGB by default +char cssFont[33] = "Verdana"; //font to use in classic UI + +bool useHSBDefault = useHSB; + + +//Sync CONFIG +bool buttonEnabled = true; + +uint16_t udpPort = 21324; //WLED notifier default port +uint16_t udpRgbPort = 19446; //Hyperion port + +bool receiveNotificationBrightness = true; //apply brightness from incoming notifications +bool receiveNotificationColor = true; //apply color +bool receiveNotificationEffects = true; //apply effects setup +bool notifyDirect = true; //send notification if change via UI or HTTP API +bool notifyButton = true; +bool notifyAlexa = false; //send notification if updated via Alexa +bool notifyMacro = false; //send notification for macro +bool notifyHue = true; //send notification if Hue light changes +bool notifyTwice = false; //notifications use UDP: enable if devices don't sync reliably + +bool alexaEnabled = true; //enable device discovery by Amazon Echo +char alexaInvocationName[33] = "Light"; //speech control name of device. Choose something voice-to-text can understand + +char blynkApiKey[36] = ""; //Auth token for Blynk server. If empty, no connection will be made + +uint16_t realtimeTimeoutMs = 2500; //ms timeout of realtime mode before returning to normal mode +int arlsOffset = 0; //realtime LED offset +bool receiveDirect = true; //receive UDP realtime +bool enableRealtimeUI = false; //web UI accessible during realtime mode (works on ESP32, lags out ESP8266) +bool arlsDisableGammaCorrection = true; //activate if gamma correction is handled by the source +bool arlsForceMaxBri = false; //enable to force max brightness if source has very dark colors that would be black + +bool e131Enabled = true; //settings for E1.31 (sACN) protocol +uint16_t e131Universe = 1; +bool e131Multicast = false; + +char mqttDeviceTopic[33] = ""; //main MQTT topic (individual per device, default is wled/mac) +char mqttGroupTopic[33] = "wled/all"; //second MQTT topic (for example to group devices) +char mqttServer[33] = ""; //both domains and IPs should work (no SSL) + +bool huePollingEnabled = false; //poll hue bridge for light state +uint16_t huePollIntervalMs = 2500; //low values (< 1sec) may cause lag but offer quicker response +char hueApiKey[47] = "api"; //key token will be obtained from bridge +byte huePollLightId = 1; //ID of hue lamp to sync to. Find the ID in the hue app ("about" section) +IPAddress hueIP = (0,0,0,0); //IP address of the bridge +bool hueApplyOnOff = true; +bool hueApplyBri = true; +bool hueApplyColor = true; + + +//Time CONFIG +bool ntpEnabled = false; //get internet time. Only required if you use clock overlays or time-activated macros +bool useAMPM = false; //12h/24h clock format +byte currentTimezone = 0; //Timezone ID. Refer to timezones array in wled10_ntp.ino +int utcOffsetSecs = 0; //Seconds to offset from UTC before timzone calculation + +byte overlayDefault = 0; //0: no overlay 1: analog clock 2: single-digit clocl 3: cronixie +byte overlayMin = 0, overlayMax = ledCount-1; //boundaries of overlay mode + +byte analogClock12pixel = 0; //The pixel in your strip where "midnight" would be +bool analogClockSecondsTrail = false; //Display seconds as trail of LEDs instead of a single pixel +bool analogClock5MinuteMarks = false; //Light pixels at every 5-minute position + +char cronixieDisplay[7] = "HHMMSS"; //Cronixie Display mask. See wled13_cronixie.ino +bool cronixieBacklight = true; //Allow digits to be back-illuminated + +bool countdownMode = false; //Clock will count down towards date +byte countdownYear = 19, countdownMonth = 1; //Countdown target date, year is last two digits +byte countdownDay = 1, countdownHour = 0; +byte countdownMin = 0, countdownSec = 0; + + +byte macroBoot = 0; //macro loaded after startup +byte macroNl = 0; //after nightlight delay over +byte macroCountdown = 0; byte macroAlexaOn = 0, macroAlexaOff = 0; -byte macroButton = 0, macroCountdown = 0, macroLongPress = 0; +byte macroButton = 0, macroLongPress = 0; -unsigned long countdownTime = 1514764800L; -//hue -bool huePollingEnabled = false, hueAttempt = false; -uint16_t huePollIntervalMs = 2500; -char hueApiKey[65] = "api"; -byte huePollLightId = 1; -IPAddress hueIP = (0,0,0,0); -bool notifyHue = true; -bool hueApplyOnOff = true, hueApplyBri = true, hueApplyColor = true; +//Security CONFIG +bool otaLock = false; //prevents OTA firmware updates without password. ALWAYS enable if system exposed to any public networks +bool wifiLock = false; //prevents access to WiFi settings when OTA lock is enabled +bool aOtaEnabled = true; //ArduinoOTA allows easy updates directly from the IDE. Careful, it does not auto-disable when OTA lock is on + uint16_t userVar0 = 0, userVar1 = 0; -//Internal vars -byte col[]{0, 0, 0}; -byte colOld[]{0, 0, 0}; -byte colT[]{0, 0, 0}; -byte colIT[]{0, 0, 0}; + + +//internal global variable declarations +//color +byte col[]{255, 159, 0}; //target RGB color +byte colOld[]{0, 0, 0}; //color before transition +byte colT[]{0, 0, 0}; //current color +byte colIT[]{0, 0, 0}; //color that was last sent to LEDs byte colSec[]{0, 0, 0}; byte colSecT[]{0, 0, 0}; byte colSecOld[]{0, 0, 0}; byte colSecIT[]{0, 0, 0}; -byte white = 0, whiteOld, whiteT, whiteIT; -byte whiteSec = 0, whiteSecOld, whiteSecT, whiteSecIT; -byte lastRandomIndex = 0; +byte white = whiteS, whiteOld, whiteT, whiteIT; +byte whiteSec = whiteSecS, whiteSecOld, whiteSecT, whiteSecIT; + +byte lastRandomIndex = 0; //used to save last random color so the new one is not the same + +//transitions +bool transitionActive = false; +uint16_t transitionDelayDefault = transitionDelay; uint16_t transitionDelayTemp = transitionDelay; unsigned long transitionStartTime; -unsigned long nightlightStartTime; -float tperLast = 0; -byte bri = 0; -byte briOld = 0; -byte briT = 0; -byte briIT = 0; -byte briLast = 127; -bool transitionActive = false; -bool buttonPressedBefore = false; -unsigned long buttonPressedTime = 0; -unsigned long notificationSentTime = 0; -byte notificationSentCallMode = 0; -bool notificationTwoRequired = false; +float tperLast = 0; //crossfade transition progress, 0.0f - 1.0f + +//nightlight bool nightlightActive = false; bool nightlightActiveOld = false; uint32_t nightlightDelayMs = 10; -byte briNlT = 0; -byte effectCurrent = 0; -byte effectSpeed = 75; -byte effectIntensity = 128; -bool onlyAP = false; +unsigned long nightlightStartTime; +byte briNlT = 0; //current nightlight brightness + +//brightness +byte bri = briS; +byte briOld = 0; +byte briT = 0; +byte briIT = 0; +byte briLast = 127; //brightness before turned off. Used for toggle function + +//button +bool buttonPressedBefore = false; +unsigned long buttonPressedTime = 0; + +//notifications +bool notifyDirectDefault = notifyDirect; +bool receiveNotifications = true; +unsigned long notificationSentTime = 0; +byte notificationSentCallMode = 0; +bool notificationTwoRequired = false; + +//effects +byte effectCurrent = effectDefault; +byte effectSpeed = effectSpeedDefault; +byte effectIntensity = effectIntensityDefault; +byte effectPalette = effectPaletteDefault; + +//network +bool onlyAP = false; //only Access Point active, no connection to home network bool udpConnected = false, udpRgbConnected = false; -char cssCol[9][5]={"","","","","",""}; -char cssFont[33]="Verdana"; + +//ui style +char cssCol[6][9]={"","","","","",""}; String cssColorString=""; -//NTP stuff -bool ntpConnected = false; -byte currentTimezone = 0; -time_t local = 0; -int utcOffsetSecs = 0; +bool showWelcomePage = false; //hue char hueError[25] = "Inactive"; @@ -187,25 +282,12 @@ uint16_t hueFailCount = 0; float hueXLast=0, hueYLast=0; uint16_t hueHueLast=0, hueCtLast=0; byte hueSatLast=0, hueBriLast=0; -long hueLastRequestSent = 0; -uint32_t huePollIntervalMsTemp = huePollIntervalMs; +unsigned long hueLastRequestSent = 0; +unsigned long huePollIntervalMsTemp = huePollIntervalMs; +bool hueAttempt = false; -//blynk -char blynkApiKey[36] = ""; -bool blynkEnabled = false; - -//e1.31 -bool e131Enabled = true; -byte e131Universe = 1; -bool e131Multicast = false; - -//overlay stuff -byte overlayDefault = 0; -byte overlayCurrent = 0; -byte overlayMin = 0, overlayMax = ledCount-1; -byte analogClock12pixel = 0; -bool analogClockSecondsTrail = false; -bool analogClock5MinuteMarks = false; +//overlays +byte overlayCurrent = overlayDefault; byte overlaySpeed = 200; unsigned long overlayRefreshMs = 200; unsigned long overlayRefreshedTime; @@ -213,40 +295,54 @@ int overlayArr[6]; uint16_t overlayDur[6]; uint16_t overlayPauseDur[6]; int nixieClockI = -1; -bool nixiePause; -byte countdownYear=19, countdownMonth=1, countdownDay=1, countdownHour=0, countdownMin=0, countdownSec=0; //year is actual year -2000 -bool countdownOverTriggered = true; +bool nixiePause = false; + //cronixie -char cronixieDisplay[] = "HHMMSS"; byte dP[]{0,0,0,0,0,0}; -bool useAMPM = false; -bool cronixieBacklight = true; -bool countdownMode = false; bool cronixieInit = false; +//countdown +unsigned long countdownTime = 1514764800L; +bool countdownOverTriggered = true; + +//timer +byte lastTimerMinute = 0; +byte timerHours[] = {0,0,0,0,0,0,0,0}; +byte timerMinutes[] = {0,0,0,0,0,0,0,0}; +byte timerMacro[] = {0,0,0,0,0,0,0,0}; +byte timerWeekday[] = {255,255,255,255,255,255,255,255}; //weekdays to activate on +//bit pattern of arr elem: 0b11111111: sat,fri,thu,wed,tue,mon,sun,validity + +//blynk +bool blynkEnabled = false; + +//preset cycling bool presetCyclingEnabled = false; byte presetCycleMin = 1, presetCycleMax = 5; uint16_t presetCycleTime = 1250; unsigned long presetCycledTime = 0; byte presetCycCurr = presetCycleMin; bool presetApplyBri = true, presetApplyCol = true, presetApplyFx = true; bool saveCurrPresetCycConf = false; -uint16_t arlsTimeoutMillis = 2500; -bool arlsTimeout = false; -bool receiveDirect = true, enableRealtimeUI = false; -bool arlsDisableGammaCorrection = true, arlsForceMaxBri = false; + +//realtime +bool realtimeActive = false; IPAddress realtimeIP = (0,0,0,0); -unsigned long arlsTimeoutTime = 0; +unsigned long realtimeTimeout = 0; + +//mqtt +bool mqttInit = false; +long lastMQTTReconnectAttempt = 0; +long lastInterfaceUpdate = 0; +byte interfaceUpdateCallMode = 0; +uint32_t mqttFailedConAttempts = 0; + +//auxiliary debug pin byte auxTime = 0; unsigned long auxStartTime = 0; bool auxActive = false, auxActiveBefore = false; -bool showWelcomePage = false; - -bool useGammaCorrectionBri = false; -bool useGammaCorrectionRGB = true; -int arlsOffset = 0; //alexa udp -WiFiUDP UDP; +WiFiUDP alexaUDP; IPAddress ipMulti(239, 255, 255, 250); unsigned int portMulti = 1900; String escapedMac; @@ -255,50 +351,61 @@ String escapedMac; DNSServer dnsServer; bool dnsActive = false; +//network time +bool ntpConnected = false; +time_t local = 0; +unsigned long ntpLastSyncTime = 999000000L; +unsigned long ntpPacketSentTime = 999000000L; +IPAddress ntpServerIP; +unsigned int ntpLocalPort = 2390; +#define NTP_PACKET_SIZE 48 + //string temp buffer #define OMAX 1750 char obuf[OMAX]; uint16_t olen = 0; +//server library objects #ifdef ARDUINO_ARCH_ESP32 WebServer server(80); #else ESP8266WebServer server(80); #endif -E131 e131; -HTTPClient hueClient; +HTTPClient* hueClient = NULL; +WiFiClient* mqttTCPClient = NULL; +PubSubClient* mqtt = NULL; + ESP8266HTTPUpdateServer httpUpdater; + +//udp interface objects WiFiUDP notifierUdp, rgbUdp; WiFiUDP ntpUdp; -IPAddress ntpServerIP; -unsigned int ntpLocalPort = 2390; -#define NTP_PACKET_SIZE 48 -unsigned long ntpLastSyncTime = 999000000L; -unsigned long ntpPacketSentTime = 999000000L; +E131* e131; +//led fx library object WS2812FX strip = WS2812FX(); +//debug macros #ifdef DEBUG #define DEBUG_PRINT(x) Serial.print (x) #define DEBUG_PRINTLN(x) Serial.println (x) #define DEBUG_PRINTF(x) Serial.printf (x) + unsigned long debugTime = 0; + int lastWifiState = 3; + unsigned long wifiStateChangedTime = 0; #else #define DEBUG_PRINT(x) #define DEBUG_PRINTLN(x) #define DEBUG_PRINTF(x) #endif +//filesystem #ifdef USEFS #include ; File fsUploadFile; #endif -#ifdef DEBUG -long debugTime = 0; -int lastWifiState = 3; -long wifiStateChangedTime = 0; -#endif - +//gamma 2.4 lookup table used for color correction const byte gamma8[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, @@ -319,8 +426,11 @@ const byte gamma8[] = { String txd = "Please disable OTA Lock in security settings!"; +//function prototypes void serveMessage(int,String,String,int=255); + +//turns all LEDs off and restarts ESP void reset() { briT = 0; @@ -329,7 +439,9 @@ void reset() ESP.restart(); } -bool oappend(char* txt) //append new c string to temp buffer efficiently + +//append new c string to temp buffer efficiently +bool oappend(char* txt) { uint16_t len = strlen(txt); if (olen + len >= OMAX) return false; //buffer full @@ -338,39 +450,57 @@ bool oappend(char* txt) //append new c string to temp buffer efficiently return true; } -bool oappendi(int i) //append new number to temp buffer efficiently + +//append new number to temp buffer efficiently +bool oappendi(int i) { char s[11]; sprintf(s,"%ld", i); return oappend(s); } + +//boot starts here void setup() { wledInit(); } + +//main program loop void loop() { server.handleClient(); handleSerial(); handleNotifications(); handleTransitions(); userLoop(); + yield(); handleButton(); handleNetworkTime(); - if (aOtaEnabled) ArduinoOTA.handle(); - handleAlexa(); + if (!onlyAP) + { + handleAlexa(); + handleMQTT(); + } + handleOverlays(); - if (!arlsTimeout) //block stuff if WARLS/Adalight is enabled + + yield(); + + + if (!realtimeActive) //block stuff if WARLS/Adalight is enabled { if (dnsActive) dnsServer.processNextRequest(); - handleHue(); + if (aOtaEnabled) ArduinoOTA.handle(); handleNightlight(); - handleBlynk(); + if (!onlyAP) { + handleHue(); + handleBlynk(); + } if (briT) strip.service(); //do not update strip if off, prevents flicker on ESP32 } - //DEBUG + //DEBUG serial logging #ifdef DEBUG if (millis() - debugTime > 5000) { @@ -384,7 +514,7 @@ void loop() { wifiStateChangedTime = millis(); } lastWifiState = WiFi.status(); - DEBUG_PRINT("Wifi state: "); DEBUG_PRINTLN(wifiStateChangedTime); + DEBUG_PRINT("State time: "); DEBUG_PRINTLN(wifiStateChangedTime); DEBUG_PRINT("NTP last sync: "); DEBUG_PRINTLN(ntpLastSyncTime); DEBUG_PRINT("Client IP: "); DEBUG_PRINTLN(WiFi.localIP()); debugTime = millis(); diff --git a/wled00/wled01_eeprom.ino b/wled00/wled01_eeprom.ino index 682b53f0..44260017 100644 --- a/wled00/wled01_eeprom.ino +++ b/wled00/wled01_eeprom.ino @@ -6,7 +6,7 @@ #define EEPSIZE 3072 //eeprom Version code, enables default settings instead of 0 init on update -#define EEPVER 7 +#define EEPVER 9 //0 -> old version, default //1 -> 0.4p 1711272 and up //2 -> 0.4p 1711302 and up @@ -15,6 +15,8 @@ //5 -> 0.5.1 and up //6 -> 0.6.0 and up //7 -> 0.7.1 and up +//8 -> 0.8.0-a and up +//9 -> 0.8.0 /* * Erase all configuration data @@ -28,6 +30,25 @@ void clearEEPROM() EEPROM.commit(); } +void writeStringToEEPROM(uint16_t pos, char* str, uint16_t len) +{ + for (int i = 0; i < len; ++i) + { + EEPROM.write(pos + i, str[i]); + if (str[i] == 0) return; + } +} + +void readStringFromEEPROM(uint16_t pos, char* str, uint16_t len) +{ + for (int i = 0; i < len; ++i) + { + str[i] = EEPROM.read(pos + i); + if (str[i] == 0) return; + } + str[len] = 0; //make sure every string is properly terminated. str must be at least len +1 big. +} + /* * Write configuration to flash */ @@ -39,26 +60,12 @@ void saveSettingsToEEPROM() EEPROM.write(233, 233); } - for (int i = 0; i < 32; ++i) - { - EEPROM.write(i, clientSSID[i]); - } - for (int i = 32; i < 96; ++i) - { - EEPROM.write(i, clientPass[i-32]); - } - for (int i = 96; i < 128; ++i) - { - EEPROM.write(i, cmDNS[i-96]); - } - for (int i = 128; i < 160; ++i) - { - EEPROM.write(i, apSSID[i-128]); - } - for (int i = 160; i < 224; ++i) - { - EEPROM.write(i, apPass[i-160]); - } + writeStringToEEPROM( 0, clientSSID, 32); + writeStringToEEPROM( 32, clientPass, 64); + writeStringToEEPROM( 96, cmDNS, 32); + writeStringToEEPROM(128, apSSID, 32); + writeStringToEEPROM(160, apPass, 64); + EEPROM.write(224, nightlightDelayMins); EEPROM.write(225, nightlightFade); EEPROM.write(226, notifyDirectDefault); @@ -69,96 +76,92 @@ void saveSettingsToEEPROM() EEPROM.write(231, notifyTwice); EEPROM.write(232, buttonEnabled); //233 reserved for first boot flag + for (int i = 0; i<4; i++) //ip addresses { EEPROM.write(234+i, staticIP[i]); EEPROM.write(238+i, staticGateway[i]); EEPROM.write(242+i, staticSubnet[i]); } + EEPROM.write(246, colS[0]); EEPROM.write(247, colS[1]); EEPROM.write(248, colS[2]); EEPROM.write(249, briS); + EEPROM.write(250, receiveNotificationBrightness); EEPROM.write(251, fadeTransition); EEPROM.write(252, reverseMode); EEPROM.write(253, (transitionDelayDefault >> 0) & 0xFF); EEPROM.write(254, (transitionDelayDefault >> 8) & 0xFF); EEPROM.write(255, briMultiplier); + //255,250,231,230,226 notifier bytes - for (int i = 256; i < 288; ++i) - { - EEPROM.write(i, otaPass[i-256]); - } + writeStringToEEPROM(256, otaPass, 32); + EEPROM.write(288, nightlightTargetBri); EEPROM.write(289, otaLock); EEPROM.write(290, (udpPort >> 0) & 0xFF); EEPROM.write(291, (udpPort >> 8) & 0xFF); - for (int i = 292; i < 324; ++i) - { - EEPROM.write(i, serverDescription[i-292]); - } + writeStringToEEPROM(292, serverDescription, 32); + EEPROM.write(324, effectDefault); EEPROM.write(325, effectSpeedDefault); EEPROM.write(326, effectIntensityDefault); + EEPROM.write(327, ntpEnabled); EEPROM.write(328, currentTimezone); EEPROM.write(329, useAMPM); EEPROM.write(330, useGammaCorrectionBri); EEPROM.write(331, useGammaCorrectionRGB); EEPROM.write(332, overlayDefault); + EEPROM.write(333, alexaEnabled); - for (int i = 334; i < 366; ++i) - { - EEPROM.write(i, alexaInvocationName[i-334]); - } - EEPROM.write(366, alexaNotify); + writeStringToEEPROM(334, alexaInvocationName, 32); + EEPROM.write(366, notifyAlexa); + EEPROM.write(367, (arlsOffset>=0)); EEPROM.write(368, abs(arlsOffset)); EEPROM.write(369, turnOnAtBoot); EEPROM.write(370, useHSBDefault); EEPROM.write(371, whiteS); EEPROM.write(372, useRGBW); - EEPROM.write(373, sweepTransition); - EEPROM.write(374, sweepDirection); + EEPROM.write(373, effectPaletteDefault); + EEPROM.write(374, strip.paletteFade); EEPROM.write(375, apWaitTimeSecs); EEPROM.write(376, recoveryAPDisabled); + EEPROM.write(377, EEPVER); //eeprom was updated to latest + EEPROM.write(378, colSecS[0]); EEPROM.write(379, colSecS[1]); EEPROM.write(380, colSecS[2]); EEPROM.write(381, whiteSecS); - EEPROM.write(382, ccIndex1); - EEPROM.write(383, ccIndex2); - EEPROM.write(384, ccNumPrimary); - EEPROM.write(385, ccNumSecondary); - EEPROM.write(386, ccFromStart); - EEPROM.write(387, ccFromEnd); - EEPROM.write(388, ccStep); + EEPROM.write(382, strip.paletteBlend); + EEPROM.write(389, bootPreset); EEPROM.write(390, aOtaEnabled); EEPROM.write(391, receiveNotificationColor); EEPROM.write(392, receiveNotificationEffects); EEPROM.write(393, wifiLock); + EEPROM.write(394, (abs(utcOffsetSecs) >> 0) & 0xFF); EEPROM.write(395, (abs(utcOffsetSecs) >> 8) & 0xFF); EEPROM.write(396, (utcOffsetSecs<0)); //is negative EEPROM.write(397, initLedsLast); EEPROM.write(398, (ledCount >> 8) & 0xFF); - EEPROM.write(399, disableSecTransition); + EEPROM.write(399, !enableSecTransition); + + //favorite setting (preset) memory (25 slots/ each 20byte) + //400 - 899 reserved for (int k=0;k<6;k++){ int in = 900+k*8; - for (int i=in; i < in+8; ++i) - { - EEPROM.write(i, cssCol[i-in][k]); - }} + writeStringToEEPROM(in, cssCol[k], 8); + } EEPROM.write(948,currentTheme); - for (int i = 950; i < 982; ++i) - { - EEPROM.write(i, cssFont[i-950]); - } + writeStringToEEPROM(950, cssFont, 32); EEPROM.write(2048, huePollingEnabled); //EEPROM.write(2049, hueUpdatingEnabled); @@ -166,10 +169,7 @@ void saveSettingsToEEPROM() { EEPROM.write(i, hueIP[i-2050]); } - for (int i = 2054; i < 2100; ++i) - { - EEPROM.write(i, hueApiKey[i-2054]); - } + writeStringToEEPROM(2054, hueApiKey, 46); EEPROM.write(2100, (huePollIntervalMs >> 0) & 0xFF); EEPROM.write(2101, (huePollIntervalMs >> 8) & 0xFF); EEPROM.write(2102, notifyHue); @@ -183,6 +183,7 @@ void saveSettingsToEEPROM() EEPROM.write(2152, analogClock12pixel); EEPROM.write(2153, analogClock5MinuteMarks); EEPROM.write(2154, analogClockSecondsTrail); + EEPROM.write(2155, countdownMode); EEPROM.write(2156, countdownYear); EEPROM.write(2157, countdownMonth); @@ -192,10 +193,7 @@ void saveSettingsToEEPROM() EEPROM.write(2161, countdownSec); setCountdown(); - for (int i = 2165; i < 2171; ++i) - { - EEPROM.write(i, cronixieDisplay[i-2165]); - } + writeStringToEEPROM(2165, cronixieDisplay, 6); EEPROM.write(2171, cronixieBacklight); setCronixie(); @@ -210,34 +208,43 @@ void saveSettingsToEEPROM() EEPROM.write(2190, (e131Universe >> 0) & 0xFF); EEPROM.write(2191, (e131Universe >> 8) & 0xFF); EEPROM.write(2192, e131Multicast); - EEPROM.write(2193, (arlsTimeoutMillis >> 0) & 0xFF); - EEPROM.write(2194, (arlsTimeoutMillis >> 8) & 0xFF); + EEPROM.write(2193, (realtimeTimeoutMs >> 0) & 0xFF); + EEPROM.write(2194, (realtimeTimeoutMs >> 8) & 0xFF); EEPROM.write(2195, arlsForceMaxBri); EEPROM.write(2196, arlsDisableGammaCorrection); - EEPROM.write(2200,!receiveDirect); - EEPROM.write(2201,enableRealtimeUI); - EEPROM.write(2202,uiConfiguration); - EEPROM.write(2203,autoRGBtoRGBW); - EEPROM.write(2204,skipFirstLed); + EEPROM.write(2200, !receiveDirect); + EEPROM.write(2201, enableRealtimeUI); + EEPROM.write(2202, uiConfiguration); + EEPROM.write(2203, autoRGBtoRGBW); + EEPROM.write(2204, skipFirstLed); if (saveCurrPresetCycConf) { - EEPROM.write(2205,presetCyclingEnabled); - EEPROM.write(2206,(presetCycleTime >> 0) & 0xFF); - EEPROM.write(2207,(presetCycleTime >> 8) & 0xFF); - EEPROM.write(2208,presetCycleMin); - EEPROM.write(2209,presetCycleMax); - EEPROM.write(2210,presetApplyBri); - EEPROM.write(2211,presetApplyCol); - EEPROM.write(2212,presetApplyFx); + EEPROM.write(2205, presetCyclingEnabled); + EEPROM.write(2206, (presetCycleTime >> 0) & 0xFF); + EEPROM.write(2207, (presetCycleTime >> 8) & 0xFF); + EEPROM.write(2208, presetCycleMin); + EEPROM.write(2209, presetCycleMax); + EEPROM.write(2210, presetApplyBri); + EEPROM.write(2211, presetApplyCol); + EEPROM.write(2212, presetApplyFx); saveCurrPresetCycConf = false; } - for (int i = 2220; i < 2255; ++i) + writeStringToEEPROM(2220, blynkApiKey, 35); + + for (int i = 0; i < 8; ++i) { - EEPROM.write(i, blynkApiKey[i-2220]); + EEPROM.write(2260 + i, timerHours[i] ); + EEPROM.write(2270 + i, timerMinutes[i]); + EEPROM.write(2280 + i, timerWeekday[i]); + EEPROM.write(2290 + i, timerMacro[i] ); } + + writeStringToEEPROM(2300, mqttServer, 32); + writeStringToEEPROM(2333, mqttDeviceTopic, 32); + writeStringToEEPROM(2366, mqttGroupTopic, 32); EEPROM.commit(); } @@ -254,47 +261,28 @@ void loadSettingsFromEEPROM(bool first) } int lastEEPROMversion = EEPROM.read(377); //last EEPROM version before update - for (int i = 0; i < 32; ++i) - { - clientSSID[i] = EEPROM.read(i); - if (clientSSID[i] == 0) break; - } - for (int i = 32; i < 96; ++i) - { - clientPass[i-32] = EEPROM.read(i); - if (clientPass[i-32] == 0) break; - } - - for (int i = 96; i < 128; ++i) - { - cmDNS[i-96] = EEPROM.read(i); - if (cmDNS[i-96] == 0) break; - } + readStringFromEEPROM( 0, clientSSID, 32); + readStringFromEEPROM( 32, clientPass, 64); + readStringFromEEPROM( 96, cmDNS, 32); + readStringFromEEPROM(128, apSSID, 32); + readStringFromEEPROM(160, apPass, 64); - for (int i = 128; i < 160; ++i) - { - apSSID[i-128] = EEPROM.read(i); - if (apSSID[i-128] == 0) break; - } - - for (int i = 160; i < 224; ++i) - { - apPass[i-160] = EEPROM.read(i); - if (apPass[i-160] == 0) break; - } nightlightDelayMins = EEPROM.read(224); nightlightFade = EEPROM.read(225); notifyDirectDefault = EEPROM.read(226); notifyDirect = notifyDirectDefault; + apChannel = EEPROM.read(227); if (apChannel > 13 || apChannel < 1) apChannel = 1; apHide = EEPROM.read(228); if (apHide > 1) apHide = 1; ledCount = ((EEPROM.read(229) << 0) & 0xFF) + ((EEPROM.read(398) << 8) & 0xFF00); if (ledCount > 1200 || ledCount == 0) ledCount = 10; + notifyButton = EEPROM.read(230); notifyTwice = EEPROM.read(231); buttonEnabled = EEPROM.read(232); + staticIP[0] = EEPROM.read(234); staticIP[1] = EEPROM.read(235); staticIP[2] = EEPROM.read(236); @@ -307,6 +295,7 @@ void loadSettingsFromEEPROM(bool first) staticSubnet[1] = EEPROM.read(243); staticSubnet[2] = EEPROM.read(244); staticSubnet[3] = EEPROM.read(245); + colS[0] = EEPROM.read(246); col[0] = colS[0]; colS[1] = EEPROM.read(247); col[1] = colS[1]; colS[2] = EEPROM.read(248); col[2] = colS[2]; @@ -322,20 +311,14 @@ void loadSettingsFromEEPROM(bool first) transitionDelay = transitionDelayDefault; briMultiplier = EEPROM.read(255); - for (int i = 256; i < 288; ++i) - { - otaPass[i-256] = EEPROM.read(i); - if (otaPass[i-256] == 0) break; - } + readStringFromEEPROM(256, otaPass, 32); + nightlightTargetBri = EEPROM.read(288); otaLock = EEPROM.read(289); udpPort = ((EEPROM.read(290) << 0) & 0xFF) + ((EEPROM.read(291) << 8) & 0xFF00); - for (int i = 292; i < 324; ++i) - { - serverDescription[i-292] = EEPROM.read(i); - if (serverDescription[i-292] == 0) break; - } + readStringFromEEPROM(292, serverDescription, 32); + effectDefault = EEPROM.read(324); effectCurrent = effectDefault; effectSpeedDefault = EEPROM.read(325); effectSpeed = effectSpeedDefault; ntpEnabled = EEPROM.read(327); @@ -344,22 +327,22 @@ void loadSettingsFromEEPROM(bool first) useGammaCorrectionBri = EEPROM.read(330); useGammaCorrectionRGB = EEPROM.read(331); overlayDefault = EEPROM.read(332); + if (lastEEPROMversion < 8 && overlayDefault > 0) overlayDefault--; //overlay mode 1 (solid) was removed + alexaEnabled = EEPROM.read(333); - for (int i = 334; i < 366; ++i) - { - alexaInvocationName[i-334] = EEPROM.read(i); - if (alexaInvocationName[i-334] == 0) break; - } - alexaNotify = EEPROM.read(366); + readStringFromEEPROM(334, alexaInvocationName, 32); + + notifyAlexa = EEPROM.read(366); arlsOffset = EEPROM.read(368); if (!EEPROM.read(367)) arlsOffset = -arlsOffset; turnOnAtBoot = EEPROM.read(369); useHSBDefault = EEPROM.read(370); whiteS = EEPROM.read(371); white = whiteS; useRGBW = EEPROM.read(372); - sweepTransition = EEPROM.read(373); - sweepDirection = EEPROM.read(374); + effectPaletteDefault = EEPROM.read(373); effectPalette = effectPaletteDefault; + //374 - strip.paletteFade + if (lastEEPROMversion > 0) { apWaitTimeSecs = EEPROM.read(375); recoveryAPDisabled = EEPROM.read(376); @@ -369,15 +352,7 @@ void loadSettingsFromEEPROM(bool first) colSecS[0] = EEPROM.read(378); colSec[0] = colSecS[0]; colSecS[1] = EEPROM.read(379); colSec[1] = colSecS[1]; colSecS[2] = EEPROM.read(380); colSec[2] = colSecS[2]; - whiteSecS = EEPROM.read(381); whiteSec = whiteSecS; - ccIndex1 = EEPROM.read(382); - ccIndex2 = EEPROM.read(383); - ccNumPrimary = EEPROM.read(384); - ccNumSecondary = EEPROM.read(385); - ccFromStart = EEPROM.read(386); - ccFromEnd = EEPROM.read(387); - ccStep = EEPROM.read(388); - strip.setCustomChase(ccIndex1, ccIndex2, ccStart, ccNumPrimary, ccNumSecondary, ccStep, ccFromStart, ccFromEnd); + whiteSecS = EEPROM.read(381); whiteSec = whiteSecS; } if (lastEEPROMversion > 3) { effectIntensityDefault = EEPROM.read(326); effectIntensity = effectIntensityDefault; @@ -385,11 +360,7 @@ void loadSettingsFromEEPROM(bool first) receiveNotificationColor = EEPROM.read(391); receiveNotificationEffects = EEPROM.read(392); - for (int i = 950; i < 982; ++i) - { - cssFont[i-950] = EEPROM.read(i); - if (cssFont[i-950] == 0) break; - } + readStringFromEEPROM(950, cssFont, 32); } else //keep receiving notification behavior from pre0.5.0 after update { receiveNotificationColor = receiveNotificationBrightness; @@ -404,11 +375,8 @@ void loadSettingsFromEEPROM(bool first) hueIP[i-2050] = EEPROM.read(i); } - for (int i = 2054; i < 2100; ++i) - { - hueApiKey[i-2054] = EEPROM.read(i); - if (hueApiKey[i-2054] == 0) break; - } + readStringFromEEPROM(2054, hueApiKey, 46); + huePollIntervalMs = ((EEPROM.read(2100) << 0) & 0xFF) + ((EEPROM.read(2101) << 8) & 0xFF00); notifyHue = EEPROM.read(2102); hueApplyOnOff = EEPROM.read(2103); @@ -431,10 +399,7 @@ void loadSettingsFromEEPROM(bool first) countdownSec = EEPROM.read(2161); setCountdown(); - for (int i = 2165; i < 2171; ++i) - { - cronixieDisplay[i-2165] = EEPROM.read(i); - } + readStringFromEEPROM(2165, cronixieDisplay, 6); cronixieBacklight = EEPROM.read(2171); macroBoot = EEPROM.read(2175); @@ -450,10 +415,32 @@ void loadSettingsFromEEPROM(bool first) { e131Universe = ((EEPROM.read(2190) << 0) & 0xFF) + ((EEPROM.read(2191) << 8) & 0xFF00); e131Multicast = EEPROM.read(2192); - arlsTimeoutMillis = ((EEPROM.read(2193) << 0) & 0xFF) + ((EEPROM.read(2194) << 8) & 0xFF00); + realtimeTimeoutMs = ((EEPROM.read(2193) << 0) & 0xFF) + ((EEPROM.read(2194) << 8) & 0xFF00); arlsForceMaxBri = EEPROM.read(2195); arlsDisableGammaCorrection = EEPROM.read(2196); } + + if (lastEEPROMversion > 7) + { + strip.paletteFade = EEPROM.read(374); + strip.paletteBlend = EEPROM.read(382); + + for (int i = 0; i < 8; ++i) + { + timerHours[i] = EEPROM.read(2260 + i); + timerMinutes[i] = EEPROM.read(2270 + i); + timerWeekday[i] = EEPROM.read(2280 + i); + if (timerWeekday[i] == 0) timerWeekday[i] = 255; + timerMacro[i] = EEPROM.read(2290 + i); + } + } + + if (lastEEPROMversion > 8) + { + readStringFromEEPROM(2300, mqttServer, 32); + readStringFromEEPROM(2333, mqttDeviceTopic, 32); + readStringFromEEPROM(2366, mqttGroupTopic, 32); + } receiveDirect = !EEPROM.read(2200); enableRealtimeUI = EEPROM.read(2201); @@ -477,19 +464,13 @@ void loadSettingsFromEEPROM(bool first) presetApplyCol = EEPROM.read(2211); presetApplyFx = EEPROM.read(2212); } - - for (int i = 2220; i < 2255; ++i) - { - blynkApiKey[i-2220] = EEPROM.read(i); - if (blynkApiKey[i-2220] == 0) break; - } bootPreset = EEPROM.read(389); wifiLock = EEPROM.read(393); utcOffsetSecs = ((EEPROM.read(394) << 0) & 0xFF) + ((EEPROM.read(395) << 8) & 0xFF00); if (EEPROM.read(396)) utcOffsetSecs = -utcOffsetSecs; //negative initLedsLast = EEPROM.read(397); - disableSecTransition = EEPROM.read(399); + enableSecTransition = !EEPROM.read(399); //favorite setting (preset) memory (25 slots/ each 20byte) //400 - 899 reserved @@ -497,15 +478,14 @@ void loadSettingsFromEEPROM(bool first) currentTheme = EEPROM.read(948); for (int k=0;k<6;k++){ int in=900+k*8; - for (int i=in; i < in+8; ++i) - { - if (EEPROM.read(i) == 0) break; - cssCol[i-in][k] =EEPROM.read(i); - }} + readStringFromEEPROM(in, cssCol[k], 8); + } //custom macro memory (16 slots/ each 64byte) //1024-2047 reserved + readStringFromEEPROM(2220, blynkApiKey, 35); + //user MOD memory //2944 - 3071 reserved @@ -514,12 +494,13 @@ void loadSettingsFromEEPROM(bool first) strip.setMode(effectCurrent); strip.setSpeed(effectSpeed); strip.setIntensity(effectIntensity); + strip.setPalette(effectPalette); overlayCurrent = overlayDefault; } //PRESET PROTOCOL 20 bytes //0: preset purpose byte 0:invalid 1:valid preset 1.0 -//1:a 2:r 3:g 4:b 5:w 6:er 7:eg 8:eb 9:ew 10:fx 11:sx | custom chase 12:numP 13:numS 14:(0:fs 1:both 2:fe) 15:step 16:ix 17-19:Zeros +//1:a 2:r 3:g 4:b 5:w 6:er 7:eg 8:eb 9:ew 10:fx 11:sx | custom chase 12:numP 13:numS 14:(0:fs 1:both 2:fe) 15:step 16:ix 17: fp 18-19:Zeros void applyPreset(byte index, bool loadBri, bool loadCol, bool loadFX) { @@ -545,15 +526,11 @@ void applyPreset(byte index, bool loadBri, bool loadCol, bool loadFX) effectCurrent = EEPROM.read(i+10); effectSpeed = EEPROM.read(i+11); effectIntensity = EEPROM.read(i+16); - ccNumPrimary = EEPROM.read(i+12); - ccNumSecondary = EEPROM.read(i+13); - ccFromEnd = EEPROM.read(i+14); - ccFromStart = (EEPROM.read(i+14)<2); - ccStep = EEPROM.read(i+15); - strip.setCustomChase(ccIndex1, ccIndex2, ccStart, ccNumPrimary, ccNumSecondary, ccStep, ccFromStart, ccFromEnd); + effectPalette = EEPROM.read(i+17); if (lastfx != effectCurrent) strip.setMode(effectCurrent); strip.setSpeed(effectSpeed); strip.setIntensity(effectIntensity); + strip.setPalette(effectPalette); } } @@ -574,14 +551,9 @@ void savePreset(byte index) EEPROM.write(i+9, whiteSec); EEPROM.write(i+10, effectCurrent); EEPROM.write(i+11, effectSpeed); - EEPROM.write(i+12, ccNumPrimary); - EEPROM.write(i+13, ccNumSecondary); - byte m = 1; - if (!ccFromStart) m = 2; - if (!ccFromEnd) m = 0; - EEPROM.write(i+14, m); - EEPROM.write(i+15, ccStep); + EEPROM.write(i+16, effectIntensity); + EEPROM.write(i+17, effectPalette); EEPROM.commit(); } @@ -606,7 +578,7 @@ void applyMacro(byte index) String mc="win&"; mc += loadMacro(index+1); mc += "&IN"; //internal, no XML response - if (!macroNotify) mc += "&NN"; + if (!notifyMacro) mc += "&NN"; String forbidden = "&M="; //dont apply if called by the macro itself to prevent loop /* * NOTE: loop is still possible if you call a different macro from a macro, which then calls the first macro again. diff --git a/wled00/wled02_xml.ino b/wled00/wled02_xml.ino index 414d5b94..7953f0cd 100644 --- a/wled00/wled02_xml.ino +++ b/wled00/wled02_xml.ino @@ -2,7 +2,7 @@ * Sending XML status files to client */ -void XML_response() +void XML_response(bool isHTTP) { olen = 0; oappend(""); @@ -39,7 +39,9 @@ void XML_response() oappendi(effectSpeed); oappend(""); oappendi(effectIntensity); - oappend(""); + oappend(""); + oappendi(effectPalette); + oappend(""); if (useRGBW && !autoRGBtoRGBW) { oappendi(white); } else { @@ -50,7 +52,7 @@ void XML_response() oappend(""); oappend(serverDescription); oappend(""); - server.send(200, "text/xml", obuf); + if (isHTTP) server.send(200, "text/xml", obuf); } void sappend(char stype, char* key, int val) //append a setting to string buffer @@ -185,17 +187,18 @@ void getSettingsJS(byte subPage) //get values for settings form in javascript sappend('v',"FX",effectDefault); sappend('v',"SX",effectSpeedDefault); sappend('v',"IX",effectIntensityDefault); + sappend('v',"FP",effectPaletteDefault); sappend('c',"GB",useGammaCorrectionBri); sappend('c',"GC",useGammaCorrectionRGB); sappend('c',"TF",fadeTransition); - sappend('c',"TS",sweepTransition); - sappend('c',"TI",!sweepDirection); sappend('v',"TD",transitionDelay); - sappend('c',"T2",!disableSecTransition); + sappend('c',"PF",strip.paletteFade); + sappend('c',"T2",enableSecTransition); sappend('v',"BF",briMultiplier); sappend('v',"TB",nightlightTargetBri); sappend('v',"TL",nightlightDelayMins); sappend('c',"TW",nightlightFade); + sappend('i',"PB",strip.paletteBlend); sappend('c',"RV",reverseMode); sappend('c',"EI",initLedsLast); sappend('c',"SL",skipFirstLed); @@ -230,15 +233,18 @@ void getSettingsJS(byte subPage) //get values for settings form in javascript sappend('c',"RD",receiveDirect); sappend('c',"EM",e131Multicast); sappend('v',"EU",e131Universe); - sappend('v',"ET",arlsTimeoutMillis); + sappend('v',"ET",realtimeTimeoutMs); sappend('c',"FB",arlsForceMaxBri); sappend('c',"RG",arlsDisableGammaCorrection); sappend('v',"WO",arlsOffset); sappend('c',"RU",enableRealtimeUI); sappend('c',"AL",alexaEnabled); sappends('s',"AI",alexaInvocationName); - sappend('c',"SA",alexaNotify); + sappend('c',"SA",notifyAlexa); sappends('s',"BK",(char*)((blynkEnabled)?"Hidden":"")); + sappends('s',"MS",mqttServer); + sappends('s',"MD",mqttDeviceTopic); + sappends('s',"MG",mqttGroupTopic); sappend('v',"H0",hueIP[0]); sappend('v',"H1",hueIP[1]); sappend('v',"H2",hueIP[2]); @@ -289,6 +295,15 @@ void getSettingsJS(byte subPage) //get values for settings form in javascript sappend('v',"ML",macroLongPress); sappend('v',"MC",macroCountdown); sappend('v',"MN",macroNl); + + k[2] = 0; //Time macros + for (int i = 0; i<8; i++) + { + k[1] = 48+i; //ascii 0,1,2,3 + k[0] = 'H'; sappend('v',k,timerHours[i]); + k[0] = 'N'; sappend('v',k,timerMinutes[i]); + k[0] = 'T'; sappend('v',k,timerMacro[i]); + } } if (subPage == 6) diff --git a/wled00/wled03_set.ino b/wled00/wled03_set.ino index a43fac2b..dc048301 100644 --- a/wled00/wled03_set.ino +++ b/wled00/wled03_set.ino @@ -13,6 +13,8 @@ void _setRandomColor(bool _sec,bool fromButton=false) if (fromButton) colorUpdated(2); } + +//called upon POST settings form submit void handleSettingsSet(byte subPage) { //0: menu 1: wifi 2: leds 3: ui 4: sync 5: time 6: sec @@ -21,60 +23,42 @@ void handleSettingsSet(byte subPage) //WIFI SETTINGS if (subPage == 1) { - if (server.hasArg("CS")) strcpy(clientSSID,server.arg("CS").c_str()); - if (server.hasArg("CP")) - { - if (!server.arg("CP").indexOf('*') == 0) - { - strcpy(clientPass,server.arg("CP").c_str()); - } - } - if (server.hasArg("CM")) strcpy(cmDNS,server.arg("CM").c_str()); - if (server.hasArg("AT")) - { - int i = server.arg("AT").toInt(); - if (i >= 0 && i <= 255) apWaitTimeSecs = i; - } - if (server.hasArg("AS")) strcpy(apSSID,server.arg("AS").c_str()); + strcpy(clientSSID,server.arg("CS").c_str()); + if (server.arg("CP").charAt(0) != '*') strcpy(clientPass, server.arg("CP").c_str()); + + strcpy(cmDNS, server.arg("CM").c_str()); + + int t = server.arg("AT").toInt(); if (t > 9 && t <= 255) apWaitTimeSecs = t; + strcpy(apSSID, server.arg("AS").c_str()); apHide = server.hasArg("AH"); - if (server.hasArg("AP")) - { - if (server.arg("AP").charAt(0) != '*') strcpy(apPass,server.arg("AP").c_str()); - } - if (server.hasArg("AC")) - { - int chan = server.arg("AC").toInt(); - if (chan > 0 && chan < 14) apChannel = chan; - } - char k[3]; k[2] = 0; int j = 0; + if (server.arg("AP").charAt(0) != '*') strcpy(apPass, server.arg("AP").c_str()); + t = server.arg("AC").toInt(); if (t > 0 && t < 14) apChannel = t; + + char k[3]; k[2] = 0; for (int i = 0; i<4; i++) { - k[1] = i+48; + k[1] = i+48;//ascii 0,1,2,3 + k[0] = 'I'; //static IP - if (server.hasArg(k)) j = server.arg(k).toInt(); - if (j >= 0 && j <= 255) staticIP[i] = j; + staticIP[i] = server.arg(k).toInt(); + k[0] = 'G'; //gateway - if (server.hasArg(k)) j = server.arg(k).toInt(); - if (j >= 0 && j <= 255) staticGateway[i] = j; + staticGateway[i] = server.arg(k).toInt(); + k[0] = 'S'; //subnet - if (server.hasArg(k)) j = server.arg(k).toInt(); - if (j >= 0 && j <= 255) staticSubnet[i] = j; + staticSubnet[i] = server.arg(k).toInt(); } } //LED SETTINGS if (subPage == 2) { - if (server.hasArg("LC")) - { - int i = server.arg("LC").toInt(); - if (i > 0 && i <= 1200) ledCount = i; - //RMT eats up too much RAM - #ifdef ARDUINO_ARCH_ESP32 - if (ledCount > 600) ledCount = 600; - #endif - } - ccIndex2 = ledCount -1; + int t = server.arg("LC").toInt(); + if (t > 0 && t <= 1200) ledCount = t; + //RMT eats up too much RAM + #ifdef ARDUINO_ARCH_ESP32 + if (ledCount > 600) ledCount = 600; + #endif useRGBW = server.hasArg("EW"); autoRGBtoRGBW = server.hasArg("AW"); if (server.hasArg("IS")) //ignore settings and save current brightness, colors and fx as default @@ -82,128 +66,76 @@ void handleSettingsSet(byte subPage) colS[0] = col[0]; colS[1] = col[1]; colS[2] = col[2]; - if (useRGBW) whiteS = white; + colSecS[0] = colSec[0]; + colSecS[1] = colSec[1]; + colSecS[2] = colSec[2]; + whiteS = white; + whiteSecS = whiteSec; briS = bri; effectDefault = effectCurrent; effectSpeedDefault = effectSpeed; + effectIntensityDefault = effectIntensity; + effectPaletteDefault = effectPalette; } else { - if (server.hasArg("CR")) - { - int i = server.arg("CR").toInt(); - if (i >= 0 && i <= 255) colS[0] = i; - } - if (server.hasArg("CG")) - { - int i = server.arg("CG").toInt(); - if (i >= 0 && i <= 255) colS[1] = i; - } - if (server.hasArg("CB")) - { - int i = server.arg("CB").toInt(); - if (i >= 0 && i <= 255) colS[2] = i; - } - if (server.hasArg("SR")) - { - int i = server.arg("SR").toInt(); - if (i >= 0 && i <= 255) colSecS[0] = i; - } - if (server.hasArg("SG")) - { - int i = server.arg("SG").toInt(); - if (i >= 0 && i <= 255) colSecS[1] = i; - } - if (server.hasArg("SB")) - { - int i = server.arg("SB").toInt(); - if (i >= 0 && i <= 255) colSecS[2] = i; - } - if (server.hasArg("SW")) - { - int i = server.arg("SW").toInt(); - if (i >= 0 && i <= 255) whiteSecS = i; - } - if (server.hasArg("CW")) - { - int i = server.arg("CW").toInt(); - if (i >= 0 && i <= 255) whiteS = i; - } - if (server.hasArg("CA")) - { - int i = server.arg("CA").toInt(); - if (i >= 0 && i <= 255) briS = i; - } - if (server.hasArg("FX")) - { - int i = server.arg("FX").toInt(); - if (i >= 0 && i <= 255) effectDefault = i; - } - if (server.hasArg("SX")) - { - int i = server.arg("SX").toInt(); - if (i >= 0 && i <= 255) effectSpeedDefault = i; - } - if (server.hasArg("IX")) - { - int i = server.arg("IX").toInt(); - if (i >= 0 && i <= 255) effectIntensityDefault = i; - } + colS[0] = server.arg("CR").toInt(); + colS[1] = server.arg("CG").toInt(); + colS[2] = server.arg("CB").toInt(); + colSecS[0] = server.arg("SR").toInt(); + colSecS[1] = server.arg("SG").toInt(); + colSecS[2] = server.arg("SB").toInt(); + whiteS = server.arg("CW").toInt(); + whiteSecS = server.arg("SW").toInt(); + briS = server.arg("CA").toInt(); + effectDefault = server.arg("FX").toInt(); + effectSpeedDefault = server.arg("SX").toInt(); + effectIntensityDefault = server.arg("IX").toInt(); + effectPaletteDefault = server.arg("FP").toInt(); } saveCurrPresetCycConf = server.hasArg("PC"); turnOnAtBoot = server.hasArg("BO"); - if (server.hasArg("BP")) - { - int i = server.arg("BP").toInt(); - if (i >= 0 && i <= 25) bootPreset = i; - } + t = server.arg("BP").toInt(); + if (t <= 25) bootPreset = t; useGammaCorrectionBri = server.hasArg("GB"); useGammaCorrectionRGB = server.hasArg("GC"); + fadeTransition = server.hasArg("TF"); - sweepTransition = server.hasArg("TS"); - sweepDirection = !server.hasArg("TI"); - if (server.hasArg("TD")) - { - int i = server.arg("TD").toInt(); - if (i > 0){ - transitionDelay = i; - } - } - disableSecTransition = !server.hasArg("T2"); - if (server.hasArg("TB")) - { - nightlightTargetBri = server.arg("TB").toInt(); - } - if (server.hasArg("TL")) - { - int i = server.arg("TL").toInt(); - if (i > 0) nightlightDelayMins = i; - } + t = server.arg("TD").toInt(); + if (t > 0) transitionDelay = t; + transitionDelayDefault = t; + strip.paletteFade = server.hasArg("PF"); + enableSecTransition = server.hasArg("T2"); + + nightlightTargetBri = server.arg("TB").toInt(); + t = server.arg("TL").toInt(); + if (t > 0) nightlightDelayMins = t; nightlightFade = server.hasArg("TW"); - reverseMode = server.hasArg("RV"); + + t = server.arg("PB").toInt(); + if (t >= 0 && t < 4) strip.paletteBlend = t; initLedsLast = server.hasArg("EI"); + reverseMode = server.hasArg("RV"); strip.setReverseMode(reverseMode); skipFirstLed = server.hasArg("SL"); - if (server.hasArg("BF")) - { - int i = server.arg("BF").toInt(); - if (i > 0) briMultiplier = i; - } + t = server.arg("BF").toInt(); + if (t > 0) briMultiplier = t; } //UI if (subPage == 3) { - if (server.hasArg("UI")) uiConfiguration = server.arg("UI").toInt(); - if (server.hasArg("DS")) strcpy(serverDescription,server.arg("DS").c_str()); + int t = server.arg("UI").toInt(); + if (t >= 0 && t < 3) uiConfiguration = t; + strcpy(serverDescription, server.arg("DS").c_str()); useHSBDefault = server.hasArg("MD"); useHSB = useHSBDefault; - if (server.hasArg("TH")) currentTheme = server.arg("TH").toInt(); + currentTheme = server.arg("TH").toInt(); char k[3]; k[0]='C'; k[2]=0; for(int i=0;i<6;i++) { k[1] = i+48; - if (server.hasArg(k)) strcpy(cssCol[i],server.arg(k).c_str()); + strcpy(cssCol[i],server.arg(k).c_str()); } - if (server.hasArg("CF")) strcpy(cssFont,server.arg("CF").c_str()); + strcpy(cssFont,server.arg("CF").c_str()); buildCssColorString(); } @@ -211,10 +143,8 @@ void handleSettingsSet(byte subPage) if (subPage == 4) { buttonEnabled = server.hasArg("BT"); - if (server.hasArg("UP")) - { - udpPort = server.arg("UP").toInt(); - } + int t = server.arg("UP").toInt(); + if (t > 0) udpPort = t; receiveNotificationBrightness = server.hasArg("RB"); receiveNotificationColor = server.hasArg("RC"); receiveNotificationEffects = server.hasArg("RX"); @@ -223,45 +153,41 @@ void handleSettingsSet(byte subPage) notifyDirect = notifyDirectDefault; notifyButton = server.hasArg("SB"); notifyTwice = server.hasArg("S2"); + receiveDirect = server.hasArg("RD"); - if (server.hasArg("EU")) - { - int i = server.arg("EU").toInt(); - if (i > 0 && i <= 63999) arlsTimeoutMillis = i; - } - if (server.hasArg("ET")) - { - int i = server.arg("ET").toInt(); - if (i > 99 && i <= 65000) arlsTimeoutMillis = i; - } + e131Multicast = server.hasArg("EM"); + t = server.arg("EU").toInt(); + if (t > 0 && t <= 63999) e131Universe = t; + t = server.arg("ET").toInt(); + if (t > 99 && t <= 65000) realtimeTimeoutMs = t; arlsForceMaxBri = server.hasArg("FB"); arlsDisableGammaCorrection = server.hasArg("RG"); - if (server.hasArg("WO")) - { - int i = server.arg("WO").toInt(); - if (i >= -255 && i <= 255) arlsOffset = i; - } + t = server.arg("WO").toInt(); + if (t >= -255 && t <= 255) arlsOffset = t; enableRealtimeUI = server.hasArg("RU"); + alexaEnabled = server.hasArg("AL"); - if (server.hasArg("AI")) strcpy(alexaInvocationName,server.arg("AI").c_str()); - alexaNotify = server.hasArg("SA"); + strcpy(alexaInvocationName, server.arg("AI").c_str()); + notifyAlexa = server.hasArg("SA"); + if (server.hasArg("BK") && !server.arg("BK").equals("Hidden")) {strcpy(blynkApiKey,server.arg("BK").c_str()); initBlynk(blynkApiKey);} + + strcpy(mqttServer, server.arg("MS").c_str()); + strcpy(mqttDeviceTopic, server.arg("MD").c_str()); + strcpy(mqttGroupTopic, server.arg("MG").c_str()); + notifyHue = server.hasArg("SH"); for (int i=0;i<4;i++){ String a = "H"+String(i); - if (server.hasArg(a)) - hueIP[i] = server.arg(a).toInt(); - } - if (server.hasArg("HL")) - { - int i = server.arg("HL").toInt(); - if (i > 0) huePollLightId = i; - } - if (server.hasArg("HI")) - { - int i = server.arg("HI").toInt(); - if (i > 50) huePollIntervalMs = i; + hueIP[i] = server.arg(a).toInt(); } + + t = server.arg("HL").toInt(); + if (t > 0) huePollLightId = t; + + t = server.arg("HI").toInt(); + if (t > 50) huePollIntervalMs = t; + hueApplyOnOff = server.hasArg("HO"); hueApplyBri = server.hasArg("HB"); hueApplyColor = server.hasArg("HC"); @@ -281,54 +207,70 @@ void handleSettingsSet(byte subPage) { ntpEnabled = server.hasArg("NT"); useAMPM = !server.hasArg("CF"); - if (server.hasArg("TZ")) currentTimezone = server.arg("TZ").toInt(); - if (server.hasArg("UO")) utcOffsetSecs = server.arg("UO").toInt(); + currentTimezone = server.arg("TZ").toInt(); + utcOffsetSecs = server.arg("UO").toInt(); if (ntpEnabled && WiFi.status() == WL_CONNECTED && !ntpConnected) ntpConnected = ntpUdp.begin(ntpLocalPort); //start if not already connected if (server.hasArg("OL")){ overlayDefault = server.arg("OL").toInt(); overlayCurrent = overlayDefault; - strip.unlockAll(); } - if (server.hasArg("O1")) overlayMin = server.arg("O1").toInt(); - if (server.hasArg("O2")) overlayMax = server.arg("O2").toInt(); - if (server.hasArg("OM")) analogClock12pixel = server.arg("OM").toInt(); + + overlayMin = server.arg("O1").toInt(); + overlayMax = server.arg("O2").toInt(); + analogClock12pixel = server.arg("OM").toInt(); analogClock5MinuteMarks = server.hasArg("O5"); analogClockSecondsTrail = server.hasArg("OS"); - if (server.hasArg("CX")) strcpy(cronixieDisplay,server.arg("CX").c_str()); + strcpy(cronixieDisplay,server.arg("CX").c_str()); bool cbOld = cronixieBacklight; cronixieBacklight = server.hasArg("CB"); - if (cbOld != cronixieBacklight && overlayCurrent == 4) + if (cbOld != cronixieBacklight && overlayCurrent == 3) { strip.setCronixieBacklight(cronixieBacklight); overlayRefreshedTime = 0; } countdownMode = server.hasArg("CE"); - if (server.hasArg("CY")) countdownYear = server.arg("CY").toInt(); - if (server.hasArg("CI")) countdownMonth = server.arg("CI").toInt(); - if (server.hasArg("CD")) countdownDay = server.arg("CD").toInt(); - if (server.hasArg("CH")) countdownHour = server.arg("CH").toInt(); - if (server.hasArg("CM")) countdownMin = server.arg("CM").toInt(); - if (server.hasArg("CS")) countdownSec = server.arg("CS").toInt(); + countdownYear = server.arg("CY").toInt(); + countdownMonth = server.arg("CI").toInt(); + countdownDay = server.arg("CD").toInt(); + countdownHour = server.arg("CH").toInt(); + countdownMin = server.arg("CM").toInt(); + countdownSec = server.arg("CS").toInt(); for (int i=1;i<17;i++) { String a = "M"+String(i); if (server.hasArg(a)) saveMacro(i,server.arg(a),false); } - if (server.hasArg("MB")) macroBoot = server.arg("MB").toInt(); - if (server.hasArg("A0")) macroAlexaOn = server.arg("A0").toInt(); - if (server.hasArg("A1")) macroAlexaOff = server.arg("A1").toInt(); - if (server.hasArg("MP")) macroButton = server.arg("MP").toInt(); - if (server.hasArg("ML")) macroLongPress = server.arg("ML").toInt(); - if (server.hasArg("MC")) macroCountdown = server.arg("MC").toInt(); - if (server.hasArg("MN")) macroNl = server.arg("MN").toInt(); + + macroBoot = server.arg("MB").toInt(); + macroAlexaOn = server.arg("A0").toInt(); + macroAlexaOff = server.arg("A1").toInt(); + macroButton = server.arg("MP").toInt(); + macroLongPress = server.arg("ML").toInt(); + macroCountdown = server.arg("MC").toInt(); + macroNl = server.arg("MN").toInt(); + + char k[3]; k[2] = 0; + for (int i = 0; i<8; i++) + { + k[1] = i+48;//ascii 0,1,2,3 + + k[0] = 'H'; //timer hours + timerHours[i] = server.arg(k).toInt(); + + k[0] = 'N'; //minutes + timerMinutes[i] = server.arg(k).toInt(); + + k[0] = 'T'; //macros + timerMacro[i] = server.arg(k).toInt(); + } } //SECURITY if (subPage == 6) { - if (server.hasArg("RS")) + if (server.hasArg("RS")) //complete factory reset { clearEEPROM(); serveMessage(200, "All Settings erased.", "Connect to WLED-AP to setup again...",255); @@ -357,15 +299,14 @@ void handleSettingsSet(byte subPage) } } saveSettingsToEEPROM(); - if (subPage == 2) strip.init(useRGBW,ledCount,PIN,skipFirstLed); + if (subPage == 2) strip.init(useRGBW,ledCount,skipFirstLed); } bool handleSet(String req) { bool effectUpdated = false; - if (!(req.indexOf("win") >= 0)) { - return false; - } + if (!(req.indexOf("win") >= 0)) return false; + int pos = 0; DEBUG_PRINT("API req: "); DEBUG_PRINTLN(req); @@ -383,7 +324,7 @@ bool handleSet(String req) } pos = req.indexOf("IN"); - if (pos < 1) XML_response(); + if (pos < 1) XML_response(true); return true; //if you save a macro in one request, other commands in that request are ignored due to unwanted behavior otherwise } @@ -448,6 +389,16 @@ bool handleSet(String req) whiteSec = req.substring(pos + 3).toInt(); } + //set color from HEX or 32bit DEC + pos = req.indexOf("CL="); + if (pos > 0) { + colorFromDecOrHexString(col, &white, (char*)req.substring(pos + 3).c_str()); + } + pos = req.indexOf("C2="); + if (pos > 0) { + colorFromDecOrHexString(colSec, &whiteSec, (char*)req.substring(pos + 3).c_str()); + } + //set 2nd to white pos = req.indexOf("SW"); if (pos > 0) { @@ -462,6 +413,7 @@ bool handleSet(String req) colSec[2] = 255; } } + //set 2nd to black pos = req.indexOf("SB"); if (pos > 0) { @@ -470,6 +422,7 @@ bool handleSet(String req) colSec[1] = 0; colSec[2] = 0; } + //set to random hue SR=0->1st SR=1->2nd pos = req.indexOf("SR"); if (pos > 0) { @@ -528,6 +481,16 @@ bool handleSet(String req) effectUpdated = true; } } + //set effect palette (only for FastLED effects) + pos = req.indexOf("FP="); + if (pos > 0) { + if (effectPalette != req.substring(pos + 3).toInt()) + { + effectPalette = req.substring(pos + 3).toInt(); + strip.setPalette(effectPalette); + effectUpdated = true; + } + } //set hue polling light: 0 -off pos = req.indexOf("HP="); @@ -553,19 +516,6 @@ bool handleSet(String req) overlayCurrent = req.substring(pos + 3).toInt(); strip.unlockAll(); } - //set individual pixel (range) to current color - pos = req.indexOf("&I="); - if (pos > 0){ - int index = req.substring(pos + 3).toInt(); - pos = req.indexOf("I2="); - if (pos > 0){ - int index2 = req.substring(pos + 3).toInt(); - strip.setRange(index, index2); - } else - { - strip.setIndividual(index); - } - } //(un)lock pixel (ranges) pos = req.indexOf("&L="); if (pos > 0){ @@ -591,6 +541,7 @@ bool handleSet(String req) } } } + //apply macro pos = req.indexOf("&M="); if (pos > 0) { @@ -605,6 +556,7 @@ bool handleSet(String req) notifyDirect = false; } } + //toggle receive UDP direct notifications if (req.indexOf("RN=") > 0) { @@ -614,6 +566,7 @@ bool handleSet(String req) receiveNotifications = false; } } + //toggle nightlight mode bool aNlDef = false; if (req.indexOf("&ND") > 0) aNlDef = true; @@ -634,12 +587,14 @@ bool handleSet(String req) nightlightActive = true; nightlightStartTime = millis(); } + //set nightlight target brightness pos = req.indexOf("NT="); if (pos > 0) { nightlightTargetBri = req.substring(pos + 3).toInt(); nightlightActiveOld = false; //re-init } + //toggle nightlight fade if (req.indexOf("NF=") > 0) { @@ -651,6 +606,7 @@ bool handleSet(String req) } nightlightActiveOld = false; //re-init } + //toggle general purpose output pos = req.indexOf("AX="); if (pos > 0) { @@ -662,9 +618,11 @@ bool handleSet(String req) if (pos > 0) { transitionDelay = req.substring(pos + 3).toInt(); } + //main toggle on/off pos = req.indexOf("&T="); if (pos > 0) { + nightlightActive = false; //always disable nightlight when toggling switch (req.substring(pos + 3).toInt()) { case 0: if (bri != 0){briLast = bri; bri = 0;} break; //off @@ -679,6 +637,7 @@ bool handleSet(String req) } } } + //deactivate nightlight if target brightness is reached if (bri == nightlightTargetBri) nightlightActive = false; //set time (unix timestamp) @@ -686,6 +645,7 @@ bool handleSet(String req) if (pos > 0) { setTime(req.substring(pos+3).toInt()); } + //set countdown goal (unix timestamp) pos = req.indexOf("CT="); if (pos > 0) { @@ -693,19 +653,6 @@ bool handleSet(String req) if (countdownTime - now() > 0) countdownOverTriggered = false; } - //set custom chase data - bool _cc_updated = false; - pos = req.indexOf("C0="); if (pos > 0) {ccStart = (req.substring(pos + 3).toInt()); _cc_updated = true;} - pos = req.indexOf("C1="); if (pos > 0) {ccIndex1 = (req.substring(pos + 3).toInt()); _cc_updated = true;} - pos = req.indexOf("C2="); if (pos > 0) {ccIndex2 = (req.substring(pos + 3).toInt()); _cc_updated = true;} - pos = req.indexOf("CP="); if (pos > 0) {ccNumPrimary = (req.substring(pos + 3).toInt()); _cc_updated = true;} - pos = req.indexOf("CS="); if (pos > 0) {ccNumSecondary = (req.substring(pos + 3).toInt()); _cc_updated = true;} - pos = req.indexOf("CM="); if (pos > 0) {ccStep = (req.substring(pos + 3).toInt()); _cc_updated = true;} - pos = req.indexOf("CF="); if (pos > 0) {ccFromStart = (req.substring(pos + 3).toInt()); _cc_updated = true;} - pos = req.indexOf("CE="); if (pos > 0) {ccFromEnd = (req.substring(pos + 3).toInt()); _cc_updated = true;} - if (ccIndex2 == 255) ccIndex2 = ledCount-1; - if (_cc_updated) strip.setCustomChase(ccIndex1, ccIndex2, ccStart, ccNumPrimary, ccNumSecondary, ccStep, ccFromStart, ccFromEnd); - //set presets pos = req.indexOf("P1="); //sets first preset for cycle if (pos > 0) presetCycleMin = req.substring(pos + 3).toInt(); @@ -773,7 +720,7 @@ bool handleSet(String req) { cronixieBacklight = false; } - if (overlayCurrent == 4) strip.setCronixieBacklight(cronixieBacklight); + if (overlayCurrent == 3) strip.setCronixieBacklight(cronixieBacklight); overlayRefreshedTime = 0; } pos = req.indexOf("U0="); //user var 0 @@ -788,7 +735,7 @@ bool handleSet(String req) //internal call, does not send XML response pos = req.indexOf("IN"); - if (pos < 1) XML_response(); + if (pos < 1) XML_response(true); //do not send UDP notifications this time pos = req.indexOf("NN"); if (pos > 0) diff --git a/wled00/wled04_file.ino b/wled00/wled04_file.ino index 66a10347..d36aaf46 100644 --- a/wled00/wled04_file.ino +++ b/wled00/wled04_file.ino @@ -7,12 +7,8 @@ void handleSerial() { if (Serial.find("Ada")) { - if (!arlsTimeout){ - if (bri == 0) strip.setBrightness(briLast); - strip.setRange(0, ledCount-1, 0); - strip.setMode(0); - } - arlsLock(arlsTimeoutMillis); + if (!realtimeActive && bri == 0) strip.setBrightness(briLast); + arlsLock(realtimeTimeoutMs); delay(1); byte hi = Serial.read(); byte ledc = Serial.read(); diff --git a/wled00/wled05_init.ino b/wled00/wled05_init.ino index e11d9f9f..a5f9f66a 100644 --- a/wled00/wled05_init.ino +++ b/wled00/wled05_init.ino @@ -5,13 +5,12 @@ void wledInit() { EEPROM.begin(EEPSIZE); - showWelcomePage = (EEPROM.read(233) != 233); ledCount = ((EEPROM.read(229) << 0) & 0xFF) + ((EEPROM.read(398) << 8) & 0xFF00); if (ledCount > 1200 || ledCount == 0) ledCount = 10; //RMT eats up too much RAM #ifdef ARDUINO_ARCH_ESP32 if (ledCount > 600) ledCount = 600; #endif - if (!EEPROM.read(397)) strip.init(EEPROM.read(372),ledCount,PIN,EEPROM.read(2204)); //quick init + if (!EEPROM.read(397)) strip.init(EEPROM.read(372),ledCount,EEPROM.read(2204)); //quick init Serial.begin(115200); Serial.setTimeout(50); @@ -27,6 +26,7 @@ void wledInit() DEBUG_PRINT(clientSSID); buildCssColorString(); userBeginPreConnection(); + if (strcmp(clientSSID,"Your_Network") == 0) showWelcomePage = true; initCon(); @@ -49,220 +49,73 @@ void wledInit() if (ntpEnabled && WiFi.status() == WL_CONNECTED) ntpConnected = ntpUdp.begin(ntpLocalPort); - //start captive portal - if (onlyAP || strlen(apSSID) > 0) + //start captive portal if AP active + if (onlyAP || strlen(apSSID) > 0) { - dnsServer.setErrorReplyCode(DNSReplyCode::NoError); - dnsServer.start(53, "*", WiFi.softAPIP()); + dnsServer.setErrorReplyCode(DNSReplyCode::ServerFailure); + dnsServer.start(53, "wled.me", WiFi.softAPIP()); dnsActive = true; } - if (!initLedsLast) strip.service(); - //SERVER INIT - //settings page - server.on("/settings", HTTP_GET, [](){ - serveSettings(0); - }); - server.on("/settings/wifi", HTTP_GET, [](){ - if (!(wifiLock && otaLock)) - { - serveSettings(1); - }else{ - serveMessage(500, "Access Denied", txd, 254); - } - }); - server.on("/settings/leds", HTTP_GET, [](){ - serveSettings(2); - }); - server.on("/settings/ui", HTTP_GET, [](){ - serveSettings(3); - }); - server.on("/settings/sync", HTTP_GET, [](){ - serveSettings(4); - }); - server.on("/settings/time", HTTP_GET, [](){ - serveSettings(5); - }); - server.on("/settings/sec", HTTP_GET, [](){ - serveSettings(6); - }); - - server.on("/favicon.ico", HTTP_GET, [](){ - if(!handleFileRead("/favicon.ico")) - { - server.send_P(200, "image/x-icon", favicon, 156); - } - }); - - server.on("/", HTTP_GET, [](){ - serveIndexOrWelcome(); - }); - server.on("/generate_204", HTTP_GET, [](){ - serveIndexOrWelcome(); - }); - - server.on("/fwlink", HTTP_GET, [](){ - serveIndexOrWelcome(); - }); - - server.on("/sliders", HTTP_GET, serveIndex); - - server.on("/welcome", HTTP_GET, [](){ - serveSettings(255); - }); - - server.on("/reset", HTTP_GET, [](){ - serveMessage(200,"Rebooting now...","(takes ~20 seconds, wait for auto-redirect)",79); - reset(); - }); - - server.on("/settings/wifi", HTTP_POST, [](){ - if (!(wifiLock && otaLock)) handleSettingsSet(1); - serveMessage(200,"WiFi settings saved.","Rebooting now... (takes ~20 seconds, wait for auto-redirect)",139); - reset(); - }); - - server.on("/settings/leds", HTTP_POST, [](){ - handleSettingsSet(2); - serveMessage(200,"LED settings saved.","Redirecting...",1); - }); - - server.on("/settings/ui", HTTP_POST, [](){ - handleSettingsSet(3); - serveMessage(200,"UI settings saved.","Reloading to apply theme...",122); - }); - - server.on("/settings/sync", HTTP_POST, [](){ - handleSettingsSet(4); - if (hueAttempt) - { - serveMessage(200,"Hue setup result",hueError,253); - } else { - serveMessage(200,"Sync settings saved.","Redirecting...",1); - } - hueAttempt = false; - }); - - server.on("/settings/time", HTTP_POST, [](){ - handleSettingsSet(5); - serveMessage(200,"Time settings saved.","Redirecting...",1); - }); - - server.on("/settings/sec", HTTP_POST, [](){ - handleSettingsSet(6); - serveMessage(200,"Security settings saved.","Rebooting now... (takes ~20 seconds, wait for auto-redirect)",139); - reset(); - }); - - server.on("/version", HTTP_GET, [](){ - server.send(200, "text/plain", (String)VERSION); - }); - - server.on("/uptime", HTTP_GET, [](){ - server.send(200, "text/plain", (String)millis()); - }); - - server.on("/freeheap", HTTP_GET, [](){ - server.send(200, "text/plain", (String)ESP.getFreeHeap()); - }); - - server.on("/power", HTTP_GET, [](){ - String val = (String)(int)strip.getPowerEstimate(ledCount,strip.getColor(),strip.getBrightness()); - val += "mA currently"; - serveMessage(200,val,"This is just an estimate (does not take into account several factors like effects and wire resistance). It is NOT an accurate measurement!",254); - }); - - server.on("/u", HTTP_GET, [](){ - server.setContentLength(strlen_P(PAGE_usermod)); - server.send(200, "text/html", ""); - server.sendContent_P(PAGE_usermod); - }); - - server.on("/teapot", HTTP_GET, [](){ - serveMessage(418, "418. I'm a teapot.","(Tangible Embedded Advanced Project Of Twinkling)",254); - }); - - server.on("/build", HTTP_GET, [](){ - getBuildInfo(); - server.send(200, "text/plain", obuf); - }); - //if OTA is allowed - if (!otaLock){ - server.on("/edit", HTTP_GET, [](){ - if(!handleFileRead("/edit.htm")) server.send(200, "text/html", PAGE_edit); - }); - #ifdef USEFS - server.on("/edit", HTTP_PUT, handleFileCreate); - server.on("/edit", HTTP_DELETE, handleFileDelete); - server.on("/edit", HTTP_POST, [](){ server.send(200, "text/plain", ""); }, handleFileUpload); - server.on("/list", HTTP_GET, handleFileList); - #endif - //init ota page - httpUpdater.setup(&server); - } else + prepareIds(); //UUID from MAC (for Alexa and MQTT) + if (mqttDeviceTopic[0] == 0) { - server.on("/edit", HTTP_GET, [](){ - serveMessage(500, "Access Denied", txd, 254); - }); - server.on("/update", HTTP_GET, [](){ - serveMessage(500, "Access Denied", txd, 254); - }); - server.on("/list", HTTP_GET, [](){ - serveMessage(500, "Access Denied", txd, 254); - }); + strcpy(mqttDeviceTopic, "wled/"); + strcat(mqttDeviceTopic, escapedMac.c_str()); } - //called when the url is not defined here, ajax-in; get-settings - server.onNotFound([](){ - DEBUG_PRINTLN("Not-Found HTTP call:"); - DEBUG_PRINTLN("URI: " + server.uri()); - DEBUG_PRINTLN("Body: " + server.arg(0)); - if(!handleSet(server.uri())){ - if(!handleAlexaApiCall(server.uri(),server.arg(0))) - server.send(404, "text/plain", "Not Found"); - } - }); - #ifndef ARDUINO_ARCH_ESP32 - const char * headerkeys[] = {"User-Agent"}; - server.collectHeaders(headerkeys,sizeof(headerkeys)/sizeof(char*)); - #else - String ua = "User-Agent"; - server.collectHeaders(ua); - #endif + //smartInit, we only init some resources when connected + if (!onlyAP && WiFi.status() == WL_CONNECTED) + { + mqttTCPClient = new WiFiClient(); + mqtt = new PubSubClient(*mqttTCPClient); + mqttInit = initMQTT(); + } + + if (!initLedsLast) strip.service(); + + //HTTP server page init + initServer(); if (!initLedsLast) strip.service(); //init Alexa hue emulation - if (alexaEnabled) alexaInit(); + if (alexaEnabled && !onlyAP) alexaInit(); server.begin(); DEBUG_PRINTLN("HTTP server started"); //init ArduinoOTA - if (aOtaEnabled) - { - ArduinoOTA.onStart([]() { - #ifndef ARDUINO_ARCH_ESP32 - wifi_set_sleep_type(NONE_SLEEP_T); - #endif - DEBUG_PRINTLN("Start ArduinoOTA"); - }); - if (strlen(cmDNS) > 0) ArduinoOTA.setHostname(cmDNS); - ArduinoOTA.begin(); - } - - if (!initLedsLast) strip.service(); - // Set up mDNS responder: - if (strlen(cmDNS) > 0 && !onlyAP) - { - MDNS.begin(cmDNS); - DEBUG_PRINTLN("mDNS responder started"); - // Add service to MDNS - MDNS.addService("http", "tcp", 80); - } - - initBlynk(blynkApiKey); + if (!onlyAP) { + if (aOtaEnabled) + { + ArduinoOTA.onStart([]() { + #ifndef ARDUINO_ARCH_ESP32 + wifi_set_sleep_type(NONE_SLEEP_T); + #endif + DEBUG_PRINTLN("Start ArduinoOTA"); + }); + if (strlen(cmDNS) > 0) ArduinoOTA.setHostname(cmDNS); + ArduinoOTA.begin(); + } - initE131(); + if (!initLedsLast) strip.service(); + // Set up mDNS responder: + if (strlen(cmDNS) > 0 && !onlyAP) + { + MDNS.begin(cmDNS); + DEBUG_PRINTLN("mDNS responder started"); + // Add service to MDNS + MDNS.addService("http", "tcp", 80); + } + if (!initLedsLast) strip.service(); + + initBlynk(blynkApiKey); + initE131(); + + hueClient = new HTTPClient(); + } else { + e131Enabled = false; + } if (initLedsLast) initStrip(); userBegin(); @@ -273,11 +126,10 @@ void wledInit() void initStrip() { // Initialize NeoPixel Strip and button - if (initLedsLast) strip.init(useRGBW,ledCount,PIN,skipFirstLed); + if (initLedsLast) strip.init(useRGBW,ledCount,skipFirstLed); strip.setReverseMode(reverseMode); strip.setColor(0); strip.setBrightness(255); - strip.start(); pinMode(buttonPin, INPUT_PULLUP); pinMode(4,OUTPUT); //this is only needed in special cases @@ -309,12 +161,12 @@ void initCon() if (strlen(apSSID)>0) { - DEBUG_PRINT("USING AP"); + DEBUG_PRINT(" USING AP"); DEBUG_PRINTLN(strlen(apSSID)); initAP(); } else { - DEBUG_PRINTLN("NO AP"); + DEBUG_PRINTLN(" NO AP"); WiFi.softAPdisconnect(true); } int fail_count = 0; @@ -355,191 +207,6 @@ void initCon() } } -void buildCssColorString() -{ - String cs[]={"","","","","",""}; - switch (currentTheme) - { - default: cs[0]="D9B310"; cs[1]="0B3C5D"; cs[2]="1D2731"; cs[3]="328CC1"; cs[4]="000"; cs[5]="328CC1"; break; //night - case 1: cs[0]="eee"; cs[1]="ddd"; cs[2]="b9b9b9"; cs[3]="049"; cs[4]="777"; cs[5]="049"; break; //modern - case 2: cs[0]="abc"; cs[1]="fff"; cs[2]="ddd"; cs[3]="000"; cs[4]="0004"; cs[5]="000"; break; //bright - case 3: cs[0]="c09f80"; cs[1]="d7cec7"; cs[2]="76323f"; cs[3]="888"; cs[4]="3334"; cs[5]="888"; break; //wine - case 4: cs[0]="3cc47c"; cs[1]="828081"; cs[2]="d9a803"; cs[3]="1e392a"; cs[4]="000a"; cs[5]="1e392a"; break; //electric - case 5: cs[0]="57bc90"; cs[1]="a5a5af"; cs[2]="015249"; cs[3]="88c9d4"; cs[4]="0004"; cs[5]="88c9d4"; break; //mint - case 6: cs[0]="f7c331"; cs[1]="dcc7aa"; cs[2]="6b7a8f"; cs[3]="f7882f"; cs[4]="0007"; cs[5]="f7882f"; break; //amber - case 7: cs[0]="fc3"; cs[1]="124"; cs[2]="334"; cs[3]="f1d"; cs[4]="f00"; cs[5]="f1d"; break;//club - case 8: cs[0]="0ac"; cs[1]="124"; cs[2]="224"; cs[3]="003eff"; cs[4]="003eff"; cs[5]="003eff"; break;//air - case 9: cs[0]="f70"; cs[1]="421"; cs[2]="221"; cs[3]="a50"; cs[4]="f70"; cs[5]="f70"; break;//nixie - case 10: cs[0]="2d2"; cs[1]="010"; cs[2]="121"; cs[3]="060"; cs[4]="040"; cs[5]="3f3"; break; //terminal - case 11: cs[0]="867ADE"; cs[1]="4033A3"; cs[2]="483AAA"; cs[3]="483AAA"; cs[4]=""; cs[5]="867ADE"; break; //c64 - case 12: cs[0]="fbe8a6"; cs[1]="d2fdff"; cs[2]="b4dfe5"; cs[3]="f4976c"; cs[4]=""; cs[5]="303c6c"; break; //c64 - case 14: cs[0]="fc7"; cs[1]="49274a"; cs[2]="94618e"; cs[3]="f4decb"; cs[4]="0008"; cs[5]="f4decb"; break; //end - case 15: for (int i=0;i<6;i++)cs[i]=cssCol[i];//custom - } - cssColorString="