 /*
  * Description: Motion activated stair lights.
  * Author: Dean Montgomery
- * Version: 0.1 (Alpha)
+ * Version: 0.2 (Beta)
+ * 
+ * 2 PIR sesors at the top and bottom of the stairs.
+ * WS28012B Addressable RGB lights - 2 LEDs on each stair - This spread out the strip of 30 and left 2-pairs for spare bulbs.
+ * My Arduino is at the top of the stairs and the RGB strip is connected at the top.
+ * This will cycle through several varitions of stair walkers.
+ * 
 */
 
 #include "FastLED.h"
-/*
+
+#define NUM_LEDS 26
+#define LEDS_PER_STAIR 2        // Number of Leds per stair.  Not yet currenlty changable - just noteable
+#define BRIGHTNESS  120         // 0...255  ( used in fade7 )
+#define PIN_LED 3               // LED Data pin
+#define PIN_PIR_DOWN 5          // PIR Downstairs Pin
+#define PIN_PIR_UP 7            // PIR Upstairs Pin
+#define GO_UP -1                // Direction control - Arduino at top of stairs
+#define GO_DOWN 1               // Direction control - Arduino at top of stairs
+int8_t  lightsOn = LOW;         // track lights on/off
+uint8_t gHue = 0;               // track color shifts.
+int8_t  gStair = 0;             // track curent stair.
+uint8_t gBright = 0;            // track brightness
+uint8_t gUpDown[NUM_LEDS];      // directional array to walk/loop up or down stairs.
+CRGB    leds[NUM_LEDS];         // setup leds object to access the string
+CRGBPalette16 gPalette;         // some favorite and random colors for display.
+int8_t  gLastPalette = 15;      // track last chosen palette.
+uint8_t gLastWalk = 1;
+
+void setup() {
+  delay (3000); // Power Up 3 second safety delay.
+  //Serial.begin(9600);
+  FastLED.addLeds<WS2812B, PIN_LED, GRB>(leds, NUM_LEDS);  // NOTE set LED string type here.
+  pinMode(PIN_PIR_DOWN, INPUT);
+  pinMode(PIN_PIR_UP, INPUT);
+  digitalWrite(PIN_PIR_DOWN, LOW);
+  digitalWrite(PIN_PIR_UP, LOW);
+  welcomeRainbow();             // rainbow - give time for PIR sensors to colibrate.
+  setUpDown(GO_DOWN);           // populate the array index used for stair direction.
+  setPalette();                 // setup some favorite & random colors
+}
+
+// Main Loop track PIR sensors.
+void loop() {
+  // Walk Down.
+  if ( digitalRead(PIN_PIR_UP) == HIGH ){
+    if ( lightsOn == LOW ) {
+      lightsOn = HIGH;
+      setUpDown(GO_DOWN);
+      walker();
+      delay(50);
+    }
+  }
+  // Walk Up.
+  if ( digitalRead(PIN_PIR_DOWN) == HIGH  ){
+    if ( lightsOn == LOW ) {
+      lightsOn = HIGH;
+      setUpDown(GO_UP);
+      walker();
+      delay(50);
+    }
+  }
+}
+
+// Cycle through stair walkers.
+void walker(){
+  switch (gLastWalk % 3) {
+    case 0:
+      fade7();
+      break;
+    case 1:
+      flicker();
+      break;
+    default:
+      walk();
+  }
+  if (gLastWalk >= 50){
+    gLastWalk = 0;
+  }else{
+    gLastWalk++;
+  }
+}
+
+void setUpDown(int8_t upDownDir){
+  // setup walking gUpDown array in forward: 0,1,2,3... or reverse:  ...3,2,1,0
+  uint8_t gStairStart = 0;
+  if (upDownDir == GO_UP){
+    for ( gStair = NUM_LEDS -1; gStair >= 0; gStair-- ){
+      gUpDown[gStair] = gStairStart++;
+    }
+  } else {
+    for ( gStair = 0; gStair <= NUM_LEDS; gStair++ ){
+      gUpDown[gStair] = gStairStart++;
+    }  
+  }
+}
+
+void welcomeRainbow(){
+  // Sparkle rainbow welcome give delay to calibrate pir sensors.  This also indicates if program crashed.
+  for ( int i = 0; i < 500; i++ ){
+    rainbowWithGlitter();
+    FastLED.show();
+    FastLED.delay(8.3);
+    EVERY_N_MILLISECONDS( 20 ) { gHue++; }
+  }
+  for (int tick=0; tick < 64; tick++){ 
+    for ( uint8_t i = 0; i < NUM_LEDS; i++ ){
+      leds[i].fadeToBlackBy( 64 );
+      FastLED.show();
+      FastLED.delay(1);
+    }
+  }
+}
+
+void walkold() {
+  static uint8_t hueStart = 208; //purple;
+  static uint8_t hueEnd = 160;
+  static uint8_t hueShift = 0;
+  static uint8_t brightTop = 200;
+  static int i = 0;
+  
+  for(gStair=0; gStair < NUM_LEDS; gStair+=2) {
+    // Fade in step
+    hueShift = hueStart;
+    for (gBright=0; gBright<=brightTop; gBright+=2) {
+      leds[gUpDown[gStair]] = CHSV( hueStart, 204, gBright );  // purple
+      leds[gUpDown[gStair + 1]] = CHSV( hueStart, 204, gBright );  // purple
+      if (  gStair >= 2 ) { // slide hue from pruple to blue on previous stair
+        //hueShift = hueShift + ((hueEnd-hueStart)/brightTop*gBright); //=D1+((160-240)/200*10)
+        if ( hueShift >= hueEnd ) {
+          hueShift--;
+          leds[gUpDown[gStair - 1]] = CHSV( hueShift, 204, 200 );
+          leds[gUpDown[gStair - 2]] = CHSV( hueShift, 204, 200 );
+        }
+      }
+      FastLED.show();
+      //FastLED.delay(1); 
+    }
+  }
+  
+  // Hue shift the last two stairs
+  hueShift = hueStart;
+  for (gBright=0; gBright<=brightTop; gBright+=2) {
+    if ( hueShift >= hueEnd )
+    //hueShift = 1/(hueShift + ((hueEnd-hueStart)/brightTop*bright));
+    hueShift--;
+    leds[gUpDown[NUM_LEDS - 1]] = CHSV( hueShift, 204, 200 );
+    leds[gUpDown[NUM_LEDS - 2]] = CHSV( hueShift, 204, 200 );
+    FastLED.show();
+    //FastLED.delay(1); 
+  }
+  //Flash
+  FastLED.delay(500); 
+  for(gStair=0; gStair < NUM_LEDS; gStair+=2) {
+    leds[gUpDown[gStair]] = CRGB( 100, 100, 100);
+    leds[gUpDown[gStair + 1]] = CRGB( 100, 100, 100);
+    FastLED.show();
+  }
+  for(gStair=0; gStair < NUM_LEDS; gStair+=2) {
+    leds[gUpDown[gStair]] = CHSV( hueEnd, 204, 200 );
+    leds[gUpDown[gStair+1]] = CHSV( hueEnd, 204, 200 );
+    FastLED.show();
+  }
+  
+  
+  // Stay on for a bit
+  fill_solid(leds, NUM_LEDS, CHSV( hueEnd, 204, 200 ));
+  //addGlitter(70);
+  FastLED.show();
+  FastLED.delay(5000);
+  
+  // Turn off steps
+  for(gStair=0; gStair < NUM_LEDS; gStair+=2) {
+    // Fade in step
+    //hueShift = hueStart;
+    for (gBright=200; gBright>=1; gBright--) { 
+      leds[gUpDown[gStair]] = CHSV(hueEnd, 204, gBright);
+      leds[gUpDown[gStair + 1]] = CHSV(hueEnd, 204, gBright);
+      FastLED.show();
+      FastLED.delay(1); 
+    }
+    leds[gUpDown[gStair]].setHSV( 0, 0, 0);
+    leds[gUpDown[gStair + 1]].setHSV( 0, 0, 0);
+    FastLED.show();
+  }
+  lightsOn = LOW;  
+}
+
+// Increment to the next color pair in the palette.
+void choosePalette(){
+  if ( gLastPalette >= 15 ) {
+    gLastPalette = 0;
+  } else {
+    gLastPalette+=2;
+  }
+}
+
+// Fill a palette with some colors that my wife picked.
+void setPalette(){
+  /*
  * Jenn's colors RGB  0 0 81  BLUE
  * 0 100 100 Teal 006464
  * 60 100 100 Cool White 3C6464

 * teal to blue
 * red to blue
 */
