FastLED with 2 PIR Switches

Hi, I am working on a project that uses Neopixel type LED strips to low level light stairs at night. I m using the FastLED library which works very well and the 'colour pallete' example is good fun. I wondered if anyone could help me with the simplist way to use a PIR at either end of the stairs to trigger the leds into action. Whichever one trips should lock the leds on until the other sensor is trip which should swicth them off restting both for the next trip action.

Being a bear of little brain I am struggling to get my head around how to latch the sensors.

Thanks in anticipation

You need to detect when a sensor becomes triggered rather than when it is triggered

See the StateChangeDetection example in the IDE

Once a sensor has become triggered turn on the LEDs until the other sensor becomes triggered then turn them off

Idk if i understand your question right, but try it like this.
Everytime one of the sensors is triggered he asks the other sensor if theyre on or off.
Everything turn off if it isnt touched for 60sec.

int TopSensor = 2;                                              //Top pir is pin 2
int BotSensor = 3;                                              //Bot pir is pin 3
bool FromTop = false;
bool FromBot = false;
int TimerToTurnOff = 60000;                                     //Time in ms to turn the leds automaticly off
unsigned long prevMillis = 0;


void setup() {
  prevMillis = millis();
}

void loop() {
  pixels.show();                                                //<-- <-- <-- turn the leds off here <-- <-- <--
  
  if (digitalRead(TopSensor) == true)                           //if pir top reacts
    prevMillis = millis();
    if (FromBot == false && FromTop== false) {                  //A person starts the leds by walking downstairs
	  	FromTop = true;
	  }
	  
	  if (FromBot == true && FromTop== false) {                   //The walking upstairs leds are ending
	  	FromBot = false;
	  }
  }
	
	if (digitalRead(BotSensor) == true)                           //if pir bottom reacts
	  prevMillis = millis();
    if (FromBot == false && FromTop== false) {                  //A person starts the leds by walking upstairs
	  	FromBot = true;
	  }
	  
	  if (FromBot == false && FromTop== true) {                   //The walking downstairs leds are ending
	  	FromTop = false;
	  }
	}
	
	
	
	if (FromTop == true || FromBot == true)
	{
    pixels.show();                                              //<-- <-- <-- turn the leds on here <-- <-- <--
	}
	
	if (millis() - prevMillis >= TimerToTurnOff)                  //After a time periodthe leds turn automaticly off
	{
	  prevMillis = millis();
	  FromTop = false;
	  FromBot = false;
	}
  
}

consider
not sure about your purpose of the timer. code below uses timer to prevent triggering in opposite direction when leaving

#define MyHW
#ifdef MyHW
struct Pixels_s {
    void show (void)  { Serial.println (__func__); }
    void off  (void)  { Serial.println (__func__); }
} pixels;

const int PinTopSensor = A1;
const int PinBotSensor = A2;

#else
const int PinTopSensor = 2;
const int PinBotSensor = 3;

#endif

bool fromTop;
bool fromBot;
bool on;

unsigned long msecLst;
unsigned long msec;

enum { Off = HIGH, On = LOW };

// -----------------------------------------------------------------------------
void
off (void)
{
    fromTop = fromBot = false;
    pixels.off ();
}

// -----------------------------------------------------------------------------
void loop()
{
    msec = millis ();

    if ((msec - msecLst) < 1000)    // timeout prevents re-triggering
        return;

    if (digitalRead(PinTopSensor) == On)  {
        msecLst = msec;

        if (fromBot == false) {    // person starts walking downstairs
            fromTop = true;
            pixels.show ();
        }
        else
            off ();
    }

	
    if (digitalRead(PinBotSensor) == On)  {
        msecLst = msec;

        if (fromTop == false) {    // person starts walking upstairs
            fromBot = true;
            pixels.show ();
        }
        else
            off ();
    }
}

// -----------------------------------------------------------------------------
void setup()
{
    Serial.begin (9600);
    pinMode (PinBotSensor, INPUT_PULLUP);
    pinMode (PinTopSensor, INPUT_PULLUP);
}

This looks like a classic state machine to me. It can only be in 3 states

OFF
MOVING DOWN
MOVING UP

Using switch/case based on the current state would simplify the code and make it clear what was going on

