3D file added
[halloween.git] / box.ino
1 //neopixel flame effect from https://github.com/schnoggo/jack-o-candle
2 //everything else, do as you wish at your own risk
3
4 #include <Adafruit_NeoPixel.h>
5 #ifdef __AVR__
6   #include <avr/power.h>
7 #endif
8
9 #define PIN 9
10 #define PWM 10
11 #define NUMBER_OF_FLAMES 7
12 #define FLAME_WIDTH 2
13 #define FLICKER_CHANCE 3
14
15 int fade = 0;
16 unsigned long ledstringtimer;
17 unsigned long previousMillis = 0;
18
19 Adafruit_NeoPixel strip = Adafruit_NeoPixel(14, PIN, NEO_GRB + NEO_KHZ800);
20
21 uint32_t rez_range = 256*3;
22 #define D_ false
23
24 struct flame_element{
25   int brightness;
26   int step;
27   int max_brightness;
28   long rgb[3];
29   byte state;
30   } flames[NUMBER_OF_FLAMES];
31   
32   int new_brightness = 0;
33   unsigned long rgb[3]; //reusable temporary array
34   uint8_t scaleD_rgb[3];
35   byte acc;
36  
37  #define SCALERVAL 256*3
38  const int flamecolors[22][3] = {
39 { SCALERVAL, 0,  0},
40 { SCALERVAL, 0,  0},
41 { SCALERVAL, 0,  0},
42 { SCALERVAL, 0,  0},
43 { SCALERVAL, 0,  0},
44 { SCALERVAL, 0,  0},
45 { SCALERVAL, 0,  0},
46 { SCALERVAL, 0,  0},
47 { SCALERVAL, SCALERVAL*.4,  },
48 { SCALERVAL, SCALERVAL*.4,  0},
49 { SCALERVAL, SCALERVAL*.4,  0},
50 { SCALERVAL, SCALERVAL*.4,  0},
51 { SCALERVAL, SCALERVAL*.3,  0},
52 { SCALERVAL, SCALERVAL*.3,  0},
53 { SCALERVAL, SCALERVAL*.3,  0},
54 { SCALERVAL, SCALERVAL*.3,  0},
55 { SCALERVAL, SCALERVAL*.3,  0},
56 { SCALERVAL, SCALERVAL*.3,  0},
57 { SCALERVAL, SCALERVAL*.3,  },
58 { SCALERVAL, SCALERVAL*.3,  SCALERVAL}, // white
59 { 0, SCALERVAL*.2,  SCALERVAL}, // that one blue flame
60 { SCALERVAL,  SCALERVAL*.3,  SCALERVAL*.5}
61 };
62
63 void setup() {
64   Serial.begin(9600);
65   ledstringtimer = millis() + 5000;
66   strip.begin();
67   strip.show(); // Initialize all pixels to 'off'
68   randomSeed(analogRead(0));
69   InitFlames();
70 }
71
72 void loop() {
73   fire();
74   if (((signed long)(millis() - ledstringtimer)) > 0) {
75     ledstring();
76     ledstringtimer = millis() + 3000;
77     long dice = random(1000);
78     if (dice > 900) {
79       glowgreen();
80     } else if (dice<100) {
81       glowred();
82     }
83   }
84 }
85
86 void ledstring() {
87   fade=random(10, 255);
88   int fadeValue=0;
89   unsigned long currentMillis = millis();
90   while (fadeValue <= fade) {
91     currentMillis = millis();
92     if (currentMillis - previousMillis >= 30) {
93       previousMillis = currentMillis;
94       fadeValue += 5;
95       analogWrite(PWM, fadeValue);
96     }
97     fire();
98   }
99   while (fadeValue > 0) {
100     currentMillis = millis();
101     if (currentMillis - previousMillis >= 30) {
102       previousMillis = currentMillis;
103       fadeValue -= 5;
104       analogWrite(PWM, fadeValue);
105     }
106     fire();
107   }
108 }
109
110 void glowgreen() {
111   for(uint16_t t=0; t<255; t++) {
112     for (uint16_t i=0; i<strip.numPixels(); i++) {
113       strip.setPixelColor(i, strip.Color(0, t, 0));
114     }
115     strip.show();
116     delay(10);
117   }
118   for(uint16_t t=255; t>0; t--) {
119     for (uint16_t i=0; i<strip.numPixels(); i++) {
120       strip.setPixelColor(i, strip.Color(0, t, 0));
121     }
122     strip.show();
123     delay(10);
124   }
125 }
126
127 void glowred() {
128   for(uint16_t t=0; t<255; t++) {
129     for (uint16_t i=0; i<strip.numPixels(); i++) {
130       strip.setPixelColor(i, strip.Color(t, 0, 0));
131     }
132     strip.show();
133     delay(10);
134   }
135   for(uint16_t t=255; t>0; t--) {
136     for (uint16_t i=0; i<strip.numPixels(); i++) {
137       strip.setPixelColor(i, strip.Color(t, 0, 0));
138     }
139     strip.show();
140     delay(10);
141   }
142 }
143
144 void fire() {
145   for(byte flame_count=0; flame_count<NUMBER_OF_FLAMES; flame_count++) {
146     switch(flames[flame_count].state){
147       case 0: // reset
148         CreateNewFlame(flame_count);
149       break;
150       
151       case 1: //increasing
152         new_brightness = flames[flame_count].brightness + flames[flame_count].step;
153         if (new_brightness > flames[flame_count].max_brightness){
154           UpdateFlameColor(flame_count, flames[flame_count].max_brightness);
155           flames[flame_count].brightness = flames[flame_count].max_brightness;
156           flames[flame_count].step = GetStepSize(); // pick a different speed for flame going out
157           flames[flame_count].state = 2;
158         } else {
159           UpdateFlameColor(flame_count, new_brightness);
160           flames[flame_count].brightness = new_brightness;
161         }
162
163       break;
164       
165       case 2: //decreasing
166         new_brightness = flames[flame_count].brightness - flames[flame_count].step;
167         // chance to flicker/rekindle:
168         if (random(new_brightness) < FLICKER_CHANCE){
169           // rekindle:
170           flames[flame_count].state = 1; //increase again
171           flames[flame_count].brightness = max(GetMaxBrightness(), flames[flame_count].brightness);
172           flames[flame_count].step = GetStepSize();    
173         } else {
174           if (new_brightness <1){
175             flames[flame_count].state = 0; // bottomed out - reset to next flame
176             flames[flame_count].brightness = 0;
177              UpdateFlameColor(flame_count, 0);
178           } else {
179             UpdateFlameColor(flame_count, new_brightness);
180              flames[flame_count].brightness = new_brightness;
181           }
182         }
183       break;
184     }
185   }
186    strip.show();
187 }
188
189 void InitFlames(){
190   for(byte i=0; i<NUMBER_OF_FLAMES; i++) {
191     flames[i].state=0;    
192   }
193 }
194
195 void UpdateFlameColor(byte flame_num, int new_brightness){
196   uint32_t c = 0;
197   uint32_t color_channel_value;
198   byte rgb_channel;
199   
200   new_brightness = min(new_brightness, flames[flame_num].max_brightness);
201   
202   for(byte rgb_channel=0; rgb_channel<3; rgb_channel++) {
203     color_channel_value = flames[flame_num].rgb[rgb_channel];
204     color_channel_value = color_channel_value * (uint32_t)new_brightness; // keep it long
205     color_channel_value = color_channel_value/(uint32_t)rez_range;
206     rgb[rgb_channel] = max(0L,color_channel_value);
207   } // step through R G B
208
209   // spread possible values of 0 -768 across 3 pixels
210   for(byte sub_pixel=0; sub_pixel<FLAME_WIDTH; sub_pixel++) {
211     for(byte i=0; i<3; i++) { // rgb
212       acc = rgb[i]/3;
213       byte d = rgb[i]%3;
214       if (sub_pixel < d){
215         acc++;
216       }
217       scaleD_rgb[i] = acc;
218     }
219     c = strip.Color(scaleD_rgb[0],scaleD_rgb[1], scaleD_rgb[2]);
220     strip.setPixelColor(flame_num * FLAME_WIDTH + sub_pixel, c);
221   } 
222 }
223
224 void CreateNewFlame(byte flame_num){
225   flames[flame_num].step = GetStepSize();
226   flames[flame_num].max_brightness = GetMaxBrightness();
227   flames[flame_num].brightness = 0;
228   flames[flame_num].state = 1;
229   byte color_index = random(22);
230   for(byte i=0; i<3; i++) {
231     flames[flame_num].rgb[i] = flamecolors[color_index][i];
232   } 
233 }
234
235 int GetStepSize(){
236    return random(70)+1;
237 }
238
239 int GetMaxBrightness(){
240   int retVal;
241   retVal = random(rez_range/2) +  rez_range/2;
242   return retVal;
243 }