#define NUM_LEDS 26
#define LEDS_PER_STAIR 2        // Number of Leds per stair.
#define BRIGHTNESS  120         // 0...255  ( needed ?)
#define UPDATES_PER_SECOND 100
#define PIN_LED 3               // LED Data pin
#define PIN_PIR_DOWN 5          // PIR Downstairs Pin
#define PIN_PIR_UP 7            // PIR Upstairs Pin
#define STEP_DELAY 200          //ms = 1/5th second. ( needed ?)
#define GO_UP -1                // Direction control - Arduino at top of stairs
#define GO_DOWN 1               // Direction control - Arduino at top of stairs
int8_t lightsOn = LOW;          // track lights on/off
uint8_t gHue = 0;
int8_t gStair = 0;
uint8_t gBright = 0;
int8_t gStairStart = 0;
int8_t gStairEnd = 0;
uint8_t gUpDown[NUM_LEDS];      // directional array to walk/loop up or down stairs.
  
CRGB leds[NUM_LEDS];




void setup() {
  delay (3000); // Power Up 3 second safety delay.
  Serial.begin(9600);
  FastLED.addLeds<WS2812B, PIN_LED, GRB>(leds, NUM_LEDS);
  //FastLED.setBrightness(BRIGHTNESS);
  //Serial.print("calibrating sensor ");
  pinMode(PIN_PIR_DOWN, INPUT);
  pinMode(PIN_PIR_UP, INPUT);
  digitalWrite(PIN_PIR_DOWN, LOW);
  digitalWrite(PIN_PIR_UP, LOW);
  Serial.println(" done");
  welcomeRainbow();  // rainbow - give time for PIR sensors.
  setUpDown(GO_DOWN);
  Serial.println("SENSOR ACTIVE");
}