Adding a timer in loop() to turn the LEDs off and move to the OFF state should they be on for too long would be a good idea

Thank you for your replies. I will give things a go over the next dat or two.

Dear UKHeliBob,

I have managed to make 2 switches change state as per the example but cannot seem to make them work like a simple electric light two-way switch. Any pointers to a code example would be gratefully received. the only examples I can find are for one switch.

Post your best effort sketch and explain the problem in more detail

Hi UKHeliBob,

I have put the sketch below. Going up, I want to use the push button at the bottom of the stairs to switch the lights on and lock the top switch until it is pressed which will then switch the lights off. Going down, I want the top switch to switch on the lights and lock the bottom switch until it is pressed to switch them off. Once working the switches will be replaced with PIR sensors.


// v0.01 - Strip Comments from example
// v0.02 - Set variables as button 1
// v0.03 - 2nd Switch setup - initial switch state = off

const int button1_pin = 2;
const int button2_pin = 3;
const int led1_pin = 6; //
const int led2_pin = 7;

int buttonPush1_Counter = 0;
int button1_State = 0;
int lastbutton1_State = 0;
int buttonPush2_Counter = 1;
int button2_State = 0;
int lastbutton2_State = 0;

void setup() {
pinMode(button1_pin, INPUT);
pinMode(led1_pin, OUTPUT);
pinMode(button2_pin, INPUT);
pinMode(led2_pin, OUTPUT);
Serial.begin(9600);

Serial.print("number of button 1 pushes: ");
Serial.println(buttonPush1_Counter);
Serial.print("number of button 2 pushes: ");
Serial.println(buttonPush2_Counter);
}

void loop() {

//*********** Button 1 ***************
button1_State = digitalRead(button1_pin);

if (button1_State != lastbutton1_State) {
if (button1_State == HIGH && buttonPush2_Counter % 2 == 0 ) {
buttonPush1_Counter++;
Serial.println("Button 1 on - Button 2 locked");
Serial.print("number of button 1 pushes: ");
Serial.println(buttonPush1_Counter);
//LED Code here - call as a function
} else {
Serial.println("Button 1 off - Button 2 unlocked");
}
delay(50); //Debounce
}
lastbutton1_State = button1_State;

if (buttonPush1_Counter % 2 == 0) { // turns on the LED every x pushes
digitalWrite(led1_pin, LOW);
} else {
digitalWrite(led1_pin, HIGH);
}
if (buttonPush1_Counter >= 4){
Serial.print("Button 1 Reset ");
buttonPush1_Counter = 0;
}

//*********** Button 2 ***************
button2_State = digitalRead(button2_pin);

if (button2_State != lastbutton2_State) {
if (button2_State == HIGH) {
buttonPush2_Counter++;
Serial.println("Button 2 on - Button 1 locked");
Serial.print("number of button 2 pushes: ");
Serial.println(buttonPush2_Counter);
//LED Code here - call as a function
} else {
Serial.println("Button 2 off - Button 1 unlocked");
}
delay(50); //Debounce
}
lastbutton2_State = button2_State;

if (buttonPush2_Counter % 2 == 0) { // turns on the LED every x pushes
digitalWrite(led2_pin, HIGH);
} else {
digitalWrite(led2_pin, LOW);
}
if (buttonPush2_Counter >= 4){
Serial.print("Button 2 Reset ");
buttonPush2_Counter = 0;
}
}

Your requirements seem to have changed since your original post. There is no mention of FastLED in the code that you posted and why have you got 2 LED pins ?

I do not understand this requirement. What do you mean by "locking" the top switch ?

Please follow the advice given in the link below when posting code, in particular the section entitled 'Posting code and common code problems'

Use code tags (the </> icon above the compose window) to make it easier to read and copy for examination

That's probably stupid in fact. The thought was to prevent someone coming down at the same time as someone going up but I guess that's redundant really. Thank you for the tip about code.

`type or paste code here`

Hi,

No the requirement hasn't changed - the switches will be replaced with PIR sensors and the single LED with the strip. I am just doing it with a single LED to simplify the test code and again you are absoultely right, it only needs one LED but two switches. I am at the age where numptyitis is very bad.

Here is a sketch for you to look at and take ideas from

