diff --git a/platformio.ini b/platformio.ini index bb02cf3..201a996 100644 --- a/platformio.ini +++ b/platformio.ini @@ -8,7 +8,7 @@ ; Please visit documentation for the other options and examples ; https://docs.platformio.org/page/projectconf.html -[env:esp01] +[env:d1_minid1_mini] platform = espressif8266 -board = esp01 +board = d1_mini framework = arduino diff --git a/platformio.pro b/platformio.pro index 79c43d1..6ab505d 100644 --- a/platformio.pro +++ b/platformio.pro @@ -64,13 +64,14 @@ DEFINES += "VTABLES_IN_FLASH" OTHER_FILES += platformio.ini -SOURCES += src/main.cpp +HEADERS += src/ledsettings.h HEADERS += src/ledcontroller.h HEADERS += src/pattern.h -HEADERS += src/patterns/rainbowpattern.h -HEADERS += src/patterns/rainbowwithglitterpattern.h +SOURCES += src/main.cpp HEADERS += src/patterns/confettipattern.h +HEADERS += src/patterns/fire2012pattern.h HEADERS += src/patterns/sineleonpattern.h +HEADERS += src/patterns/rainbowpattern.h HEADERS += src/patterns/jugglepattern.h HEADERS += src/patterns/bpmpattern.h -HEADERS += src/patterns/fire2012pattern.h +HEADERS += src/patterns/rainbowwithglitterpattern.h diff --git a/src/ledcontroller.h b/src/ledcontroller.h index d441eb8..2c9f18d 100644 --- a/src/ledcontroller.h +++ b/src/ledcontroller.h @@ -5,6 +5,7 @@ #include +#include "ledsettings.h" #include "patterns/rainbowpattern.h" #include "patterns/rainbowwithglitterpattern.h" #include "patterns/confettipattern.h" @@ -13,13 +14,42 @@ #include "patterns/bpmpattern.h" #include "patterns/fire2012pattern.h" -class LedController { +FASTLED_USING_NAMESPACE + +class LedController +{ public: + LedController() : + controller(FastLED.addLeds(&leds[0], leds.size())), + m_rainbow(leds), + m_rainbowWithGlitter(leds), + m_confetti(leds), + m_sineleon(leds), + m_juggle(leds), + m_bpm(leds), + m_fire2012(leds), + patterns { &m_rainbow, &m_rainbowWithGlitter, &m_confetti, &m_sineleon, &m_juggle, &m_bpm, &m_fire2012 }, + iter(patterns.begin()) + { + controller.setCorrection(TypicalLEDStrip); + } + + void nextPattern() + { + iter++; + if (iter == patterns.end()) + iter = patterns.begin(); + } + + void run() + { + (*iter)->run(); + FastLED.show(); + } private: - static constexpr auto NUM_LEDS = 100; - std::array leds; + CLEDController &controller; RainbowPattern m_rainbow; RainbowWithGlitterPattern m_rainbowWithGlitter; @@ -29,5 +59,7 @@ private: BpmPattern m_bpm; Fire2012Pattern m_fire2012; - using PatternContainer = std::array; +public: + const PatternContainer patterns; + PatternContainer::const_iterator iter; }; diff --git a/src/ledsettings.h b/src/ledsettings.h new file mode 100644 index 0000000..db5901a --- /dev/null +++ b/src/ledsettings.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +#include + +FASTLED_USING_NAMESPACE + +class Pattern; + +constexpr auto pin = 0; +constexpr auto NUM_LEDS = 100; +using LedContainer = std::array; +using PatternContainer = std::array; diff --git a/src/main.cpp b/src/main.cpp index 857e4f8..7a46a75 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,235 +6,240 @@ #include #include -#include - #include "ledcontroller.h" -FASTLED_USING_NAMESPACE - constexpr auto WIFI_SSID = "McDonalds Free WiFi 2.4GHz"; constexpr auto WIFI_PASSWD = "Passwort_123"; LedController ledController; -constexpr auto pin = 0; -constexpr auto NUM_LEDS = 100; - -std::array leds; - ESP8266WebServer server(80); -uint8_t gHue = 0; - bool rotatePattern = true; -void addGlitter(fract8 chanceOfGlitter) -{ - if(random8() < chanceOfGlitter) - leds[random16(leds.size())] += CRGB::White; -} - -const std::array, 7> patterns { - []() - { - fill_rainbow(&leds[0], leds.size(), gHue, 7); - }, - []() - { - fill_rainbow(&leds[0], leds.size(), gHue, 7); - addGlitter(80); - }, - []() - { - fadeToBlackBy(&leds[0], leds.size(), 10); - int pos = random16(leds.size()); - leds[pos] += CHSV(gHue + random8(64), 200, 255); - }, - []() - { - fadeToBlackBy(&leds[0], leds.size(), 20); - int pos = beatsin16(13, 0, leds.size() - 1); - leds[pos] += CHSV(gHue, 255, 192); - }, - []() - { - fadeToBlackBy(&leds[0], leds.size(), 20); - byte dothue = 0; - for(int i = 0; i < 8; i++) { - leds[beatsin16(i+7, 0, leds.size() - 1)] |= CHSV(dothue, 200, 255); - dothue += 32; - } - }, - []() - { - uint8_t BeatsPerMinute = 62; - CRGBPalette16 palette = PartyColors_p; - uint8_t beat = beatsin8(BeatsPerMinute, 64, 255); - for(int i = 0; i < leds.size(); i++) - leds[i] = ColorFromPalette(palette, gHue+(i*2), beat-gHue+(i*10)); - }, - []() - { - static constexpr auto COOLING = 55; - static constexpr auto SPARKING = 120; - static constexpr auto gReverseDirection = false; - - // Array of temperature readings at each simulation cell - static std::array heat; - - // Step 1. Cool down every cell a little - for( int i = 0; i < leds.size(); i++) { - heat[i] = qsub8( heat[i], random8(0, ((COOLING * 10) / leds.size()) + 2)); - } - - // Step 2. Heat from each cell drifts 'up' and diffuses a little - for( int k= leds.size() - 1; k >= 2; k--) { - heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2] ) / 3; - } - - // Step 3. Randomly ignite new 'sparks' of heat near the bottom - if( random8() < SPARKING ) { - int y = random8(7); - heat[y] = qadd8( heat[y], random8(160,255) ); - } - - // Step 4. Map from heat cells to LED colors - for( int j = 0; j < leds.size(); j++) { - CRGB color = HeatColor( heat[j]); - int pixelnumber; - if( gReverseDirection ) { - pixelnumber = (leds.size()-1) - j; - } else { - pixelnumber = j; - } - leds[pixelnumber] = color; - } - } -}; - -auto iter = patterns.begin(); - -void nextPattern() -{ - iter++; - if (iter == patterns.end()) - iter = patterns.begin(); -} - -void index_handler() -{ - String str = "" - "" - "" - "" - "

