Implemented website

This commit is contained in:
2019-05-04 11:28:57 +02:00
committed by 0xFEEDC0DE64
parent a49d20da89
commit dbfae0cdcc
13 changed files with 494 additions and 234 deletions

View File

@@ -8,7 +8,7 @@
; Please visit documentation for the other options and examples ; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html ; https://docs.platformio.org/page/projectconf.html
[env:esp01] [env:d1_minid1_mini]
platform = espressif8266 platform = espressif8266
board = esp01 board = d1_mini
framework = arduino framework = arduino

View File

@@ -64,13 +64,14 @@ DEFINES += "VTABLES_IN_FLASH"
OTHER_FILES += platformio.ini OTHER_FILES += platformio.ini
SOURCES += src/main.cpp HEADERS += src/ledsettings.h
HEADERS += src/ledcontroller.h HEADERS += src/ledcontroller.h
HEADERS += src/pattern.h HEADERS += src/pattern.h
HEADERS += src/patterns/rainbowpattern.h SOURCES += src/main.cpp
HEADERS += src/patterns/rainbowwithglitterpattern.h
HEADERS += src/patterns/confettipattern.h HEADERS += src/patterns/confettipattern.h
HEADERS += src/patterns/fire2012pattern.h
HEADERS += src/patterns/sineleonpattern.h HEADERS += src/patterns/sineleonpattern.h
HEADERS += src/patterns/rainbowpattern.h
HEADERS += src/patterns/jugglepattern.h HEADERS += src/patterns/jugglepattern.h
HEADERS += src/patterns/bpmpattern.h HEADERS += src/patterns/bpmpattern.h
HEADERS += src/patterns/fire2012pattern.h HEADERS += src/patterns/rainbowwithglitterpattern.h

View File

