Fire2012 Code "reset"? I've got Fire2012 running on a neopixel strip with a capacitive

Fire2012 Code “reset”? I’ve got Fire2012 running on a neopixel strip with a capacitive touch on/off button. The button fades the fire nicely out when it’s pressed, and then turns the fire back on when it’s pressed again. Right now my code shows the same animation frame the fire was displaying when it was turned off (i.e. bright and hot burning fire). Instead, I want the fire to slowly burn up from the bottom of the strip – the same way it does when I first boot up the arduino.

Is there a way to “reset” the fire animation during my button press so it goes back to frame 0? Code in the comments. Thank you!

#include <Adafruit_CircuitPlayground.h>
#include <FastLED.h>

#define STRIP1_DATA_PIN 9
#define NUM_MODES 1

#define COLOR_ORDER GRB

#define NUM_LEDS 80

#define CAP_THRESHOLD 50
#define FRAMES_PER_SECOND 35

CRGBPalette16 currentPalette;
TBlendType currentBlending;
CRGBPalette16 gPal;
CRGB leds[NUM_LEDS];

//BUTTON SETUP STUFF
byte prevKeyState = HIGH;

//FIRST ACTIVE MODE
int ledMode = 0;

//GET CAP TOUCH BUTTON STATE
boolean capButton(uint8_t pad) {
if (CircuitPlayground.readCap(pad) > CAP_THRESHOLD) {
return true;
} else {
return false;
}
}

void setup() {
// Initialize serial.
Serial.begin(9600);

// Initialize Circuit Playground library.
CircuitPlayground.begin();
FastLED.addLeds<WS2812B, STRIP1_DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );

currentBlending = LINEARBLEND;
}
////////////////////////////////////////////////////////////////////////////
void loop() {
switch (ledMode) {
case 0: fire(); break;
case 1: alloff(); break;
}
// CHECK IF BUTTON IS PRESSED
byte currKeyState = capButton(10);
Serial.println (capButton(10));
if ((prevKeyState == true) && (currKeyState == false)) {
keyRelease();
}

    prevKeyState = currKeyState;

}

//BUTTON CONTROL
void keyRelease() {
Serial.println(“short”);
ledMode++;
if (ledMode > NUM_MODES){
ledMode=0; }
}

void fire()
{

currentPalette = HeatColors_p;
Fire2012WithPalette(); // run simulation frame, using palette colors
FastLED.show(); // display this frame
FastLED.delay(1000 / FRAMES_PER_SECOND);

}

#define COOLING 55 // Less cooling = taller flames. Default 55, suggested range 20-100
#define SPARKING 120 //Higher chance = more roaring fire. Default 120, suggested range 50-200

void Fire2012WithPalette()
{
random16_add_entropy( random());
static byte heat[NUM_LEDS];
for( int i = 0; i < NUM_LEDS; i++) {
heat[i] = qsub8( heat[i], random8(0, ((COOLING * 10) / NUM_LEDS) + 2));
}
for( int k= NUM_LEDS - 3; k > 0; k–) {
heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2] ) / 3;
}
if( random8() < SPARKING ) {
int y = random8(7);
heat[y] = qadd8( heat[y], random8(160,255) );
}
for( int j = 0; j < NUM_LEDS; j++) {
byte colorindex = scale8( heat[j], 240);
leds[j] = ColorFromPalette( currentPalette, colorindex);

}

}

void alloff() { // Fade all LEDs slowly to black
for (int i = 0; i < NUM_LEDS; i++){
leds[i].fadeToBlackBy( 64 );
}

FastLED.show();
delay(20);
}

@Erin_St_Blaine Just guessing, but here’s what I’d try:

Move the ‘static byte heat[NUM_LEDS]’ declaration out of the Fire2012Palette() function, and make it global.

Then in alloff(), add another for loop to clear the heat array:

for(int i = 0; i < NUM_LEDS; i++){
heat[i] = 0;
}

