ElectroPeak
Published © GPL3+

Play with Fire Over Wi-Fi (ESP8266, NeoPixels & Android App)

Create a cool fire simulation effect with Wi-Fi wireless control. An Android app is also ready to play with your creation!

IntermediateFull instructions provided5 hours15,655

Things used in this project

Hardware components

ElectroPeak ESP8266 Serial WIFI Witty Cloud Board
×1
Neopixels Smart LED Strip (60LED/m strip)
×3
ElectroPeak Logic Level Converter
×1
ElectroPeak 21cm 40P Male To Female Jumper Wire
×1
PVC pipe 60cm size 2”
×1
Tracing paper
×1
Glass cylinder
×1
5V power supply (at least 9A)
×1
Arduino Nano R3
Arduino Nano R3
×1

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

Hot glue gun (generic)
Hot glue gun (generic)
Soldering iron (generic)
Soldering iron (generic)

Story

Read more

Custom parts and enclosures

EP's Flame Android App

Code

Fire Effect Code

Arduino
#include 
#include 
#include "FastLED.h"
#include "EEPROM.h"
#include "FS.h"  //required for SPIFFS

#define DATA_PIN 5
#define LED_TYPE WS2811
#define COLOR_ORDER GRB
#define NUM_LEDS 30
#define NUM_STRIPS 6
#define CHIPSET     WS2812B

//addresses to save data to EEPROM to preserve the state of fire simulation
#define cs0Adr 0
#define cs1Adr 3
#define cs2Adr 6
#define cs3Adr 9
#define BriAdr 15
#define FpsAdr 16
#define SparkingAdr 17
#define CoolingAdr 18
#define EEPROMCheckAdr 20 //if this value is 250 we assume we have previously saved to EEPROM and load data from that

CRGB leds[NUM_STRIPS * NUM_LEDS];

String inData;
uint8_t FPS = 100; //FRAMES_PER_SECOND
uint8_t SPARKING = 150;
uint8_t COOLING = 90; 
uint8_t BRIGHTNESS = 100;
uint8_t csRGB[4][3] = {{0, 0, 0},
                       {255, 0, 0},
                       {255, 127, 0},
                       {255, 255, 255}};

unsigned long previousMillis = 0;
bool change = false;            //if true we go to save to EEprom.
unsigned long changeMillis = 0; //changes will be saved 1 minute after no change is applied to avoid EEPROM wear.

bool initSetup = true;


CRGBPalette16 gPal;

ESP8266WebServer server(80); //Web server object. Will be listening in port 80 (default for HTTP)

void setup()
{
  EEPROM.begin(200);
  cWiFi();
  setupFastLED();
  loadConfig();
  gPal = CRGBPalette16( CRGB(csRGB[0][0],csRGB[0][1],csRGB[0][2]), 
                        CRGB(csRGB[1][0],csRGB[1][1],csRGB[1][2]), 
                        CRGB(csRGB[2][0],csRGB[2][1],csRGB[2][2]),  
                        CRGB(csRGB[3][0],csRGB[3][1],csRGB[3][2]));
                                           
}

inline void setupFastLED()
{
  delay(1000); // sanity delay
  FastLED.addLeds<CHIPSET, DATA_PIN, COLOR_ORDER>(leds, NUM_STRIPS * NUM_LEDS).setCorrection(TypicalLEDStrip);
  FastLED.setBrightness(BRIGHTNESS);
}

void loop()
{

  server.handleClient(); //Handling of incoming requests
  if (change)
  {
    if (millis() - changeMillis > 60000)
    {
      change = false;
      saveToEEPROM();
    }
  }
  fire();
  FastLED.show();
  FastLED.delay(1000 / FPS);
}


void Fire2012WithPalette(int stripNo)
{
  static byte heat[NUM_STRIPS][NUM_LEDS];

  // Step 1.  Cool down every cell a little
    for( int i = 0; i < NUM_LEDS; i++) { heat[stripNo][i] = qsub8( heat[stripNo][i], random8(0, ((COOLING * 10) / NUM_LEDS) + 2)); } // Step 2. Heat from each cell drifts 'up' and diffuses a little for( int k= NUM_LEDS - 1; k >= 2; k--) {
      heat[stripNo][k] = (heat[stripNo][k - 1] + heat[stripNo][k - 2] + heat[stripNo][k - 2] ) / 3;
    }
    
    // Step 3.  Randomly ignite new 'sparks' of heat near the bottom
    if( random8() < SPARKING ) {
      int y = random8(5);
      heat[stripNo][y] = qadd8( heat[stripNo][y], random8(160,200) );
    }

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

void fire(){
  for (int i=0; i<NUM_STRIPS; i++){ Fire2012WithPalette(i); } } int str2int(String InputStr) { return InputStr.toInt(); } boolean EveryNSec(uint8_t period) { unsigned long currentMillis = millis(); if (currentMillis - previousMillis >= period * 1000)
  {
    // save the last time you blinked the LED
    previousMillis = currentMillis;
    return true;
  }
  else
  {
    return false;
  }
}

void EEPROMupdate(byte address, byte value)
{
  if (EEPROM.read(address) != value)
  {
    EEPROM.write(address, value);
    EEPROM.commit();
  }
  return;
}

void saveToEEPROM()
{
  EEPROMupdate(BriAdr, BRIGHTNESS);
  EEPROMupdate(FpsAdr, FPS);
  EEPROMupdate(SparkingAdr, SPARKING);
  EEPROMupdate(CoolingAdr, COOLING);
  for (uint8_t i = 0; i < 4; i++)
  {
    for (uint8_t j = 0; j < 3; j++)
    {
      EEPROMupdate((i * 3 + j), csRGB[i][j]);
    }
  }
}