// Main Loop track PIR sensors.
void loop() {
  // Walk Down.
  if ( digitalRead(PIN_PIR_UP) == HIGH ){
    if ( lightsOn == LOW ) {
      lightsOn = HIGH;
      setUpDown(GO_DOWN);
      // TODO: Add random pattern picker.
      fade7();
      //walk(1);
      //flicker(1);
      delay(50);
    }
  }
  // Walk Up.
  if ( digitalRead(PIN_PIR_DOWN) == HIGH  ){
    if ( lightsOn == LOW ) {
      lightsOn = HIGH;
      setUpDown(GO_UP);
      fade7(); //Up
      //walk(-1); // Up
      //flicker(-1);
      delay(50);
    }
  }
}

void setUpDown(int8_t upDownDir){
  // setup walking gUpDown array in forward: 0,1,2,3... or reverse:  ...3,2,1,0
  gStairStart = 0;
  if (upDownDir == GO_UP){
    for ( gStair = NUM_LEDS -1; gStair >= 0; gStair-- ){
      gUpDown[gStair] = gStairStart++;
    }
  } else {
    for ( gStair = 0; gStair <= NUM_LEDS; gStair++ ){
      gUpDown[gStair] = gStairStart++;
    }  
  }
  //printUpDown();
}

void printUpDown(){
  for (gStair = 0; gStair < NUM_LEDS; gStair++){
    Serial.print (gStair);
    Serial.print (" " );
    Serial.println (gUpDown[gStair]);
  }
}

void welcomeRainbow(){
  // Sparkle rainbow welcome give delay to calibrate pir sensors.  This also indicates if program crashed.
  for ( int i = 0; i < 500; i++ ){
    rainbowWithGlitter();
    FastLED.show();
    FastLED.delay(8.3);
    EVERY_N_MILLISECONDS( 20 ) { gHue++; }
  }
  for (int tick=0; tick < 64; tick++){ 
    for ( uint8_t i = 0; i < NUM_LEDS; i++ ){
      leds[i].fadeToBlackBy( 64 );
      FastLED.show();
      FastLED.delay(1);
    }
  }
}