@@ -5,6 +5,7 @@
#include <FastLED.h> #include <FastLED.h>
#include "ledsettings.h"
#include "patterns/rainbowpattern.h" #include "patterns/rainbowpattern.h"
#include "patterns/rainbowwithglitterpattern.h" #include "patterns/rainbowwithglitterpattern.h"
#include "patterns/confettipattern.h" #include "patterns/confettipattern.h"
@@ -13,13 +14,42 @@
#include "patterns/bpmpattern.h" #include "patterns/bpmpattern.h"
#include "patterns/fire2012pattern.h" #include "patterns/fire2012pattern.h"
class LedController { FASTLED_USING_NAMESPACE
class LedController
{
public: public:
LedController() :
controller(FastLED.addLeds<WS2812, pin, RGB>(&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: private:
static constexpr auto NUM_LEDS = 100;
std::array<CRGB, NUM_LEDS> leds; std::array<CRGB, NUM_LEDS> leds;
CLEDController &controller;
RainbowPattern m_rainbow; RainbowPattern m_rainbow;
RainbowWithGlitterPattern m_rainbowWithGlitter; RainbowWithGlitterPattern m_rainbowWithGlitter;
@@ -29,5 +59,7 @@ private:
BpmPattern m_bpm; BpmPattern m_bpm;
Fire2012Pattern m_fire2012; Fire2012Pattern m_fire2012;
using PatternContainer = std::array<Pattern*, 7>; public:
const PatternContainer patterns;
PatternContainer::const_iterator iter;
}; };

14
src/ledsettings.h Normal file
View File

@@ -0,0 +1,14 @@
#pragma once
#include <array>
#include <FastLED.h>
FASTLED_USING_NAMESPACE
class Pattern;
constexpr auto pin = 0;
constexpr auto NUM_LEDS = 100;
using LedContainer = std::array<CRGB, NUM_LEDS>;
using PatternContainer = std::array<Pattern*, 7>;

View File

@@ -6,235 +6,240 @@
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include <ESP8266WebServer.h> #include <ESP8266WebServer.h>
#include <FastLED.h>
#include "ledcontroller.h" #include "ledcontroller.h"
FASTLED_USING_NAMESPACE
constexpr auto WIFI_SSID = "McDonalds Free WiFi 2.4GHz"; constexpr auto WIFI_SSID = "McDonalds Free WiFi 2.4GHz";
constexpr auto WIFI_PASSWD = "Passwort_123"; constexpr auto WIFI_PASSWD = "Passwort_123";
LedController ledController; LedController ledController;
constexpr auto pin = 0;
constexpr auto NUM_LEDS = 100;
std::array<CRGB, NUM_LEDS> leds;
ESP8266WebServer server(80); ESP8266WebServer server(80);
uint8_t gHue = 0;
bool rotatePattern = true; bool rotatePattern = true;
void addGlitter(fract8 chanceOfGlitter)
{
if(random8() < chanceOfGlitter)
leds[random16(leds.size())] += CRGB::White;
}
const std::array<std::function<void()>, 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<byte, NUM_LEDS> 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 = "<html>"
"<head>"
"</head>"
"<body>"
"<h1>Total Entchen-Control 1.0</h1>"
"<p>"
"<a href=\"cmd?var=nextPattern&val=\">Next pattern</a> ";
if (rotatePattern)
str += "<a href=\"cmd?var=rotatePattern&val=false\">Disable pattern rotate</a>";
else
str += "<a href=\"cmd?var=rotatePattern&val=true\">Enable pattern rotate</a> ";
const auto index = std::distance(patterns.begin(), iter);
str += "</p>"
"<form action=\"cmd\" method=\"GET\">"
"<input type=\"hidden\" name=\"var\" value=\"setPattern\" />"
"<select name=\"val\" size=\"7\">"
"<option value=\"0\"";
if (index == 0)
str += " selected";
str += ">rainbow</option>"
"<option value=\"1\"";
if (index == 1)
str += " selected";
str += ">rainbowWithGlitter</option>"
"<option value=\"2\"";
if (index == 2)
str += " selected";
str += ">confetti</option>"
"<option value=\"3\"";
if (index == 3)
str += " selected";
str += ">sinelon</option>"
"<option value=\"4\"";
if (index == 4)
str += " selected";
str += ">juggle</option>"
"<option value=\"5\"";
if (index == 5)
str += " selected";
str += ">bpm</option>"
"<option value=\"6\"";
if (index == 6)
str += " selected";
str += ">Fire2012</option>"
"</select>"
"<button type=\"submit\">submit</button>"
"</form>"
"</body>"
"</html>";
server.sendHeader("Connection", "close");
server.send(200, "text/html", str.c_str());
}
void cmd_handler()
{
server.sendHeader("Connection", "close");
const String *var = nullptr;
const String *val = nullptr;
for (int i = 0; i < server.args(); i++)
{
if (server.argName(i) == "var")
var = &server.arg(i);
else if (server.argName(i) == "val")
val = &server.arg(i);
}
if (var == nullptr || val == nullptr)
server.send(400, "text/html", "var or val missing");
if (*var == "nextPattern")
{
nextPattern();
server.send(200, "text/html", "ok");
return;
}
else if (*var == "setPattern")
{
const auto index = atoi(val->c_str());
if (index < 0 || index >= patterns.size())
{
server.send(500, "text/html", "out of range");
return;
}
iter = patterns.begin() + index;
server.send(200, "text/html", "ok");
return;
}
else if (*var == "rotatePattern")
{
rotatePattern = *val == "true";
server.send(200, "text/html", "ok");
return;
}
server.send(500, "text/html", "unknown var");
}
void setup() void setup()
{ {
WiFi.begin(WIFI_SSID, WIFI_PASSWD); WiFi.begin(WIFI_SSID, WIFI_PASSWD);
FastLED.addLeds<WS2812, pin, RGB>(&leds[0], leds.size()).setCorrection(TypicalLEDStrip); server.on("/", HTTP_GET, []()
{
server.sendHeader("Connection", "close");
server.send(200, "text/html",
"<!doctype html>"
"<html lang=\"en\">"
"<head>"
"<!-- Required meta tags -->"
"<meta charset=\"utf-8\">"
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">"
"<!-- Bootstrap CSS -->"
"<link rel=\"stylesheet\" href=\"https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css\" integrity=\"sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T\" crossorigin=\"anonymous\">"
"<style>"
".hidden {"
"display: none;"
"}"
"</style>"
"<title>Hello, world!</title>"
"</head>"
"<body>"
"<div class=\"container\">"
"<h1>Hello, world!</h1>"
"<p>"
"<a href=\"nextPattern\" class=\"softLink\">Next pattern</a>"
"<a href=\"setPatternRotate?val=true\" id=\"enableRotate\" class=\"softLink\">Enable automatic pattern rotate</a>"
"<a href=\"setPatternRotate?val=false\" id=\"disableRotate\" class=\"softLink\">Disable automatic pattern rotate</a>"
"</p>"
"<select id=\"patternSelect\"></select>"
"<input type=\"range\" min=\"0\" max=\"255\" id=\"brightness\" />"
"</div>"
"<script src=\"https://code.jquery.com/jquery-3.3.1.slim.min.js\" integrity=\"sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo\" crossorigin=\"anonymous\"></script>"
"<script>"
"jQuery(document).ready(function($){"
"$('.softLink').click(function(){"
"var xhr = new XMLHttpRequest();"
"xhr.open('GET', this.getAttribute('href'));"
"xhr.send();"
"return false;"
"});"
"$('#patternSelect').change(function(){"
"var xhr = new XMLHttpRequest();"
"xhr.open('GET', 'setPattern?val=' + this.selectedIndex);"
"xhr.send();"
"});"
"$('#brightness').change(function(){"
"var xhr = new XMLHttpRequest();"
"xhr.open('GET', 'setBrightness?val=' + this.value);"
"xhr.send();"
"});"
"var refreshStatus = function() {"
"var xhr = new XMLHttpRequest();"
"xhr.open('GET', 'status');"
"xhr.onload = function() {"
"var parsed = JSON.parse(xhr.responseText);"
"if (parsed.autoRotate) {"
"$('#enableRotate').addClass('hidden');"
"$('#disableRotate').removeClass('hidden');"
"} else {"
"$('#enableRotate').removeClass('hidden');"
"$('#disableRotate').addClass('hidden');"
"}"
"var select = $('#patternSelect');"
"select.empty();"
"select.attr('size', parsed.patterns.length);"
"for (var pattern of parsed.patterns) {"
"select.append($('<option>')"
".text(pattern.name)"
".attr('selected', pattern.selected)"
");"
"}"
"$('#brightness').val(parsed.brightness)"
"};"
"xhr.send();"
"};"
"refreshStatus();"
"setInterval(refreshStatus, 1000);"
"});"
"</script>"
"</body>"
"</html>"
);
});
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(); server.begin();
} }
@@ -242,15 +247,14 @@ void loop()
{ {
EVERY_N_MILLISECONDS(20) EVERY_N_MILLISECONDS(20)
{ {
(*iter)(); ledController.run();
FastLED.show();
} }
if (rotatePattern) if (rotatePattern)
{ {
EVERY_N_SECONDS(10) EVERY_N_SECONDS(10)
{ {
nextPattern(); ledController.nextPattern();
} }
} }

View File

@@ -1,5 +1,17 @@
#pragma once #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;
}; };

View File

@@ -2,6 +2,31 @@
#include "pattern.h" #include "pattern.h"
class BpmPattern : public Pattern { #include <FastLED.h>
#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;
}; };

View File

@@ -2,6 +2,29 @@
#include "pattern.h" #include "pattern.h"
class ConfettiPattern : public Pattern { #include <FastLED.h>
#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;
}; };

View File

@@ -2,6 +2,62 @@
#include "pattern.h" #include "pattern.h"
class Fire2012Pattern : public Pattern { #include <FastLED.h>
#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<byte, NUM_LEDS> 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;
}
}
}; };

View File

@@ -2,6 +2,29 @@
#include "pattern.h" #include "pattern.h"
class JugglePattern : public Pattern { #include <FastLED.h>
#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;
}
}
}; };

View File

@@ -2,6 +2,27 @@
#include "pattern.h" #include "pattern.h"
class RainbowPattern : public Pattern { #include <FastLED.h>
#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;
}; };

View File

@@ -2,6 +2,32 @@
#include "rainbowpattern.h" #include "rainbowpattern.h"
class RainbowWithGlitterPattern : public RainbowPattern { #include <FastLED.h>
#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;
}
}; };

View File

@@ -2,6 +2,29 @@
#include "pattern.h" #include "pattern.h"
class SineleonPattern : public Pattern { #include <FastLED.h>
#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;
}; };