#include <FastLED.h>
#define LED_PIN 6 // pin for LED Neopixel strip
#define BTN_PIN 2 // pin for button input
const uint8_t COLS = 12;
const uint8_t ROWS = 18;
#define TOTAL_LEDS (COLS * ROWS)
// palettes matrix
DEFINE_GRADIENT_PALETTE(blueFire) {
0, 0, 0, 0,
40, 0, 10, 60,
100, 0, 50, 190,
160, 0, 140, 255,
220, 80, 220, 255,
255, 240, 250, 255
};
DEFINE_GRADIENT_PALETTE(redFire) {
0, 0, 0, 0,
30, 50, 0, 0,
80, 180, 20, 0,
150, 255, 90, 0,
210, 255, 195, 0,
255, 255, 255, 220
};
CRGB leds[TOTAL_LEDS];
byte heat[COLS][ROWS];
CRGBPalette16 curPal = blueFire;
CRGBPalette16 tgtPal = blueFire;
bool flareActive = false;
unsigned long flareTimer = 0;
int lastBtn = HIGH;
// map 2d coordinates to 1d strip
// strips wired top to bottom around ring
uint16_t XY(int x, int y) {
if (x < 0 || x >= COLS || y < 0 || y >= ROWS) return 0;
return (x * ROWS) + (ROWS - 1 - y);
}
void checkButton() {
int btn = digitalRead(BTN_PIN);
if (btn == LOW) {
if (!flareActive) {
flareActive = true;
Serial.println("FLARE ON");
}
flareTimer = millis();
} else {
if (flareActive && (millis() - flareTimer >= 3000)) {
flareActive = false;
Serial.println("flare off");
}
}
lastBtn = btn;
}
void fireStep() {
// adjust cooling and sparks based on button flare
byte cMin = flareActive ? 4 : 10;
byte cMax = flareActive ? 12 : 22;
byte spProb = flareActive ? 210 : 110;
byte spHigh = flareActive ? 150 : 40;
// 1. cool
for (int x = 0; x < COLS; x++) {
for (int y = 0; y < ROWS; y++) {
heat[x][y] = qsub8(heat[x][y], random8(cMin, cMax));
}
}
// 2. diffuse upward & wrap cylinder
for (int y = ROWS - 1; y >= 1; y--) {
for (int x = 0; x < COLS; x++) {
int left = (x == 0) ? (COLS - 1) : (x - 1);
int right = (x == COLS - 1) ? 0 : (x + 1);
heat[x][y] = (heat[x][y - 1] * 2 + heat[left][y - 1] + heat[right][y - 1]) / 4;
}
}
// 3. spark bottom
for (int x = 0; x < COLS; x++) {
if (random8() < spProb) {
heat[x][0] = qadd8(heat[x][0], random8(160, 255));
}
if (random8() < spHigh) {
int y = flareActive ? random8(1, 4) : 1;
heat[x][y] = qadd8(heat[x][y], random8(130, 220));
}
}
// 4. push to leds
for (int x = 0; x < COLS; x++) {
for (int y = 0; y < ROWS; y++) {
leds[XY(x, y)] = ColorFromPalette(curPal, heat[x][y]);
}
}
}
void setup() {
Serial.begin(115200);
pinMode(BTN_PIN, INPUT_PULLUP);
FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, TOTAL_LEDS);
FastLED.setBrightness(200);
FastLED.setMaxPowerInVoltsAndMilliamps(5, 3000);
FastLED.clear();
FastLED.show();
}
void loop() {
checkButton();
EVERY_N_MILLISECONDS(20) {
tgtPal = flareActive ? redFire : blueFire;
nblendPaletteTowardPalette(curPal, tgtPal, 16);
fireStep();
FastLED.show();
}
}