I was wondering if you changed
#define COOLING 55
to
uint8_t COOLING 55;
so you could animate it to a higher value when turning the flame Off, and then back down to your setting of 55 when turning the flame On how that might effect the look?

I would just zero out your heat array. You could put that as one extra for loop line in your alloff() function if you want

Or another cool way to do it, as @marmil kind of mentioned - instead of increasing your cooling, take your sparking to zero… that would be like extinguishing the fire from the bottom and the last flames will drift up and it will fade :slight_smile:

And anything you do that makes your heat[ ] array full of zeros will make it start back at frame zero, with the fire building from the bottom, the next time you go into the fire() function

I built a piece using Fire2012 with flames that rise up. I’m happy to share the code.

Zeroing out the heat array did the trick. Thanks guys! I’ll post my code in Code Samples when it’s finished.

Here is the central Flame class: pass a percentage from 0 to 100 to get less or more flames. Zero is off.

template<int NUM_LEDS, int LED_PIN>
class Flame
{
private:
CRGB leds[NUM_LEDS];
byte heat[NUM_LEDS];

public:
Flame()
{
for (int i = 0; i < NUM_LEDS; i++) {
heat[i] = 0;
leds[i] = CRGB::Black;
}
}

void init()
{
FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
}

void render(int percent)
{
// Fire2012 by Mark Kriegsman, July 2012
// as part of “Five Elements” shown here: http://youtu.be/knWiGsmgycY
//
// This basic one-dimensional ‘fire’ simulation works roughly as follows:
// There’s a underlying array of ‘heat’ cells, that model the temperature
// at each point along the line. Every cycle through the simulation,
// four steps are performed:
// 1) All cells cool down a little bit, losing heat to the air
// 2) The heat from each cell drifts ‘up’ and diffuses a little
// 3) Sometimes randomly new ‘sparks’ of heat are added at the bottom
// 4) The heat from each cell is rendered as a color into the leds array
// The heat-to-color mapping uses a black-body radiation approximation.
//
// Temperature is in arbitrary units from 0 (cold black) to 255 (white hot).

// COOLING: How much does the air cool as it rises?
// Less cooling = taller flames.  More cooling = shorter flames.
// Default 55, suggested range 20-100 
int cooling = 100 - ((percent * 2) / 3);

int cur_size = (NUM_LEDS * percent + 1) / 100;

// Step 1.  Cool down every cell a little
for( int i = 0; i < cur_size; i++) {
  heat[i] = qsub8( heat[i],  random8(0, ((cooling * 10) / cur_size) + 2));
}

// Step 2.  Heat from each cell drifts 'up' and diffuses a little
for( int k= cur_size - 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(100,150) );
}

// Step 4.  Map from heat cells to LED colors
for( int j = 0; j < cur_size; j++) {
  // Scale the heat value from 0-255 down to 0-240
  // for best results with color palettes.
  byte colorindex = scale8( heat[j], 170);
  CRGB color = ColorFromPalette( gPal, colorindex);
  leds[j] = color;
}

for (int j = cur_size; j < NUM_LEDS; j++) {
  leds[j] = CRGB::Black;
}

}
};

Also: you can instantiate the template as many times as you like (my piece had three separate flames):

Flame<FLAME_1_SIZE, FLAME_1_PIN> flame_1;

void setup()
{
flame_1.init();
}

void loop()
{
flame_1.render(percent);
…etc…
}

That’s cool @Sam_Guyer , thank you. Would you mind putting the code on http://gist.github.com ?

Here is the gist link:

Note that I am using a library I wrote called “Adel” that gives me a kind of concurrency for the button and sensors. I can share that code as well, if you like.

@Sam_Guyer Since I’m now curious what you mean by concurrency, yes, I would be interested. Thanks.

@marmil It is a library of C macros that give you a kind of cooperative concurrency – like coroutines. You can check it out here:

I’ve written a lot in the readme, and there are a bunch of examples.