/******************************************************************************
* Addressable LED Strip Fireworks Show
* By Joe Larson, the 3D Printing Professor
* http://3dpprofessor.com
******************************************************************************/
#include "FastLED.h"
/***************************************
* Hardware definitions *
***************************************/
#define NUM_LEDS 20
#define LED_DATA_PIN 3
#define POT_PIN A3
#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))
/***************************************/
#define Brightness 255
CRGB leds[NUM_LEDS];
bool active = true;
bool done = false;
void setup()
{
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println();
pinMode(POT_PIN, INPUT);
randomSeed(analogRead(A0));
FastLED.addLeds<WS2812B, LED_DATA_PIN, GRB>(leds, NUM_LEDS); // Added "GRB" for my manufacturer who decided to mix up the colors
FastLED.setBrightness(Brightness);
}
void loop()
{
EVERY_N_MILLIS(50){fireworks(active);}
FastLED.show();
}
/******************************************************************************/
struct fworkObj{
const int sparks = NUM_LEDS/3; //
const float decele = 0.08; // 0.11
const float veloMin = 0.1;
const uint8_t minFly = 5;
const uint8_t maxFly = 13 ;
uint8_t type[NUM_LEDS/3];
float heat[NUM_LEDS/3];
CRGB lcolor[NUM_LEDS/3];
float location[NUM_LEDS/3];
float velocity[NUM_LEDS/3];
bool inv[NUM_LEDS/3];
bool lastInv = false;
};
fworkObj fw;
CRGB greenColors[] = {
CRGB::Chartreuse,
CRGB(0, 255, 47),
CRGB(41, 241, 141),
CRGB(28, 188, 0),
CRGB(22, 255, 96),
CRGB(67, 255, 86),
CRGB(107, 240, 12)};
CRGB randomColor(){ return greenColors[random(ARRAY_SIZE(greenColors))];}
bool fireworks(bool active)
{
fadeToBlackBy(leds, NUM_LEDS, 96);
if (sparkCount() == 0){ float sparkVel = getVelByDist(fw.minFly, fw.maxFly);
newSpark(1, CRGB(29, 48, 48), 0, sparkVel, fw.lastInv);
fw.lastInv = !fw.lastInv;
}
updateFireworks();
showFireworks();
return (!active && alldead());
}
void updateFireworks() {
for (int i = 0; i < fw.sparks; i++) {
switch (fw.type[i]) {
case 0: break;
case 1: // rising
fw.location[i] += constrain(fw.velocity[i], -1.0, 1.0);
fw.velocity[i] -= fw.decele; // gravity
if (fw.velocity[i] < fw.veloMin) { // Explode
fw.type[i] = 0;
int numNew = 4 + random(4);
float newDiamter = (((float)random16(20) / 10.0) + 2) / 1.8;
CRGB newColor = randomColor();
//CRGB newColor = CHSV(random(255), 192, 255);
uint8_t firstDir = random(0,2);
for (int j = 0; j < numNew; j++){
float newVel = ((newDiamter /(float)numNew) * (float)(j) );
float newVel2 = (float)random16(10)/20.0;
if (((j+firstDir) % 2) == 0) {newVel *= -1; newVel2 *= -1;}
newSpark(2, newColor, fw.location[i], newVel + newVel2, fw.inv[i]);
}
}
break;
case 2: // exploding
fw.location[i] += fw.velocity[i];
fw.heat[i] -= 0.07;
if (fw.heat[i] <= 0) { fw.type[i] = 0;}
else if (fw.heat[i] < 0.5){
fw.lcolor[i] -= CRGB(128,128,128);
fw.velocity[i] /= 3;
if (random8(100) < 50){fw.velocity[i] += 0.05;}
else {fw.velocity[i] -= 0.05;}
if (random8(100) < 50){fw.lcolor[i] += CRGB(25,25,25);}
else{fw.lcolor[i] -= CRGB(25,25,25);}
}
break;
}
}
}
void newSpark(uint8_t type, CRGB newCol, int newLoc, float newVel, bool invert)
{
int newfirework = nextdead();
if (newfirework < 0) {return;}
fw.inv[newfirework] = invert;
fw.type[newfirework] = type;
fw.heat[newfirework] = 1.0;
fw.lcolor[newfirework] = newCol;
fw.location[newfirework] = newLoc;
fw.velocity[newfirework] = newVel;
}
void showFireworks(){
for (int i = 0; i < fw.sparks; i++) {
if (fw.type[i] > 0) {
if ((fw.location[i] < 0)|| (fw.location[i] >= NUM_LEDS)){ fw.type[i] = 0; }// just kill it if it goes out of bounds.
else{
int pos = fw.inv[i] ? NUM_LEDS-1 - (int)fw.location[i] : (int)fw.location[i];
leds[pos] += fw.lcolor[i];
}
}
}
}
int sparkCount(){
int retval = 0;
for (int i = 0; i < fw.sparks; i++){if (fw.type[i] > 0){retval++;}}
return retval;
}
int nextdead(){
uint8_t addDead = 0;
for (int i = 0; i < fw.sparks; i++){
if (fw.type[i] == 0){
addDead++;
if(addDead > 2){return i;}
}
}
return -1;
}
bool alldead(){ for (int i = 0; i < fw.sparks; i++){ if (fw.type[i] != 0){ return false;} } return true;}
float getVelByDist(uint8_t from, uint8_t to){
float distGoal = (float)random((float)from*10, (float)to * 10 + 1) / 10;
float dist = fw.veloMin ;
float veloAdd = fw.veloMin;
while(true){
dist+= veloAdd > 1 ? 1 : veloAdd;
veloAdd += fw.decele ;
if(dist>distGoal){break;}
}
veloAdd -= fw.decele ;
return veloAdd;
}
uno:A5.2
uno:A4.2
uno:AREF
uno:GND.1
uno:13
uno:12
uno:11
uno:10
uno:9
uno:8
uno:7
uno:6
uno:5
uno:4
uno:3
uno:2
uno:1
uno:0
uno:IOREF
uno:RESET
uno:3.3V
uno:5V
uno:GND.2
uno:GND.3
uno:VIN
uno:A0
uno:A1
uno:A2
uno:A3
uno:A4
uno:A5
neopixels:DOUT
neopixels:VDD
neopixels:VSS
neopixels:DIN