void handleCS0Change(){
    csRGB[0][0] = str2int(server.arg("R"));
    csRGB[0][1] = str2int(server.arg("G"));
    csRGB[0][2] = str2int(server.arg("B"));
    gPal = CRGBPalette16( CRGB(csRGB[0][0],csRGB[0][1],csRGB[0][2]), CRGB(csRGB[1][0],csRGB[1][1],csRGB[1][2]), CRGB(csRGB[2][0],csRGB[2][1],csRGB[2][2]),  CRGB(csRGB[3][0],csRGB[3][1],csRGB[3][2]));
    changeMillis = millis();
    change = true;
}
void handleCS1Change(){
    csRGB[1][0] = str2int(server.arg("R"));
    csRGB[1][1] = str2int(server.arg("G"));
    csRGB[1][2] = str2int(server.arg("B"));
    gPal = CRGBPalette16( CRGB(csRGB[0][0],csRGB[0][1],csRGB[0][2]), CRGB(csRGB[1][0],csRGB[1][1],csRGB[1][2]), CRGB(csRGB[2][0],csRGB[2][1],csRGB[2][2]),  CRGB(csRGB[3][0],csRGB[3][1],csRGB[3][2]));
    changeMillis = millis();
    change = true;
}
void handleCS2Change(){
    csRGB[2][0] = str2int(server.arg("R"));
    csRGB[2][1] = str2int(server.arg("G"));
    csRGB[2][2] = str2int(server.arg("B"));
    gPal = CRGBPalette16( CRGB(csRGB[0][0],csRGB[0][1],csRGB[0][2]), CRGB(csRGB[1][0],csRGB[1][1],csRGB[1][2]), CRGB(csRGB[2][0],csRGB[2][1],csRGB[2][2]),  CRGB(csRGB[3][0],csRGB[3][1],csRGB[3][2]));
    changeMillis = millis();
    change = true;
}
void handleCS3Change(){
    csRGB[3][0] = str2int(server.arg("R"));
    csRGB[3][1] = str2int(server.arg("G"));
    csRGB[3][2] = str2int(server.arg("B"));
    gPal = CRGBPalette16( CRGB(csRGB[0][0],csRGB[0][1],csRGB[0][2]), CRGB(csRGB[1][0],csRGB[1][1],csRGB[1][2]), CRGB(csRGB[2][0],csRGB[2][1],csRGB[2][2]),  CRGB(csRGB[3][0],csRGB[3][1],csRGB[3][2]));
    changeMillis = millis();
    change = true;
}

void handleConf()
{
  if (server.arg("brightness") != "")
  {
    BRIGHTNESS = str2int(server.arg("brightness"));
    FastLED.setBrightness(BRIGHTNESS);
    changeMillis = millis();
    change = true;
  }
  if (server.arg("fps") != "")
  {
    FPS = str2int(server.arg("fps"));
    changeMillis = millis();
    change = true;
  }
  if (server.arg("sparking") != "")
  {
    SPARKING = str2int(server.arg("sparking"));
    changeMillis = millis();
    change = true;
  }
  if (server.arg("cooling") != "")
  {
    COOLING = str2int(server.arg("cooling"));
    changeMillis = millis();
    change = true;
  }
  
  server.sendHeader("Connection", "close");
  server.sendHeader("Access-Control-Allow-Origin", "*");
  server.send(200, "text/plain", ""); //Returns the HTTP response
}

void loadConfig()
{

  if (EEPROM.read(EEPROMCheckAdr) == 250)
  {
    BRIGHTNESS = EEPROM.read(BriAdr);
    SPARKING = EEPROM.read(SparkingAdr);
    COOLING = EEPROM.read(CoolingAdr);
    FPS = EEPROM.read(FpsAdr);
    if (FPS == 0)
      FPS = 100;

    for (uint8_t i = 0; i < 4; i++)
    {
      for (uint8_t j = 0; j < 3; j++)
      {
        csRGB[i][j] = EEPROM.read(i * 3 + j);
      }
    }
  }else{
    EEPROMupdate(BriAdr,BRIGHTNESS);
    EEPROMupdate(FpsAdr,FPS);
    EEPROMupdate(CoolingAdr,COOLING);
    EEPROMupdate(SparkingAdr, SPARKING);
    for (uint8_t i = 0; i < 4; i++)
    {
      for (uint8_t j = 0; j < 3; j++)
      {
        EEPROMupdate((i*3+j) , csRGB[i][j]);
      }
    }
    EEPROMupdate(EEPROMCheckAdr, 250);
  }
}

void cWiFi()
{
  WiFi.softAP("ElectroPeak's Flame", ""); //set a password here if you want i.e. WiFi.softAP("ElectroPeak's Flame", "12345678");

  IPAddress myIP = WiFi.softAPIP();
  server.on("/cs0", handleCS0Change);
  server.on("/cs1", handleCS1Change);
  server.on("/cs2", handleCS2Change);
  server.on("/cs3", handleCS3Change);
  server.on("/conf", handleConf);
  server.serveStatic("/", SPIFFS, "/", "max-age=86400");
  server.begin(); //Start the server
}

Sketch and Data folder

Arduino
This zip file contains both the sketch file and the data folder (SPIFFS upload)
No preview (download only).

Credits

ElectroPeak

ElectroPeak

57 projects • 731 followers
At ElectroPeak we want to teach you to enjoy electronics more. We offer Top-notch guides and worry-free shopping experience.

Comments