const byte topButtonPin = A3;
const byte bottomButtonPin = A2;
const byte ledPin = 3;

enum states
{
  IDLE,
  GOING_DOWN,
  GOING_UP
};

states currentState = IDLE;

void setup()
{
  Serial.begin(115200);
  pinMode(bottomButtonPin, INPUT_PULLUP);
  pinMode(topButtonPin, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH); //LED off initially
}

void loop()
{
  switch (currentState)
  {
    case IDLE:
      if (testTopButton())
      {
        digitalWrite(ledPin, LOW);  //LED on
        Serial.println("moving to GOING_DOWN");
        currentState = GOING_DOWN;
      }
      else if (testBottomButton())
      {
        digitalWrite(ledPin, LOW);  //LED on
        Serial.println("moving to GOING_UP");
        currentState = GOING_UP;
      }
      break;
    case GOING_DOWN:
      if (testBottomButton())
      {
        digitalWrite(ledPin, HIGH); //LED off
        Serial.println("moving to IDLE");
        currentState = IDLE;
      }
      break;
    case GOING_UP:
      if (testTopButton())
      {
        digitalWrite(ledPin, HIGH); //LED off
        Serial.println("moving to IDLE");
        currentState = IDLE;
      }
      break;
  };
}

bool testTopButton()
{
  bool becamePressed = false;
  static byte prevTopButtonState = HIGH;
  byte currentTopButtonState = digitalRead(topButtonPin);
  if (currentTopButtonState != prevTopButtonState && currentTopButtonState == LOW)
  {
    becamePressed = true;
  }
  prevTopButtonState = currentTopButtonState;
  return becamePressed;
}

bool testBottomButton()
{
  bool becamePressed = false;
  static byte prevBottomButtonState = HIGH;
  byte currentBottomButtonState = digitalRead(bottomButtonPin);
  if (currentBottomButtonState != prevBottomButtonState && currentBottomButtonState == LOW)
  {
    becamePressed = true;
  }
  prevBottomButtonState = currentBottomButtonState;
  return becamePressed;
}

The use of switch/case isolates the code that runs in each state and is, IMO, easier to use , read and understand nested if/else statements

NOTE:

  • the inputs are INPUT_PULLUP so LOW indicates that a button is pressed
  • the LED output is active LOW so LOW turns it on
  • it would be simple to add a timer to it to turn the LED off after a period, but get the basics working first

why not just turn the LEDs on for a limited amount of time whenever either trigger occurs. if someone starts walking down while someone is walking up, the timeout is reset

Thank you all very, very much - I now have something that is working as a test.

Hi Again,

I have this now working beautifully with the two push button switches but and struggling a bit understanding what to change when I replace the push buttons with PIR sensors. If I use the code 'as is' with the sensors instead of switches there is no 'latching' effect and the LED's switch off after the built-in 2 second delay. A pointer or two would be much appriated.

// ****  Push button state changer for 2 buttons ******
// v1.01 - First Iteration
// v1.02 - HIGH/LOW Swapped to correct on/off
// v2.01 - Add functions code for LED's
// v2.11 - Switch operates all leds
// v2.20 - Working Version (push buttons)


#include <FastLED.h>

//User Variables
#define NUM_LEDS    89
#define BRIGHTNESS  64
#define LED_Delay 2000

// ********* PIR/Switch Variables ******
const byte topButtonPin = 3;  //switch
const byte bottomButtonPin = 2;//switch

const byte ledPin = 6;

enum states
{
  IDLE,
  GOING_DOWN,
  GOING_UP
};

states currentState = IDLE;


// ********* FastLED Variables ******
#define FastLED_PIN     10
#define LED_TYPE    WS2811
#define COLOR_ORDER GRB
CRGB leds[NUM_LEDS];

#define UPDATES_PER_SECOND 100


CRGBPalette16 currentPalette;
TBlendType    currentBlending;

extern CRGBPalette16 myRedWhiteBluePalette;
extern const TProgmemPalette16 myRedWhiteBluePalette_p PROGMEM;



