From 7e308b3f07a49e4c2eef5281c055d9711d0adab7 Mon Sep 17 00:00:00 2001 From: Juergen Jung Date: Fri, 17 Feb 2017 00:40:42 +0100 Subject: [PATCH] New way of effect handling --- .gitignore | 1 + esp-wemos-schild/NeoPatterns.cpp | 260 +++++++++++++++++++++++ esp-wemos-schild/NeoPatterns.h | 51 +++++ esp-wemos-schild/data/homie/config.json | 6 +- esp-wemos-schild/esp-wemos-schild.ino | 269 +++++++----------------- platformio.ini | 7 +- 6 files changed, 398 insertions(+), 196 deletions(-) create mode 100644 esp-wemos-schild/NeoPatterns.cpp create mode 100644 esp-wemos-schild/NeoPatterns.h diff --git a/.gitignore b/.gitignore index 5bcdef9..b4de7ac 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ .clang_complete .gcc-flags.json .DS_Store +esp-wemos-schild/data/homie/config.json diff --git a/esp-wemos-schild/NeoPatterns.cpp b/esp-wemos-schild/NeoPatterns.cpp new file mode 100644 index 0000000..ba04826 --- /dev/null +++ b/esp-wemos-schild/NeoPatterns.cpp @@ -0,0 +1,260 @@ +#include "NeoPatterns.h" + +NeoPatterns::NeoPatterns(uint16_t pixels, uint8_t pin, uint8_t type, void (*callback)()) : + Adafruit_NeoPixel(pixels, pin, type) +{ + OnComplete = callback; +} + +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 NONE: + break; + default: + break; + } + } +} + +void NeoPatterns::Increment() +{ + if (Direction == FORWARD) + { + Index++; + if (Index >= TotalSteps) + { + Index = 0; + if (OnComplete != NULL) + { + OnComplete(); // call the comlpetion callback + } + } + } + else // Direction == REVERSE + { + --Index; + if (Index <= 0) + { + Index = TotalSteps-1; + if (OnComplete != NULL) + { + OnComplete(); // call the comlpetion callback + } + } + } +} + +void NeoPatterns::Reverse(){ + if (Direction == FORWARD) + { + Direction = REVERSE; + Index = TotalSteps-1; + } + else + { + Direction = FORWARD; + Index = 0; + } +} + +void NeoPatterns::None(){ + if(ActivePattern != NONE) { + clear(); + show(); + } + ActivePattern = NONE; +} + +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) +{ + ActivePattern = SCANNER; + Interval = interval; + TotalSteps = (numPixels() - 1) * 2; + Color1 = color1; + Index = 0; +} + +// Update the Scanner Pattern +void NeoPatterns::ScannerUpdate() +{ + for (int i = 0; i < numPixels(); i++) + { + if (i == Index) // Scan Pixel to the right + { + setPixelColor(i, Color1); + } + else if (i == TotalSteps - Index) // Scan Pixel to the left + { + setPixelColor(i, Color1); + } + else // Fading tail + { + setPixelColor(i, DimColor(getPixelColor(i))); + } + } + 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(); +} + +// 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(); +} + +// 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 colours 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); + } +} diff --git a/esp-wemos-schild/NeoPatterns.h b/esp-wemos-schild/NeoPatterns.h new file mode 100644 index 0000000..17f07e9 --- /dev/null +++ b/esp-wemos-schild/NeoPatterns.h @@ -0,0 +1,51 @@ +#include + +// Pattern types supported: +enum pattern { NONE, RAINBOW_CYCLE, THEATER_CHASE, COLOR_WIPE, SCANNER, FADE }; +// 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(); +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, uint8_t interval); +void ScannerUpdate(); +void Fade(uint32_t color1, uint32_t color2, uint16_t steps, uint8_t interval, direction dir = FORWARD); +void FadeUpdate(); +//Utilities +void ColorSet(uint32_t color); +uint8_t Red(uint32_t color); +uint8_t Green(uint32_t color); +uint8_t Blue(uint32_t color); +uint32_t Wheel(byte WheelPos); + +private: + +// Member Variables: +pattern ActivePattern; // which pattern is running +direction Direction; // direction to run the pattern + +unsigned long Interval; // milliseconds between updates +unsigned long lastUpdate; // last update of position + +uint32_t Color1, Color2; // What colors are in use +uint16_t TotalSteps; // total number of steps in the pattern +uint16_t Index; // current step within the pattern + +uint32_t DimColor(uint32_t color); +void Increment(); +void (*OnComplete)(); // Callback on completion of pattern + +}; diff --git a/esp-wemos-schild/data/homie/config.json b/esp-wemos-schild/data/homie/config.json index 9de67c9..8063e3f 100644 --- a/esp-wemos-schild/data/homie/config.json +++ b/esp-wemos-schild/data/homie/config.json @@ -2,11 +2,11 @@ "name": "Homie CTDO Schild", "device_id": "schild", "wifi": { - "ssid": "ctdo", - "password": "ctdo2342" + "ssid": "Nudel", + "password": "Unser WLAN ist sicher!" }, "mqtt": { - "host": "raum.ctdo.de", + "host": "prometheus.local", "port": 1883, "auth": false }, diff --git a/esp-wemos-schild/esp-wemos-schild.ino b/esp-wemos-schild/esp-wemos-schild.ino index 91e20fa..e1ba9e7 100644 --- a/esp-wemos-schild/esp-wemos-schild.ino +++ b/esp-wemos-schild/esp-wemos-schild.ino @@ -3,229 +3,118 @@ #include #include #include +#include "NeoPatterns.h" #define PIN D1 -#define NUMPIXELS 30 +#define NUMPIXELS 144 + + -uint16_t effectI=0,effectJ=0,wait = 50; -unsigned long lastCall = 0; byte wPos = 0; uint8_t state = 0; -Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); +void StripComplete(){ + return; +} + +NeoPatterns pixels = NeoPatterns(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800,&StripComplete); HomieNode stripNode("strip", "strip"); -String effect = "none"; - -// Input a value 0 to 255 to get a color value. -// The colours are a transition r - g - b - back to r. -uint32_t wheel(byte wheelPos) { - wheelPos = 255 - wheelPos; - if(wheelPos < 85) { - return pixels.Color(255 - wheelPos * 3, 0, wheelPos * 3); - } - if(wheelPos < 170) { - wheelPos -= 85; - return pixels.Color(0, wheelPos * 3, 255 - wheelPos * 3); - } - wheelPos -= 170; - return pixels.Color(wheelPos * 3, 255 - wheelPos * 3, 0); -} - -void getRGBValues(uint32_t *rgbBuffer,uint32_t const color){ - rgbBuffer[0] = color >> 16 & 255; - rgbBuffer[1] = color >> 8 & 255; - rgbBuffer[2] = color & 255; - return ; -} - bool onSetPixel(const HomieRange& range, const String& value){ - if(!range.isRange){ - effect = "none"; - pixels.clear(); - for(int i=0;i pixels.numPixels()-1) { - return false; - } - effect = "none"; - pixels.setPixelColor(range.index, value.toInt()); - pixels.show(); - stripNode.setProperty("pixel_" + String(range.index)).send(value); + if(!range.isRange) { + pixels.None(); + pixels.ColorSet(value.toInt()); + stripNode.setProperty("pixel").send(value); + return true; + } + if (range.index < 0 || range.index > pixels.numPixels()-1) { + return false; + } + pixels.None(); + pixels.setPixelColor(range.index, value.toInt()); + pixels.show(); + stripNode.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; - } - pixels.setBrightness(brightness); - pixels.show(); - stripNode.setProperty("brightness").send(value); + long brightness= value.toInt(); + if (brightness < 0 || brightness > 255) { + return false; + } + pixels.setBrightness(brightness); + pixels.show(); + stripNode.setProperty("brightness").send(value); } bool onSetEffect(const HomieRange& range, const String& value){ - effect = value; - effect.toLowerCase(); - effectI=0,effectJ=0,wait=50; - stripNode.setProperty("effect").send(value); + String effect = value; + effect.toLowerCase(); + if(effect == "scanner") { + pixels.Scanner(pixels.Color(255,0,0), 55); + } + else if(effect == "rainbowcycle") { + pixels.RainbowCycle(50); + } + else if(effect == "theaterchase") { + pixels.TheaterChase(pixels.Color(0,0,255), pixels.Color(255,0,00), 100); + } + else if(effect == "fade") { + pixels.Fade(pixels.Wheel(255),pixels.Wheel(0),255,25); + } + else { + pixels.None(); + } + + stripNode.setProperty("effect").send(value); } bool onSetClear(const HomieRange& range, const String& value){ - effect = "none"; - pixels.clear(); - pixels.show(); - stripNode.setProperty("clear").send(value); + pixels.None(); + pixels.clear(); + pixels.show(); + stripNode.setProperty("clear").send(value); } bool onSetLength(const HomieRange& range, const String& value){ - effect = "none"; - pixels.clear(); - pixels.show(); - int newLength = value.toInt(); - if(newLength > 0){ - pixels.updateLength(newLength); - } - stripNode.setProperty("length").send(value); + pixels.None(); + pixels.clear(); + pixels.show(); + int newLength = value.toInt(); + if(newLength > 0) { + pixels.updateLength(newLength); + } + stripNode.setProperty("length").send(value); } void loopHandler() { - if (effect == "none"){ - return; - } - else if (effect == "larson") { - int SpeedDelay = 20; - int EyeSize = 5; - uint32_t rgb[3] = {0}; - - switch(state){ - case 0: - if(lastCall + wait < millis()){ - state++; - } - break; - case 1: - for(int i = 0; i < pixels.numPixels()-EyeSize-2; i++) { - pixels.clear(); - getRGBValues(rgb,wheel(wPos)); - pixels.setPixelColor(i, rgb[0]/10, rgb[1]/10, rgb[2]/10); - for(int j = 1; j <= EyeSize; j++) { - pixels.setPixelColor(i+j, wheel(wPos++)); - } - getRGBValues(rgb,wheel(wPos)); - pixels.setPixelColor(i+EyeSize+1, rgb[0]/10, rgb[1]/10, rgb[2]/10); - pixels.show(); - - delay(SpeedDelay); - } - lastCall = millis(); - state++; - break; - case 2: - if(lastCall + wait < millis()){ - state++; - } - break; - case 3: - for(int i = pixels.numPixels()-EyeSize-2; i > 0; i--) { - pixels.clear(); - getRGBValues(rgb,wheel(wPos)); - pixels.setPixelColor(i, rgb[0]/10, rgb[1]/10, rgb[2]/10); - for(int j = 1; j <= EyeSize; j++) { - pixels.setPixelColor(i+j, wheel(wPos++)); - } - pixels.setPixelColor(i+EyeSize+1, rgb[0]/10, rgb[1]/10, rgb[2]/10); - pixels.show(); - - delay(SpeedDelay); - } - lastCall = millis(); - state++; - break; - default: - state = 0; - } - } - else if (effect == "randomfade") { - if(lastCall + wait > millis()){ - return; - } - lastCall = millis(); - for(int i=0;i= millis()){ - return; - } - if(effectJ<256) { - if(effectI