diff --git a/NeoPatterns.cpp b/NeoPatterns.cpp new file mode 100644 index 0000000..b7698fe --- /dev/null +++ b/NeoPatterns.cpp @@ -0,0 +1,654 @@ +#include "NeoPatterns.h" + +NeoPatterns::NeoPatterns(uint16_t pixels, uint8_t pin, uint8_t type, void (*callback)()) : + Adafruit_NeoPixel(pixels, pin, type) +{ + OnComplete = callback; + //Allocate a zero initialized block of memory big enough to hold "pixels" uint8_t. + pixelR = ( uint8_t* ) calloc( pixels, sizeof( uint8_t ) ); + pixelG = ( uint8_t* ) calloc( pixels, sizeof( uint8_t ) ); + pixelB = ( uint8_t* ) calloc( pixels, sizeof( uint8_t ) ); + pixelR_buffer = ( uint8_t* ) calloc( pixels, sizeof( uint8_t ) ); + pixelG_buffer = ( uint8_t* ) calloc( pixels, sizeof( uint8_t ) ); + pixelB_buffer = ( uint8_t* ) calloc( pixels, sizeof( uint8_t ) ); +} + +void NeoPatterns::Update() { + if ((millis() - lastUpdate) > Interval) // time to update + { + lastUpdate = millis(); + switch (ActivePattern) + { + case RAINBOW_CYCLE: + RainbowCycleUpdate(); + break; + case THEATER_CHASE: + TheaterChaseUpdate(); + break; + case COLOR_WIPE: + ColorWipeUpdate(); + break; + case SCANNER: + ScannerUpdate(); + break; + case FADE: + FadeUpdate(); + break; + case RANDOM_FADE: + RandomFadeUpdate(); + break; + case RANDOM_FADE_SINGLE: + RandomFadeSingleUpdate(); + break; + case SMOOTH: + SmoothUpdate(); + break; + case PLASMA: + PlasmaUpdate(); + break; + case FILL: + break; + case RANDOM: + break; + case NONE: + break; + default: + break; + } + } else { + delay(1); + } +} + +void NeoPatterns::Increment() +{ + if (Direction == FORWARD) + { + Index++; + if (Index >= TotalSteps) + { + Index = 0; + if (OnComplete != NULL) + { + OnComplete(); // call the completion callback + } + } + } + else // Direction == REVERSE + { + --Index; + if (Index <= 0) + { + Index = TotalSteps - 1; + if (OnComplete != NULL) + { + OnComplete(); // call the completion callback + } + } + } +} + +void NeoPatterns::Reverse() { + if (Direction == FORWARD) + { + Direction = REVERSE; + Index = TotalSteps - 1; + } + else + { + Direction = FORWARD; + Index = 0; + } +} + +void NeoPatterns::Stop(uint8_t interval) { + Interval = interval; + ActivePattern = NONE; +} + +void NeoPatterns::None(uint8_t interval) { + Interval = interval; + if (ActivePattern != NONE) { + clear(); + show(); + } + ActivePattern = NONE; +} + +/****************** Effects ******************/ + +void NeoPatterns::RainbowCycle(uint8_t interval, direction dir) { + ActivePattern = RAINBOW_CYCLE; + Interval = interval; + TotalSteps = 255; + Index = 0; + Direction = dir; +} + +void NeoPatterns::RainbowCycleUpdate() +{ + for (int i = 0; i < numPixels(); i++) + { + setPixelColor(i, Wheel(((i * 256 / numPixels()) + Index) & 255)); + } + show(); + Increment(); +} + +void NeoPatterns::TheaterChase(uint32_t color1, uint32_t color2, uint8_t interval, direction dir) { + ActivePattern = THEATER_CHASE; + Interval = interval; + TotalSteps = numPixels(); + Color1 = color1; + Color2 = color2; + Index = 0; + Direction = dir; +} +void NeoPatterns::TheaterChaseUpdate() { + for (int i = 0; i < numPixels(); i++) + { + if ((i + Index) % 3 == 0) + { + setPixelColor(i, Color1); + } + else + { + setPixelColor(i, Color2); + } + } + show(); + Increment(); +} + +void NeoPatterns::ColorWipe(uint32_t color, uint8_t interval, direction dir) +{ + ActivePattern = COLOR_WIPE; + Interval = interval; + TotalSteps = numPixels(); + Color1 = color; + Index = 0; + Direction = dir; +} + +// Update the Color Wipe Pattern +void NeoPatterns::ColorWipeUpdate() +{ + setPixelColor(Index, Color1); + show(); + Increment(); +} + +// Initialize for a SCANNNER +void NeoPatterns::Scanner(uint32_t color1, uint8_t interval, bool colorful, bool spiral) +{ + ActivePattern = SCANNER; + Interval = interval; + TotalSteps = (numPixels() - 1) * 2; + Color1 = color1; + Index = 0; + wPos = 0; + this->colorful = colorful; + this->spiral = spiral; +} + +// Update the Scanner Pattern +void NeoPatterns::ScannerUpdate() +{ + if (colorful) { + Color1 = Wheel(wPos); + if (wPos >= 255) { + wPos = 0; + } + else { + wPos++; + } + } + for (int i = 0; i < numPixels(); i++) + { + int finalpos; + if (spiral) { + finalpos = numToSpiralPos(i); + } + else + { + finalpos = i; + } + if (i == Index) // Scan Pixel to the right + { + setPixelColor(finalpos, Color1); + } + else if (i == TotalSteps - Index) // Scan Pixel to the left + { + setPixelColor(finalpos, Color1); + } + else // Fading tail + { + setPixelColor(finalpos, DimColor(getPixelColor(finalpos))); + } + } + show(); + Increment(); + +} + +void NeoPatterns::Fade(uint32_t color1, uint32_t color2, uint16_t steps, uint8_t interval, direction dir) +{ + ActivePattern = FADE; + Interval = interval; + TotalSteps = steps; + Color1 = color1; + Color2 = color2; + Index = 0; + Direction = dir; +} + +// Update the Fade Pattern +void NeoPatterns::FadeUpdate() +{ + // Calculate linear interpolation between Color1 and Color2 + // Optimise order of operations to minimize truncation error + uint8_t red = ((Red(Color1) * (TotalSteps - Index)) + (Red(Color2) * Index)) / TotalSteps; + uint8_t green = ((Green(Color1) * (TotalSteps - Index)) + (Green(Color2) * Index)) / TotalSteps; + uint8_t blue = ((Blue(Color1) * (TotalSteps - Index)) + (Blue(Color2) * Index)) / TotalSteps; + + ColorSet(Color(red, green, blue)); + show(); + Increment(); +} + +void NeoPatterns::RandomFade(uint8_t interval ) { + ActivePattern = RANDOM_FADE; + Interval = 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 + ActivePattern = RANDOM; + 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; + Index = 0; + WheelSpeed = wheelSpeed; + Smoothing = smoothing; + Strength = strength; + movingPoint_x = 3; + movingPoint_y = 3; + // Clear buffer (from previous or different effects) + for (int i = 0; i < numPixels(); i++) { + pixelR_buffer[i] = 0; + pixelG_buffer[i] = 0; + pixelB_buffer[i] = 0; + } +} + +void NeoPatterns::SmoothUpdate() { + uint32_t c = Wheel(wPos); + wPosSlow += WheelSpeed; + wPos = (wPos + (wPosSlow / 10) ) % 255; + wPosSlow = wPosSlow % 16; + + uint8_t r = (uint8_t)(c >> 16); + uint8_t g = (uint8_t)(c >> 8); + uint8_t b = (uint8_t)c; + + movingPoint_x = movingPoint_x + 8 + random(-random(0, 1 + 1), random(0, 1 + 1) + 1); + movingPoint_y = movingPoint_y + 8 + random(-random(0, 1 + 1), random(0, 1 + 1) + 1); + if (movingPoint_x < 8) { + movingPoint_x = 8 - movingPoint_x; + } else if (movingPoint_x >= 16) { + movingPoint_x = 22 - movingPoint_x; + } else { + movingPoint_x -= 8; + } + + if (movingPoint_y < 8) { + movingPoint_y = 8 - movingPoint_y; + } else if (movingPoint_y >= 16) { + movingPoint_y = 22 - movingPoint_y; + } else { + movingPoint_y -= 8; + } + uint8_t startx = movingPoint_x; + uint8_t starty = movingPoint_y; + + for (int i = 0; i < Strength; i++) { + + movingPoint_x = startx + 8 + random(-random(0, 2 + 1), random(0, 2 + 1) + 1); + movingPoint_y = starty + 8 + random(-random(0, 2 + 1), random(0, 2 + 1) + 1); + + if (movingPoint_x < 8) { + movingPoint_x = 8 - movingPoint_x; + } else if (movingPoint_x >= 16) { + movingPoint_x = 22 - movingPoint_x; + } else { + movingPoint_x -= 8; + } + + if (movingPoint_y < 8) { + movingPoint_y = 8 - movingPoint_y; + } else if (movingPoint_y >= 16) { + movingPoint_y = 22 - movingPoint_y; + } else { + movingPoint_y -= 8; + } + + if (pixelR[xyToPos(movingPoint_x, movingPoint_y)] < r) { + pixelR[xyToPos(movingPoint_x, movingPoint_y)]++; + } else if (pixelR[xyToPos(movingPoint_x, movingPoint_y)] > r) { + pixelR[xyToPos(movingPoint_x, movingPoint_y)]--; + } + if (pixelG[xyToPos(movingPoint_x, movingPoint_y)] < g) { + pixelG[xyToPos(movingPoint_x, movingPoint_y)]++; + } else if (pixelG[xyToPos(movingPoint_x, movingPoint_y)] > g) { + pixelG[xyToPos(movingPoint_x, movingPoint_y)]--; + } + if (pixelB[xyToPos(movingPoint_x, movingPoint_y)] < b) { + pixelB[xyToPos(movingPoint_x, movingPoint_y)]++; + } else if (pixelB[xyToPos(movingPoint_x, movingPoint_y)] > b) { + pixelB[xyToPos(movingPoint_x, movingPoint_y)]--; + } + } + + movingPoint_x = startx; + movingPoint_y = starty; + + for (int i = 0; i < numPixels(); i++) { + pixelR_buffer[i] = (Smoothing / 100.0) * pixelR[i] + (1.0 - (Smoothing / 100.0)) * getAverage(pixelR, i, 0, 0); + pixelG_buffer[i] = (Smoothing / 100.0) * pixelG[i] + (1.0 - (Smoothing / 100.0)) * getAverage(pixelG, i, 0, 0); + pixelB_buffer[i] = (Smoothing / 100.0) * pixelB[i] + (1.0 - (Smoothing / 100.0)) * getAverage(pixelB, i, 0, 0); + + } + + for (int i = 0; i < numPixels(); i++) { + pixelR[i] = pixelR_buffer[i]; + pixelG[i] = pixelG_buffer[i]; + pixelB[i] = pixelB_buffer[i]; + setPixelColor(i, pixelR[i], pixelG[i], pixelB[i]); + } + + show(); +} + +// Based upon https://github.com/johncarl81/neopixelplasma +void NeoPatterns::Plasma(float phase, float phaseIncrement, float colorStretch, uint8_t interval) +{ + ActivePattern = PLASMA; + Interval = interval; + PlasmaPhase = phase; + PlasmaPhaseIncrement = phaseIncrement; + PlasmaColorStretch = colorStretch; +} + +void NeoPatterns::PlasmaUpdate() +{ + PlasmaPhase += PlasmaPhaseIncrement; + int edge = (int)sqrt(numPixels()); + // The two points move along Lissajious curves, see: http://en.wikipedia.org/wiki/Lissajous_curve + // The sin() function returns values in the range of -1.0..1.0, so scale these to our desired ranges. + // The phase value is multiplied by various constants; I chose these semi-randomly, to produce a nice motion. + Point p1 = { (sin(PlasmaPhase * 1.000) + 1.0) * (edge / 2), (sin(PlasmaPhase * 1.310) + 1.0) * (edge / 2) }; + Point p2 = { (sin(PlasmaPhase * 1.770) + 1.0) * (edge / 2), (sin(PlasmaPhase * 2.865) + 1.0) * (edge / 2) }; + Point p3 = { (sin(PlasmaPhase * 0.250) + 1.0) * (edge / 2), (sin(PlasmaPhase * 0.750) + 1.0) * (edge / 2)}; + + byte row, col; + + // For each row... + for ( row = 0; row < edge; row++ ) { + float row_f = float(row); // Optimization: Keep a floating point value of the row number, instead of recasting it repeatedly. + + // For each column... + for ( col = 0; col < edge; col++ ) { + float col_f = float(col); // Optimization. + + // Calculate the distance between this LED, and p1. + Point dist1 = { col_f - p1.x, row_f - p1.y }; // The vector from p1 to this LED. + float distance1 = sqrt( dist1.x * dist1.x + dist1.y * dist1.y ); + + // Calculate the distance between this LED, and p2. + Point dist2 = { col_f - p2.x, row_f - p2.y }; // The vector from p2 to this LED. + float distance2 = sqrt( dist2.x * dist2.x + dist2.y * dist2.y ); + + // Calculate the distance between this LED, and p3. + Point dist3 = { col_f - p3.x, row_f - p3.y }; // The vector from p3 to this LED. + float distance3 = sqrt( dist3.x * dist3.x + dist3.y * dist3.y ); + + // Warp the distance with a sin() function. As the distance value increases, the LEDs will get light,dark,light,dark,etc... + // You can use a cos() for slightly different shading, or experiment with other functions. Go crazy! + float color_1 = distance1; // range: 0.0...1.0 + float color_2 = distance2; + float color_3 = distance3; + float color_4 = (sin( distance1 * distance2 * PlasmaColorStretch )) + 2.0 * 0.5; + + // Square the color_f value to weight it towards 0. The image will be darker and have higher contrast. + color_1 *= color_1 * color_4; + color_2 *= color_2 * color_4; + color_3 *= color_3 * color_4; + color_4 *= color_4; + + // Scale the color up to 0..7 . Max brightness is 7. + //strip.setPixelColor(col + (edge * row), strip.Color(color_4, 0, 0) ); + + setPixelColor(xyToPos(row, col), Color(color_1, color_2, color_3)); + } + } + show(); +} + + +/****************** Helper functions ******************/ + +void NeoPatterns::SetColor1(uint32_t color) { + Color1 = color; +} +void NeoPatterns::SetColor2(uint32_t color) { + Color2 = color; +} + +// Calculate 50% dimmed version of a color (used by ScannerUpdate) +uint32_t NeoPatterns::DimColor(uint32_t color) +{ + // Shift R, G and B components one bit to the right + uint32_t dimColor = Color(Red(color) >> 1, Green(color) >> 1, Blue(color) >> 1); + return dimColor; +} + +// Set all pixels to a color (synchronously) +void NeoPatterns::ColorSet(uint32_t color) +{ + for (int i = 0; i < numPixels(); i++) + { + setPixelColor(i, color); + } + show(); +} + +void NeoPatterns::ColorSetParameters(String parameters) +{ + None(); + ActivePattern = FILL; + ColorSet(parseColor(parameters)); +} + +// Returns the Red component of a 32-bit color +uint8_t NeoPatterns::Red(uint32_t color) +{ + return (color >> 16) & 0xFF; +} + +// Returns the Green component of a 32-bit color +uint8_t NeoPatterns::Green(uint32_t color) +{ + return (color >> 8) & 0xFF; +} + +// Returns the Blue component of a 32-bit color +uint8_t NeoPatterns::Blue(uint32_t color) +{ + return color & 0xFF; +} + +// Input a value 0 to 255 to get a color value. +// The colors are a transition r - g - b - back to r. +uint32_t NeoPatterns::Wheel(byte WheelPos) +{ + WheelPos = 255 - WheelPos; + if (WheelPos < 85) + { + return Color(255 - WheelPos * 3, 0, WheelPos * 3); + } + else if (WheelPos < 170) + { + WheelPos -= 85; + return Color(0, WheelPos * 3, 255 - WheelPos * 3); + } + else + { + WheelPos -= 170; + return Color(WheelPos * 3, 255 - WheelPos * 3, 0); + } +} + +// Convert x y pixel position to matrix position +uint8_t NeoPatterns::xyToPos(int x, int y) { + if (y % 2 == 0) { + return (y * 8 + x); + } else { + return (y * 8 + (7 - x)); + } +} + +//convert pixel number to actual 8x8 matrix position +uint8_t NeoPatterns::numToPos(int num) { + int x = num % 8; + int y = num / 8; + return xyToPos(x, y); +} + +// Convert pixel number to actual 8x8 matrix position in a spiral +uint8_t NeoPatterns::numToSpiralPos(int num) { + int edge = (int)sqrt(numPixels()); + int findx = edge - 1; // 7 + int findy = 0; + int stepsize = edge - 1; // initial value (0..7) + int stepnumber = 0; // each "step" should be used twice + int count = -1; + int dir = 1; // direction: 0 = incX, 1=incY, 2=decX, 3=decY + if (num < edge) { + return num; // trivial + } + for (int i = edge; i <= num; i++) + { + count++; + if (count == stepsize) { + count = 0; + // Change direction + dir++; + stepnumber++; + if (stepnumber == 2) { + stepsize -= 1; + stepnumber = 0; + } + if (dir == 4) { + dir = 0; + } + } + switch (dir) { + case 0: + findx++; + break; + case 1: + findy++; + break; + case 2: + findx--; + break; + case 3: + findy--; + break; + } + } + return xyToPos(findx, findy); +} + +uint8_t NeoPatterns::getAverage(uint8_t array[], uint8_t i, int x, int y) +{ + // TODO: This currently works only with 8x8 (64 pixel)! + uint16_t sum = 0; + uint8_t count = 0; + if (i >= 8) { //up + sum += array[i - 8]; + count++; + } + if (i < (64 - 8)) { //down + sum += array[i + 8]; + count++; + } + if (i >= 1) { //left + sum += array[i - 1]; + count++; + } + if (i < (64 - 1)) { //right + sum += array[i + 1]; + count++; + } + return sum / count; +} + +uint32_t NeoPatterns::parseColor(String value) { + if (value.charAt(0) == '#') { //solid fill + String color = value.substring(1); + int number = (int) strtol( &color[0], NULL, 16); + // Split them up into r, g, b values + int r = number >> 16; + int g = number >> 8 & 0xFF; + int b = number & 0xFF; + return Color(r, g, b); + } + return 0; +} + + + + diff --git a/NeoPatterns.h b/NeoPatterns.h new file mode 100644 index 0000000..e2d6069 --- /dev/null +++ b/NeoPatterns.h @@ -0,0 +1,107 @@ +#include + +// Pattern types supported: +enum pattern { NONE, RAINBOW_CYCLE, THEATER_CHASE, COLOR_WIPE, SCANNER, FADE, RANDOM_FADE, SMOOTH, ICON, RANDOM_FADE_SINGLE, PLASMA, FILL, RANDOM }; +// Patern directions supported: +enum direction { FORWARD, REVERSE }; + +class NeoPatterns : public Adafruit_NeoPixel +{ + public: + NeoPatterns(uint16_t pixels, uint8_t pin, uint8_t type, void (*callback)()); + + void Update(); + void Reverse(); + void None(uint8_t interval = 40); + void Stop(uint8_t interval = 40); + void RainbowCycle(uint8_t interval, direction dir = FORWARD); + void RainbowCycleUpdate(); + void TheaterChase(uint32_t color1, uint32_t color2, uint8_t interval, direction dir = FORWARD); + void TheaterChaseUpdate(); + void ColorWipe(uint32_t color, uint8_t interval, direction dir = FORWARD); + void ColorWipeUpdate(); + 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 Plasma(float phase = 0, float phaseIncrement = 0.08, float colorStretch = 0.11, uint8_t interval = 60); // 0.08 and 0.11 // 0.03 und 0.3 + void PlasmaUpdate(); + + void SetColor1(uint32_t color); + void SetColor2(uint32_t color); + //Utilities + void ColorSet(uint32_t color); + void ColorSetParameters(String parameters); + uint8_t Red(uint32_t color); + uint8_t Green(uint32_t color); + uint8_t Blue(uint32_t color); + uint32_t Wheel(byte WheelPos); + uint8_t numToSpiralPos(int num); + uint8_t xyToPos(int x, int y); + uint8_t numToPos(int num); + uint8_t getAverage(uint8_t array[], uint8_t i, int x, int y); + uint32_t parseColor(String value); + 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; + bool colorful; + bool spiral; + uint8_t wPosSlow; + uint8_t WheelSpeed; + uint8_t Smoothing; + uint8_t Strength; + uint8_t movingPoint_x; + uint8_t movingPoint_y; + uint8_t *pixelR; + uint8_t *pixelG; + uint8_t *pixelB; + uint8_t *pixelR_buffer; + uint8_t *pixelG_buffer; + uint8_t *pixelB_buffer; + + float PlasmaPhase; + float SavedPlasmaPhase; + float PlasmaPhaseIncrement; + float SavedPlasmaPhaseIncrement; + float PlasmaColorStretch; + float SavedPlasmaColorStretch; + + + uint32_t DimColor(uint32_t color); + void Increment(); + void (*OnComplete)(); // Callback on completion of pattern + + // Convenient 2D point structure + struct Point { + float x; + float y; + }; + + +}; diff --git a/esp-videoswitcher.ino b/esp-videoswitcher.ino index cff272d..599fa59 100644 --- a/esp-videoswitcher.ino +++ b/esp-videoswitcher.ino @@ -2,6 +2,14 @@ #include #include #include +#include "NeoPatterns.h" + +#define PIN D6 +#define NUMPIXELS 81 + +NeoPatterns strip = NeoPatterns(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ400, &StripComplete); +// NeoPatterns strip = NeoPatterns(NUMPIXELS, PIN, NEO_RGB + NEO_KHZ400, &StripComplete); +HomieNode homieNode("pixel", "commands"); // Timeout, wann die Verbindung als "zurückgesetzt" angesehen werden soll und wieder auf das erste Byte gewartet wird #define TIMEOUT 500 @@ -18,6 +26,155 @@ String output2 = ""; HomieNode switchNode("switch", "switch"); +void StripComplete(){ + return; +} + +bool onSetColor(const HomieRange& range, const String& value) { + if (!range.isRange || range.index < 0 || range.index > 1) { + return false; + } + switch (range.index) { + case 0: + strip.SetColor1(value.toInt()); + break; + case 1: + strip.SetColor2(value.toInt()); + break; + } + homieNode.setProperty("color_" + String(range.index)).send(value); +} + +bool onSetPixel(const HomieRange& range, const String& value) { + if (!range.isRange) { + strip.None(); + strip.ColorSet(value.toInt()); + homieNode.setProperty("pixel").send(value); + return true; + } + if (range.index < 0 || range.index > strip.numPixels() - 1) { + return false; + } + strip.None(); + strip.setPixelColor(range.index, value.toInt()); + strip.show(); + homieNode.setProperty("pixel_" + String(range.index)).send(value); +} + +bool onSetBrightness(const HomieRange& range, const String& value) { + long brightness = value.toInt(); + if (brightness < 0 || brightness > 255) { + return false; + } + strip.setBrightness(brightness); + strip.show(); + homieNode.setProperty("brightness").send(value); +} + +bool onSetPixels(const HomieRange& range, const String& value) { + + String remaining = value; + int i = 0; + // Kein Effekt + strip.Stop(); + do { + String current = remaining.substring(0, 7); + Homie.getLogger() << i << ":" << current << endl; + uint32_t currentcolor = strip.parseColor(current); + + strip.setPixelColor(strip.numToPos(i), currentcolor); + i++; + + remaining = remaining.substring(7); + + } while (remaining.length() > 2 && (i < strip.numPixels())); + Homie.getLogger() << " filling rest with black" << endl; + while (i < strip.numPixels()) { + strip.setPixelColor(strip.numToPos(i), strip.Color(0, 0, 0)); + i++; + } + + strip.show(); + + return true; +} + +bool onSetEffect(const HomieRange& range, const String& value) { + String effect = value; + effect.toLowerCase(); + if (effect == "scanner") { + strip.Scanner(strip.Color(255, 0, 0)); + } + else if (effect == "randomscanner") { + strip.Scanner(strip.Color(255, 0, 0), 40, true); + } + else if (effect == "larsonspiral") { + strip.Scanner(strip.Color(255, 0, 0), 40, true, true); + } + else if (effect == "rainbowcycle") { + strip.RainbowCycle(50); + } + else if (effect == "theaterchase" || effect == "chase") { + strip.TheaterChase(strip.Color(255, 0, 0), strip.Color(0, 0, 255), 100); + } + else if (effect == "fade") { + strip.Fade(strip.Color(255, 0, 0), strip.Color(0, 0, 255), 200, 100); + } + else if (effect == "randomfade") { + strip.RandomFade(); + } + 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 if (effect == "plasma") { + strip.Plasma(); + } + else { + // Test whether command with parameters was sent + int sep = value.indexOf("|"); + String command = value.substring(0, sep); + String parameters = value.substring(sep + 1); + if (command.equals("fill")) { + strip.ColorSetParameters(parameters); + } + 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 onSetClear(const HomieRange& range, const String& value) { + strip.None(); + strip.clear(); + strip.show(); + homieNode.setProperty("clear").send(value); +} + +bool onSetLength(const HomieRange& range, const String& value) { + strip.None(); + strip.clear(); + strip.show(); + int newLength = value.toInt(); + if (newLength > 0) { + strip.updateLength(newLength); + } + homieNode.setProperty("length").send(value); +} + + + bool switchHandler(const HomieRange& range, const String& value) { Homie.getLogger() << "switch " << ": " << value << endl; int localByte = 0; @@ -56,6 +213,11 @@ bool switchHandler(const HomieRange& range, const String& value) { return true; } +void loopHandler() { + strip.Update(); +} + + void setup() { Serial.begin(115200); swSer.begin(9600); @@ -64,10 +226,25 @@ void setup() { Homie_setFirmware(FW_NAME, FW_VERSION); Homie_setBrand(FW_NAME); + Homie.setLoopFunction(loopHandler); + switchNode.advertise("switch").settable(switchHandler); + homieNode.advertiseRange("pixel", 0, NUMPIXELS - 1).settable(onSetPixel); + homieNode.advertiseRange("color", 0, 1).settable(onSetColor); + homieNode.advertise("brightness").settable(onSetBrightness); + homieNode.advertise("effect").settable(onSetEffect); + homieNode.advertise("clear").settable(onSetClear); + homieNode.advertise("length").settable(onSetLength); + homieNode.advertiseRange("pixels", 0, (NUMPIXELS - 1)*7).settable(onSetPixels); + + Homie.setup(); + strip.begin(); + strip.clear(); + strip.show(); + ArduinoOTA.setHostname(Homie.getConfiguration().deviceId); ArduinoOTA.begin(); } @@ -75,7 +252,7 @@ void setup() { void loop() { Homie.loop(); ArduinoOTA.handle(); - + while (swSer.available() > 0) { int r1 = swSer.read(); Serial.print(currentnumber);