MATERIALS
WS2812B Addressable LED
Green Cast Matte Metallic® - Antique Gold Metallic Acrylic 12x20"
Green Cast Nacre® - Mother of Pearl Silver Acrylic 12x24
ARDUINO CODE:
//GET OUR LIBRARIES
#include <FastLED.h>
#include <OneButton.h>
//DEFINE OUR WHAT IS CONNECTED TO OUR PINES
#define LED_PIN_CENTER 4 //CENTER
#define LED_PIN_A 2 //SIDE A
#define LED_PIN_B 7 //SIDE B
#define BTN_PIN 14 //BUTTON
//DEFINE HOW MANY LEDS EACH STRIP HAS
#define NUM_LEDS_CENTER 139 //NUMBER LEDS CENTER
#define NUM_LEDS_SIDE_A 56 //NUMBER LEDS SIDE
#define NUM_LEDS_SIDE_B 56 //NUMBER LEDS SIDE
//DEFINE SETTINGS FOR SUB LOOPS
#define COOLING 55
#define SPARKING 120
// Define the array of leds, This is what we will use to turn on a specific strand of LEDs
CRGB ledsC[NUM_LEDS_CENTER];
CRGB ledsA[NUM_LEDS_SIDE_A];
CRGB ledsB[NUM_LEDS_SIDE_B];
//Global Variables that can be used in any function
unsigned long interval=25; // the time we need to wait
unsigned long previousMillis=0; // millis() returns an unsigned long.
unsigned long interval_b = 100; // the time we need to wait Part 2
uint8_t patternCounter = 0;
uint8_t minBright = 20;
uint8_t maxBright = 80;
bool gReverseDirection = false;
//MORE GLOBAL VARIABLES FOR SUB LOOPS
int numColors = 1;
int ra = 60;
int rb = 0;
int dir = 0;
int dirb = 0;
int dirc = 0;
int la = 0;
int sat = 0;
// Push button connected between pin 14 and GND (no resistor required) Defining our Push Button
OneButton btn = OneButton(BTN_PIN, true, true);
void setup() {
//Initializing our LEDs
FastLED.addLeds<WS2812, LED_PIN_CENTER, GRB>(ledsC, NUM_LEDS_CENTER);
FastLED.addLeds<WS2812, LED_PIN_A, GRB>(ledsA, NUM_LEDS_SIDE_A);
FastLED.addLeds<WS2812, LED_PIN_B, GRB>(ledsB, NUM_LEDS_SIDE_B);
//Set our inital LED Brightness
FastLED.setBrightness(50);
//Serial.begin(9600);
//One Button lets us tell the program what to do when the button is clicked, so it will Run - nextPattern
btn.attachClick(nextPattern);
//This gives us time will testing to upload a new sketch to the board in case it gets stuck, Can take this out once code is finalized
delay(5000);
}
//MAIN LOOP
void loop() {
//SWITCH & CASE - controls the flow of programs by allowing programmers to specify different code that should be executed in various conditions
//BREAK - keyword exits the switch statement, and is typically used at the end of each case. Without a break statement, the switch statement will
//continue executing the following expressions ("falling-through") until a break, or the end of the switch statement is reached.
switch (patternCounter) {
case 0:
solidColor();
break;
case 1:
rainbowBeat();
break;
case 2:
redAlertB();
break;
case 3:
fire();
break;
case 4:
juggle();
break;
case 5:
movingDots();
break;
case 6:
redAlert();
break;
case 7:
redgold();
break;
case 8:
gradientChangeSlow();
break;
case 9:
gradientChangeFast();
break;
}
//NOTICE FastLED.show is here, and not in our Sub Loops
FastLED.show();
btn.tick();
}
void nextPattern() {
//This changes what Case we are on
patternCounter = (patternCounter + 1) % 10; // Change the number after the % to the number of patterns you have
FastLED.clear (); //Clears our current LEDs
}
//------- Put your patterns below -------//
void solidColor() {
//TO Change the Speed Change the 5000
float breath = (exp(sin(millis()/5000.0*PI)) - 0.36787944)*108.0;
//Map Breath Value from above to 0-255, then get the GLOBAL minBright & maxBright Variable
breath = map(breath, 0, 255, minBright, maxBright);
FastLED.setBrightness(breath);
fill_solid(ledsC, NUM_LEDS_CENTER, CRGB::SlateGray);
fill_solid(ledsA, NUM_LEDS_SIDE_A, CRGB::Gold);
fill_solid(ledsB, NUM_LEDS_SIDE_B, CRGB::Gold);
}
void rainbowBeat() {
uint16_t beatA = beatsin16(30, 0, 255);
uint16_t beatB = beatsin16(20, 0, 255);
fill_rainbow(ledsC, NUM_LEDS_CENTER, (beatA+beatB)/2, 8); // Initial Hue - Delta HUE - How fast to advance the led
fill_rainbow(ledsA, NUM_LEDS_SIDE_A, (beatA+beatB)/2, 8);
fill_rainbow(ledsB, NUM_LEDS_SIDE_B, (beatA+beatB)/2, 8);
}
void redAlertB() {
unsigned long currentMillis = millis();
if ((unsigned long)(currentMillis - previousMillis) >= interval) {
//LEFT SIDE OF CENTER
ledsC[ra] = CRGB(255,0,0);
if (dir == 0){
ra ++;
if (ra == 140){
dir = 1;
}
}
else if (dir == 1){
ra --;
if (ra == 60){
dir = 0;
}
}
//RIGHT SIDE OF CENTER
ledsC[rb] = CRGB(255,0,0);
if (dirb == 0){
rb ++;
if (rb == 60){
dirb = 1;
}
}
else if (dirb == 1){
rb --;
if (rb == 0){
dirb = 0;
}
}
ledsA[la] = CRGB(255,0,0);
ledsB[la] = CRGB(255,0,0);
if (dirc == 0){
la ++;
if (la == NUM_LEDS_SIDE_A){
dirc = 1;
}
}
else if (dirc == 1){
la --;
if (la == 0){
dirc = 0;
}
}
fadeToBlackBy(ledsC, NUM_LEDS_CENTER, 8);
fadeToBlackBy(ledsA, NUM_LEDS_SIDE_A, 15);
fadeToBlackBy(ledsB, NUM_LEDS_SIDE_B, 15);
previousMillis = millis();
}
}
void fire() {
// Array of temperature readings at each simulation cell
static byte heat[NUM_LEDS_CENTER];
// Step 1. Cool down every cell a little
for( int i = 0; i < NUM_LEDS_CENTER; i++) {
heat[i] = qsub8( heat[i], random8(0, ((COOLING * 10) / NUM_LEDS_CENTER) + 2));
}
for( int i = 0; i < NUM_LEDS_SIDE_A; i++) {
heat[i] = qsub8( heat[i], random8(0, ((COOLING * 10) / NUM_LEDS_SIDE_A) + 2));
}
// Step 2. Heat from each cell drifts 'up' and diffuses a little
for( int k= NUM_LEDS_CENTER - 1; k >= 2; k--) {
heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2] ) / 3;
}
for( int k= NUM_LEDS_SIDE_A - 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_CENTER; j++) {
CRGB color = HeatColor( heat[j]);
int pixelnumber;
if( gReverseDirection ) {
pixelnumber = (NUM_LEDS_CENTER-1) - j;
} else {
pixelnumber = j;
}
ledsC[pixelnumber] = color;
}
// Step 4. SIDE A
for( int j = 0; j < NUM_LEDS_SIDE_A; j++) {
CRGB color = HeatColor( heat[j]);
int pixelnumber;
if( gReverseDirection ) {
pixelnumber = (NUM_LEDS_SIDE_A-1) - j;
} else {
pixelnumber = j;
}
ledsA[pixelnumber] = color;
}
// Step 4. SIDE B
for( int j = 0; j < NUM_LEDS_SIDE_B; j++) {
CRGB color = HeatColor( heat[j]);
int pixelnumber;
if( gReverseDirection ) {
pixelnumber = (NUM_LEDS_SIDE_B-1) - j;
} else {
pixelnumber = j;
}
ledsB[pixelnumber] = color;
}
}
void juggle() {
fadeToBlackBy( ledsC, NUM_LEDS_CENTER, 20);
fadeToBlackBy( ledsA, NUM_LEDS_SIDE_A, 20);
fadeToBlackBy( ledsB, NUM_LEDS_SIDE_B, 20);
uint8_t dothue = 0;
for( int i = 0; i < 8; i++) {
ledsC[beatsin16( i+7, 0, NUM_LEDS_CENTER-1 )] |= CHSV(dothue, 200, 255);
ledsA[beatsin16( i+7, 0, NUM_LEDS_SIDE_A-1 )] |= CHSV(dothue, 200, 255);
ledsB[beatsin16( i+7, 0, NUM_LEDS_SIDE_B-1 )] |= CHSV(dothue, 200, 255);
dothue += 32;
}
}
void movingDots() {
// beatsin16( BPM, uint16_t low, uint16_t high) returns a 16-bit value
// that rises and falls in a sine wave, 'BPM' times per
// minute, between the values of 'low' and 'high'.
//CENTER
uint16_t posBeat = beatsin16(30, 0, NUM_LEDS_CENTER - 1, 0, 0);
uint16_t posBeat2 = beatsin16(60, 0, NUM_LEDS_CENTER - 1, 0, 0);
uint16_t posBeat3 = beatsin16(30, 0, NUM_LEDS_CENTER - 1, 0, 32767);
uint16_t posBeat4 = beatsin16(60, 0, NUM_LEDS_CENTER - 1, 0, 32767);
//SIDES A & B
uint16_t posBeat5 = beatsin16(30, 0, NUM_LEDS_SIDE_A - 1, 0, 0);
uint16_t posBeat6 = beatsin16(60, 0, NUM_LEDS_SIDE_B - 1, 0, 0);
uint16_t posBeat7 = beatsin16(30, 0, NUM_LEDS_SIDE_A - 1, 0, 32767);
uint16_t posBeat8 = beatsin16(60, 0, NUM_LEDS_SIDE_B - 1, 0, 32767);
// Wave for LED color
uint8_t colBeat = beatsin8(45, 0, 255, 0, 0);
//HUE SATURATION VALUE (Brightness)
ledsC[(posBeat + posBeat2) / 2] = CHSV(colBeat, 255, 255);
ledsC[(posBeat3 + posBeat4) / 2] = CHSV(colBeat, 255, 255);
ledsA[(posBeat5 + posBeat6) / 2] = CHSV(colBeat, 255, 255);
ledsA[(posBeat7 + posBeat8) / 2] = CHSV(colBeat, 255, 255);
ledsB[(posBeat5 + posBeat6) / 2] = CHSV(colBeat, 255, 255);
ledsB[(posBeat7 + posBeat8) / 2] = CHSV(colBeat, 255, 255);
//Turn Off Lights by fadeing
fadeToBlackBy(ledsC, NUM_LEDS_CENTER, 10);
fadeToBlackBy(ledsA, NUM_LEDS_SIDE_A, 10);
fadeToBlackBy(ledsB, NUM_LEDS_SIDE_B, 10);
}
void redAlert() {
FastLED.setBrightness(50);
//(BEATS per min, FIRST LED, LAST LED, TIMEBASE, PHASE OFFSET)
//beatsin16 generates a 16-bit sine wave at a given BPM, that oscillates within a given range
//So we are generating this SinWave between 60 & 139 on our LED Strip for the Center part
uint16_t sinBeatA = beatsin16(15, 60, 139, 0, 21845);
uint8_t sinBeatAA = beatsin8(15, 60, 139, 0, 0);
uint16_t sinBeatB = beatsin16(30, 0, 60, 0, 21845);
uint8_t sinBeatBB = beatsin8(15, 0, 60, 0, 0);
uint16_t sinBeatL = beatsin16(15, 0, 28, 0, 21845);
uint8_t sinBeatLL = beatsin8(15, 0, 28, 0, 0);
uint16_t sinBeatM = beatsin16(15, 28, 56, 0, 21845);
uint8_t sinBeatMM = beatsin8(15, 28, 56, 0, 0);
ledsC[sinBeatA] = CRGB(255,0,0);
ledsC[sinBeatB] = CRGB(255,0,0);
ledsC[sinBeatAA] = CRGB(255,0,0);
ledsC[sinBeatBB] = CRGB(255,0,0);
ledsA[sinBeatL] = CRGB(255,0,0);
ledsA[sinBeatLL] = CRGB(255,0,0);
ledsA[sinBeatM] = CRGB(255,0,0);
ledsA[sinBeatMM] = CRGB(255,0,0);
ledsB[sinBeatL] = CRGB(255,0,0);
ledsB[sinBeatLL] = CRGB(255,0,0);
ledsB[sinBeatM] = CRGB(255,0,0);
ledsB[sinBeatMM] = CRGB(255,0,0);
fadeToBlackBy(ledsC, NUM_LEDS_CENTER, 5);
fadeToBlackBy(ledsA, NUM_LEDS_CENTER, 10);
fadeToBlackBy(ledsB, NUM_LEDS_CENTER, 10);
}
void redgold() {
uint16_t sinBeat = beatsin16(30, 0, NUM_LEDS_CENTER - 1, 0, 0);
uint16_t sinBeat2 = beatsin16(30, 0, NUM_LEDS_CENTER - 1, 0, 21845);
uint16_t sinBeat3 = beatsin16(30, 0, NUM_LEDS_CENTER - 1, 0, 43690);
uint16_t sinBeat4 = beatsin16(30, 0, NUM_LEDS_SIDE_A - 1, 0, 0);
uint16_t sinBeat5 = beatsin16(30, 0, NUM_LEDS_SIDE_A - 1, 0, 21845);
uint16_t sinBeat6 = beatsin16(30, 0, NUM_LEDS_SIDE_A - 1, 0, 43690);
ledsC[sinBeat] = CRGB::Red;
ledsC[sinBeat2] = CRGB::DarkRed;
ledsC[sinBeat3] = CRGB::Maroon;
ledsA[sinBeat4] = CRGB::DarkGoldenrod;
ledsA[sinBeat5] = CRGB::Goldenrod;
ledsA[sinBeat6] = CRGB::Gold;
ledsB[sinBeat4] = CRGB::DarkGoldenrod;
ledsB[sinBeat5] = CRGB::Goldenrod;
ledsB[sinBeat6] = CRGB::Gold;
fadeToBlackBy(ledsC, NUM_LEDS_CENTER, 6);
fadeToBlackBy(ledsA, NUM_LEDS_SIDE_A, 6);
fadeToBlackBy(ledsB, NUM_LEDS_SIDE_A, 6);
}
void gradientChangeSlow() {
uint8_t starthue_c = beatsin8(4, 0, 255);
uint8_t endhue_c = beatsin8(8, 255, 255);
uint8_t starthue_ab = beatsin8(2, 0, 255);
uint8_t endhue_ab = beatsin8(4, 255, 255);
unsigned long currentMillis = millis();
if ((unsigned long)(currentMillis - previousMillis) >= interval_b) {
fill_gradient(ledsC,NUM_LEDS_CENTER,CHSV(starthue_c, 255, 255),CHSV(endhue_c, starthue_c, 255),FORWARD_HUES);
fill_gradient(ledsA,NUM_LEDS_SIDE_A,CHSV(starthue_ab, 255, 255),CHSV(endhue_ab, starthue_ab, 255),FORWARD_HUES);
fill_gradient(ledsB,NUM_LEDS_SIDE_B,CHSV(starthue_ab, 255, 255),CHSV(endhue_ab, starthue_ab, 255),FORWARD_HUES);
}
}
void gradientChangeFast() {
uint8_t starthue_c = beatsin8(32, 0, 255);
uint8_t endhue_c = beatsin8(32, 255, 0);
unsigned long currentMillis = millis();
if ((unsigned long)(currentMillis - previousMillis) >= interval_b) {
fill_gradient(ledsC,NUM_LEDS_CENTER,CHSV(starthue_c, 255, 255),CHSV(endhue_c, starthue_c, 255),FORWARD_HUES);
fill_gradient(ledsA,NUM_LEDS_SIDE_A,CHSV(starthue_c, 255, 255),CHSV(endhue_c, starthue_c, 255),FORWARD_HUES);
fill_gradient(ledsB,NUM_LEDS_SIDE_B,CHSV(starthue_c, 255, 255),CHSV(endhue_c, starthue_c, 255),FORWARD_HUES);
}
}