diff --git a/pixelprojektor/NeoPatterns.cpp b/pixelprojektor/NeoPatterns.cpp index c68d487..ac7a82b 100644 --- a/pixelprojektor/NeoPatterns.cpp +++ b/pixelprojektor/NeoPatterns.cpp @@ -37,9 +37,15 @@ void NeoPatterns::Update() { case RANDOM_FADE: RandomFadeUpdate(); break; + case RANDOM_FADE_SINGLE: + RandomFadeSingleUpdate(); + break; case SMOOTH: SmoothUpdate(); break; + case ICON: + IconUpdate(); + break; case NONE: break; default: @@ -244,15 +250,52 @@ void NeoPatterns::RandomFade(uint8_t interval ) { TotalSteps = 255; Index = 0; } + void NeoPatterns::RandomFadeUpdate() { ColorSet(Wheel(Index)); Increment(); } +void NeoPatterns::RandomFadeSingle(uint8_t interval, uint8_t speed) { + ActivePattern = RANDOM_FADE_SINGLE; + Interval = interval; + TotalSteps = 255; + Index = 0; + WheelSpeed = speed; + RandomBuffer(); +} + +void NeoPatterns::RandomFadeSingleUpdate() { + for (int i = 0; i < numPixels(); i++) { + pixelR_buffer[i] += random(0, random(0, WheelSpeed + 1) + 1); //use buffer red channel for color wheel + setPixelColor(i, Wheel(pixelR_buffer[i])); + } + show(); + Increment(); +} + +void NeoPatterns::RandomBuffer() +{ + for (int i = 0; i < numPixels(); i++) { + uint32_t c = Wheel(random(0, 256)); + pixelR_buffer[i] = (uint8_t)(c >> 16); + pixelG_buffer[i] = (uint8_t)(c >> 8); + pixelB_buffer[i] = (uint8_t)c; + } +} + +void NeoPatterns::Random() +{ + None(); // Stop all other effects + for (int i = 0; i < numPixels(); i++) { + setPixelColor(i, Wheel(random(0, 256))); + } + show(); +} + void NeoPatterns::Smooth(uint8_t wheelSpeed, uint8_t smoothing, uint8_t strength, uint8_t interval) { ActivePattern = SMOOTH; Interval = interval; - // TotalSteps = 1; // TODO: Beim Smooth nicht sinnvoll? Index = 0; WheelSpeed = wheelSpeed; Smoothing = smoothing; @@ -353,8 +396,57 @@ void NeoPatterns::SmoothUpdate() { } show(); - // Increment(); +} + +/****************** Icon ******************/ + +void NeoPatterns::Icon(uint8_t fontchar, String iconcolor, uint8_t interval) +{ + // Save last effect, should be called after completion again + SavedPattern = ActivePattern; + SavedInterval = Interval; + SavedTotalSteps = TotalSteps; + SavedIndex = Index; + SavedColor1 = Color1; + SavedDirection = Direction; + ActivePattern = ICON; + Interval = interval; + TotalSteps = 80; + Index = 80; + Color1 = parseColor(iconcolor); + FontChar = fontchar; + Direction = REVERSE; +} + +void NeoPatterns::IconUpdate() +{ + for (int i = 0; i < numPixels(); i++) { + uint64_t mask = 1LL << (uint64_t)i; + + if ( (font[FontChar]&mask) == 0) { + setPixelColor(numToPos(i), Color(0, 0, 0)); //bit is 0 at pos i + } else { + float _brightness = 1.0 - ( (TotalSteps - Index) * 1.0 / TotalSteps ); + uint8_t _r = (uint8_t)(Color1 >> 16); + uint8_t _g = (uint8_t)(Color1 >> 8); + uint8_t _b = (uint8_t)Color1; + setPixelColor(numToPos(i), Color(_r * _brightness, _g * _brightness, _b * _brightness)); //bit is 1 at pos i + } + } + show(); + Increment(); +} + +void NeoPatterns::IconComplete() +{ + // Reload last effect + ActivePattern = SavedPattern; + Interval = SavedInterval; + TotalSteps = SavedTotalSteps; + Index = SavedIndex; + Color1 = SavedColor1; + Direction = SavedDirection; } /****************** Helper functions ******************/ @@ -527,3 +619,7 @@ uint32_t NeoPatterns::parseColor(String value) { } return 0; } + + + + diff --git a/pixelprojektor/NeoPatterns.h b/pixelprojektor/NeoPatterns.h index d175364..4f87547 100644 --- a/pixelprojektor/NeoPatterns.h +++ b/pixelprojektor/NeoPatterns.h @@ -1,7 +1,8 @@ #include +#include "font.h" // Pattern types supported: -enum pattern { NONE, RAINBOW_CYCLE, THEATER_CHASE, COLOR_WIPE, SCANNER, FADE, RANDOM_FADE, SMOOTH }; +enum pattern { NONE, RAINBOW_CYCLE, THEATER_CHASE, COLOR_WIPE, SCANNER, FADE, RANDOM_FADE, SMOOTH, ICON, RANDOM_FADE_SINGLE }; // Patern directions supported: enum direction { FORWARD, REVERSE }; @@ -20,14 +21,21 @@ class NeoPatterns : public Adafruit_NeoPixel void TheaterChaseUpdate(); void ColorWipe(uint32_t color, uint8_t interval, direction dir = FORWARD); void ColorWipeUpdate(); - void Scanner(uint32_t color1, uint8_t interval = 40, bool colorful = false, bool spiral = false); + void Scanner(uint32_t color1 = 16711680, uint8_t interval = 40, bool colorful = false, bool spiral = false); void ScannerUpdate(); void Fade(uint32_t color1, uint32_t color2, uint16_t steps, uint8_t interval, direction dir = FORWARD); void FadeUpdate(); void RandomFade(uint8_t interval = 100); void RandomFadeUpdate(); + void RandomFadeSingle(uint8_t interval = 100, uint8_t speed = 5); + void RandomFadeSingleUpdate(); + void RandomBuffer(); + void Random(); void Smooth(uint8_t wheelSpeed = 16, uint8_t smoothing = 80, uint8_t strength = 50, uint8_t interval = 40); void SmoothUpdate(); + void Icon(uint8_t fontchar, String iconcolor = "#FFFFFF", uint8_t interval = 30); + void IconUpdate(); + void IconComplete(); void SetColor1(uint32_t color); void SetColor2(uint32_t color); @@ -43,18 +51,24 @@ class NeoPatterns : public Adafruit_NeoPixel uint8_t numToPos(int num); uint8_t getAverage(uint8_t array[], uint8_t i, int x, int y); uint32_t parseColor(String value); - private: + private: // Member Variables: pattern ActivePattern; // which pattern is running + pattern SavedPattern; direction Direction; // direction to run the pattern + direction SavedDirection; unsigned long Interval; // milliseconds between updates + unsigned long SavedInterval; unsigned long lastUpdate; // last update of position uint32_t Color1, Color2; // What colors are in use + uint32_t SavedColor1; uint16_t TotalSteps; // total number of steps in the pattern + uint16_t SavedTotalSteps; uint16_t Index; // current step within the pattern + uint16_t SavedIndex; uint8_t Every; // Turn every "Every" pixel in Color1/Color2 byte wPos; @@ -71,7 +85,9 @@ class NeoPatterns : public Adafruit_NeoPixel uint8_t *pixelB; uint8_t *pixelR_buffer; uint8_t *pixelG_buffer; - uint8_t *pixelB_buffer; + uint8_t *pixelB_buffer; + + uint8_t FontChar; uint32_t DimColor(uint32_t color); void Increment(); diff --git a/pixelprojektor/pixelprojektor.ino b/pixelprojektor/pixelprojektor.ino index c9724cd..31c535a 100644 --- a/pixelprojektor/pixelprojektor.ino +++ b/pixelprojektor/pixelprojektor.ino @@ -2,7 +2,6 @@ #include #include #include "NeoPatterns.h" -#include "font.h" #ifdef __AVR__ #include #endif @@ -10,12 +9,18 @@ #define PIN D1 //data pin for ws2812 (pixelprojektor @ ctdo: PIN 2) #define NUMPIXELS 64 +NeoPatterns strip = NeoPatterns(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800, &StripComplete); + +bool stopAfterCompletion; + void StripComplete() { + if (stopAfterCompletion) + { + strip.IconComplete(); + } return; } -NeoPatterns strip = NeoPatterns(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800, &StripComplete); - HomieNode homieNode("pixel", "commands"); @@ -61,6 +66,7 @@ bool onSetBrightness(const HomieRange& range, const String& value) { } bool onSetEffect(const HomieRange& range, const String& value) { + stopAfterCompletion = false; String effect = value; effect.toLowerCase(); if (effect == "scanner") { @@ -75,7 +81,7 @@ bool onSetEffect(const HomieRange& range, const String& value) { else if (effect == "rainbowcycle") { strip.RainbowCycle(50); } - else if (effect == "theaterchase") { + else if (effect == "theaterchase" || effect == "chase") { strip.TheaterChase(strip.Color(255, 0, 0), strip.Color(0, 0, 255), 100); } else if (effect == "fade") { @@ -84,7 +90,9 @@ bool onSetEffect(const HomieRange& range, const String& value) { else if (effect == "randomfade") { strip.RandomFade(); } - else if (effect == "smooth") { //example: smooth|[wheelspeed]|[smoothing]|[strength] wheelspeed=1-255, smoothing=0-100, strength=1-255 + else if (effect == "random") { + strip.Random(); + } else if (effect == "smooth") { //example: smooth|[wheelspeed]|[smoothing]|[strength] wheelspeed=1-255, smoothing=0-100, strength=1-255 strip.Smooth(16, 80, 50, 40); } else { @@ -92,16 +100,36 @@ bool onSetEffect(const HomieRange& range, const String& value) { int sep = value.indexOf("|"); String command = value.substring(0, sep); String parameters = value.substring(sep + 1); - if (command.equals("fill")) - { + if (command.equals("fill")) { strip.ColorSetParameters(parameters); - } else { + } + else if (command.equals("randomfade")) { + int sepparam = parameters.indexOf("|"); + int p1 = parameters.substring(0, sepparam).toInt(); + if (p1 <= 0) { + p1 = 5; + } + strip.RandomFadeSingle(p1); + } + else { strip.None(); } } homieNode.setProperty("effect").send(value); } +bool onSetIcon(const HomieRange& range, const String& value) { + stopAfterCompletion = true; + String _iconname = value; + if (value[0] == '#') { //color given + strip.Icon(value.substring(7)[0], value.substring(0, 6)); + } + else { + strip.Icon(value[0]); + } + homieNode.setProperty("icon").send(value); +} + bool onSetClear(const HomieRange& range, const String& value) { strip.None(); strip.clear(); @@ -122,7 +150,6 @@ bool onSetLength(const HomieRange& range, const String& value) { void loopHandler() { strip.Update(); - } void setup() { @@ -137,19 +164,20 @@ void setup() { homieNode.advertise("effect").settable(onSetEffect); homieNode.advertise("clear").settable(onSetClear); homieNode.advertise("length").settable(onSetLength); - + homieNode.advertise("icon").settable(onSetIcon); Homie.setup(); - + strip.begin(); strip.clear(); strip.setBrightness(64); strip.show(); - + stopAfterCompletion = false; // Default ArduinoOTA.setHostname("pixelprojektor"); ArduinoOTA.onStart([]() { strip.clear(); + strip.setBrightness(64); }); ArduinoOTA.onEnd([]() { strip.clear(); @@ -184,29 +212,6 @@ void loop() { /************ Old stuff ************/ /* int fadespeedmax = 5; //1 to 255 - int iconCountStart = 0; //for percentage calculation - int iconCountdown = 0; //0=off - uint8_t iconchar = 0; //last displayed char - int32_t iconcolor = 0; //last icon color - - long lastMillis = 0; - long fpsdelay = 1000 / FPS; - - - uint32_t wheel(byte WheelPos) { - WheelPos = 255 - WheelPos; - if (WheelPos < 85) { - return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3); - } - if (WheelPos < 170) { - WheelPos -= 85; - return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3); - } - WheelPos -= 170; - return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0); - } - - void led_random() { @@ -222,37 +227,6 @@ void loop() { // line(0,0,950*cos(radians(iAngle)),-950*sin(radians(iAngle))); } - void led_larson() - { - int EyeSize = 5; - uint32_t rgb[3] = {0}; - wheelPos++; - if (wheelPos >= 256) { - wheelPos = 0; - } - int Color1 = wheel(wheelPos); - - for (int i = 0; i < strip.numPixels(); i++) - { - int realpos = numToSpiralPos(i); - if (i == Index) // Scan Pixel to the right - { - strip.setPixelColor(realpos, Color1); - } - else if (i == ((strip.numPixels() - 1) * 2) - Index) // Scan Pixel to the left - { - strip.setPixelColor(realpos, Color1); - } - else // Fading tail - { - strip.setPixelColor(realpos, DimColor(strip.getPixelColor(realpos))); - } - } - - strip.show(); - Increment(); - } - void led_spiral() { @@ -274,48 +248,6 @@ void loop() { } - void led_randomfade() - { - for (int i = 0; i < strip.numPixels(); i++) { - pixelR_buffer[i] += random(0, random(0, fadespeedmax + 1) + 1); //use buffer red channel for color wheel - strip.setPixelColor(i, wheel(pixelR_buffer[i])); - } - strip.show(); - } - - void led_icon(uint8_t fontchar, uint32_t iconcolor) - { - for (int i = 0; i < strip.numPixels(); i++) { - uint64_t mask = 1LL << (uint64_t)i; - - if ( (font[fontchar]&mask) == 0) { - strip.setPixelColor(numToPos(i), strip.Color(0, 0, 0)); //bit is 0 at pos i - } else { - - float _brightness = 1.0 - ( (iconCountStart - iconCountdown) * 1.0 / iconCountStart ); - uint8_t _r = (uint8_t)(iconcolor >> 16); - uint8_t _g = (uint8_t)(iconcolor >> 8); - uint8_t _b = (uint8_t)iconcolor; - strip.setPixelColor(numToPos(i), strip.Color(_r * _brightness, _g * _brightness, _b * _brightness)); //bit is 1 at pos i - } - - } - strip.show(); - } - - void set_randomBuffer() - { - for (int i = 0; i < strip.numPixels(); i++) { - uint32_t c = wheel(random(0, 256)); - pixelR_buffer[i] = (uint8_t)(c >> 16); - pixelG_buffer[i] = (uint8_t)(c >> 8); - pixelB_buffer[i] = (uint8_t)c; - } - } - - - - bool effectHandler(const HomieRange& range, const String& value) { Homie.getLogger() << "-> " << value << endl; int sep = value.indexOf("|"); @@ -434,26 +366,5 @@ void loop() { return true; } - bool iconHandler(const HomieRange& range, const String& value) { - String _iconname = value; - iconcolor = strip.Color(255, 255, 255); //default color - if (value[0] == '#') { //color given - iconcolor = parseColor(value.substring(0, 6)); - _iconname = value.substring(7); // example: #ff00dc|A (pipe will be ignored) - } - - iconCountStart = FPS * 2; - iconCountdown = iconCountStart; - if (_iconname.length() == 1) { //only one character - iconchar = value[0]; - } else { - - } - - strip.show(); - - return true; - } - */