 /*
  * Description: Motion activated stair lights.
  * Author: Dean Montgomery
- * Version: 1.1
- * Date: Aug 8, 2015
+ * Version: 2.1
+ * Date: Feb 8, 2016
  * 
  * 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.
  * 
+ * Version 2 is a rewrite to properly handle multi-tasking the PIR sensors in parallel with LED updates.
+ * TODO: Do some code cleanup, variable naming etc.
+ * 
 */
 
 #include "FastLED.h"
-#include <avr/eeprom.h>
+//#include <avr/eeprom.h>
 
 #define NUM_LEDS 26
+//#define NUM_LEDS 14
 #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_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  gLightsOn = 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);
  randomSeed(analogRead(0));
  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 ( gLightsOn == LOW ) {
      gLightsOn = HIGH;
      setUpDown(GO_DOWN);
      walker();
      delay(50);
    }
  }
  // Walk Up.
  if ( digitalRead(PIN_PIR_DOWN) == HIGH  ){
    if ( gLightsOn == LOW ) {
      gLightsOn = HIGH;
      setUpDown(GO_UP);
      walker();
      delay(50);
    }
  }
}

// Cycle through stair walkers.
void walker(){
  static uint8_t r = 0;
  r = random8(1, 255); r = random8(1, 255);  // Call random twice - as it wasn't very random.
  if ( r >= 0 && r <= 100 ){
    walk(); // My favorite with random variations.
  } else if ( r > 100 && r <= 175 ){
    flicker(); // Candle with embers.
  } else {
    fade7();
  }
}

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

        leds[gStair+1] = CHSV( 60, 200, gBright );
      }
    }
  } else if ( stage == stage_init_dim ){
    // Blow out candles and leave an ember.
    for(gStair=0; gStair < NUM_LEDS; gStair+=2) {
      rnd = random8(4, 6);
      r = rnd+1;
      g = rnd-2;
      leds[gUpDown[gStair]] = CRGB( r,g,0 );
      leds[gUpDown[gStair + 1]] = CRGB( r,g,0 );
      FastLED.show();
      FastLED.delay(50);
    }
    i = 0;
    gStair=0;
    stage = stage_dim;
  } else if ( stage == stage_dim ){
    if ( i <= 150 ){
      rnd = random8(0, NUM_LEDS);
      leds[gUpDown[rnd]].fadeToBlackBy( 3 );
      i++;
    } else {
      fill_solid(leds, NUM_LEDS, CRGB( 0, 0, 0 ));
      FastLED.show();
      stage = off;
    }
  } else {
    stage = off;
  }  
}

// Fade6 effect with each led: r,rb,b,bg,g,gr rgb(white)
void fade(){
  if ( stage == stage_init ){
    gBright = 0;
    gStair = 0;
    x = 0;
    interval = 7;
    r = 0;
    h = 0;
    s = 255;
    v = BRIGHTNESS;
    g = ( random8() < 120 );
    stage = stage_grow;
  } else if ( stage == stage_grow ){
    if ( gBright<255 ){
      if ( gStair < NUM_LEDS ){
        trans = blend(CRGB::Black,CHSV(h,s,v),gBright);
        leds[gUpDown[gStair]] = trans;
        leds[gUpDown[gStair + 1]] = trans;
        gBright = qadd8(gBright, 1);
      } else {
        stage = stage_init_run;
        interval = 50;
        gBright=0;
        gStair=0;
        r = 0;
      }
      gBright = qadd8(gBright, 2);
    } else {
      gBright = 0;
      gStair += 2;
    }
  } else if ( stage == stage_init_run ) {
    v = BRIGHTNESS;
    interval = 2;
    stage = stage_run;
  } else if ( stage == stage_run ){
    if ( gStair < NUM_LEDS ){
      h+=1;
      leds[gUpDown[gStair]] = CHSV(gStair + h, s, v);
      //if (g) addGlitter(40);
      gStair++;
    } else {
      gStair = 0;
      h = h - NUM_LEDS + 1;
    }
  } else if ( stage == stage_init_dim ){
    interval = 7;
    r = BRIGHTNESS;
    h = h - gStair;
    gStair = 0;
    stage = stage_dim;
  } else if ( stage == stage_dim ){
    if ( v > 0 ) {
      if ( gStair < NUM_LEDS ){
        leds[gUpDown[gStair]] = CHSV(gStair + h, s, v);
        leds[gUpDown[gStair + 1]]= CHSV(gStair + h, s, v);
        v--;
      } else {
        stage = off;
      }
    } else {
      leds[gUpDown[gStair]] = CRGB( 0, 0, 0);
      leds[gUpDown[gStair + 1]] = CRGB( 0, 0, 0);
      gStair += 2; 
      v = BRIGHTNESS;
      h+=2;
    }
  } else {
    stage = off;
  }
}


