// Source: https://github.com/s-marley/FastLED-basics
#include <FastLED.h>
#include "palette.h"
#define NUM_LEDS 20
#define LED_PIN 2
#define SECONDS_PER_PALETTE 10
#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))
#define LEDS_OFF -1
#define LEDS_COOL 0
#define LEDS_HEAT 1
#define LEDS_BOOM 2
FASTLED_USING_NAMESPACE
CRGB leds[NUM_LEDS];
CRGB ledsNext[NUM_LEDS];
const int8_t ledIdx2Pos[NUM_LEDS][2] = {
{ 0, 7 }, { 0, 6 }, { 0, 5 }, { 0, 4 }, { 0, 3 }, { 0, 2 }, { 0, 1 }, //left side
{ 1, 0 }, { 2, 0 }, { 3, 0 }, { 4, 0 }, { 5, 0 }, { 6, 0 }, //middle
{ 7, 1 }, { 7, 2 }, { 7, 3 }, { 7, 4 }, { 7, 5 }, { 7, 6 }, { 7, 7 } //right side
};
void setup() {
FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS);
FastLED.setBrightness(50);
Serial.begin(115200);
}
typedef void (*ledAniList[])();
ledAniList animations = { coolPlasma,heatPulse,greenExplosion };
int8_t aniIdxNew = LEDS_COOL;
void loop() {
ledsMain();
}
void ledsMain(){
EVERY_N_MILLIS(20){
chkAniIdx();
//animations[]();
}
//
EVERY_N_MILLIS(50){aniIdxNew = map(analogRead(A0),0,1023,-1,2);}
// EVERY_N_SECONDS(8){ aniIdxNew++ % 3;}
}
void chkAniIdx(){
static int8_t aniIdxLast = aniIdxNew;
static uint16_t fadeval = 0;
if(aniIdxNew == -1 && aniIdxLast == -1){return;}
else if(aniIdxNew != -1 && aniIdxLast == -1){fadeval = 127; aniIdxLast = aniIdxNew; }
animations[aniIdxLast]();
if(aniIdxLast == aniIdxNew && fadeval == 0){FastLED.show(); return; }
else if(aniIdxLast != aniIdxNew && fadeval < 127){fadeval+=2;}
else if(aniIdxLast != aniIdxNew && fadeval >= 127){ aniIdxLast = aniIdxNew; FastLED.clear(); FastLED.show(); return;}
else if(aniIdxLast == aniIdxNew && fadeval >= 127 && fadeval < 255){fadeval+=2; if(aniIdxNew == LEDS_BOOM){fadeval=0;}}
else if(aniIdxLast == aniIdxNew && fadeval >= 255){fadeval=0;}
fadeLightBy ( leds, NUM_LEDS, cos8(fadeval+127));//
if(aniIdxLast != -1){FastLED.show();}
}
void coolPlasma(){
static bool stateLast = false;
if( currentPal != cool_pal){currentPal = cool_pal;}
static uint8_t gHue = 0;
const float plasmaSpeed = 0.25; //0.1 to 1
const uint8_t plasmaZoom = 30; // 20 to 80
uint16_t ms = plasmaSpeed * millis();
for( int i = 0; i< NUM_LEDS; i++){
byte noises = inoise8 (i * plasmaZoom, 6 * plasmaZoom, ms);
leds[i] = ColorFromPalette(currentPal, noises+gHue, 255, LINEARBLEND);
EVERY_N_MILLIS(60){gHue++;}
}
}
void heatPulse(){
if( currentPal != heat_pal){currentPal = heat_pal;}
static uint8_t fadeVal = 0;
const uint16_t brightnessScale =150;// 150;
const uint16_t indexScale = 100;
for (int i = 0; i < NUM_LEDS; i++) {
uint8_t brightness = inoise8(i * brightnessScale, millis() / 5);
uint8_t index = inoise8(i * indexScale, millis() /10);
leds[i] = ColorFromPalette( currentPal , index, brightness);
}
fadeLightBy ( leds, NUM_LEDS, triwave8(fadeVal) * 0.75);
fadeVal+=2;
}
void greenExplosion(){EVERY_N_MILLIS(50){fireworks();}}
/******************************************************************************/
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))];}
void fireworks(){
fadeToBlackBy(leds, NUM_LEDS, 96);
if (sparkCount() == 0 && aniIdxNew == LEDS_BOOM){ float sparkVel = getVelByDist(fw.minFly, fw.maxFly);
newSpark(1, CRGB(29, 48, 48), 0, sparkVel, fw.lastInv);
fw.lastInv = !fw.lastInv;
}
updateFireworks();
showFireworks();
}
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 freeIdx = nextdead();
if (freeIdx < 0) {return;}
fw.inv[freeIdx] = invert;
fw.type[freeIdx] = type;
fw.heat[freeIdx] = 1.0;
fw.lcolor[freeIdx] = newCol;
fw.location[freeIdx] = newLoc;
fw.velocity[freeIdx] = 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 n = 0; for (int i = 0; i < fw.sparks; i++){if (fw.type[i] > 0){n++;}} return n; }
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
pot1:GND
pot1:SIG
pot1:VCC
neopixels1:DOUT
neopixels1:VDD
neopixels1:VSS
neopixels1:DIN
neopixels2:DOUT
neopixels2:VDD
neopixels2:VSS
neopixels2:DIN