void setup()
{
  //Switch Setup
    Serial.begin(115200);
    pinMode(bottomButtonPin, INPUT_PULLUP);
    pinMode(topButtonPin, INPUT_PULLUP);
    pinMode(ledPin, OUTPUT);
    digitalWrite(ledPin, LOW); //LED off initially

  //FastLED Setup
    delay( 3000 ); // power-up safety delay
    FastLED.addLeds<LED_TYPE, FastLED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
    FastLED.setBrightness(  BRIGHTNESS );
    leds[0] = CRGB::Blue;
    leds[1] = CRGB::White;
    FastLED.show();
    delay(LED_Delay*.5);
    FastLED.clear();
    FastLED.show();
        
    currentPalette = RainbowColors_p;
    currentBlending = LINEARBLEND;  
}

void loop()
{
  switch (currentState)
  {
    case IDLE:
      if (testTopButton())
      {
        digitalWrite(ledPin, HIGH);  //LED on
        Serial.println("moving to GOING_DOWN");
        currentState = GOING_DOWN;
      }
      else if (testBottomButton())
      {
        digitalWrite(ledPin, HIGH);  //LED on
        Serial.println("moving to GOING_UP");
        currentState = GOING_UP;
      }
      break;
    case GOING_DOWN:
      if (testBottomButton())
      {
        digitalWrite(ledPin, LOW); //LED off
        Serial.println("moving to IDLE");
        currentState = IDLE;
        delay(LED_Delay);
        FastLED.clear();
        FastLED.show();
      }
      break;
    case GOING_UP:
      if (testTopButton())
      {
        digitalWrite(ledPin, LOW); //LED off
        Serial.println("moving to IDLE");
        currentState = IDLE;
        delay(LED_Delay);
        FastLED.clear();
        FastLED.show();
      }
      break;
  };

if (currentState == GOING_DOWN){
    ChangePalettePeriodically();
    
    static uint8_t startIndex = 0;
    startIndex = startIndex + 1; /* motion speed */
    
    FillLEDsFromPaletteColors( startIndex);
    
    FastLED.show();
    FastLED.delay(1000 / UPDATES_PER_SECOND);
}
if (currentState == GOING_UP){
    ChangePalettePeriodically();
    
    static uint8_t startIndex = 0;
    startIndex = startIndex + 1; /* motion speed */
    
    FillLEDsFromPaletteColors( startIndex);
    
    FastLED.show();
    FastLED.delay(1000 / UPDATES_PER_SECOND);
  }
}

// ****** End of loop ******

// ****** Switch Functions ******
bool testTopButton()
{
  bool becamePressed = false;
  static byte prevTopButtonState = LOW;
  byte currentTopButtonState = digitalRead(topButtonPin);
  if (currentTopButtonState != prevTopButtonState && currentTopButtonState == LOW)
  {
    becamePressed = true;
  }
  prevTopButtonState = currentTopButtonState;
  return becamePressed;
}

bool testBottomButton()
{
  bool becamePressed = false;
  static byte prevBottomButtonState = LOW;
  byte currentBottomButtonState = digitalRead(bottomButtonPin);
  if (currentBottomButtonState != prevBottomButtonState && currentBottomButtonState == LOW)
  {
    becamePressed = true;
  }
  prevBottomButtonState = currentBottomButtonState;
  return becamePressed;
}

//**** FAST LedColour Pallette Functions *****

void FillLEDsFromPaletteColors( uint8_t colorIndex)
{
    uint8_t brightness = 255;
    
    for( int i = 0; i < NUM_LEDS; ++i) {
        leds[i] = ColorFromPalette( currentPalette, colorIndex, brightness, currentBlending);
        colorIndex += 3;
    }
}


// There are several different palettes of colors demonstrated here.
//
// FastLED provides several 'preset' palettes: RainbowColors_p, RainbowStripeColors_p,
// OceanColors_p, CloudColors_p, LavaColors_p, ForestColors_p, and PartyColors_p.
//
// Additionally, you can manually define your own color palettes, or you can write
// code that creates color palettes on the fly.  All are shown here.

