--- /dev/null
+//neopixel flame effect from https://github.com/schnoggo/jack-o-candle
+//everything else, do as you wish at your own risk
+
+#include <Adafruit_NeoPixel.h>
+#ifdef __AVR__
+ #include <avr/power.h>
+#endif
+
+#define PIN 9
+#define PWM 10
+#define NUMBER_OF_FLAMES 7
+#define FLAME_WIDTH 2
+#define FLICKER_CHANCE 3
+
+int fade = 0;
+unsigned long ledstringtimer;
+unsigned long previousMillis = 0;
+
+Adafruit_NeoPixel strip = Adafruit_NeoPixel(14, PIN, NEO_GRB + NEO_KHZ800);
+
+uint32_t rez_range = 256*3;
+#define D_ false
+
+struct flame_element{
+ int brightness;
+ int step;
+ int max_brightness;
+ long rgb[3];
+ byte state;
+ } flames[NUMBER_OF_FLAMES];
+
+ int new_brightness = 0;
+ unsigned long rgb[3]; //reusable temporary array
+ uint8_t scaleD_rgb[3];
+ byte acc;
+
+ #define SCALERVAL 256*3
+ const int flamecolors[22][3] = {
+{ SCALERVAL, 0, 0},
+{ SCALERVAL, 0, 0},
+{ SCALERVAL, 0, 0},
+{ SCALERVAL, 0, 0},
+{ SCALERVAL, 0, 0},
+{ SCALERVAL, 0, 0},
+{ SCALERVAL, 0, 0},
+{ SCALERVAL, 0, 0},
+{ SCALERVAL, SCALERVAL*.4, },
+{ SCALERVAL, SCALERVAL*.4, 0},
+{ SCALERVAL, SCALERVAL*.4, 0},
+{ SCALERVAL, SCALERVAL*.4, 0},
+{ SCALERVAL, SCALERVAL*.3, 0},
+{ SCALERVAL, SCALERVAL*.3, 0},
+{ SCALERVAL, SCALERVAL*.3, 0},
+{ SCALERVAL, SCALERVAL*.3, 0},
+{ SCALERVAL, SCALERVAL*.3, 0},
+{ SCALERVAL, SCALERVAL*.3, 0},
+{ SCALERVAL, SCALERVAL*.3, },
+{ SCALERVAL, SCALERVAL*.3, SCALERVAL}, // white
+{ 0, SCALERVAL*.2, SCALERVAL}, // that one blue flame
+{ SCALERVAL, SCALERVAL*.3, SCALERVAL*.5}
+};
+
+void setup() {
+ Serial.begin(9600);
+ ledstringtimer = millis() + 5000;
+ strip.begin();
+ strip.show(); // Initialize all pixels to 'off'
+ randomSeed(analogRead(0));
+ InitFlames();
+}
+
+void loop() {
+ fire();
+ if (((signed long)(millis() - ledstringtimer)) > 0) {
+ ledstring();
+ ledstringtimer = millis() + 3000;
+ long dice = random(1000);
+ if (dice > 900) {
+ glowgreen();
+ } else if (dice<100) {
+ glowred();
+ }
+ }
+}
+
+void ledstring() {
+ fade=random(10, 255);
+ int fadeValue=0;
+ unsigned long currentMillis = millis();
+ while (fadeValue <= fade) {
+ currentMillis = millis();
+ if (currentMillis - previousMillis >= 30) {
+ previousMillis = currentMillis;
+ fadeValue += 5;
+ analogWrite(PWM, fadeValue);
+ }
+ fire();
+ }
+ while (fadeValue > 0) {
+ currentMillis = millis();
+ if (currentMillis - previousMillis >= 30) {
+ previousMillis = currentMillis;
+ fadeValue -= 5;
+ analogWrite(PWM, fadeValue);
+ }
+ fire();
+ }
+}
+
+void glowgreen() {
+ for(uint16_t t=0; t<255; t++) {
+ for (uint16_t i=0; i<strip.numPixels(); i++) {
+ strip.setPixelColor(i, strip.Color(0, t, 0));
+ }
+ strip.show();
+ delay(10);
+ }
+ for(uint16_t t=255; t>0; t--) {
+ for (uint16_t i=0; i<strip.numPixels(); i++) {
+ strip.setPixelColor(i, strip.Color(0, t, 0));
+ }
+ strip.show();
+ delay(10);
+ }
+}
+
+void glowred() {
+ for(uint16_t t=0; t<255; t++) {
+ for (uint16_t i=0; i<strip.numPixels(); i++) {
+ strip.setPixelColor(i, strip.Color(t, 0, 0));
+ }
+ strip.show();
+ delay(10);
+ }
+ for(uint16_t t=255; t>0; t--) {
+ for (uint16_t i=0; i<strip.numPixels(); i++) {
+ strip.setPixelColor(i, strip.Color(t, 0, 0));
+ }
+ strip.show();
+ delay(10);
+ }
+}
+
+void fire() {
+ for(byte flame_count=0; flame_count<NUMBER_OF_FLAMES; flame_count++) {
+ switch(flames[flame_count].state){
+ case 0: // reset
+ CreateNewFlame(flame_count);
+ break;
+
+ case 1: //increasing
+ new_brightness = flames[flame_count].brightness + flames[flame_count].step;
+ if (new_brightness > flames[flame_count].max_brightness){
+ UpdateFlameColor(flame_count, flames[flame_count].max_brightness);
+ flames[flame_count].brightness = flames[flame_count].max_brightness;
+ flames[flame_count].step = GetStepSize(); // pick a different speed for flame going out
+ flames[flame_count].state = 2;
+ } else {
+ UpdateFlameColor(flame_count, new_brightness);
+ flames[flame_count].brightness = new_brightness;
+ }
+
+ break;
+
+ case 2: //decreasing
+ new_brightness = flames[flame_count].brightness - flames[flame_count].step;
+ // chance to flicker/rekindle:
+ if (random(new_brightness) < FLICKER_CHANCE){
+ // rekindle:
+ flames[flame_count].state = 1; //increase again
+ flames[flame_count].brightness = max(GetMaxBrightness(), flames[flame_count].brightness);
+ flames[flame_count].step = GetStepSize();
+ } else {
+ if (new_brightness <1){
+ flames[flame_count].state = 0; // bottomed out - reset to next flame
+ flames[flame_count].brightness = 0;
+ UpdateFlameColor(flame_count, 0);
+ } else {
+ UpdateFlameColor(flame_count, new_brightness);
+ flames[flame_count].brightness = new_brightness;
+ }
+ }
+ break;
+ }
+ }
+ strip.show();
+}
+
+void InitFlames(){
+ for(byte i=0; i<NUMBER_OF_FLAMES; i++) {
+ flames[i].state=0;
+ }
+}
+
+void UpdateFlameColor(byte flame_num, int new_brightness){
+ uint32_t c = 0;
+ uint32_t color_channel_value;
+ byte rgb_channel;
+
+ new_brightness = min(new_brightness, flames[flame_num].max_brightness);
+
+ for(byte rgb_channel=0; rgb_channel<3; rgb_channel++) {
+ color_channel_value = flames[flame_num].rgb[rgb_channel];
+ color_channel_value = color_channel_value * (uint32_t)new_brightness; // keep it long
+ color_channel_value = color_channel_value/(uint32_t)rez_range;
+ rgb[rgb_channel] = max(0L,color_channel_value);
+ } // step through R G B
+
+ // spread possible values of 0 -768 across 3 pixels
+ for(byte sub_pixel=0; sub_pixel<FLAME_WIDTH; sub_pixel++) {
+ for(byte i=0; i<3; i++) { // rgb
+ acc = rgb[i]/3;
+ byte d = rgb[i]%3;
+ if (sub_pixel < d){
+ acc++;
+ }
+ scaleD_rgb[i] = acc;
+ }
+ c = strip.Color(scaleD_rgb[0],scaleD_rgb[1], scaleD_rgb[2]);
+ strip.setPixelColor(flame_num * FLAME_WIDTH + sub_pixel, c);
+ }
+}
+
+void CreateNewFlame(byte flame_num){
+ flames[flame_num].step = GetStepSize();
+ flames[flame_num].max_brightness = GetMaxBrightness();
+ flames[flame_num].brightness = 0;
+ flames[flame_num].state = 1;
+ byte color_index = random(22);
+ for(byte i=0; i<3; i++) {
+ flames[flame_num].rgb[i] = flamecolors[color_index][i];
+ }
+}
+
+int GetStepSize(){
+ return random(70)+1;
+}
+
+int GetMaxBrightness(){
+ int retVal;
+ retVal = random(rez_range/2) + rez_range/2;
+ return retVal;
+}