esp8266-nanoleaf-webserver/esp8266-fastled-webserver.ino

1269 lines
34 KiB
Arduino
Raw Normal View History

2016-03-10 14:57:02 +01:00
/*
ESP8266 FastLED WebServer: https://github.com/jasoncoon/esp8266-fastled-webserver
Copyright (C) 2015-2018 Jason Coon
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//#define FASTLED_ALLOW_INTERRUPTS 1
//#define INTERRUPT_THRESHOLD 1
#define FASTLED_INTERRUPT_RETRY_COUNT 0
2016-03-10 14:57:02 +01:00
#include <FastLED.h>
2016-03-10 14:57:02 +01:00
FASTLED_USING_NAMESPACE
extern "C" {
#include "user_interface.h"
}
#include <ESP8266WiFi.h>
//#include <ESP8266mDNS.h>
2016-03-10 14:57:02 +01:00
#include <ESP8266WebServer.h>
#include <ESP8266HTTPUpdateServer.h>
//#include <WebSocketsServer.h>
2016-03-10 14:57:02 +01:00
#include <FS.h>
#include <EEPROM.h>
//#include <IRremoteESP8266.h>
2016-03-10 14:57:02 +01:00
#include "GradientPalettes.h"
#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))
#include "Field.h"
//#define RECV_PIN D4
//IRrecv irReceiver(RECV_PIN);
//#include "Commands.h"
2016-03-10 14:57:02 +01:00
ESP8266WebServer webServer(80);
//WebSocketsServer webSocketsServer = WebSocketsServer(81);
ESP8266HTTPUpdateServer httpUpdateServer;
2016-03-10 14:57:02 +01:00
#include "FSBrowser.h"
#define DATA_PIN D5
#define LED_TYPE WS2811
#define COLOR_ORDER RGB
#define NUM_LEDS 200
#define MILLI_AMPS 2000 // IMPORTANT: set the max milli-Amps of your power supply (4A = 4000mA)
#define FRAMES_PER_SECOND 120 // here you can control the speed. With the Access Point / Web Server the animations run a bit slower.
const bool apMode = false;
#include "Secrets.h" // this file is intentionally not included in the sketch, so nobody accidentally commits their secret information.
// create a Secrets.h file with the following:
// AP mode password
// const char WiFiAPPSK[] = "your-password";
// Wi-Fi network to connect to (if not in AP mode)
// char* ssid = "your-ssid";
// char* password = "your-password";
2016-03-10 14:57:02 +01:00
CRGB leds[NUM_LEDS];
const uint8_t brightnessCount = 5;
uint8_t brightnessMap[brightnessCount] = { 16, 32, 64, 128, 255 };
uint8_t brightnessIndex = 0;
2016-03-10 14:57:02 +01:00
// ten seconds per color palette makes a good demo
// 20-120 is better for deployment
uint8_t secondsPerPalette = 10;
// COOLING: How much does the air cool as it rises?
// Less cooling = taller flames. More cooling = shorter flames.
// Default 50, suggested range 20-100
uint8_t cooling = 49;
// SPARKING: What chance (out of 255) is there that a new spark will be lit?
// Higher chance = more roaring fire. Lower chance = more flickery fire.
// Default 120, suggested range 50-200.
uint8_t sparking = 60;
uint8_t speed = 30;
2016-03-10 14:57:02 +01:00
///////////////////////////////////////////////////////////////////////
// Forward declarations of an array of cpt-city gradient palettes, and
// a count of how many there are. The actual color palette definitions
// are at the bottom of this file.
extern const TProgmemRGBGradientPalettePtr gGradientPalettes[];
uint8_t gCurrentPaletteNumber = 0;
CRGBPalette16 gCurrentPalette( CRGB::Black);
CRGBPalette16 gTargetPalette( gGradientPalettes[0] );
CRGBPalette16 IceColors_p = CRGBPalette16(CRGB::Black, CRGB::Blue, CRGB::Aqua, CRGB::White);
2016-03-10 14:57:02 +01:00
uint8_t currentPatternIndex = 0; // Index number of which pattern is current
uint8_t autoplay = 0;
2016-03-10 14:57:02 +01:00
uint8_t autoplayDuration = 10;
unsigned long autoPlayTimeout = 0;
2016-03-10 14:57:02 +01:00
uint8_t currentPaletteIndex = 0;
2016-03-10 14:57:02 +01:00
uint8_t gHue = 0; // rotating "base color" used by many of the patterns
CRGB solidColor = CRGB::Blue;
// scale the brightness of all pixels down
void dimAll(byte value)
{
for (int i = 0; i < NUM_LEDS; i++) {
leds[i].nscale8(value);
}
}
typedef void (*Pattern)();
typedef Pattern PatternList[];
typedef struct {
Pattern pattern;
String name;
} PatternAndName;
typedef PatternAndName PatternAndNameList[];
#include "Twinkles.h"
#include "TwinkleFOX.h"
// List of patterns to cycle through. Each is defined as a separate function below.
PatternAndNameList patterns = {
{ pride, "Pride" },
{ colorWaves, "Color Waves" },
// twinkle patterns
{ rainbowTwinkles, "Rainbow Twinkles" },
{ snowTwinkles, "Snow Twinkles" },
{ cloudTwinkles, "Cloud Twinkles" },
{ incandescentTwinkles, "Incandescent Twinkles" },
// TwinkleFOX patterns
{ retroC9Twinkles, "Retro C9 Twinkles" },
{ redWhiteTwinkles, "Red & White Twinkles" },
{ blueWhiteTwinkles, "Blue & White Twinkles" },
{ redGreenWhiteTwinkles, "Red, Green & White Twinkles" },
{ fairyLightTwinkles, "Fairy Light Twinkles" },
{ snow2Twinkles, "Snow 2 Twinkles" },
{ hollyTwinkles, "Holly Twinkles" },
{ iceTwinkles, "Ice Twinkles" },
{ partyTwinkles, "Party Twinkles" },
{ forestTwinkles, "Forest Twinkles" },
{ lavaTwinkles, "Lava Twinkles" },
{ fireTwinkles, "Fire Twinkles" },
{ cloud2Twinkles, "Cloud 2 Twinkles" },
{ oceanTwinkles, "Ocean Twinkles" },
{ rainbow, "Rainbow" },
{ rainbowWithGlitter, "Rainbow With Glitter" },
{ rainbowSolid, "Solid Rainbow" },
{ confetti, "Confetti" },
{ sinelon, "Sinelon" },
{ bpm, "Beat" },
{ juggle, "Juggle" },
{ fire, "Fire" },
{ water, "Water" },
{ showSolidColor, "Solid Color" }
};
const uint8_t patternCount = ARRAY_SIZE(patterns);
typedef struct {
CRGBPalette16 palette;
String name;
} PaletteAndName;
typedef PaletteAndName PaletteAndNameList[];
const CRGBPalette16 palettes[] = {
RainbowColors_p,
RainbowStripeColors_p,
CloudColors_p,
LavaColors_p,
OceanColors_p,
ForestColors_p,
PartyColors_p,
HeatColors_p
};
const uint8_t paletteCount = ARRAY_SIZE(palettes);
const String paletteNames[paletteCount] = {
"Rainbow",
"Rainbow Stripe",
"Cloud",
"Lava",
"Ocean",
"Forest",
"Party",
"Heat",
};
#include "Fields.h"
2016-03-10 14:57:02 +01:00
void setup() {
WiFi.setSleepMode(WIFI_NONE_SLEEP);
2016-03-10 14:57:02 +01:00
Serial.begin(115200);
delay(100);
Serial.setDebugOutput(true);
FastLED.addLeds<LED_TYPE, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS); // for WS2812 (Neopixel)
//FastLED.addLeds<LED_TYPE,DATA_PIN,CLK_PIN,COLOR_ORDER>(leds, NUM_LEDS); // for APA102 (Dotstar)
FastLED.setDither(false);
2016-03-10 14:57:02 +01:00
FastLED.setCorrection(TypicalLEDStrip);
FastLED.setBrightness(brightness);
FastLED.setMaxPowerInVoltsAndMilliamps(5, MILLI_AMPS);
fill_solid(leds, NUM_LEDS, CRGB::Black);
2016-03-10 14:57:02 +01:00
FastLED.show();
EEPROM.begin(512);
loadSettings();
FastLED.setBrightness(brightness);
// irReceiver.enableIRIn(); // Start the receiver
2016-03-10 14:57:02 +01:00
Serial.println();
Serial.print( F("Heap: ") ); Serial.println(system_get_free_heap_size());
Serial.print( F("Boot Vers: ") ); Serial.println(system_get_boot_version());
Serial.print( F("CPU: ") ); Serial.println(system_get_cpu_freq());
Serial.print( F("SDK: ") ); Serial.println(system_get_sdk_version());
Serial.print( F("Chip ID: ") ); Serial.println(system_get_chip_id());
Serial.print( F("Flash ID: ") ); Serial.println(spi_flash_get_id());
Serial.print( F("Flash Size: ") ); Serial.println(ESP.getFlashChipRealSize());
Serial.print( F("Vcc: ") ); Serial.println(ESP.getVcc());
Serial.println();
SPIFFS.begin();
{
Serial.println("SPIFFS contents:");
2016-03-10 14:57:02 +01:00
Dir dir = SPIFFS.openDir("/");
while (dir.next()) {
String fileName = dir.fileName();
size_t fileSize = dir.fileSize();
Serial.printf("FS File: %s, size: %s\n", fileName.c_str(), String(fileSize).c_str());
}
Serial.printf("\n");
}
//disabled due to https://github.com/jasoncoon/esp8266-fastled-webserver/issues/62
//initializeWiFi();
if (apMode)
{
WiFi.mode(WIFI_AP);
// Do a little work to get a unique-ish name. Append the
// last two bytes of the MAC (HEX'd) to "Thing-":
uint8_t mac[WL_MAC_ADDR_LENGTH];
WiFi.softAPmacAddress(mac);
String macID = String(mac[WL_MAC_ADDR_LENGTH - 2], HEX) +
String(mac[WL_MAC_ADDR_LENGTH - 1], HEX);
macID.toUpperCase();
String AP_NameString = "ESP8266 Thing " + macID;
char AP_NameChar[AP_NameString.length() + 1];
memset(AP_NameChar, 0, AP_NameString.length() + 1);
for (int i = 0; i < AP_NameString.length(); i++)
AP_NameChar[i] = AP_NameString.charAt(i);
WiFi.softAP(AP_NameChar, WiFiAPPSK);
Serial.printf("Connect to Wi-Fi access point: %s\n", AP_NameChar);
Serial.println("and open http://192.168.4.1 in your browser");
}
else
{
WiFi.mode(WIFI_STA);
Serial.printf("Connecting to %s\n", ssid);
if (String(WiFi.SSID()) != String(ssid)) {
WiFi.begin(ssid, password);
}
}
httpUpdateServer.setup(&webServer);
2016-03-10 14:57:02 +01:00
webServer.on("/all", HTTP_GET, []() {
String json = getFieldsJson(fields, fieldCount);
webServer.send(200, "text/json", json);
});
2016-03-10 14:57:02 +01:00
webServer.on("/fieldValue", HTTP_GET, []() {
String name = webServer.arg("name");
String value = getFieldValue(name, fields, fieldCount);
webServer.send(200, "text/json", value);
2016-03-10 14:57:02 +01:00
});
webServer.on("/fieldValue", HTTP_POST, []() {
String name = webServer.arg("name");
String value = webServer.arg("value");
String newValue = setFieldValue(name, value, fields, fieldCount);
webServer.send(200, "text/json", newValue);
2016-03-10 14:57:02 +01:00
});
webServer.on("/power", HTTP_POST, []() {
String value = webServer.arg("value");
2016-03-10 14:57:02 +01:00
setPower(value.toInt());
sendInt(power);
2016-03-10 14:57:02 +01:00
});
webServer.on("/cooling", HTTP_POST, []() {
String value = webServer.arg("value");
cooling = value.toInt();
broadcastInt("cooling", cooling);
sendInt(cooling);
2016-03-10 14:57:02 +01:00
});
webServer.on("/sparking", HTTP_POST, []() {
String value = webServer.arg("value");
sparking = value.toInt();
broadcastInt("sparking", sparking);
sendInt(sparking);
2016-03-10 14:57:02 +01:00
});
webServer.on("/speed", HTTP_POST, []() {
String value = webServer.arg("value");
speed = value.toInt();
broadcastInt("speed", speed);
sendInt(speed);
2016-03-10 14:57:02 +01:00
});
webServer.on("/twinkleSpeed", HTTP_POST, []() {
String value = webServer.arg("value");
twinkleSpeed = value.toInt();
if (twinkleSpeed < 0) twinkleSpeed = 0;
else if (twinkleSpeed > 8) twinkleSpeed = 8;
broadcastInt("twinkleSpeed", twinkleSpeed);
sendInt(twinkleSpeed);
2016-03-10 14:57:02 +01:00
});
webServer.on("/twinkleDensity", HTTP_POST, []() {
String value = webServer.arg("value");
twinkleDensity = value.toInt();
if (twinkleDensity < 0) twinkleDensity = 0;
else if (twinkleDensity > 8) twinkleDensity = 8;
broadcastInt("twinkleDensity", twinkleDensity);
sendInt(twinkleDensity);
2016-03-10 14:57:02 +01:00
});
webServer.on("/solidColor", HTTP_POST, []() {
String r = webServer.arg("r");
String g = webServer.arg("g");
String b = webServer.arg("b");
setSolidColor(r.toInt(), g.toInt(), b.toInt());
sendString(String(solidColor.r) + "," + String(solidColor.g) + "," + String(solidColor.b));
2016-03-10 14:57:02 +01:00
});
webServer.on("/pattern", HTTP_POST, []() {
String value = webServer.arg("value");
setPattern(value.toInt());
sendInt(currentPatternIndex);
2016-03-10 14:57:02 +01:00
});
webServer.on("/patternName", HTTP_POST, []() {
String value = webServer.arg("value");
setPatternName(value);
sendInt(currentPatternIndex);
2016-03-10 14:57:02 +01:00
});
webServer.on("/palette", HTTP_POST, []() {
String value = webServer.arg("value");
setPalette(value.toInt());
sendInt(currentPaletteIndex);
});
webServer.on("/paletteName", HTTP_POST, []() {
String value = webServer.arg("value");
setPaletteName(value);
sendInt(currentPaletteIndex);
});
webServer.on("/brightness", HTTP_POST, []() {
String value = webServer.arg("value");
setBrightness(value.toInt());
sendInt(brightness);
2016-03-10 14:57:02 +01:00
});
webServer.on("/autoplay", HTTP_POST, []() {
String value = webServer.arg("value");
setAutoplay(value.toInt());
sendInt(autoplay);
2016-03-10 14:57:02 +01:00
});
webServer.on("/autoplayDuration", HTTP_POST, []() {
String value = webServer.arg("value");
setAutoplayDuration(value.toInt());
sendInt(autoplayDuration);
});
2016-03-10 14:57:02 +01:00
//list directory
webServer.on("/list", HTTP_GET, handleFileList);
//load editor
webServer.on("/edit", HTTP_GET, []() {
if (!handleFileRead("/edit.htm")) webServer.send(404, "text/plain", "FileNotFound");
});
//create file
webServer.on("/edit", HTTP_PUT, handleFileCreate);
//delete file
webServer.on("/edit", HTTP_DELETE, handleFileDelete);
//first callback is called after the request has ended with all parsed arguments
//second callback handles file uploads at that location
webServer.on("/edit", HTTP_POST, []() {
webServer.send(200, "text/plain", "");
}, handleFileUpload);
webServer.serveStatic("/", SPIFFS, "/", "max-age=86400");
webServer.begin();
Serial.println("HTTP web server started");
// webSocketsServer.begin();
// webSocketsServer.onEvent(webSocketEvent);
// Serial.println("Web socket server started");
autoPlayTimeout = millis() + (autoplayDuration * 1000);
}
2016-03-10 14:57:02 +01:00
void sendInt(uint8_t value)
{
sendString(String(value));
2016-03-10 14:57:02 +01:00
}
void sendString(String value)
{
webServer.send(200, "text/plain", value);
}
void broadcastInt(String name, uint8_t value)
{
String json = "{\"name\":\"" + name + "\",\"value\":" + String(value) + "}";
// webSocketsServer.broadcastTXT(json);
}
void broadcastString(String name, String value)
{
String json = "{\"name\":\"" + name + "\",\"value\":\"" + String(value) + "\"}";
// webSocketsServer.broadcastTXT(json);
}
void loop() {
2016-03-10 14:57:02 +01:00
// Add entropy to random number generator; we use a lot of it.
random16_add_entropy(random(65535));
// dnsServer.processNextRequest();
// webSocketsServer.loop();
webServer.handleClient();
2016-03-10 14:57:02 +01:00
// handleIrInput();
2016-03-10 14:57:02 +01:00
if (power == 0) {
fill_solid(leds, NUM_LEDS, CRGB::Black);
FastLED.show();
// FastLED.delay(15);
2016-03-10 14:57:02 +01:00
return;
}
static bool hasConnected = false;
EVERY_N_SECONDS(1) {
if (WiFi.status() != WL_CONNECTED) {
// Serial.printf("Connecting to %s\n", ssid);
hasConnected = false;
}
else if (!hasConnected) {
hasConnected = true;
Serial.print("Connected! Open http://");
Serial.print(WiFi.localIP());
Serial.println(" in your browser");
}
}
2016-03-10 14:57:02 +01:00
// EVERY_N_SECONDS(10) {
// Serial.print( F("Heap: ") ); Serial.println(system_get_free_heap_size());
// }
// change to a new cpt-city gradient palette
EVERY_N_SECONDS( secondsPerPalette ) {
2016-03-10 14:57:02 +01:00
gCurrentPaletteNumber = addmod8( gCurrentPaletteNumber, 1, gGradientPaletteCount);
gTargetPalette = gGradientPalettes[ gCurrentPaletteNumber ];
}
EVERY_N_MILLISECONDS(40) {
// slowly blend the current palette to the next
nblendPaletteTowardPalette( gCurrentPalette, gTargetPalette, 8);
gHue++; // slowly cycle the "base color" through the rainbow
2016-03-10 14:57:02 +01:00
}
if (autoplay && (millis() > autoPlayTimeout)) {
2016-03-10 14:57:02 +01:00
adjustPattern(true);
autoPlayTimeout = millis() + (autoplayDuration * 1000);
2016-03-10 14:57:02 +01:00
}
// Call the current pattern function once, updating the 'leds' array
patterns[currentPatternIndex].pattern();
FastLED.show();
// insert a delay to keep the framerate modest
FastLED.delay(1000 / FRAMES_PER_SECOND);
}
//void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length) {
//
// switch (type) {
// case WStype_DISCONNECTED:
// Serial.printf("[%u] Disconnected!\n", num);
// break;
//
// case WStype_CONNECTED:
// {
// IPAddress ip = webSocketsServer.remoteIP(num);
// Serial.printf("[%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload);
//
// // send message to client
// // webSocketsServer.sendTXT(num, "Connected");
// }
// break;
//
// case WStype_TEXT:
// Serial.printf("[%u] get Text: %s\n", num, payload);
//
// // send message to client
// // webSocketsServer.sendTXT(num, "message here");
//
// // send data to all connected clients
// // webSocketsServer.broadcastTXT("message here");
// break;
//
// case WStype_BIN:
// Serial.printf("[%u] get binary length: %u\n", num, length);
// hexdump(payload, length);
//
// // send message to client
// // webSocketsServer.sendBIN(num, payload, lenght);
// break;
// }
//}
2016-03-10 14:57:02 +01:00
//void handleIrInput()
//{
// InputCommand command = readCommand();
//
// if (command != InputCommand::None) {
// Serial.print("command: ");
// Serial.println((int) command);
// }
//
// switch (command) {
// case InputCommand::Up: {
// adjustPattern(true);
// break;
// }
// case InputCommand::Down: {
// adjustPattern(false);
// break;
// }
// case InputCommand::Power: {
// setPower(power == 0 ? 1 : 0);
// break;
// }
// case InputCommand::BrightnessUp: {
// adjustBrightness(true);
// break;
// }
// case InputCommand::BrightnessDown: {
// adjustBrightness(false);
// break;
// }
// case InputCommand::PlayMode: { // toggle pause/play
// setAutoplay(!autoplay);
// break;
// }
//
// // pattern buttons
//
// case InputCommand::Pattern1: {
// setPattern(0);
// break;
// }
// case InputCommand::Pattern2: {
// setPattern(1);
// break;
// }
// case InputCommand::Pattern3: {
// setPattern(2);
// break;
// }
// case InputCommand::Pattern4: {
// setPattern(3);
// break;
// }
// case InputCommand::Pattern5: {
// setPattern(4);
// break;
// }
// case InputCommand::Pattern6: {
// setPattern(5);
// break;
// }
// case InputCommand::Pattern7: {
// setPattern(6);
// break;
// }
// case InputCommand::Pattern8: {
// setPattern(7);
// break;
// }
// case InputCommand::Pattern9: {
// setPattern(8);
// break;
// }
// case InputCommand::Pattern10: {
// setPattern(9);
// break;
// }
// case InputCommand::Pattern11: {
// setPattern(10);
// break;
// }
// case InputCommand::Pattern12: {
// setPattern(11);
// break;
// }
//
// // custom color adjustment buttons
//
// case InputCommand::RedUp: {
// solidColor.red += 8;
// setSolidColor(solidColor);
// break;
// }
// case InputCommand::RedDown: {
// solidColor.red -= 8;
// setSolidColor(solidColor);
// break;
// }
// case InputCommand::GreenUp: {
// solidColor.green += 8;
// setSolidColor(solidColor);
// break;
// }
// case InputCommand::GreenDown: {
// solidColor.green -= 8;
// setSolidColor(solidColor);
// break;
// }
// case InputCommand::BlueUp: {
// solidColor.blue += 8;
// setSolidColor(solidColor);
// break;
// }
// case InputCommand::BlueDown: {
// solidColor.blue -= 8;
// setSolidColor(solidColor);
// break;
// }
//
// // color buttons
//
// case InputCommand::Red: {
// setSolidColor(CRGB::Red);
// break;
// }
// case InputCommand::RedOrange: {
// setSolidColor(CRGB::OrangeRed);
// break;
// }
// case InputCommand::Orange: {
// setSolidColor(CRGB::Orange);
// break;
// }
// case InputCommand::YellowOrange: {
// setSolidColor(CRGB::Goldenrod);
// break;
// }
// case InputCommand::Yellow: {
// setSolidColor(CRGB::Yellow);
// break;
// }
//
// case InputCommand::Green: {
// setSolidColor(CRGB::Green);
// break;
// }
// case InputCommand::Lime: {
// setSolidColor(CRGB::Lime);
// break;
// }
// case InputCommand::Aqua: {
// setSolidColor(CRGB::Aqua);
// break;
// }
// case InputCommand::Teal: {
// setSolidColor(CRGB::Teal);
// break;
// }
// case InputCommand::Navy: {
// setSolidColor(CRGB::Navy);
// break;
// }
//
// case InputCommand::Blue: {
// setSolidColor(CRGB::Blue);
// break;
// }
// case InputCommand::RoyalBlue: {
// setSolidColor(CRGB::RoyalBlue);
// break;
// }
// case InputCommand::Purple: {
// setSolidColor(CRGB::Purple);
// break;
// }
// case InputCommand::Indigo: {
// setSolidColor(CRGB::Indigo);
// break;
// }
// case InputCommand::Magenta: {
// setSolidColor(CRGB::Magenta);
// break;
// }
//
// case InputCommand::White: {
// setSolidColor(CRGB::White);
// break;
// }
// case InputCommand::Pink: {
// setSolidColor(CRGB::Pink);
// break;
// }
// case InputCommand::LightPink: {
// setSolidColor(CRGB::LightPink);
// break;
// }
// case InputCommand::BabyBlue: {
// setSolidColor(CRGB::CornflowerBlue);
// break;
// }
// case InputCommand::LightBlue: {
// setSolidColor(CRGB::LightBlue);
// break;
// }
// }
//}
2016-03-10 14:57:02 +01:00
void loadSettings()
{
brightness = EEPROM.read(0);
currentPatternIndex = EEPROM.read(1);
if (currentPatternIndex < 0)
currentPatternIndex = 0;
else if (currentPatternIndex >= patternCount)
currentPatternIndex = patternCount - 1;
byte r = EEPROM.read(2);
byte g = EEPROM.read(3);
byte b = EEPROM.read(4);
if (r == 0 && g == 0 && b == 0)
{
}
else
{
solidColor = CRGB(r, g, b);
}
power = EEPROM.read(5);
autoplay = EEPROM.read(6);
autoplayDuration = EEPROM.read(7);
currentPaletteIndex = EEPROM.read(8);
if (currentPaletteIndex < 0)
currentPaletteIndex = 0;
else if (currentPaletteIndex >= paletteCount)
currentPaletteIndex = paletteCount - 1;
2016-03-10 14:57:02 +01:00
}
void setPower(uint8_t value)
2016-03-10 14:57:02 +01:00
{
power = value == 0 ? 0 : 1;
2016-03-10 14:57:02 +01:00
EEPROM.write(5, power);
EEPROM.commit();
2016-03-10 14:57:02 +01:00
broadcastInt("power", power);
}
2016-03-10 14:57:02 +01:00
void setAutoplay(uint8_t value)
{
autoplay = value == 0 ? 0 : 1;
2016-03-10 14:57:02 +01:00
EEPROM.write(6, autoplay);
EEPROM.commit();
2016-03-10 14:57:02 +01:00
broadcastInt("autoplay", autoplay);
2016-03-10 14:57:02 +01:00
}
void setAutoplayDuration(uint8_t value)
2016-03-10 14:57:02 +01:00
{
autoplayDuration = value;
2016-03-10 14:57:02 +01:00
EEPROM.write(7, autoplayDuration);
EEPROM.commit();
2016-03-10 14:57:02 +01:00
autoPlayTimeout = millis() + (autoplayDuration * 1000);
2016-03-10 14:57:02 +01:00
broadcastInt("autoplayDuration", autoplayDuration);
2016-03-10 14:57:02 +01:00
}
void setSolidColor(CRGB color)
{
setSolidColor(color.r, color.g, color.b);
}
void setSolidColor(uint8_t r, uint8_t g, uint8_t b)
{
solidColor = CRGB(r, g, b);
EEPROM.write(2, r);
EEPROM.write(3, g);
EEPROM.write(4, b);
EEPROM.commit();
2016-03-10 14:57:02 +01:00
setPattern(patternCount - 1);
broadcastString("color", String(solidColor.r) + "," + String(solidColor.g) + "," + String(solidColor.b));
2016-03-10 14:57:02 +01:00
}
// increase or decrease the current pattern number, and wrap around at the ends
void adjustPattern(bool up)
{
if (up)
currentPatternIndex++;
else
currentPatternIndex--;
// wrap around at the ends
if (currentPatternIndex < 0)
currentPatternIndex = patternCount - 1;
if (currentPatternIndex >= patternCount)
currentPatternIndex = 0;
if (autoplay == 0) {
EEPROM.write(1, currentPatternIndex);
EEPROM.commit();
}
broadcastInt("pattern", currentPatternIndex);
2016-03-10 14:57:02 +01:00
}
void setPattern(uint8_t value)
2016-03-10 14:57:02 +01:00
{
if (value >= patternCount)
2016-03-10 14:57:02 +01:00
value = patternCount - 1;
currentPatternIndex = value;
if (autoplay == 0) {
EEPROM.write(1, currentPatternIndex);
EEPROM.commit();
}
broadcastInt("pattern", currentPatternIndex);
}
void setPatternName(String name)
{
for (uint8_t i = 0; i < patternCount; i++) {
if (patterns[i].name == name) {
setPattern(i);
break;
}
}
2016-03-10 14:57:02 +01:00
}
void setPalette(uint8_t value)
{
if (value >= paletteCount)
value = paletteCount - 1;
currentPaletteIndex = value;
EEPROM.write(8, currentPaletteIndex);
EEPROM.commit();
broadcastInt("palette", currentPaletteIndex);
}
void setPaletteName(String name)
{
for (uint8_t i = 0; i < paletteCount; i++) {
if (paletteNames[i] == name) {
setPalette(i);
break;
}
}
}
2016-03-10 14:57:02 +01:00
void adjustBrightness(bool up)
{
if (up && brightnessIndex < brightnessCount - 1)
2016-03-10 14:57:02 +01:00
brightnessIndex++;
else if (!up && brightnessIndex > 0)
2016-03-10 14:57:02 +01:00
brightnessIndex--;
brightness = brightnessMap[brightnessIndex];
FastLED.setBrightness(brightness);
EEPROM.write(0, brightness);
EEPROM.commit();
broadcastInt("brightness", brightness);
2016-03-10 14:57:02 +01:00
}
void setBrightness(uint8_t value)
2016-03-10 14:57:02 +01:00
{
if (value > 255)
value = 255;
else if (value < 0) value = 0;
brightness = value;
FastLED.setBrightness(brightness);
EEPROM.write(0, brightness);
EEPROM.commit();
broadcastInt("brightness", brightness);
}
void strandTest()
{
static uint8_t i = 0;
EVERY_N_SECONDS(1)
{
i++;
if (i >= NUM_LEDS)
i = 0;
}
fill_solid(leds, NUM_LEDS, CRGB::Black);
leds[i] = solidColor;
2016-03-10 14:57:02 +01:00
}
void showSolidColor()
{
fill_solid(leds, NUM_LEDS, solidColor);
}
// Patterns from FastLED example DemoReel100: https://github.com/FastLED/FastLED/blob/master/examples/DemoReel100/DemoReel100.ino
2016-03-10 14:57:02 +01:00
void rainbow()
{
// FastLED's built-in rainbow generator
fill_rainbow( leds, NUM_LEDS, gHue, 255 / NUM_LEDS);
2016-03-10 14:57:02 +01:00
}
void rainbowWithGlitter()
{
// built-in FastLED rainbow, plus some random sparkly glitter
rainbow();
addGlitter(80);
}
void rainbowSolid()
2016-03-10 14:57:02 +01:00
{
fill_solid(leds, NUM_LEDS, CHSV(gHue, 255, 255));
2016-03-10 14:57:02 +01:00
}
void confetti()
{
// random colored speckles that blink in and fade smoothly
fadeToBlackBy( leds, NUM_LEDS, 10);
int pos = random16(NUM_LEDS);
// leds[pos] += CHSV( gHue + random8(64), 200, 255);
leds[pos] += ColorFromPalette(palettes[currentPaletteIndex], gHue + random8(64));
2016-03-10 14:57:02 +01:00
}
void sinelon()
{
// a colored dot sweeping back and forth, with fading trails
fadeToBlackBy( leds, NUM_LEDS, 20);
int pos = beatsin16(speed, 0, NUM_LEDS);
static int prevpos = 0;
CRGB color = ColorFromPalette(palettes[currentPaletteIndex], gHue, 255);
if ( pos < prevpos ) {
fill_solid( leds + pos, (prevpos - pos) + 1, color);
} else {
fill_solid( leds + prevpos, (pos - prevpos) + 1, color);
}
prevpos = pos;
2016-03-10 14:57:02 +01:00
}
void bpm()
{
// colored stripes pulsing at a defined Beats-Per-Minute (BPM)
uint8_t beat = beatsin8( speed, 64, 255);
CRGBPalette16 palette = palettes[currentPaletteIndex];
for ( int i = 0; i < NUM_LEDS; i++) {
leds[i] = ColorFromPalette(palette, gHue + (i * 2), beat - gHue + (i * 10));
2016-03-10 14:57:02 +01:00
}
}
void juggle()
{
static uint8_t numdots = 4; // Number of dots in use.
static uint8_t faderate = 2; // How long should the trails be. Very low value = longer trails.
static uint8_t hueinc = 255 / numdots - 1; // Incremental change in hue between each dot.
static uint8_t thishue = 0; // Starting hue.
static uint8_t curhue = 0; // The current hue
static uint8_t thissat = 255; // Saturation of the colour.
static uint8_t thisbright = 255; // How bright should the LED/display be.
static uint8_t basebeat = 5; // Higher = faster movement.
static uint8_t lastSecond = 99; // Static variable, means it's only defined once. This is our 'debounce' variable.
uint8_t secondHand = (millis() / 1000) % 30; // IMPORTANT!!! Change '30' to a different value to change duration of the loop.
if (lastSecond != secondHand) { // Debounce to make sure we're not repeating an assignment.
lastSecond = secondHand;
switch (secondHand) {
case 0: numdots = 1; basebeat = 20; hueinc = 16; faderate = 2; thishue = 0; break; // You can change values here, one at a time , or altogether.
case 10: numdots = 4; basebeat = 10; hueinc = 16; faderate = 8; thishue = 128; break;
case 20: numdots = 8; basebeat = 3; hueinc = 0; faderate = 8; thishue = random8(); break; // Only gets called once, and not continuously for the next several seconds. Therefore, no rainbows.
case 30: break;
}
}
// Several colored dots, weaving in and out of sync with each other
curhue = thishue; // Reset the hue values.
fadeToBlackBy(leds, NUM_LEDS, faderate);
for ( int i = 0; i < numdots; i++) {
//beat16 is a FastLED 3.1 function
leds[beatsin16(basebeat + i + numdots, 0, NUM_LEDS)] += CHSV(gHue + curhue, thissat, thisbright);
curhue += hueinc;
2016-03-10 14:57:02 +01:00
}
}
void fire()
{
heatMap(HeatColors_p, true);
}
void water()
{
heatMap(IceColors_p, false);
}
2016-03-10 14:57:02 +01:00
// Pride2015 by Mark Kriegsman: https://gist.github.com/kriegsman/964de772d64c502760e5
// This function draws rainbows with an ever-changing,
// widely-varying set of parameters.
void pride()
{
2016-03-10 14:57:02 +01:00
static uint16_t sPseudotime = 0;
static uint16_t sLastMillis = 0;
static uint16_t sHue16 = 0;
uint8_t sat8 = beatsin88( 87, 220, 250);
uint8_t brightdepth = beatsin88( 341, 96, 224);
uint16_t brightnessthetainc16 = beatsin88( 203, (25 * 256), (40 * 256));
uint8_t msmultiplier = beatsin88(147, 23, 60);
uint16_t hue16 = sHue16;//gHue * 256;
uint16_t hueinc16 = beatsin88(113, 1, 3000);
uint16_t ms = millis();
uint16_t deltams = ms - sLastMillis ;
sLastMillis = ms;
sPseudotime += deltams * msmultiplier;
sHue16 += deltams * beatsin88( 400, 5, 9);
uint16_t brightnesstheta16 = sPseudotime;
for ( uint16_t i = 0 ; i < NUM_LEDS; i++) {
hue16 += hueinc16;
uint8_t hue8 = hue16 / 256;
brightnesstheta16 += brightnessthetainc16;
uint16_t b16 = sin16( brightnesstheta16 ) + 32768;
uint16_t bri16 = (uint32_t)((uint32_t)b16 * (uint32_t)b16) / 65536;
uint8_t bri8 = (uint32_t)(((uint32_t)bri16) * brightdepth) / 65536;
bri8 += (255 - brightdepth);
CRGB newcolor = CHSV( hue8, sat8, bri8);
uint16_t pixelnumber = i;
pixelnumber = (NUM_LEDS - 1) - pixelnumber;
nblend( leds[pixelnumber], newcolor, 64);
}
}
void radialPaletteShift()
{
for (uint16_t i = 0; i < NUM_LEDS; i++) {
// leds[i] = ColorFromPalette( gCurrentPalette, gHue + sin8(i*16), brightness);
leds[i] = ColorFromPalette(gCurrentPalette, i + gHue, 255, LINEARBLEND);
2016-03-10 14:57:02 +01:00
}
}
// based on FastLED example Fire2012WithPalette: https://github.com/FastLED/FastLED/blob/master/examples/Fire2012WithPalette/Fire2012WithPalette.ino
void heatMap(CRGBPalette16 palette, bool up)
{
fill_solid(leds, NUM_LEDS, CRGB::Black);
// Add entropy to random number generator; we use a lot of it.
random16_add_entropy(random(256));
// Array of temperature readings at each simulation cell
static byte heat[NUM_LEDS];
byte colorindex;
// Step 1. Cool down every cell a little
for ( uint16_t i = 0; i < NUM_LEDS; i++) {
heat[i] = qsub8( heat[i], random8(0, ((cooling * 10) / NUM_LEDS) + 2));
}
// Step 2. Heat from each cell drifts 'up' and diffuses a little
for ( uint16_t k = NUM_LEDS - 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 ( uint16_t j = 0; j < NUM_LEDS; j++) {
// Scale the heat value from 0-255 down to 0-240
// for best results with color palettes.
colorindex = scale8(heat[j], 190);
CRGB color = ColorFromPalette(palette, colorindex);
if (up) {
leds[j] = color;
}
else {
leds[(NUM_LEDS - 1) - j] = color;
}
}
}
void addGlitter( uint8_t chanceOfGlitter)
{
if ( random8() < chanceOfGlitter) {
leds[ random16(NUM_LEDS) ] += CRGB::White;
}
}
///////////////////////////////////////////////////////////////////////
// Forward declarations of an array of cpt-city gradient palettes, and
// a count of how many there are. The actual color palette definitions
// are at the bottom of this file.
extern const TProgmemRGBGradientPalettePtr gGradientPalettes[];
extern const uint8_t gGradientPaletteCount;
uint8_t beatsaw8( accum88 beats_per_minute, uint8_t lowest = 0, uint8_t highest = 255,
uint32_t timebase = 0, uint8_t phase_offset = 0)
{
uint8_t beat = beat8( beats_per_minute, timebase);
uint8_t beatsaw = beat + phase_offset;
uint8_t rangewidth = highest - lowest;
uint8_t scaledbeat = scale8( beatsaw, rangewidth);
uint8_t result = lowest + scaledbeat;
return result;
}
void colorWaves()
{
colorwaves( leds, NUM_LEDS, gCurrentPalette);
}
2016-03-10 14:57:02 +01:00
// ColorWavesWithPalettes by Mark Kriegsman: https://gist.github.com/kriegsman/8281905786e8b2632aeb
// This function draws color waves with an ever-changing,
// widely-varying set of parameters, using a color palette.
void colorwaves( CRGB* ledarray, uint16_t numleds, CRGBPalette16& palette)
2016-03-10 14:57:02 +01:00
{
static uint16_t sPseudotime = 0;
static uint16_t sLastMillis = 0;
static uint16_t sHue16 = 0;
// uint8_t sat8 = beatsin88( 87, 220, 250);
uint8_t brightdepth = beatsin88( 341, 96, 224);
uint16_t brightnessthetainc16 = beatsin88( 203, (25 * 256), (40 * 256));
uint8_t msmultiplier = beatsin88(147, 23, 60);
uint16_t hue16 = sHue16;//gHue * 256;
uint16_t hueinc16 = beatsin88(113, 300, 1500);
uint16_t ms = millis();
uint16_t deltams = ms - sLastMillis ;
sLastMillis = ms;
sPseudotime += deltams * msmultiplier;
sHue16 += deltams * beatsin88( 400, 5, 9);
uint16_t brightnesstheta16 = sPseudotime;
for ( uint16_t i = 0 ; i < numleds; i++) {
2016-03-10 14:57:02 +01:00
hue16 += hueinc16;
uint8_t hue8 = hue16 / 256;
uint16_t h16_128 = hue16 >> 7;
if ( h16_128 & 0x100) {
hue8 = 255 - (h16_128 >> 1);
} else {
hue8 = h16_128 >> 1;
}
brightnesstheta16 += brightnessthetainc16;
uint16_t b16 = sin16( brightnesstheta16 ) + 32768;
uint16_t bri16 = (uint32_t)((uint32_t)b16 * (uint32_t)b16) / 65536;
uint8_t bri8 = (uint32_t)(((uint32_t)bri16) * brightdepth) / 65536;
bri8 += (255 - brightdepth);
uint8_t index = hue8;
//index = triwave8( index);
index = scale8( index, 240);
CRGB newcolor = ColorFromPalette( palette, index, bri8);
uint16_t pixelnumber = i;
pixelnumber = (numleds - 1) - pixelnumber;
2016-03-10 14:57:02 +01:00
nblend( ledarray[pixelnumber], newcolor, 128);
2016-03-10 14:57:02 +01:00
}
}
// Alternate rendering function just scrolls the current palette
// across the defined LED strip.
void palettetest( CRGB* ledarray, uint16_t numleds, const CRGBPalette16& gCurrentPalette)
2016-03-10 14:57:02 +01:00
{
static uint8_t startindex = 0;
startindex--;
fill_palette( ledarray, numleds, startindex, (256 / NUM_LEDS) + 1, gCurrentPalette, 255, LINEARBLEND);
2016-03-10 14:57:02 +01:00
}