void ChangePalettePeriodically()
{
    uint8_t secondHand = (millis() / 1000) % 60;
    static uint8_t lastSecond = 99;
    
    if( lastSecond != secondHand) {
        lastSecond = secondHand;
        if( secondHand ==  0)  { currentPalette = RainbowColors_p;         currentBlending = LINEARBLEND; }
        if( secondHand == 10)  { currentPalette = RainbowStripeColors_p;   currentBlending = NOBLEND;  }
        if( secondHand == 15)  { currentPalette = RainbowStripeColors_p;   currentBlending = LINEARBLEND; }
        if( secondHand == 20)  { SetupPurpleAndGreenPalette();             currentBlending = LINEARBLEND; }
        if( secondHand == 25)  { SetupTotallyRandomPalette();              currentBlending = LINEARBLEND; }
        if( secondHand == 30)  { SetupBlackAndWhiteStripedPalette();       currentBlending = NOBLEND; }
        if( secondHand == 35)  { SetupBlackAndWhiteStripedPalette();       currentBlending = LINEARBLEND; }
        if( secondHand == 40)  { currentPalette = CloudColors_p;           currentBlending = LINEARBLEND; }
        if( secondHand == 45)  { currentPalette = PartyColors_p;           currentBlending = LINEARBLEND; }
        if( secondHand == 50)  { currentPalette = myRedWhiteBluePalette_p; currentBlending = NOBLEND;  }
        if( secondHand == 55)  { currentPalette = myRedWhiteBluePalette_p; currentBlending = LINEARBLEND; }
    }
}

// This function fills the palette with totally random colors.
void SetupTotallyRandomPalette()
{
    for( int i = 0; i < 16; ++i) {
        currentPalette[i] = CHSV( random8(), 255, random8());
    }
}

// This function sets up a palette of black and white stripes,
// using code.  Since the palette is effectively an array of
// sixteen CRGB colors, the various fill_* functions can be used
// to set them up.
void SetupBlackAndWhiteStripedPalette()
{
    // 'black out' all 16 palette entries...
    fill_solid( currentPalette, 16, CRGB::Black);
    // and set every fourth one to white.
    currentPalette[0] = CRGB::White;
    currentPalette[4] = CRGB::White;
    currentPalette[8] = CRGB::White;
    currentPalette[12] = CRGB::White;
    
}

// This function sets up a palette of purple and green stripes.
void SetupPurpleAndGreenPalette()
{
    CRGB purple = CHSV( HUE_PURPLE, 255, 255);
    CRGB green  = CHSV( HUE_GREEN, 255, 255);
    CRGB black  = CRGB::Black;
    
    currentPalette = CRGBPalette16(
                                   green,  green,  black,  black,
                                   purple, purple, black,  black,
                                   green,  green,  black,  black,
                                   purple, purple, black,  black );
}


// This example shows how to set up a static color palette
// which is stored in PROGMEM (flash), which is almost always more
// plentiful than RAM.  A static PROGMEM palette like this
// takes up 64 bytes of flash.
const TProgmemPalette16 myRedWhiteBluePalette_p PROGMEM =
{
    CRGB::Red,
    CRGB::Gray, // 'white' is too bright compared to red and blue
    CRGB::Blue,
    CRGB::Black,
    
    CRGB::Red,
    CRGB::Gray,
    CRGB::Blue,
    CRGB::Black,
    
    CRGB::Red,
    CRGB::Red,
    CRGB::Gray,
    CRGB::Gray,
    CRGB::Blue,
    CRGB::Blue,
    CRGB::Black,
    CRGB::Black
};

Pressing one of the buttons takes the associated input, which is normally HIGH, to LOW. Do the PIRs do the same thing when activated and how are they powered ?

The PIR's are AM312 with a voltage range of 2.7v to 12v so I am powering them from the Arduino input power supply. They sit HIGH but drop LOW when activated. I think they are actually working but are just a tad slow triggering. There is about a 2.5 second lag. Anyway, I will do a bit more testing and checking connections!

Cheers.

After messing about quite a bit, I am finding that the PIR is slow switching on and off (typically about 2.5 seconds). I can't quite undertsand what is causing the delay.

// ****  Push button state changer for 2 buttons ******
// v1.01 - First Iteration
// v1.02 - HIGH/LOW Swapped to correct on/off
// v2.01 - Add functions code for LED's
// v2.11 - Switch operates all leds
// v2.20 - Working Version (push buttons)
// v2.21 - Working Version (PIR Sensor)


#include <FastLED.h>

//User Variables
#define NUM_LEDS    89
#define BRIGHTNESS  64
#define LED_Delay 2000