void walk(int8_t dir) {
  Serial.print("Walk dir: ");
  Serial.println(dir);
  static uint8_t hueStart = 208; //purple;
  static uint8_t hueEnd = 160;
  static uint8_t hueShift = 0;
  static uint8_t brightTop = 200;
  static int i = 0;
  setStartEnd(dir);
  
  for(gStair=gStairStart; (dir == 1 && gStair < gStairEnd ) || (dir == -1 && gStair >= gStairEnd && gStair <= gStairStart+1 ); gStair+=(2*dir)) {
    // Fade in step
    hueShift = hueStart;
    for (gBright=0; gBright<=brightTop; gBright+=2) {
      leds[gStair] = CHSV( hueStart, 204, gBright );  // purple
      leds[gStair + 1*dir] = CHSV( hueStart, 204, gBright );  // purple
      if (  (dir == 1 && gStair >= 2) || (dir == -1 && gStair <= (gStairStart-2)) ) { // slide hue from pruple to blue on previous stair
        //hueShift = hueShift + ((hueEnd-hueStart)/brightTop*gBright); //=D1+((160-240)/200*10)
        if ( hueShift >= hueEnd ) {
          hueShift--;
          leds[gStair - 1*dir] = CHSV( hueShift, 204, 200 );
          leds[gStair - 2*dir] = CHSV( hueShift, 204, 200 );
        }
      }
      FastLED.show();
      //FastLED.delay(1); 
    }
    Serial.print(gStair);
    Serial.println(" step");
  }
  
  Serial.println("Last Stairs");
  hueShift = hueStart;
  for (gBright=0; gBright<=brightTop; gBright+=2) {
    if ( hueShift >= hueEnd )
    //hueShift = 1/(hueShift + ((hueEnd-hueStart)/brightTop*bright));
    hueShift--;
    leds[gStairEnd] = CHSV( hueShift, 204, 200 );
    leds[gStairEnd - 1*dir] = CHSV( hueShift, 204, 200 );
    FastLED.show();
    //FastLED.delay(1); 
  }
  //Flash
  FastLED.delay(500); 
  for(gStair=gStairStart; (dir == 1 && gStair <= gStairEnd ) || (dir == -1 && gStair >= gStairEnd && gStair <= gStairStart+1 ); gStair+=(2*dir)) {
    leds[gStair] = CRGB( 100, 100, 100);
    leds[gStair + 1*dir] = CRGB( 100, 100, 100);
    FastLED.show();
  }
  for(gStair=gStairStart; (dir == 1 && gStair <= gStairEnd ) || (dir == -1 && gStair >= gStairEnd && gStair <= gStairStart+1 ); gStair+=(2*dir)) {
    leds[gStair] = CHSV( hueEnd, 204, 200 );
    leds[gStair+1*dir] = CHSV( hueEnd, 204, 200 );
    FastLED.show();
  }
  
  
  Serial.println("Delay");
  // Stay on for a bit
  fill_solid(leds, NUM_LEDS, CHSV( hueEnd, 204, 200 ));
  //addGlitter(70);
  FastLED.show();
  FastLED.delay(5000);
  
  // Turn off steps
  Serial.println("Steps Off");
  for(gStair=gStairStart; (dir == 1 && gStair <= gStairEnd ) || (dir == -1 && gStair >= gStairEnd && gStair <= gStairStart+1 ); gStair+=(2*dir)) {
    // Fade in step
    //hueShift = hueStart;
    for (gBright=200; gBright>=1; gBright--) { 
      leds[gStair] = CHSV(hueEnd, 204, gBright);
      leds[gStair + 1*dir] = CHSV(hueEnd, 204, gBright);
      FastLED.show();
      FastLED.delay(1); 
    }
    leds[gStair].setHSV( 0, 0, 0);
    leds[gStair + 1*dir].setHSV( 0, 0, 0);
    FastLED.show();
  }
  lightsOn = LOW;  
  
  Serial.println("Done");
}

// startup rainbow

  rainbow();
  addGlitter(80);
}
void addGlitter( fract8 chanceOfGlitter) 
{
  if( random8() < chanceOfGlitter) {