Total Entchen-Control 1.0

" - "

" - "Next pattern "; - if (rotatePattern) - str += "Disable pattern rotate"; - else - str += "Enable pattern rotate "; - - const auto index = std::distance(patterns.begin(), iter); - - str += "

" - "
" - "" - "" + + "" + "" + + "" + "" + "" + "" + ); + }); + + server.on("/status", HTTP_GET, []() + { + server.sendHeader("Connection", "close"); + server.sendHeader("Access-Control-Allow-Origin", "*"); + + String str = "{"; + + str += "\"patterns\":["; + bool first = true; + for (auto pattern : ledController.patterns) + { + if (first) + first = false; + else + str += ','; + + str += "{\"name\":\""; + str += pattern->name(); + str += "\",\"selected\":"; + str += (*ledController.iter) == pattern ? "true" : "false"; + str += '}'; + } + str += "],"; + + str += "\"autoRotate\":"; + str += rotatePattern ? "true" : "false"; + str += ","; + + str += "\"brightness\":"; + str += String(int(FastLED.getBrightness())); + + str += "}"; + + server.send(200, "text/json", str.c_str()); + }); + + server.on("/nextPattern", HTTP_GET, []() + { + ledController.nextPattern(); + server.send(200, "text/html", "ok"); + }); + + server.on("/setPattern", HTTP_GET, []() + { + const String *val = nullptr; + + for (int i = 0; i < server.args(); i++) + if (server.argName(i) == "val") + val = &server.arg(i); + + if (!val) + { + server.send(400, "text/html", "val missing"); + return; + } + + const auto index = atoi(val->c_str()); + if (index < 0 || index >= ledController.patterns.size()) + { + server.send(400, "text/html", "out of range"); + return; + } + + ledController.iter = ledController.patterns.begin() + index; + + server.send(200, "text/html", "ok"); + }); + + server.on("/setPatternRotate", HTTP_GET, []() + { + const String *val = nullptr; + + for (int i = 0; i < server.args(); i++) + if (server.argName(i) == "val") + val = &server.arg(i); + + if (!val) + { + server.send(400, "text/html", "val missing"); + return; + } + + if (*val != "true" && *val != "false") + { + server.send(400, "text/html", "invalid val"); + return; + } + + rotatePattern = *val == "true"; + + server.send(200, "text/html", "ok"); + }); + + server.on("/setBrightness", HTTP_GET, []() + { + const String *val = nullptr; + + for (int i = 0; i < server.args(); i++) + if (server.argName(i) == "val") + val = &server.arg(i); + + if (!val) + { + server.send(400, "text/html", "val missing"); + return; + } + + const auto brightness = atoi(val->c_str()); + if (brightness < 0 || brightness > 255) + { + server.send(400, "text/html", "out of range"); + return; + } + + FastLED.setBrightness(brightness); + + server.send(200, "text/html", "ok"); + }); - server.on("/", HTTP_GET, index_handler); - server.on("/cmd", HTTP_GET, cmd_handler); server.begin(); } @@ -242,15 +247,14 @@ void loop() { EVERY_N_MILLISECONDS(20) { - (*iter)(); - FastLED.show(); + ledController.run(); } if (rotatePattern) { EVERY_N_SECONDS(10) { - nextPattern(); + ledController.nextPattern(); } } diff --git a/src/pattern.h b/src/pattern.h index 16d4ddd..636fddb 100644 --- a/src/pattern.h +++ b/src/pattern.h @@ -1,5 +1,17 @@ #pragma once -class Pattern { +#include "ledcontroller.h" +class Pattern { +public: + Pattern(LedContainer leds) : + leds(leds) + { + } + + virtual const char *name() const = 0; + virtual void run() = 0; + +protected: + LedContainer &leds; }; diff --git a/src/patterns/bpmpattern.h b/src/patterns/bpmpattern.h index 042cebe..7040ffe 100644 --- a/src/patterns/bpmpattern.h +++ b/src/patterns/bpmpattern.h @@ -2,6 +2,31 @@ #include "pattern.h" -class BpmPattern : public Pattern { +#include +#include "ledsettings.h" +#include "ledcontroller.h" + +FASTLED_USING_NAMESPACE + +class BpmPattern : public Pattern { +public: + using Pattern::Pattern; + + const char *name() const override + { + return "bpm"; + } + + void run() override + { + uint8_t BeatsPerMinute = 62; + CRGBPalette16 palette = PartyColors_p; + uint8_t beat = beatsin8(BeatsPerMinute, 64, 255); + for(int i = 0; i < leds.size(); i++) + leds[i] = ColorFromPalette(palette, gHue+(i*2), beat-(gHue++)+(i*10)); + } + +private: + uint8_t gHue = 0; }; diff --git a/src/patterns/confettipattern.h b/src/patterns/confettipattern.h index 0c0e09e..60a3600 100644 --- a/src/patterns/confettipattern.h +++ b/src/patterns/confettipattern.h @@ -2,6 +2,29 @@ #include "pattern.h" -class ConfettiPattern : public Pattern { +#include +#include "ledsettings.h" +#include "ledcontroller.h" + +FASTLED_USING_NAMESPACE + +class ConfettiPattern : public Pattern { +public: + using Pattern::Pattern; + + const char *name() const override + { + return "confetti"; + } + + void run() override + { + fadeToBlackBy(&leds[0], leds.size(), 10); + int pos = random16(leds.size()); + leds[pos] += CHSV(gHue++ + random8(64), 200, 255); + } + +private: + uint8_t gHue = 0; }; diff --git a/src/patterns/fire2012pattern.h b/src/patterns/fire2012pattern.h index d8957fa..a6cd1a0 100644 --- a/src/patterns/fire2012pattern.h +++ b/src/patterns/fire2012pattern.h @@ -2,6 +2,62 @@ #include "pattern.h" -class Fire2012Pattern : public Pattern { +#include +#include "ledsettings.h" +#include "ledcontroller.h" + +FASTLED_USING_NAMESPACE + +class Fire2012Pattern : public Pattern +{ + static constexpr auto COOLING = 55; + static constexpr auto SPARKING = 120; + static constexpr auto gReverseDirection = false; + + std::array heat; + +public: + using Pattern::Pattern; + + const char *name() const override + { + return "fire2012"; + } + + void run() override + { + // Step 1. Cool down every cell a little + for( int i = 0; i < leds.size(); i++) + { + heat[i] = qsub8( heat[i], random8(0, ((COOLING * 10) / leds.size()) + 2)); + } + + // Step 2. Heat from each cell drifts 'up' and diffuses a little + for( int k= leds.size() - 1; k >= 2; k--) + { + heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2] ) / 3; + } + + // Step 3. Randomly ignite new 'sparks' of heat near the bottom + if( random8() < SPARKING ) + { + int y = random8(7); + heat[y] = qadd8( heat[y], random8(160,255) ); + } + + // Step 4. Map from heat cells to LED colors + for( int j = 0; j < leds.size(); j++) + { + CRGB color = HeatColor( heat[j]); + int pixelnumber; + + if( gReverseDirection ) + pixelnumber = (leds.size()-1) - j; + else + pixelnumber = j; + + leds[pixelnumber] = color; + } + } }; diff --git a/src/patterns/jugglepattern.h b/src/patterns/jugglepattern.h index 5d3cefd..30d46ea 100644 --- a/src/patterns/jugglepattern.h +++ b/src/patterns/jugglepattern.h @@ -2,6 +2,29 @@ #include "pattern.h" -class JugglePattern : public Pattern { +#include +#include "ledsettings.h" +#include "ledcontroller.h" + +FASTLED_USING_NAMESPACE + +class JugglePattern : public Pattern { +public: + using Pattern::Pattern; + + const char *name() const override + { + return "juggle"; + } + + void run() override + { + fadeToBlackBy(&leds[0], leds.size(), 20); + byte dothue = 0; + for(int i = 0; i < 8; i++) { + leds[beatsin16(i+7, 0, leds.size() - 1)] |= CHSV(dothue, 200, 255); + dothue += 32; + } + } }; diff --git a/src/patterns/rainbowpattern.h b/src/patterns/rainbowpattern.h index 9dcef47..ae6739e 100644 --- a/src/patterns/rainbowpattern.h +++ b/src/patterns/rainbowpattern.h @@ -2,6 +2,27 @@ #include "pattern.h" -class RainbowPattern : public Pattern { +#include +#include "ledsettings.h" +#include "ledcontroller.h" + +FASTLED_USING_NAMESPACE + +class RainbowPattern : public Pattern { +public: + using Pattern::Pattern; + + const char *name() const override + { + return "rainbow"; + } + + void run() override + { + fill_rainbow(&leds[0], leds.size(), gHue++, 7); + } + +private: + uint8_t gHue = 0; }; diff --git a/src/patterns/rainbowwithglitterpattern.h b/src/patterns/rainbowwithglitterpattern.h index 65f6832..f361e74 100644 --- a/src/patterns/rainbowwithglitterpattern.h +++ b/src/patterns/rainbowwithglitterpattern.h @@ -2,6 +2,32 @@ #include "rainbowpattern.h" -class RainbowWithGlitterPattern : public RainbowPattern { +#include +#include "ledsettings.h" +#include "ledcontroller.h" + +FASTLED_USING_NAMESPACE + +class RainbowWithGlitterPattern : public RainbowPattern { +public: + using RainbowPattern::RainbowPattern; + + const char *name() const override + { + return "rainbowWithGlitter"; + } + + void run() override + { + RainbowPattern::run(); + addGlitter(80); + } + +private: + void addGlitter(fract8 chanceOfGlitter) + { + if(random8() < chanceOfGlitter) + leds[random16(leds.size())] += CRGB::White; + } }; diff --git a/src/patterns/sineleonpattern.h b/src/patterns/sineleonpattern.h index 93c3c5e..6228c75 100644 --- a/src/patterns/sineleonpattern.h +++ b/src/patterns/sineleonpattern.h @@ -2,6 +2,29 @@ #include "pattern.h" -class SineleonPattern : public Pattern { +#include +#include "ledsettings.h" +#include "ledcontroller.h" + +FASTLED_USING_NAMESPACE + +class SineleonPattern : public Pattern { +public: + using Pattern::Pattern; + + const char *name() const override + { + return "sineleon"; + } + + void run() override + { + fadeToBlackBy(&leds[0], leds.size(), 20); + int pos = beatsin16(13, 0, leds.size() - 1); + leds[pos] += CHSV(gHue++, 255, 192); + } + +private: + uint8_t gHue = 0; };