// ********* PIR/Switch Variables ******
//const byte topButtonPin = 3;  //switch
//const byte bottomButtonPin = 2;//switch

const byte topButtonPin = 5;  //pir
const byte bottomButtonPin = 4;//pir

const byte ledPin = 6;

enum states
{
  IDLE,
  GOING_DOWN,
  GOING_UP
};

states currentState = IDLE;


// ********* FastLED Variables ******
#define FastLED_PIN     10
#define LED_TYPE    WS2811
#define COLOR_ORDER GRB
CRGB leds[NUM_LEDS];

#define UPDATES_PER_SECOND 100


CRGBPalette16 currentPalette;
TBlendType    currentBlending;

extern CRGBPalette16 myRedWhiteBluePalette;
extern const TProgmemPalette16 myRedWhiteBluePalette_p PROGMEM;



void setup()
{
  //Switch Setup
    Serial.begin(115200);
    pinMode(bottomButtonPin, INPUT_PULLUP);
    pinMode(topButtonPin, INPUT_PULLUP);
    pinMode(ledPin, OUTPUT);
    digitalWrite(ledPin, LOW); //LED off initially

  //FastLED Setup
    delay(3000); // power-up safety delay
    FastLED.addLeds<LED_TYPE, FastLED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
    FastLED.setBrightness(  BRIGHTNESS );
    leds[0] = CRGB::Blue;
    leds[1] = CRGB::White;
    FastLED.show();
    delay(LED_Delay*.5);
    FastLED.clear();
    FastLED.show();
        
    currentPalette = RainbowColors_p;
    currentBlending = LINEARBLEND;  
}

void loop()
{
  switch (currentState)
  {
    case IDLE:
      if (testTopButton())
      {
        digitalWrite(ledPin, HIGH);  //LED on
        Serial.println("moving to GOING_DOWN");
        currentState = GOING_DOWN;
      }
      else if (testBottomButton())
      {
        digitalWrite(ledPin, HIGH);  //LED on
        Serial.println("moving to GOING_UP");
        currentState = GOING_UP;
      }
      break;
    case GOING_DOWN:
      if (testBottomButton())
      {
        digitalWrite(ledPin, LOW); //LED off
        Serial.println("moving to IDLE");
        currentState = IDLE;
        FastLED.clear();
        FastLED.show();
      }
      break;
    case GOING_UP:
      if (testTopButton())
      {
        digitalWrite(ledPin, LOW); //LED off
        Serial.println("moving to IDLE");
        currentState = IDLE;
        FastLED.clear();
        FastLED.show();
      }
      break;
  };

if (currentState == GOING_DOWN){
    ChangePalettePeriodically();
    
    static uint8_t startIndex = 0;
    startIndex = startIndex + 1; /* motion speed */
    
    FillLEDsFromPaletteColors( startIndex);
    
    FastLED.show();
    FastLED.delay(1000 / UPDATES_PER_SECOND);
}
if (currentState == GOING_UP){
    ChangePalettePeriodically();
    
    static uint8_t startIndex = 0;
    startIndex = startIndex + 1; /* motion speed */
    
    FillLEDsFromPaletteColors( startIndex);
    
    FastLED.show();
    FastLED.delay(1000 / UPDATES_PER_SECOND);
  }
}

// ****** End of loop ******

// ****** Switch Functions ******
bool testTopButton()
{
  bool becamePressed = false;
  static byte prevTopButtonState = LOW;
  byte currentTopButtonState = digitalRead(topButtonPin);
  if (currentTopButtonState != prevTopButtonState && currentTopButtonState == LOW)
  {
    becamePressed = true;
  }
  prevTopButtonState = currentTopButtonState;
  return becamePressed;
}

bool testBottomButton()
{
  bool becamePressed = false;
  static byte prevBottomButtonState = LOW;
  byte currentBottomButtonState = digitalRead(bottomButtonPin);
  if (currentBottomButtonState != prevBottomButtonState && currentBottomButtonState == LOW)
  {
    becamePressed = true;
  }
  prevBottomButtonState = currentBottomButtonState;
  return becamePressed;
}

//**** FAST LedColour Pallette Functions *****

void FillLEDsFromPaletteColors( uint8_t colorIndex)
{
    uint8_t brightness = 255;
    
    for( int i = 0; i < NUM_LEDS; ++i) {
        leds[i] = ColorFromPalette( currentPalette, colorIndex, brightness, currentBlending);
        colorIndex += 3;
    }
}


// There are several different palettes of colors demonstrated here.
//
// FastLED provides several 'preset' palettes: RainbowColors_p, RainbowStripeColors_p,
// OceanColors_p, CloudColors_p, LavaColors_p, ForestColors_p, and PartyColors_p.
//
// Additionally, you can manually define your own color palettes, or you can write
// code that creates color palettes on the fly.  All are shown here.

void ChangePalettePeriodically()
{
    uint8_t secondHand = (millis() / 1000) % 60;
    static uint8_t lastSecond = 99;
    
    if( lastSecond != secondHand) {
        lastSecond = secondHand;
        if( secondHand ==  0)  { currentPalette = RainbowColors_p;         currentBlending = LINEARBLEND; }
        if( secondHand == 10)  { currentPalette = RainbowStripeColors_p;   currentBlending = NOBLEND;  }
        if( secondHand == 15)  { currentPalette = RainbowStripeColors_p;   currentBlending = LINEARBLEND; }
        if( secondHand == 20)  { SetupPurpleAndGreenPalette();             currentBlending = LINEARBLEND; }
        if( secondHand == 25)  { SetupTotallyRandomPalette();              currentBlending = LINEARBLEND; }
        if( secondHand == 30)  { SetupBlackAndWhiteStripedPalette();       currentBlending = NOBLEND; }
        if( secondHand == 35)  { SetupBlackAndWhiteStripedPalette();       currentBlending = LINEARBLEND; }
        if( secondHand == 40)  { currentPalette = CloudColors_p;           currentBlending = LINEARBLEND; }
        if( secondHand == 45)  { currentPalette = PartyColors_p;           currentBlending = LINEARBLEND; }
        if( secondHand == 50)  { currentPalette = myRedWhiteBluePalette_p; currentBlending = NOBLEND;  }
        if( secondHand == 55)  { currentPalette = myRedWhiteBluePalette_p; currentBlending = LINEARBLEND; }
    }
}

// This function fills the palette with totally random colors.
void SetupTotallyRandomPalette()
{
    for( int i = 0; i < 16; ++i) {
        currentPalette[i] = CHSV( random8(), 255, random8());
    }
}

// This function sets up a palette of black and white stripes,
// using code.  Since the palette is effectively an array of
// sixteen CRGB colors, the various fill_* functions can be used
// to set them up.
void SetupBlackAndWhiteStripedPalette()
{
    // 'black out' all 16 palette entries...
    fill_solid( currentPalette, 16, CRGB::Black);
    // and set every fourth one to white.
    currentPalette[0] = CRGB::White;
    currentPalette[4] = CRGB::White;
    currentPalette[8] = CRGB::White;
    currentPalette[12] = CRGB::White;
    
}

// This function sets up a palette of purple and green stripes.
void SetupPurpleAndGreenPalette()
{
    CRGB purple = CHSV( HUE_PURPLE, 255, 255);
    CRGB green  = CHSV( HUE_GREEN, 255, 255);
    CRGB black  = CRGB::Black;
    
    currentPalette = CRGBPalette16(
                                   green,  green,  black,  black,
                                   purple, purple, black,  black,
                                   green,  green,  black,  black,
                                   purple, purple, black,  black );
}


// This example shows how to set up a static color palette
// which is stored in PROGMEM (flash), which is almost always more
// plentiful than RAM.  A static PROGMEM palette like this
// takes up 64 bytes of flash.
const TProgmemPalette16 myRedWhiteBluePalette_p PROGMEM =
{
    CRGB::Red,
    CRGB::Gray, // 'white' is too bright compared to red and blue
    CRGB::Blue,
    CRGB::Black,
    
    CRGB::Red,
    CRGB::Gray,
    CRGB::Blue,
    CRGB::Black,
    
    CRGB::Red,
    CRGB::Red,
    CRGB::Gray,
    CRGB::Gray,
    CRGB::Blue,
    CRGB::Blue,
    CRGB::Black,
    CRGB::Black
};