Based on a post Jona's Blog with own learnings
Last active
January 8, 2022 11:13
-
-
Save efinder2/4624967d5117a361805f2f2b72d2f51e to your computer and use it in GitHub Desktop.
Control LED-Strip via WiFi
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// other name due to name conflict | |
void bpmEffect(){ | |
uint8_t BeatsPerMinute = 62; | |
CRGBPalette16 palette = PartyColors_p; | |
uint8_t beat = beatsin8( BeatsPerMinute, 64, 255); | |
for ( int i = 0; i < NUM_LEDS; i++) { //9948 | |
leds[i] = ColorFromPalette(palette, gHue + (i * 2), beat - gHue + (i * 10)); | |
} | |
if (transitionTime == 0 or transitionTime == NULL) { | |
transitionTime = 30; | |
} | |
showleds(); | |
} | |
void candyCane(){ | |
static uint8_t startIndex = 0; | |
startIndex = startIndex + 1; /* higher = faster motion */ | |
fill_palette( leds, NUM_LEDS, | |
startIndex, 16, /* higher = narrower stripes */ | |
currentPalettestriped, 255, LINEARBLEND); | |
if (transitionTime == 0 or transitionTime == NULL) { | |
transitionTime = 0; | |
} | |
showleds(); | |
} | |
void confetti(){ | |
fadeToBlackBy( leds, NUM_LEDS, 25); | |
int pos = random16(NUM_LEDS); | |
leds[pos] += CRGB(realRed + random8(64), realGreen, realBlue); | |
if (transitionTime == 0 or transitionTime == NULL) { | |
transitionTime = 30; | |
} | |
showleds(); | |
} | |
void cyclonRainbow(){ | |
static uint8_t hue = 0; | |
// First slide the led in one direction | |
for (int i = 0; i < NUM_LEDS; i++) { | |
// Set the i'th led to red | |
leds[i] = CHSV(hue++, 255, 255); | |
// Show the leds | |
showleds(); | |
// now that we've shown the leds, reset the i'th led to black | |
// leds[i] = CRGB::Black; | |
fadeall(); | |
// Wait a little bit before we loop around and do it again | |
delay(10); | |
} | |
for (int i = (NUM_LEDS) - 1; i >= 0; i--) { | |
// Set the i'th led to red | |
leds[i] = CHSV(hue++, 255, 255); | |
// Show the leds | |
showleds(); | |
// now that we've shown the leds, reset the i'th led to black | |
// leds[i] = CRGB::Black; | |
fadeall(); | |
// Wait a little bit before we loop around and do it again | |
delay(10); | |
} | |
} | |
void dots(){ | |
uint8_t inner = beatsin8(bpm, NUM_LEDS / 4, NUM_LEDS / 4 * 3); | |
uint8_t outer = beatsin8(bpm, 0, NUM_LEDS - 1); | |
uint8_t middle = beatsin8(bpm, NUM_LEDS / 3, NUM_LEDS / 3 * 2); | |
leds[middle] = CRGB::Purple; | |
leds[inner] = CRGB::Blue; | |
leds[outer] = CRGB::Aqua; | |
nscale8(leds, NUM_LEDS, fadeval); | |
if (transitionTime == 0 or transitionTime == NULL) { | |
transitionTime = 30; | |
} | |
showleds(); | |
} | |
void fire() { | |
Fire2012WithPalette(); | |
if (transitionTime == 0 or transitionTime == NULL) { | |
transitionTime = 150; | |
} | |
showleds(); | |
} | |
void glitter(){ | |
fadeToBlackBy( leds, NUM_LEDS, 20); | |
addGlitterColor(80, realRed, realGreen, realBlue); | |
if (transitionTime == 0 or transitionTime == NULL) { | |
transitionTime = 30; | |
} | |
showleds(); | |
} | |
// eight colored dots, weaving in and out of sync with each other | |
void jungle() { | |
fadeToBlackBy(leds, NUM_LEDS, 20); | |
for (int i = 0; i < 8; i++) { | |
leds[beatsin16(i + 7, 0, NUM_LEDS - 1 )] |= CRGB(realRed, realGreen, realBlue); | |
} | |
if (transitionTime == 0 or transitionTime == NULL) { | |
transitionTime = 130; | |
} | |
showleds(); | |
} | |
void lightning() { | |
twinklecounter = twinklecounter + 1; //Resets strip if previous animation was running | |
if (twinklecounter < 2) { | |
FastLED.clear(); | |
FastLED.show(); | |
FastLED.show(); | |
} | |
ledstart = random8(NUM_LEDS); // Determine starting location of flash | |
ledlen = random8(NUM_LEDS - ledstart); // Determine length of flash (not to go beyond NUM_LEDS-1) | |
for (int flashCounter = 0; flashCounter < random8(3, flashes); flashCounter++) { | |
if (flashCounter == 0) dimmer = 5; // the brightness of the leader is scaled down by a factor of 5 | |
else dimmer = random8(1, 3); // return strokes are brighter than the leader | |
fill_solid(leds + ledstart, ledlen, CHSV(255, 0, 255 / dimmer)); | |
showleds(); // Show a section of LED's | |
delay(random8(4, 10)); // each flash only lasts 4-10 milliseconds | |
fill_solid(leds + ledstart, ledlen, CHSV(255, 0, 0)); // Clear the section of LED's | |
showleds(); | |
if (flashCounter == 0) delay (130); // longer delay until next flash after the leader | |
delay(50 + random8(100)); // shorter delay between strokes | |
} | |
delay(random8(frequency) * 100); // delay between strikes | |
if (transitionTime == 0 or transitionTime == NULL) { | |
transitionTime = 0; | |
} | |
showleds(); | |
} | |
void policeAll() { | |
// TODO globale variable entfernen | |
idex++; | |
if (idex >= NUM_LEDS) { | |
idex = 0; | |
} | |
int idexR = idex; | |
int idexB = antipodal_index(idexR); | |
int thathue = (thishuepolice + 160) % 255; | |
leds[idexR] = CHSV(thishuepolice, thissat, 255); | |
leds[idexB] = CHSV(thathue, thissat, 255); | |
if (transitionTime == 0 or transitionTime == NULL) { | |
transitionTime = 30; | |
} | |
showleds(); | |
} | |
void policeOne() { | |
idex++; | |
if (idex >= NUM_LEDS) { | |
idex = 0; | |
} | |
int idexR = idex; | |
int idexB = antipodal_index(idexR); | |
int thathue = (thishuepolice + 160) % 255; | |
for (int i = 0; i < NUM_LEDS; i++ ) { | |
if (i == idexR) { | |
leds[i] = CHSV(thishuepolice, thissat, 255); | |
} | |
else if (i == idexB) { | |
leds[i] = CHSV(thathue, thissat, 255); | |
} | |
else { | |
leds[i] = CHSV(0, 0, 0); | |
} | |
} | |
if (transitionTime == 0 or transitionTime == NULL) { | |
transitionTime = 30; | |
} | |
showleds(); | |
} | |
void rainbow() { | |
// FastLED's built-in rainbow generator | |
static uint8_t starthue = 0; thishue++; | |
fill_rainbow(leds, NUM_LEDS, thishue, deltahue); | |
if (transitionTime == 0 or transitionTime == NULL) { | |
transitionTime = 130; | |
} | |
showleds(); | |
} | |
void rainbowWithGlitter() { | |
static uint8_t starthue = 0; | |
thishue++; | |
fill_rainbow(leds, NUM_LEDS, thishue, deltahue); | |
addGlitter(80); | |
if (transitionTime == 0 or transitionTime == NULL) { | |
transitionTime = 130; | |
} | |
showleds(); | |
} | |
void sinelon() { | |
fadeToBlackBy( leds, NUM_LEDS, 20); | |
int pos = beatsin16(13, 0, NUM_LEDS - 1); | |
leds[pos] += CRGB(realRed, realGreen, realBlue); | |
if (transitionTime == 0 or transitionTime == NULL) { | |
transitionTime = 150; | |
} | |
showleds(); | |
} | |
void twinkle() { | |
twinklecounter = twinklecounter + 1; | |
if (twinklecounter < 2) { //Resets strip if previous animation was running | |
FastLED.clear(); | |
FastLED.show(); | |
FastLED.show(); | |
} | |
const CRGB lightcolor(8, 7, 1); | |
for ( int i = 0; i < NUM_LEDS; i++) { | |
if ( !leds[i]) continue; // skip black pixels | |
if ( leds[i].r & 1) { // is red odd? | |
leds[i] -= lightcolor; // darken if red is odd | |
} else { | |
leds[i] += lightcolor; // brighten if red is even | |
} | |
} | |
if ( random8() < DENSITY) { | |
int j = random16(NUM_LEDS); | |
if ( !leds[j] ) leds[j] = lightcolor; | |
} | |
if (transitionTime == 0 or transitionTime == NULL) { | |
transitionTime = 0; | |
} | |
showleds(); | |
} | |
void noise() { | |
for (int i = 0; i < NUM_LEDS; i++) { // Just onE loop to fill up the LED array as all of the pixels change. | |
uint8_t index = inoise8(i * scale, dist + i * scale) % 255; // Get a value from the noise function. I'm using both x and y axis. | |
leds[i] = ColorFromPalette(currentPalette, index, 255, LINEARBLEND); // With that value, look up the 8 bit colour palette value and assign it to the current LED. | |
} | |
dist += beatsin8(10, 1, 4); // Moving along the distance (that random number we started out with). Vary it a bit with a sine wave. | |
// In some sketches, I've used millis() instead of an incremented counter. Works a treat. | |
if (transitionTime == 0 or transitionTime == NULL) { | |
transitionTime = 0; | |
} | |
showleds(); | |
} | |
void ripple() { | |
for (int i = 0; i < NUM_LEDS; i++) leds[i] = CHSV(bgcol++, 255, 15); // Rotate background colour. | |
switch (step) { | |
case -1: // Initialize ripple variables. | |
center = random(NUM_LEDS); | |
colour = random8(); | |
step = 0; | |
break; | |
case 0: | |
leds[center] = CHSV(colour, 255, 255); // Display the first pixel of the ripple. | |
step ++; | |
break; | |
case maxsteps: // At the end of the ripples. | |
step = -1; | |
break; | |
default: // Middle of the ripples. | |
leds[(center + step + NUM_LEDS) % NUM_LEDS] += CHSV(colour, 255, myfade / step * 2); // Simple wrap from Marc Miller | |
leds[(center - step + NUM_LEDS) % NUM_LEDS] += CHSV(colour, 255, myfade / step * 2); | |
step ++; // Next step. | |
break; | |
} | |
if (transitionTime == 0 or transitionTime == NULL) { | |
transitionTime = 30; | |
} | |
showleds(); | |
} | |
/********************************************************************************************/ | |
/***************************** Additional Effect Logic **************************************/ | |
/********************************************************************************************/ | |
/********************************** START FIRE **********************************************/ | |
void Fire2012WithPalette() | |
{ | |
// Array of temperature readings at each simulation cell | |
static byte heat[NUM_LEDS]; | |
// Step 1. Cool down every cell a little | |
for ( int 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 ( int 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 ( int j = 0; j < NUM_LEDS; j++) { | |
// Scale the heat value from 0-255 down to 0-240 | |
// for best results with color palettes. | |
byte colorindex = scale8( heat[j], 240); | |
CRGB color = ColorFromPalette( gPal, colorindex); | |
int pixelnumber; | |
if ( gReverseDirection ) { | |
pixelnumber = (NUM_LEDS - 1) - j; | |
} else { | |
pixelnumber = j; | |
} | |
leds[pixelnumber] = color; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void callback(char* topic, byte* payload, unsigned int length) { | |
Serial.print("Message arrived ["); | |
Serial.print(topic); | |
Serial.print("] "); | |
char message[length + 1]; | |
for (int i = 0; i < length; i++) { | |
message[i] = (char)payload[i]; | |
} | |
message[length] = '\0'; | |
Serial.println(message); | |
if (!processJson(message)) { | |
return; | |
} | |
if (stateOn) { | |
realRed = map(red, 0, 255, 0, brightness); | |
realGreen = map(green, 0, 255, 0, brightness); | |
realBlue = map(blue, 0, 255, 0, brightness); | |
} | |
else { | |
realRed = 0; | |
realGreen = 0; | |
realBlue = 0; | |
} | |
Serial.println(effect); | |
startFade = true; | |
inFade = false; // Kill the current fade | |
sendState(); | |
} | |
bool processJson(char* message) { | |
Serial.println("processing Json"); | |
Serial.println(message); | |
StaticJsonDocument<BUFFER_SIZE> jsonDocument; | |
auto error = deserializeJson(jsonDocument, message); | |
if (error) { | |
Serial.print(F("deserializeJson() failed with code ")); | |
Serial.println(error.c_str()); | |
return false; | |
} | |
if (jsonDocument.containsKey("state")) { | |
if (strcmp(jsonDocument["state"], on_cmd) == 0) { | |
stateOn = true; | |
} | |
else if (strcmp(jsonDocument["state"], off_cmd) == 0) { | |
stateOn = false; | |
onbeforeflash = false; | |
} | |
} | |
// If "flash" is included, treat RGB and brightness differently | |
if (jsonDocument.containsKey("flash")) { | |
flashLength = (int)jsonDocument["flash"] * 1000; | |
oldeffectString = effectString; | |
if (jsonDocument.containsKey("brightness")) { | |
flashBrightness = jsonDocument["brightness"]; | |
} | |
else { | |
flashBrightness = brightness; | |
} | |
if (jsonDocument.containsKey("color")) { | |
flashRed = jsonDocument["color"]["r"]; | |
flashGreen = jsonDocument["color"]["g"]; | |
flashBlue = jsonDocument["color"]["b"]; | |
} | |
else { | |
flashRed = red; | |
flashGreen = green; | |
flashBlue = blue; | |
} | |
if (jsonDocument.containsKey("effect")) { | |
effect = jsonDocument["effect"]; | |
effectString = effect; | |
twinklecounter = 0; //manage twinklecounter | |
} | |
if (jsonDocument.containsKey("transition")) { | |
transitionTime = jsonDocument["transition"]; | |
} | |
else if ( effectString == "solid") { | |
transitionTime = 0; | |
} | |
flashRed = map(flashRed, 0, 255, 0, flashBrightness); | |
flashGreen = map(flashGreen, 0, 255, 0, flashBrightness); | |
flashBlue = map(flashBlue, 0, 255, 0, flashBrightness); | |
flash = true; | |
startFlash = true; | |
} | |
else { // Not flashing | |
flash = false; | |
if (stateOn) { //if the light is turned on and the light isn't flashing | |
onbeforeflash = true; | |
} | |
if (jsonDocument.containsKey("color")) { | |
red = jsonDocument["color"]["r"]; | |
green = jsonDocument["color"]["g"]; | |
blue = jsonDocument["color"]["b"]; | |
} | |
if (jsonDocument.containsKey("color_temp")) { | |
//temp comes in as mireds, need to convert to kelvin then to RGB | |
int color_temp = jsonDocument["color_temp"]; | |
unsigned int kelvin = 1000000 / color_temp; | |
temp2rgb(kelvin); | |
} | |
if (jsonDocument.containsKey("brightness")) { | |
brightness = jsonDocument["brightness"]; | |
} | |
if (jsonDocument.containsKey("effect")) { | |
effect = jsonDocument["effect"]; | |
effectString = effect; | |
twinklecounter = 0; //manage twinklecounter | |
} | |
if (jsonDocument.containsKey("transition")) { | |
transitionTime = jsonDocument["transition"]; | |
} | |
else if ( effectString == "solid") { | |
transitionTime = 0; | |
} | |
} | |
return true; | |
} | |
void sendState() { | |
DynamicJsonDocument root(1024); | |
root["state"] = (stateOn) ? on_cmd : off_cmd; | |
JsonObject color = root.createNestedObject("color"); | |
color["r"] = red; | |
color["g"] = green; | |
color["b"] = blue; | |
root["brightness"] = brightness; | |
root["effect"] = effectString.c_str(); | |
String output; | |
serializeJson(root, output); | |
int len = measureJson(root) + 1; | |
char buffer[len]; | |
output.toCharArray(buffer, len); | |
Serial.println(output); | |
client.publish(light_state_topic, buffer, true); | |
} | |
void reconnect() { | |
// Loop until we're reconnected | |
while (!client.connected()) { | |
Serial.print("Attempting MQTT connection..."); | |
// Attempt to connect | |
if (client.connect(SENSORNAME, mqtt_username, mqtt_password)) { | |
Serial.println("connected"); | |
client.subscribe(light_set_topic); | |
setColor(100, 100, 100); | |
sendState(); | |
} else { | |
Serial.print("failed, rc="); | |
Serial.print(client.state()); | |
Serial.println(" try again in 5 seconds"); | |
// Wait 5 seconds before retrying | |
delay(5000); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
light: | |
- platform: mqtt | |
schema: json | |
unique_id: "UNIQUE_EXAMPLE_STRING_BLA" | |
name: "LED-Strip-Schreibtisch" | |
state_topic: "home/desk" | |
command_topic: "home/desk/set" | |
effect: true | |
effect_list: | |
- bpm | |
- candy cane | |
- confetti | |
- cyclon rainbow | |
- dots | |
- fire | |
- glitter | |
- juggle | |
- lightning | |
- noise | |
- police all | |
- police one | |
- rainbow | |
- rainbow with glitter | |
- ripple | |
- sinelon | |
- solid | |
- twinkle | |
brightness: true | |
rgb: true | |
optimistic: false | |
qos: 0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
.______ .______ __ __ __ __ ___ __ __ .___________. ______ .___ ___. ___ .___________. __ ______ .__ __. | |
| _ \ | _ \ | | | | | | | | / \ | | | | | | / __ \ | \/ | / \ | || | / __ \ | \ | | | |
| |_) | | |_) | | | | | | |__| | / ^ \ | | | | `---| |----`| | | | | \ / | / ^ \ `---| |----`| | | | | | | \| | | |
| _ < | / | | | | | __ | / /_\ \ | | | | | | | | | | | |\/| | / /_\ \ | | | | | | | | | . ` | | |
| |_) | | |\ \-.| `--' | | | | | / _____ \ | `--' | | | | `--' | | | | | / _____ \ | | | | | `--' | | |\ | | |
|______/ | _| `.__| \______/ |__| |__| /__/ \__\ \______/ |__| \______/ |__| |__| /__/ \__\ |__| |__| \______/ |__| \__| | |
Thanks much to @corbanmailloux for providing a great framework for implementing flash/fade with HomeAssistant https://github.com/corbanmailloux/esp-mqtt-rgb-led | |
To use this code you will need the following dependancies: | |
- Support for the ESP8266 boards. | |
- You can add it to the board manager by going to File -> Preference and pasting http://arduino.esp8266.com/stable/package_esp8266com_index.json into the Additional Board Managers URL field. | |
- Next, download the ESP8266 dependancies by going to Tools -> Board -> Board Manager and searching for ESP8266 and installing it. | |
- You will also need to download the follow libraries by going to Sketch -> Include Libraries -> Manage Libraries | |
- FastLED | |
- PubSubClient | |
- ArduinoJSON | |
*/ | |
#include <ArduinoJson.h> | |
#include <ESP8266WiFi.h> | |
#include <PubSubClient.h> | |
#include "FastLED.h" | |
#include <ESP8266mDNS.h> | |
#include <WiFiUdp.h> | |
#include <ArduinoOTA.h> | |
/************ WIFI and MQTT Information (CHANGE THESE FOR YOUR SETUP) ******************/ | |
const char* ssid = ""; //type your WIFI information inside the quotes | |
const char* password = ""; // WIFI password | |
const char* mqtt_server = ""; // IP address of the MQTT server | |
const char* mqtt_username = ""; | |
const char* mqtt_password = ""; | |
const int mqtt_port = 1883; | |
/**************************** FOR OTA **************************************************/ | |
#define SENSORNAME "blinkie" //change this to whatever you want to call your device | |
#define OTApassword "blinkie" //the password you will need to enter to upload remotely via the ArduinoIDE | |
#define OTAport 8266 | |
/************* MQTT TOPICS (change these topics as you wish) **************************/ | |
const char* light_state_topic = "home/desk"; | |
const char* light_set_topic = "home/desk/set"; | |
/*********************************** FastLED Defintions ********************************/ | |
#define NUM_LEDS 65 | |
#define DATA_PIN 2 | |
//#define CLOCK_PIN 5 | |
#define CHIPSET WS2811 | |
#define COLOR_ORDER GRB | |
const char* on_cmd = "ON"; | |
const char* off_cmd = "OFF"; | |
const char* effect = "solid"; | |
String effectString = "solid"; | |
String oldeffectString = "solid"; | |
/****************************************FOR JSON***************************************/ | |
const int BUFFER_SIZE = JSON_OBJECT_SIZE(10); | |
#define MQTT_MAX_PACKET_SIZE 512 | |
byte realRed = 0; | |
byte realGreen = 0; | |
byte realBlue = 0; | |
byte red = 255; | |
byte green = 255; | |
byte blue = 255; | |
byte brightness = 255; | |
/******************************** GLOBALS for fade/flash *******************************/ | |
bool stateOn = false; | |
bool startFade = false; | |
bool onbeforeflash = false; | |
unsigned long lastLoop = 0; | |
int transitionTime = 0; | |
int effectSpeed = 0; | |
bool inFade = false; | |
int loopCount = 0; | |
int stepR, stepG, stepB; | |
int redVal, grnVal, bluVal; | |
bool flash = false; | |
bool startFlash = false; | |
int flashLength = 0; | |
unsigned long flashStartTime = 0; | |
byte flashRed = red; | |
byte flashGreen = green; | |
byte flashBlue = blue; | |
byte flashBrightness = brightness; | |
/********************************** GLOBALS for EFFECTS ******************************/ | |
//RAINBOW | |
uint8_t thishue = 0; // Starting hue value. | |
uint8_t deltahue = 10; | |
//CANDYCANE | |
CRGBPalette16 currentPalettestriped; //for Candy Cane | |
CRGBPalette16 gPal; //for fire | |
//NOISE | |
static uint16_t dist; // A random number for our noise generator. | |
uint16_t scale = 30; // Wouldn't recommend changing this on the fly, or the animation will be really blocky. | |
uint8_t maxChanges = 48; // Value for blending between palettes. | |
CRGBPalette16 targetPalette(OceanColors_p); | |
CRGBPalette16 currentPalette(CRGB::Black); | |
//TWINKLE | |
#define DENSITY 80 | |
int twinklecounter = 0; | |
//RIPPLE | |
uint8_t colour; // Ripple colour is randomized. | |
int center = 0; // Center of the current ripple. | |
int step = -1; // -1 is the initializing step. | |
uint8_t myfade = 255; // Starting brightness. | |
#define maxsteps 16 // Case statement wouldn't allow a variable. | |
uint8_t bgcol = 0; // Background colour rotates. | |
int thisdelay = 20; // Standard delay value. | |
//DOTS | |
uint8_t count = 0; // Count up to 255 and then reverts to 0 | |
uint8_t fadeval = 224; // Trail behind the LED's. Lower => faster fade. | |
uint8_t bpm = 30; | |
//LIGHTNING | |
uint8_t frequency = 50; // controls the interval between strikes | |
uint8_t flashes = 8; //the upper limit of flashes per strike | |
unsigned int dimmer = 1; | |
uint8_t ledstart; // Starting location of a flash | |
uint8_t ledlen; | |
int lightningcounter = 0; | |
//FUNKBOX | |
int idex = 0; //-LED INDEX (0 to NUM_LEDS-1 | |
int TOP_INDEX = int(NUM_LEDS / 2); | |
int thissat = 255; //-FX LOOPS DELAY VAR | |
uint8_t thishuepolice = 0; | |
int antipodal_index(int i) { | |
int iN = i + TOP_INDEX; | |
if (i >= TOP_INDEX) { | |
iN = ( i + TOP_INDEX ) % NUM_LEDS; | |
} | |
return iN; | |
} | |
//FIRE | |
#define COOLING 55 | |
#define SPARKING 120 | |
bool gReverseDirection = false; | |
//BPM | |
uint8_t gHue = 0; | |
WiFiClient espClient; | |
PubSubClient client(espClient); | |
struct CRGB leds[NUM_LEDS]; | |
/********************************** START SETUP*****************************************/ | |
void setup() { | |
Serial.begin(115200); | |
FastLED.addLeds<CHIPSET, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS); | |
setupStripedPalette( CRGB::Red, CRGB::Red, CRGB::White, CRGB::White); //for CANDY CANE | |
gPal = HeatColors_p; //for FIRE | |
setup_wifi(); | |
client.setServer(mqtt_server, mqtt_port); | |
client.setCallback(callback); | |
//OTA SETUP | |
ArduinoOTA.setPort(OTAport); | |
// Hostname defaults to esp8266-[ChipID] | |
ArduinoOTA.setHostname(SENSORNAME); | |
// No authentication by default | |
ArduinoOTA.setPassword((const char *)OTApassword); | |
ArduinoOTA.onStart([]() { | |
Serial.println("Starting"); | |
}); | |
ArduinoOTA.onEnd([]() { | |
Serial.println("\nEnd"); | |
}); | |
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { | |
Serial.printf("Progress: %u%%\r", (progress / (total / 100))); | |
}); | |
ArduinoOTA.onError([](ota_error_t error) { | |
Serial.printf("Error[%u]: ", error); | |
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed"); | |
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed"); | |
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed"); | |
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed"); | |
else if (error == OTA_END_ERROR) Serial.println("End Failed"); | |
}); | |
ArduinoOTA.begin(); | |
Serial.println("Ready"); | |
Serial.print("IP Address: "); | |
Serial.println(WiFi.localIP()); | |
} | |
/********************************** START SETUP WIFI*****************************************/ | |
void setup_wifi() { | |
delay(10); | |
// We start by connecting to a WiFi network | |
Serial.println(); | |
Serial.print("Connecting to "); | |
Serial.println(ssid); | |
WiFi.mode(WIFI_STA); | |
WiFi.begin(ssid, password); | |
while (WiFi.status() != WL_CONNECTED) { | |
delay(500); | |
Serial.print("."); | |
} | |
Serial.println(""); | |
Serial.println("WiFi connected"); | |
Serial.println("IP address: "); | |
Serial.println(WiFi.localIP()); | |
} | |
/* | |
SAMPLE PAYLOAD: | |
{ | |
"brightness": 120, | |
"color": { | |
"r": 255, | |
"g": 100, | |
"b": 100 | |
}, | |
"flash": 2, | |
"transition": 5, | |
"state": "ON" | |
} | |
*/ | |
/********************************** START Set Color*****************************************/ | |
void setColor(int inR, int inG, int inB) { | |
for (int i = 0; i < NUM_LEDS; i++) { | |
leds[i].red = inR; | |
leds[i].green = inG; | |
leds[i].blue = inB; | |
} | |
customShow(); | |
Serial.println("Setting LEDs:"); | |
Serial.print("r: "); | |
Serial.print(inR); | |
Serial.print(", g: "); | |
Serial.print(inG); | |
Serial.print(", b: "); | |
Serial.println(inB); | |
} | |
/********************************** START MAIN LOOP*****************************************/ | |
void loop() { | |
if (!client.connected()) { | |
reconnect(); | |
} | |
if (WiFi.status() != WL_CONNECTED) { | |
delay(1); | |
Serial.print("WIFI Disconnected. Attempting reconnection."); | |
setup_wifi(); | |
return; | |
} | |
client.loop(); | |
ArduinoOTA.handle(); | |
random16_add_entropy( random8()); | |
if (effectString == "bpm") { | |
bpmEffect(); | |
} else if (effectString == "candy cane") { | |
candyCane(); | |
} else if (effectString == "confetti") { | |
confetti(); | |
} else if (effectString == "cyclon rainbow") { | |
cyclonRainbow(); | |
} else if (effectString =="dots") { | |
dots(); | |
} else if (effectString == "fire") { | |
fire(); | |
} else if (effectString == "glitter") { | |
glitter(); | |
} else if (effectString == "jungle") { | |
jungle(); | |
} else if (effectString == "lightning") { | |
lightning(); | |
} else if (effectString == "police all") { | |
policeAll(); | |
} else if (effectString == "police one") { | |
policeOne(); | |
} else if (effectString == "rainbow") { | |
rainbow(); | |
} else if (effectString == "rainbow with glitter") { | |
rainbowWithGlitter(); | |
} else if (effectString == "sinelon") { | |
sinelon(); | |
} else if (effectString == "twinkle") { | |
twinkle(); | |
} | |
EVERY_N_MILLISECONDS(10) { | |
nblendPaletteTowardPalette(currentPalette, targetPalette, maxChanges); // FOR NOISE ANIMATIon | |
{ | |
gHue++; | |
} | |
//EFFECT NOISE | |
if (effectString == "noise") { | |
noise(); | |
} | |
//EFFECT RIPPLE | |
if (effectString == "ripple") { | |
ripple(); | |
} | |
} | |
EVERY_N_SECONDS(5) { | |
targetPalette = CRGBPalette16(CHSV(random8(), 255, random8(128, 255)), CHSV(random8(), 255, random8(128, 255)), CHSV(random8(), 192, random8(128, 255)), CHSV(random8(), 255, random8(128, 255))); | |
} | |
//FLASH AND FADE SUPPORT | |
if (flash) { | |
if (startFlash) { | |
startFlash = false; | |
flashStartTime = millis(); | |
} | |
if ((millis() - flashStartTime) <= flashLength) { | |
if ((millis() - flashStartTime) % 1000 <= 500) { | |
setColor(flashRed, flashGreen, flashBlue); | |
} | |
else { | |
setColor(0, 0, 0); | |
// If you'd prefer the flashing to happen "on top of" | |
// the current color, uncomment the next line. | |
// setColor(realRed, realGreen, realBlue); | |
} | |
} | |
else { | |
flash = false; | |
effectString = oldeffectString; | |
if (onbeforeflash) { //keeps light off after flash if light was originally off | |
setColor(realRed, realGreen, realBlue); | |
} | |
else { | |
Serial.println("state off -2 "); | |
stateOn = false; | |
setColor(0, 0, 0); | |
sendState(); | |
} | |
} | |
} | |
if (startFade && effectString == "solid") { | |
// If we don't want to fade, skip it. | |
if (transitionTime == 0) { | |
setColor(realRed, realGreen, realBlue); | |
redVal = realRed; | |
grnVal = realGreen; | |
bluVal = realBlue; | |
startFade = false; | |
} | |
else { | |
loopCount = 0; | |
stepR = calculateStep(redVal, realRed); | |
stepG = calculateStep(grnVal, realGreen); | |
stepB = calculateStep(bluVal, realBlue); | |
inFade = true; | |
} | |
} | |
if (inFade) { | |
startFade = false; | |
unsigned long now = millis(); | |
if (now - lastLoop > transitionTime) { | |
if (loopCount <= 1020) { | |
lastLoop = now; | |
redVal = calculateVal(stepR, redVal, loopCount); | |
grnVal = calculateVal(stepG, grnVal, loopCount); | |
bluVal = calculateVal(stepB, bluVal, loopCount); | |
if (effectString == "solid") { | |
setColor(redVal, grnVal, bluVal); // Write current values to LED pins | |
} | |
loopCount++; | |
} | |
else { | |
inFade = false; | |
} | |
} | |
} | |
} | |
/**************************** START TRANSITION FADER *****************************************/ | |
// From https://www.arduino.cc/en/Tutorial/ColorCrossfader | |
/* BELOW THIS LINE IS THE MATH -- YOU SHOULDN'T NEED TO CHANGE THIS FOR THE BASICS | |
The program works like this: | |
Imagine a crossfade that moves the red LED from 0-10, | |
the green from 0-5, and the blue from 10 to 7, in | |
ten steps. | |
We'd want to count the 10 steps and increase or | |
decrease color values in evenly stepped increments. | |
Imagine a + indicates raising a value by 1, and a - | |
equals lowering it. Our 10 step fade would look like: | |
1 2 3 4 5 6 7 8 9 10 | |
R + + + + + + + + + + | |
G + + + + + | |
B - - - | |
The red rises from 0 to 10 in ten steps, the green from | |
0-5 in 5 steps, and the blue falls from 10 to 7 in three steps. | |
In the real program, the color percentages are converted to | |
0-255 values, and there are 1020 steps (255*4). | |
To figure out how big a step there should be between one up- or | |
down-tick of one of the LED values, we call calculateStep(), | |
which calculates the absolute gap between the start and end values, | |
and then divides that gap by 1020 to determine the size of the step | |
between adjustments in the value. | |
*/ | |
int calculateStep(int prevValue, int endValue) { | |
int step = endValue - prevValue; // What's the overall gap? | |
if (step) { // If its non-zero, | |
step = 1020 / step; // divide by 1020 | |
} | |
return step; | |
} | |
/* The next function is calculateVal. When the loop value, i, | |
reaches the step size appropriate for one of the | |
colors, it increases or decreases the value of that color by 1. | |
(R, G, and B are each calculated separately.) | |
*/ | |
int calculateVal(int step, int val, int i) { | |
if ((step) && i % step == 0) { // If step is non-zero and its time to change a value, | |
if (step > 0) { // increment the value if step is positive... | |
val += 1; | |
} | |
else if (step < 0) { // ...or decrement it if step is negative | |
val -= 1; | |
} | |
} | |
// Defensive driving: make sure val stays in the range 0-255 | |
if (val > 255) { | |
val = 255; | |
} | |
else if (val < 0) { | |
val = 0; | |
} | |
return val; | |
} | |
/**************************** START STRIPLED PALETTE *****************************************/ | |
void setupStripedPalette( CRGB A, CRGB AB, CRGB B, CRGB BA) { | |
currentPalettestriped = CRGBPalette16( | |
A, A, A, A, A, A, A, A, B, B, B, B, B, B, B, B | |
// A, A, A, A, A, A, A, A, B, B, B, B, B, B, B, B | |
); | |
} | |
/********************************** START FADE************************************************/ | |
void fadeall() { | |
for (int i = 0; i < NUM_LEDS; i++) { | |
leds[i].nscale8(250); //for CYCLon | |
} | |
} | |
/********************************** START ADD GLITTER *********************************************/ | |
void addGlitter( fract8 chanceOfGlitter) | |
{ | |
if ( random8() < chanceOfGlitter) { | |
leds[ random16(NUM_LEDS) ] += CRGB::White; | |
} | |
} | |
/********************************** START ADD GLITTER COLOR ****************************************/ | |
void addGlitterColor( fract8 chanceOfGlitter, int red, int green, int blue) | |
{ | |
if ( random8() < chanceOfGlitter) { | |
leds[ random16(NUM_LEDS) ] += CRGB(red, green, blue); | |
} | |
} | |
/********************************** START SHOW LEDS ***********************************************/ | |
void showleds() { | |
delay(1); | |
if (stateOn) { | |
FastLED.setBrightness(brightness); //EXECUTE EFFECT COLOR | |
customShow(); | |
if (transitionTime > 0 && transitionTime < 130) { //Sets animation speed based on receieved value | |
FastLED.delay(1000 / transitionTime); | |
//delay(10*transitionTime); | |
} | |
} | |
else if (startFade) { | |
setColor(0, 0, 0); | |
startFade = false; | |
} | |
} | |
void temp2rgb(unsigned int kelvin) { | |
int tmp_internal = kelvin / 100.0; | |
// red | |
if (tmp_internal <= 66) { | |
red = 255; | |
} else { | |
float tmp_red = 329.698727446 * pow(tmp_internal - 60, -0.1332047592); | |
if (tmp_red < 0) { | |
red = 0; | |
} else if (tmp_red > 255) { | |
red = 255; | |
} else { | |
red = tmp_red; | |
} | |
} | |
// green | |
if (tmp_internal <=66){ | |
float tmp_green = 99.4708025861 * log(tmp_internal) - 161.1195681661; | |
if (tmp_green < 0) { | |
green = 0; | |
} else if (tmp_green > 255) { | |
green = 255; | |
} else { | |
green = tmp_green; | |
} | |
} else { | |
float tmp_green = 288.1221695283 * pow(tmp_internal - 60, -0.0755148492); | |
if (tmp_green < 0) { | |
green = 0; | |
} else if (tmp_green > 255) { | |
green = 255; | |
} else { | |
green = tmp_green; | |
} | |
} | |
// blue | |
if (tmp_internal >=66) { | |
blue = 255; | |
} else if (tmp_internal <= 19) { | |
blue = 0; | |
} else { | |
float tmp_blue = 138.5177312231 * log(tmp_internal - 10) - 305.0447927307; | |
if (tmp_blue < 0) { | |
blue = 0; | |
} else if (tmp_blue > 255) { | |
blue = 255; | |
} else { | |
blue = tmp_blue; | |
} | |
} | |
} | |
void customShow() { | |
FastLED.show(); | |
delay(1); | |
FastLED.show(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment