FastLED Code Review?

Hey folks, I am not at all a programmer, but have played with Arduinos and such off and on over the years, and have generally managed to string bits and pieces I find around the net together to get something fairly simple done.

My most recent project is also my largest. I've built a Little Free Library, and have an Arduino in the attic driving 5 WS2812b LED Strips to light the thing up at night. I've been using the FastLED library, which is clearly quite powerful, and has been very useful, if a bit tough to figure out at times.

All that said, what I have now is essentially a finished, and working project. The lights do what I want them to do, and I'm satisfied with the results.

However, I expect that my code isn't exactly clean or efficient, and I'm probably doing things in ham-fisted ways in places.

What I'd like is, in the interest of getting better at this stuff, and learning, for people to look through things, and let me know about those things that could be handled better, done differently, made more efficient, more cleanly, etc.

I don't really need tips like using 'a += b' instead of 'a = a + b', those are the things I think I'll get better at with time, and I have intentionally done a lot here in a longhand method, just to make it clearer to me as I am reviewing it myself, and trying to track things down. (Similarly, I know I over-commented on everything, but it was useful for me)

What I'm looking for more, is overall structural stuff. "This whole thing should be a separate function that you call this way, so it's not taking up cycles." or "I don't get why you're calling this thing repeatedly instead of just doing this. . . "

Thanks in advance for any tips an advice.

Context: The Library has 5 LED strips. There are 4 in the corners of the main cabinet (Front Left & Right, Back Left & Right), and then a smaller strip in the attic section. The goal is for the lights not to come on at all during the day (via the photoresistor). At night, I'd like it to run a pattern of light (currently watery blue) for the first could hours after sunset, then go dark. As long as it's dark out, if the doors are opened, the front LEDs will come up to white, to illuminate the books. Once the door is closed, the white light lingers for a time, before fading back to the idle pattern/darkness. I hope that all makes sense.


// Updated - 11/27/22 - 5:16PM

#include <FastLED.h>                                    // FastLED library.

#define NUM_LEDS_FRONT 21                               // Number of LEDs for the Front strips
#define NUM_LEDS_BACK 22                                // Number of LEDs for the Back strips
#define NUM_LEDS_ATTIC 8                                // Number of LEDs for the Attic Strip
#define NUM_LEDS_MAX 22                                 // Largest of the above numbers (used for setting a temporary array of colors)

#define LED_PIN_FRONT_LEFT 13                           // Pin for the Front Left Strip
#define LED_PIN_FRONT_RIGHT 12                          // Pin for the Front Right Strip
#define LED_PIN_BACK_LEFT 11                            // Pin for the Back Left Strip
#define LED_PIN_BACK_RIGHT 10                           // Pin for the Back Right Strip
#define LED_PIN_ATTIC 9                                 // Pin for the Attic Strip

#define LED_TYPE WS2812B                                // LED Strip type

#define SWITCH_PIN_LEFT 4                               // Pin for the Left Door Switch
#define SWITCH_PIN_RIGHT 3                              // Pin for the RIght Door Switch
#define SWITCH_PIN_ATTIC 2                              // Pin for the Attic Switch

#define PHOTO_PIN A0                                    // Analog Pin for the Photoresistor

#define SWITCH_DEBOUNCE 250                             // How long to wait between sampling the door switches
#define PHOTO_SAMPLE_TIME 30                            // How often to sample the photoresistor (in seconds)
#define PHOTO_DARK 100                                  // Light Level at which it's now dark enough to turn on the lights

#define DUSK_TIMER 7200000                              // How long to keep the backlight on when it first gets dark.
#define LINGER_TIMER 20000                              // How long to keep the lights on after the doors get closed
#define FADE_STEP 1                                     // A multiplier used to set how fast the fades happen.

CRGB ledsWhite [NUM_LEDS_MAX];                          // Array that is just bright white, used to fill in the front/attic when the doors are opened.
CRGB ledsTemp [NUM_LEDS_MAX];                           // Temporary Array used to copy the pattern colors to all of the other arrays.
CRGB ledsFrontLeft[NUM_LEDS_FRONT];                     // Array for the Front Left LEDs
CRGB ledsFrontRight[NUM_LEDS_FRONT];                    // Array for the Front Right LEDs
CRGB ledsBackLeft[NUM_LEDS_BACK];                       // Array for the Back Left LEDs
CRGB ledsBackRight[NUM_LEDS_BACK];                      // Array for the Back Right LEDs
CRGB ledsAttic[NUM_LEDS_ATTIC];                         // Array for the Attic LEDs

int switchLeft = 1;                                     // To track the status of the Left Door switch
int switchRight = 1;                                    // To track the status of the Right Door switch
int switchAttic = 1;                                    // To track the status of the Attic Door switch

bool doorMain = false;                                  // To track when the main doors are open.
bool doorAttic = false;                                 // To track when the attic door is open.
                                                        //
bool itsDark = false;                                   // Is it dark now?
bool itsDusk = false;                                   // Is it dusk now?
bool lightLinger = false;                               // Are we lingering?
  
unsigned long timeNow = millis();                       // What time is it now?
unsigned long lastLight = millis();                     // Used to store the last point in time when photoAvg is greater than PHOTO_DARK
unsigned long lastOpened = millis();                    // Used to store the last time a Main cabinet door was opened.
                                                        
uint8_t activeBright = 255;                             // How bright should the backlight be while in standby mode during dusk?
uint8_t idleBright = 128;                               // How bright should the lights be at dusk with the doors closed?

uint8_t blendAmountMain = 0;                                // Used to blend the pattern to white for the Front and Attic lights
uint8_t blendAmountAttic = 0;                           // U

int mainBright = 0;                                     // Used to store the starting brightness of the Main Cabinet
int atticBright = 0;                                    // Used to store the starting brightness of the Attic

//#############################################
//################### SETUP ###################
//#############################################

void setup() {

  delay( 3000 );                                                                            // Power-up safety delay
   
  FastLED.addLeds<LED_TYPE, LED_PIN_FRONT_LEFT, GRB>(ledsFrontLeft, NUM_LEDS_FRONT);        // Adding Front Left LEDs
  FastLED.addLeds<LED_TYPE, LED_PIN_FRONT_RIGHT, GRB>(ledsFrontRight, NUM_LEDS_FRONT);      // Adding Front Right LEDs
  
  FastLED.addLeds<LED_TYPE, LED_PIN_BACK_LEFT, GRB>(ledsBackLeft, NUM_LEDS_BACK);           // Adding Back Left LEDs
  FastLED.addLeds<LED_TYPE, LED_PIN_BACK_RIGHT, GRB>(ledsBackRight, NUM_LEDS_BACK);         // Adding Back Right LEDs

  FastLED.addLeds<LED_TYPE, LED_PIN_ATTIC, GRB>(ledsAttic, NUM_LEDS_ATTIC);                 // Adding Attic LEDs

  FastLED.setCorrection(TypicalPixelString);                                                // Color Correction 
  FastLED.setBrightness(255);                                                               // Setting Overall max brightness

  fill_solid(ledsWhite, NUM_LEDS_MAX, CHSV(45,64,255));

  pinMode(SWITCH_PIN_LEFT, INPUT_PULLUP);                                                   // Setting up the pins for the Left Door switch
  pinMode(SWITCH_PIN_RIGHT, INPUT_PULLUP);                                                  // Setting up the pins for the Right Door switch
  pinMode(SWITCH_PIN_ATTIC, INPUT_PULLUP);                                                  // Adjusting the RTC to match the Date/Time of the computer as the sketch gets uploaded

  Serial.begin(115200);                                                                     // Starting Serial Communications
  Serial.println("Setup Complete");                                                         // Checkpoint text
}



//######################################################
//################### SET BRIGHTNESS ###################
//######################################################

void setBright(bool lightLinger){  

  int mainFadeDir = 0;                                                      // Used to store which way we're fading.
  int atticFadeDir = 0;                                                     // Used to store which way we're fading.

//##### Main Brightness #####

  if (doorMain) {                                                           // If the main doors are open
    mainFadeDir = 1;                                                        // Fade Up
  } else if ((!doorMain) && (lightLinger)) {                                // Or if the main doors are closed, but we're lingering
    mainFadeDir = 1;                                                        // Fade Up
  } else {                                                                  // Otherwise
    mainFadeDir = -1;                                                       // Fade down
  }

//  Serial.print("Main Fade Direction: ");
//  Serial.println(mainFadeDir);

  mainFadeDir = mainFadeDir * FADE_STEP;                                    // Increses/Decreases the Fade Direction based on the Fade Step
  mainBright = mainBright + mainFadeDir;                                    // Add the current brightness to the fade direction

  if (mainBright <= idleBright) {                                           // If brightness is less than target
    mainBright = idleBright;                                                // Reset to target
  } else if (mainBright >= activeBright) {                                  // Or if it's maxed out
    mainBright = activeBright;                                              // Keep it maxed out.
  }

  blendAmountMain = map(mainBright, idleBright, activeBright, 0, 255);      // Sets Blend Amount to always be in the 0-255 range, but based on the difference between the Idle & Active brightnesses)

  if (blendAmountMain <= 0) {                                               // If blend amount is less than 0
    blendAmountMain = 0;                                                    // Reset to 0
  } else if (blendAmountMain >= 255) {                                      // Or if it's maxed out
    blendAmountMain = 255;                                                  // Keep it maxed out.
  }

//  Serial.print("Main Fade Dir: ");
//  Serial.println(mainFadeDir);
//  Serial.print("Main Brightness: ");
//  Serial.println(mainBright);
//  Serial.print("Blend Amount: ");
//  Serial.println(blendAmountMain);
  

//##### Attic Brightness #####

  if (doorAttic) {                                                          // If the main doors are open
    atticFadeDir = 1;                                                       // Fade Up
  } else if ((!doorAttic) && (lightLinger)){                                // Or if the main doors are closed, but we're lingering
    atticFadeDir = 1;                                                       // Fade Up
  } else {                                                                  // Otherwise
    atticFadeDir = -1;                                                      // Fade down
  }

  atticBright = (atticBright + (atticFadeDir * FADE_STEP));                 // Add the current brightness to the fade direction

  if (atticBright <= idleBright) {                                          // If brightness is less than target
    atticBright = idleBright;                                               // Reset to target
  } else if (atticBright >= activeBright) {                                 // Or if it's maxed out
    atticBright = activeBright;                                             // Keep it maxed out.
  }

  blendAmountAttic = map(atticBright, idleBright, activeBright, 0, 255);    // Sets Blend Amount to always be in the 0-255 range, but based on the difference between the Idle & Active brightnesses)

  if (blendAmountAttic <= 0) {                                              // If blend amount is less than 0
    blendAmountAttic = 0;                                                   // Reset to 0
  } else if (blendAmountAttic >= 255) {                                     // Or if it's maxed out
    blendAmountAttic = 255;                                                 // Keep it maxed out.
  }

//  Serial.print("Attic Brightness: ");
//  Serial.println(atticBright);

}





//######################################################
//################### LIGHT PATTERNS ###################
//######################################################

void lightsWatery(uint8_t brightness, int timeOffset) {

//  Serial.print("Watery Brightness = ");
//  Serial.println(brightness);

  unsigned long t = ((millis()/5) + timeOffset);            // Sets a variable to use as time with the noise functions, including an offset from the function calls, so they don't all have to be in sync

  for (int i = 0; i < NUM_LEDS_MAX; i++) {                  // Step through each LED in the strip
    uint8_t noiseA = inoise8(i * 10 + 20, t);               // Creating and constraining Noise A
            noiseA = constrain(noiseA, 0, 255);
    uint8_t noiseB = inoise8(i * 5 + 50, 2.8*t);            // Creating and constraining Noise B
            noiseB = constrain(noiseB, 0, 255);
    uint8_t noiseC = inoise8(i * 20 - 10, 3.7*t);           // Creating and constraining Noise C
            noiseC = constrain(noiseC, 0, 255);

    uint8_t ledHue = map(noiseA, 50, 190, 130, 160);        // Mapping and constraining Hue based on Noise A
            ledHue = constrain(ledHue, 130, 160);
    uint8_t ledSat = map(noiseB, 50, 190, 230, 255);        // Mapping and constraining Saturation based on Noise B
            ledSat = constrain(ledSat, 230, 255);
    uint8_t ledVal = map(noiseC, 50, 190, 128, 255);        // Mapping and constraining Value based on Noise C
            ledVal = constrain(ledVal, 128, 255);           // Modulating backVal by the brightnessBack

    float brightPct = (brightness/255.0);                   // Converting brightness to a percentage to be multiplied on backVal

    ledVal = (brightPct*ledVal);                            // Attenuate the Light Value by the Brightness Percent

    ledsTemp[i] = CHSV(ledHue, ledSat, ledVal);             // Set the temporary Array
  }
}



//#############################################
//################### PHOTO ###################
//#############################################

void photo(){

  static int photoIndex = 0;                                                    // Used to save photo readings into the next slot in the array
  static int photoReadings[10] = {500,500,500,500,500,500,500,500,500,500};     // Array to hold the 10 most recent photoresistor samples
  int photoLevel = analogRead(A0);                                              // Temporarily stores the photoresistor sample level
  int photoSum = 0;                                                             // Used to total the contents of the array
  static int photoAvg;                                                          // Average of the 10 light samplees stored in photoReadings[]
  
  photoReadings[photoIndex] = photoLevel;                                       // Insert that reading into the next slot of the array

  for(int i=0; i<10; i++){                                                      // Total up the current contents of the array
    photoSum = (photoSum + photoReadings[i]);
  }

  photoAvg = photoSum/10;                                                       // Average the total of the array
  photoSum = 0;                                                                 // Reset the total of the array, so it recounts from 0 next time it rolls through  photoIndex++;                                                                             // Move the index up so the next time we go through, we put the new reading in the next slot.

  if (photoAvg < PHOTO_DARK) {                                                  // If the average light is below a threshold
    itsDark = true;                                                             // It's Dark!
//    Serial.print("It's Dark! - ");
//    Serial.println(photoAvg);
  } else {                                                                      // Otherwise
    itsDark = false;                                                            // It ain't!
//    Serial.print("It's Bright! - ");
//    Serial.println(photoAvg);
  }

//  Serial.print("Photo Readings: ");
//  for(int j=0; j<10; j++){
//    Serial.print(photoReading[j]);
//    Serial.print(", ");
//  }
//  Serial.println();
//  Serial.print("Photo Average: ");
//  Serial.println(photoAvg);

  if (photoIndex >= 10){                                                        // reset the index to 0 to continue the rolling 10 average
    photoIndex = 0;
  }
}


//############################################
//################### LOOP ###################
//############################################
 
void loop () {

  timeNow = millis();                                                                       // What time is it right now?

//#### Sample the Photoresistor and keep time as long as it's bright
  EVERY_N_SECONDS(PHOTO_SAMPLE_TIME){                                                       // Only sample the lighting conditions every 30 seconds or so)
    photo();                                                                                // Run the Photoresistor Function       
    if (!itsDark){                                                                          // If it's not dark
      lastLight = millis();                                                                 // Store the last time it was light out
    }
  }
  
  if ((timeNow - lastLight) < DUSK_TIMER) {                                                 // If the last time it was light is longer ago than the Dusk Timer
    itsDusk = true;                                                                         // It's Dusk!
//    Serial.println("It's Dusk!");
  } else {                                                                                  // Otherwise
    itsDusk = false;                                                                        // It ain't!
  }

//#### Sample the Switches ####
  EVERY_N_MILLISECONDS(SWITCH_DEBOUNCE){                                                    // Debounce the switches
    switchLeft = digitalRead(SWITCH_PIN_LEFT);                                              // Sample the Left Door Switch
    switchRight = digitalRead(SWITCH_PIN_RIGHT);                                            // Sample the Right Door Switch
    switchAttic = digitalRead(SWITCH_PIN_ATTIC);                                            // Sample the Attic Door Switch
                                                                                            //
    if ((switchLeft == LOW) || (switchRight == LOW)){                                       // If one or the other front door is open
      doorMain = true;
//      Serial.println("Main Door Open");
    } else {
      doorMain = false;
    }

    if (switchAttic == LOW){                                                                // If the attic door is open
      doorAttic = true;
//      Serial.println("Attic Door Open");
    } else {
      doorAttic = false;
    }
  }

//#### Record the last time the door was open ###
  if ((itsDark) && (doorMain)){                                                             // If it's dark and either the Left or Right Door is open
    lastOpened = millis();                                                                  // As long as a door is open, this is constantly updating to the current time.
  }

//#### Are we in Linger mode? ####
  if ((((millis() - lastOpened) < LINGER_TIMER)) && (mainBright >= activeBright)) {         // If the last time the doors were opened is less than the Linger Timer
    lightLinger = true;                                                                     // Then we be lingerin'
//    Serial.println("Lingering. . . . ");
  } else {                                                                                  // Otherwise
    lightLinger = false;                                                                    // Don't Linger
  }

//#### Idle Brightness depends on whether it's Dusk or not.
  if (itsDusk) {                                                                            // If it's dusk
    idleBright = 128;                                                                       // Then when the doors aren't open, things should still glow.
  } else {                                                                                  // Otherwise
    idleBright = 0;                                                                         // Turn them off
  }

//#### Set the Brightness ####
  setBright(lightLinger);                                                                   // Run the setBright Function, and tell it if we're lingering or not.

//####Set the light patterns ####

  //## Front Lights ##
  lightsWatery(mainBright, 0);                                                              // set the temporary LED Array with some colors, and send the current brightness value
  for (int i = 0; i < NUM_LEDS_FRONT; i++){                                                 // Step through the LEDs one by one
    ledsFrontLeft[i] = blend(ledsTemp[i], ledsWhite[i], blendAmountMain);                   // Copy the colors from Temp Array (and/or blend to white) into the real LED Array.
  }
      
  lightsWatery(mainBright, 6742);                                                           // set the temporary LED Array with some colors, and send the current brightness value
  for (int i = 0; i < NUM_LEDS_FRONT; i++){                                                 // Step through the LEDs one by one
    ledsFrontRight[i] = blend(ledsTemp[i], ledsWhite[i], blendAmountMain);                  // Copy the colors from Temp Array (and/or blend to white) into the real LED Array.
  }

  //## Back Lights ##
  lightsWatery(mainBright, 12475);                                                          // set the temporary LED Array with some colors, and send the current brightness value
  for (int i = 0; i < NUM_LEDS_BACK; i++){                                                  // Step through the LEDs one by one
    ledsBackLeft[i] = ledsTemp[i];                                                          // And copy the color from the Temp Array to the real LED Array
  }
  
  lightsWatery(mainBright, 18736);                                                          // set the temporary LED Array with some colors, and send the current brightness value
  for (int i = 0; i < NUM_LEDS_BACK; i++){                                                  // Step through the LEDs one by one
    ledsBackRight[i] = ledsTemp[i];                                                         // And copy the color from the Temp Array to the real LED Array
  }

  //## Attic Lights ## 
  lightsWatery(atticBright, 0);                                                             // set the temporary LED Array with some colors, and send the current brightness value
  for (int i = 0; i < NUM_LEDS_ATTIC; i++){                                                 // Step through the LEDs one by one
    ledsAttic[i] = blend(ledsTemp[i], ledsWhite[i], blendAmountAttic);                      // Copy the colors from Temp Array (and/or blend to white) into the real LED Array.
  }
  
  FastLED.show();                                                                           // Aziz, Light!
  
//  Serial.println("boop");
//  delay(2000);
}

One question I did have is, if I want to add more idle lighting patterns, is it ok to just include more, separate void functions for each other pattern, and then just switch out the function calls? Or is it bad form to leave unused functions in? I know it beefs up the file size, but does having the extra lines of code matter if none of it is getting called?

For instance, if I want to do a Christmasy lighting scheme for the month, is it ok to leave in the "watery" function? Or is it better to delete/replace that function? Is there a better way to handle multiple lighting patterns that I may only call now and then?

Unused code will usually not use memory on the Arduino.

Just through the small window I wonder if you forget to increment photoIndex in the photo() function.

a7

Use an IR remote and receiver to switch patterns.

First of all, I'd like to say that that is really nice code, especially for someone who claims not to be a "real programmer." My biggest complaint is the widescreen commenting style, but that's just something I'm not used to. It looked pretty good when I made my window wide enough! (but ... not all of the comments line up perfectly.) (Hmm. And it makes it harder to edit the code.)

The little library is pretty, too.

I know I over-commented on everything, but it was useful for me)

If it was useful for you, it's NOT over-commented!

But since you said you wanted suggestions, I guess I can come up with a few...


There needs to be a header at the top of the program: your name (or alias), the (approximate) date, the general purpose of the whole thing, what the target hardware is, what versions of Arduino you were using, a copyright notice, and licensing terms.
Some of that you can copy from your post here.


What does "linger" mean?

Also, I found "photo" confusing when you meant "photocell" - I was like "does it take a picture or something?" You've got lots of nice long and descriptive variable and function names, I think this one should get longer.


void lightsWatery(uint8_t brightness, int timeOffset) {
...
 //## Back Lights ##
  lightsWatery(mainBright, 12475);   
  lightsWatery(mainBright, 18736);

What kind of Arduino? Because if it's an AVR, then using "int" for a timeOffset (instead of an unsigned long) is somewhat dangerous. I think you squeak by in all the cases you actually use, though.

Also, what do those weird-looking numbers mean, anyway? Why are they weird?


The C++ folk would probably want a bunch of your #define statements to be static int variables.

You have a bunch of "int" variables that could be bytes/uint8_t (loop counters) or even booleans (switchLeft, etc.)


//  Serial.print("Main Fade Direction: ");
//  Serial.println(mainFadeDir);

Instead of commenting out your debug code, you might want to put it inside of

if (debug) {
}

statements, where debug is a constant defined true or false at the top of your program. (if the value is false, the code will be completely omitted from your final object code.)


  //## Front Lights ##
  lightsWatery(mainBright, 0);
  for (int i = 0; i < NUM_LEDS_FRONT; i++){
    ledsFrontLeft[i] = blend(ledsTemp[i], ledsWhite[i], blendAmountMain);  
  }
      
  lightsWatery(mainBright, 6742);
  for (int i = 0; i < NUM_LEDS_FRONT; i++){
    ledsFrontRight[i] = blend(ledsTemp[i], ledsWhite[i], blendAmountMain); 
  }

  //## Back Lights ##
  lightsWatery(mainBright, 12475);
  for (int i = 0; i < NUM_LEDS_BACK; i++){
    ledsBackLeft[i] = ledsTemp[i];
  }
  
  lightsWatery(mainBright, 18736);
  for (int i = 0; i < NUM_LEDS_BACK; i++){
    ledsBackRight[i] = ledsTemp[i];
  }

  //## Attic Lights ## 
  lightsWatery(atticBright, 0);
  for (int i = 0; i < NUM_LEDS_ATTIC; i++){
    ledsAttic[i] = blend(ledsTemp[i], ledsWhite[i], blendAmountAttic);
  }

I feel like there is enough duplication of code here that it could use "refactoring."
Maybe a

   lightsWatery(CRGB strip[], int stripSize, CRGB *blending=NULL, uint8_t blendAmount=0) {...}

You might have to learn about pointers or references. ledsTemp can probably be eliminated. Maybe ledsWhite too.


if you're going to add additional effects, you probably want the loop() to put each effect in a separate function:

//####Set the light patterns ####
//  wateryEffect();
  xmasEffect();
  FastLED.show();

If the functions aren't called, they won't end up included in the binary.
If you end up wanting multiple effects, you can figure out tables of function pointers...

This code appears a few times (spotted 4, could be more), with different variables. You can replace it with the standard Arduino function constrain().

EDIT: you do use constrain() elsewhere in your code... copied from someone else's code perhaps.

In both cases

else if (lightLinger) …

Should be enough

This can be shortened to

  itsDark = (photoAvg < PHOTO_DARK);

Or

mainFadeDir = doorMain || lightLinger ? 1 : -1;

I wouldn't call millis() multiple times within the loop() function. You call it once at the top:

void loop () {

  timeNow = millis(); 

Just use that 'timeNow' value everywhere you need time later in loop() rather than calling millis() again like you do here:

      lastLight = millis(); 

and here:

    lastOpened = millis();

and here:

  if ((((millis() - lastOpened) < LINGER_TIMER)) && (mainBright >= activeBright)) {
1 Like

Hey all, thank you so much for your replies overnight. I really do appreciate all of the feedback and guidance here.

You appear to be 100% correct. This was definitely being done previously (right after the 'photoSum = 0;' line. In fact, the comment is still there. Dunno what I did, but

HA! Thank you so much. I'm an artist by trade, and have been working in/around programmers for nigh on 20 years. But I've never had any official training, and have always just kind of felt my way along as needed. This project definitely pushed me a lot more than I have previously.

re: the widescreen comments - I think for me it was easier to put them off to the side, because while the code may be harder to edit, it was much easier to read the lines that all go together, without having the comments in between. If this were something I were more comfortable with, I'm sure there would be many fewer comments, and thus, it would be more reasonable to intersperse.

Interesting. It didn't even occur to me that this was something I should do. It's just a silly little side project, not something I'm expecting anyone else to ever use, or even see beyond this thread.

A couple people have asked about that. The idea was to keep cabinet lights on (as if the doors were open), for a short time after the doors are closed. That way if someone walks up at night, opens a door, and then closes it again, it doesn't go dark immediately.

Though I admit that after posting this, I noticed last night that this isn't even working in practice. It was definitely working in a previous version, so I'm not sure what broke. I'll have to do some testing tonight.

That's fair. The photo() function is what samples a photoresistor, and then turns the lights off during the day. It was one of the first things I worked on. Since everything was about LEDs and Light already, I wanted to avoid using the word "light" in the names, even if that's what my brain wanted to default to. I think my variables and such got more verbose as I went, so photo just kind of stuck.

This is running on an Arduino Uno.

The TimeOffset thing was somthing added just in the last couple of days, as I noticed that the patterns were all perfectly symmetrical/in sync with each other. I just wanted a way to create a more random look. The 'weird numbers' are added onto the millis() time used in the noise functions in the pattern. They were literally just a couple of random keystrokes. Nothing of import. I'm sure there's a better way to do this, I just wanted to create an apparent randomized pattern per strip, without locking myself into that (I can set all the offset to be the same to put them back in sync for future patterns)

I am admittedly still pretty hazy on the #define vs const vs static thing. I was certainly referencing things from all over, but I think the majority of my FastLED specific learning came from Scott Marley's FastLED Basics Youtube series, and I think he mostly used #define. Since using that seemed to work, I question it much.

Is there a good reference that goes over the difference and intended use cases of the define/const/static thing?

Oh! That's very clever. Thanks!

Passing things between function is something I seem to have a lot of trouble wrapping my brain around. I was getting really frustrated towards the end, trying to figure out how to properly pass the pattern function an Array name, and then somehow getting that back to Loop again. In the end, the ledsTemp thing was the only thing I could get working, since it was a global array I could fill up and then copy from. It also seems like there's probably a better way to copy the contents of an array into another array, other than what I'm doing, stepping through to copy index for index?

That's a good idea. Thanks!

Yeah, you're definitely right. I realize looking at it now, it didn't even occur to me that I could use variable names in place of straight numbers for the min/max of constrain. Again, not a programmer, so it's always funny what things my brain doesn't even consider. Thanks!

The Attic and Main Doors are on separate switches, and should linger separately. Is there something I'm missing here?

Ah! Thanks!

I'm not sure I follow this one. I see the doorMain OR lightLinger, but what's the "? 1 : -1;"?

Ah! Yes! Thank you!

I don't spot your library. I see just your sketch.
Add one comment line on the top what your sketch is all about.
The explanation / comments for the variables are nice.
To many empty lines in the code
If you have debug code you want to deactivate use some precompiler defines.
Don't use precompiler defines where you could use const variables or constexpr.
Check the remaining int variables if they will ever become negative ... chose an unsigned type instead.
If you really think you will need a delay(3000) at the start of your setup explain it in the code why you set it there.
Use the F-Makro for Serial.prints.
Press CTRL-T in the IDE before you post code.
The loop is very long and some code looks like "duplicated code". May be you can use some for loops.

  //## Back Lights ##
  lightsWatery(mainBright, 12475);                                                          // set the temporary LED Array with some colors, and send the current brightness value
  for (int i = 0; i < NUM_LEDS_BACK; i++) {                                                 // Step through the LEDs one by one
    ledsBackLeft[i] = ledsTemp[i];                                                          // And copy the color from the Temp Array to the real LED Array
  }

  lightsWatery(mainBright, 18736);                                                          // set the temporary LED Array with some colors, and send the current brightness value
  for (int i = 0; i < NUM_LEDS_BACK; i++) {                                                 // Step through the LEDs one by one
    ledsBackRight[i] = ledsTemp[i];                                                         // And copy the color from the Temp Array to the real LED Array
  }

Thought I should come back and post and update. I've taken a lot of your advice to heart, and reformatted things a bit, including many of your suggestions.

The Xmas program is a bit clumsy, but it works, and it had a bit of a deadline.

Thanks for all the help. I do appreciate it.

Here's a short video showing the cycle: Little Cahalan Library - Xmas 2022 Lighting Scheme - YouTube

And the code:

// Updated - 12/15/22 - 9:04AM

// Arduino code by Nick Duguid (Tumerboy)
// This is a program to drive 5 different LED strips located in my Little Free Library.  The strips are controlled via a photoresistor, and several switches mounted to the doors.
// These inputs are used to keep the lights off during the day, and turn on the lights when the doors are opened.
// Running on an Arduino Uno

#include <FastLED.h>                                    // FastLED library.

#define NUM_LEDS_FRONT 21                               // Number of LEDs for the Front strips
#define NUM_LEDS_BACK 22                                // Number of LEDs for the Back strips
#define NUM_LEDS_ATTIC 8                                // Number of LEDs for the Attic Strip
#define NUM_LEDS_MAX 22                                 // Largest of the above numbers (used for setting a temporary array of colors)

#define LED_PIN_FRONT_LEFT 13                           // Pin for the Front Left Strip
#define LED_PIN_FRONT_RIGHT 12                          // Pin for the Front Right Strip
#define LED_PIN_BACK_LEFT 11                            // Pin for the Back Left Strip
#define LED_PIN_BACK_RIGHT 10                           // Pin for the Back Right Strip
#define LED_PIN_ATTIC 9                                 // Pin for the Attic Strip

#define LED_TYPE WS2812B                                // LED Strip type

#define SWITCH_PIN_LEFT 4                               // Pin for the Left Door Switch
#define SWITCH_PIN_RIGHT 3                              // Pin for the RIght Door Switch
#define SWITCH_PIN_ATTIC 2                              // Pin for the Attic Switch

#define PHOTO_PIN A0                                    // Analog Pin for the Photoresistor

#define SWITCH_DEBOUNCE 250                             // How long to wait between sampling the door switches
#define AMBIENT_LIGHT_SAMPLE_TIME 30                    // How often to sample the photoresistor (in seconds)
#define AMBIENT_DARK 350                                // Light Level at which it's now dark enough to turn on the lights

#define DUSK_TIMER 7200000
#define LINGER_TIMER 30000
#define FADE_STEP 1                                     // A multiplier used to set how fast the fades happen.

CRGB ledsWhite [NUM_LEDS_MAX];                          // Array that is just bright white, used to fill in the front/attic when the doors are opened.
CRGB ledsFrontLeft[NUM_LEDS_FRONT];                     // Array for the Front Left LEDs
CRGB ledsFrontRight[NUM_LEDS_FRONT];                    // Array for the Front Right LEDs
CRGB ledsBackLeft[NUM_LEDS_BACK];                       // Array for the Back Left LEDs
CRGB ledsBackRight[NUM_LEDS_BACK];                      // Array for the Back Right LEDs
CRGB ledsAttic[NUM_LEDS_ATTIC];                         // Array for the Attic LEDs

int switchLeft = 1;                                     // To track the status of the Left Door switch
int switchRight = 1;                                    // To track the status of the Right Door switch
int switchAttic = 1;                                    // To track the status of the Attic Door switch

bool debug = false;                                     // Enables Debug Serial messages
unsigned int debugDelay = 0;                            // How long to delay each ccyle while in Debug Slow

bool doorMain = false;                                  // To track when the main doors are open.
bool doorAttic = false;                                 // To track when the attic door is open.
                                                        //
bool itsDark = false;                                   // Is it dark now?
bool itsDusk = false;                                   // Is it dusk now?
bool lightLinger = false;                               // Are we lingering?
  
unsigned long timeNow = millis();                       // What time is it now?
unsigned long lastLight = millis();                     // Used to store the last point in time when photoAvg is greater than AMBIENT_DARK
unsigned long lastOpened = millis();                    // Used to store the last time a Main cabinet door was opened.
                                                        
byte activeBright = 255;                                // How bright should the backlight be while in standby mode during dusk?
byte idleBright = 128;                                  // How bright should the lights be at dusk with the doors closed?

byte blendAmountMain = 0;                               // Used to blend the pattern to white for the Front lights
byte blendAmountAttic = 0;                              // Used to blend the pattern to white for the Attic lights

byte mainBright = 0;                                    // Used to store the starting brightness of the Main Cabinet
byte atticBright = 0;                                   // Used to store the starting brightness of the Attic

byte lightPattern = 1;                                  // Sets which pattern is on display. 0 = Watery 1 = X-mas

//#############################################
//################### SETUP ###################
//#############################################

void setup() {
   
  FastLED.addLeds<LED_TYPE, LED_PIN_FRONT_LEFT, GRB>(ledsFrontLeft, NUM_LEDS_FRONT);        // Adding Front Left LEDs
  FastLED.addLeds<LED_TYPE, LED_PIN_FRONT_RIGHT, GRB>(ledsFrontRight, NUM_LEDS_FRONT);      // Adding Front Right LEDs
  
  FastLED.addLeds<LED_TYPE, LED_PIN_BACK_LEFT, GRB>(ledsBackLeft, NUM_LEDS_BACK);           // Adding Back Left LEDs
  FastLED.addLeds<LED_TYPE, LED_PIN_BACK_RIGHT, GRB>(ledsBackRight, NUM_LEDS_BACK);         // Adding Back Right LEDs

  FastLED.addLeds<LED_TYPE, LED_PIN_ATTIC, GRB>(ledsAttic, NUM_LEDS_ATTIC);                 // Adding Attic LEDs

  FastLED.setCorrection(TypicalPixelString);                                                // Color Correction 
  FastLED.setBrightness(255);                                                               // Setting Overall max brightness

  fill_solid(ledsWhite, NUM_LEDS_MAX, CHSV(45,64,255));

  pinMode(SWITCH_PIN_LEFT, INPUT_PULLUP);                                                   // Setting up the pins for the Left Door switch
  pinMode(SWITCH_PIN_RIGHT, INPUT_PULLUP);                                                  // Setting up the pins for the Right Door switch
  pinMode(SWITCH_PIN_ATTIC, INPUT_PULLUP);                                                  // Adjusting the RTC to match the Date/Time of the computer as the sketch gets uploaded

  Serial.begin(115200);                                                                     // Starting Serial Communications
  Serial.println("Setup Complete");                                                         // Checkpoint text
}



//######################################################
//################### SET BRIGHTNESS ###################
//######################################################

void setBright(bool lightLinger){  

  int mainFadeDir = 0;                                                        // Used to store which way we're fading.
  int atticFadeDir = 0;                                                       // Used to store which way we're fading.

//##### Main Brightness #####

  if ((doorMain) || (lightLinger)) {                                          // If the main doors are open, or we're lingering
    mainFadeDir = 1;                                                          // Fade Up
  } else {                                                                    // Otherwise
    mainFadeDir = -1;                                                         // Fade down
  }

  mainFadeDir = mainFadeDir * FADE_STEP;                                      // Increses/Decreases the Fade Direction based on the Fade Step

  int tempBrightMain = mainBright;

  if (tempBrightMain + mainFadeDir >= activeBright) {                         // If mainBright (by way of tempBrightMain) is out of range
    mainBright = activeBright;                                                // Set it back to Active Bright
  } else if (tempBrightMain + mainFadeDir <= idleBright) {                    // Or if mainBright is out of range the other way
    mainBright = idleBright;                                                  // Set it back to Idle Bright
  } else {                                                                    // Otherwise
    mainBright = mainBright + mainFadeDir;                                    // Increment main Bright
  }

  if (itsDark) {                                                              // If it's Dark
    blendAmountMain = map(mainBright, idleBright, activeBright, 0, 255);      // Sets Blend Amount to always be in the 0-255 range, but based on the difference between the Idle & Active brightnesses)
  } else {                                                                    // Otherwise
    blendAmountMain = 0;                                                      // Blend Amount should be 0
  }

  if (debug) {
    EVERY_N_MILLISECONDS(debugDelay) {
      Serial.print("Main Fade Dir: ");
      Serial.println(mainFadeDir);
      Serial.print("Main Brightness: ");
      Serial.println(mainBright);
      Serial.print("Blend Amount: ");
      Serial.println(blendAmountMain);
    }
  }
  

//##### Attic Brightness #####

  if ((doorAttic) || (lightLinger)) {                                         // If the attic door is open, or we're lingering
    atticFadeDir = 1;                                                         // Fade Up
  } else {                                                                    // Otherwise
    atticFadeDir = -1;                                                        // Fade down
  }

  atticFadeDir = atticFadeDir * FADE_STEP;                                    // Increses/Decreases the Fade Direction based on the Fade Step

  int tempBrightAttic = atticBright;
  
  if (tempBrightAttic + atticFadeDir >= activeBright) {                       // If mainBright (by way of tempBrightAttic) is out of range
    atticBright = activeBright;                                               // Set it back to Active Bright
  } else if (tempBrightAttic + atticFadeDir <= idleBright) {                  // Or if mainBright is out of range the other way
    atticBright = idleBright;                                                 // Set it back to Idle Bright
  } else {                                                                    // Otherwise
    atticBright = atticBright + atticFadeDir;                                 // Increment main Bright
  }

  
  if (itsDark) {                                                              // If it's Dark
    blendAmountAttic = map(atticBright, idleBright, activeBright, 0, 255);    // Sets Blend Amount to always be in the 0-255 range, but based on the difference between the Idle & Active brightnesses)
  } else {                                                                    // Otherwise
    blendAmountAttic = 0;                                                     // Blend Amount should be 0
  }

  if (debug) {
    EVERY_N_MILLISECONDS(debugDelay) {
      Serial.print("Attic Fade Dir: ");
      Serial.println(atticFadeDir);
      Serial.print("Attic Brightness: ");
      Serial.println(atticBright);
    }
  }

}

//######################################################
//################### LIGHT PATTERNS ###################
//######################################################

void lightsWatery(CRGB ledStrip[], int numLeds, byte ledsBrightness, byte blendAmount, int timeOffset) {

  unsigned long t = ((timeNow / 5) + timeOffset);                         // Sets a variable to use as time with the noise functions, including an offset from the function calls, so they don't all have to be in sync

  for (int i = 0; i < numLeds; i++) {                                     // Step through each LED in the strip
    byte noiseA = inoise8(i * 10 + 20, t);                                // Creating and constraining Noise A
            noiseA = constrain(noiseA, 0, 255);
    byte noiseB = inoise8(i * 5 + 50, 2.8*t);                             // Creating and constraining Noise B
            noiseB = constrain(noiseB, 0, 255);
    byte noiseC = inoise8(i * 20 - 10, 3.7*t);                            // Creating and constraining Noise C
            noiseC = constrain(noiseC, 0, 255);

    byte ledHue = map(noiseA, 50, 190, 130, 160);                         // Mapping and constraining Hue based on Noise A
            ledHue = constrain(ledHue, 130, 160);
    byte ledSat = map(noiseB, 50, 190, 230, 255);                         // Mapping and constraining Saturation based on Noise B
            ledSat = constrain(ledSat, 230, 255);
    byte ledVal = map(noiseC, 50, 190, 128, 255);                         // Mapping and constraining Value based on Noise C
            ledVal = constrain(ledVal, 128, 255);                           

    float brightPct = (ledsBrightness/255.0);                             // Converting brightness to a percentage to be multiplied on backVal

    ledVal = (brightPct*ledVal);                                          // Attenuate the Light Value by the Brightness Percent

    ledStrip[i] = CHSV(ledHue, ledSat, ledVal);                           // Set the temporary Array

  }

  if (blendAmount > 1) {
    for (int i = 0; i < numLeds; i++){                                    // Step through the LEDs one by one
      ledStrip[i] = blend(ledStrip[i], ledsWhite[i], blendAmount);        // Copy the colors from Temp Array (and/or blend to white) into the real LED Array.
    }
  }
  
}

void lightsXmas(CRGB ledStrip[], int numLeds, byte ledsBrightness, byte blendAmount, int sideSwitch, int index, bool colorSwap) {

  if (sideSwitch){                                                        // Changes colors based on sideSwitch, which is set in the function call, so that one side will be red, and one side will be green
    if (colorSwap){                                                       // Either starts red, and fills green
      for (int i = 0; i < numLeds; i++){                                  // Fill all leds with green
        ledStrip[i] = CHSV(100, 255, ledsBrightness);                     
      }
      for (int i = index; i < numLeds; i++){                              // Then change the Index # led, and those after it to red
        ledStrip[i] = CHSV(0, 255, ledsBrightness);    
      }
    } else {                                                              // Or starts green, and fills with red
      for (int i = 0; i < numLeds; i++){                                  // Fill all the leds with red
        ledStrip[i] = CHSV(0, 255, ledsBrightness);    
      }
      for (int i = index; i < numLeds; i++){                              // Then change the Index # led, and those after it to green
        ledStrip[i] = CHSV(100, 255, ledsBrightness);    
      }
    }
  } else {                                                                // Or if we're on the other side
    if (colorSwap){                                                       // Start green, and fill with red
      for (int i = 0; i < numLeds; i++){                                  // Fill all leds with red
        ledStrip[i] = CHSV(0, 255, ledsBrightness);    
      }
      for (int i = index; i < numLeds; i++){                              // Then change the Index # led, and those after it to green
        ledStrip[i] = CHSV(100, 255, ledsBrightness);    
      }
    } else {                                                              // Or Start red, and fill with green
      for (int i = 0; i < numLeds; i++){                                  // Fill all leds with green
        ledStrip[i] = CHSV(100, 255, ledsBrightness);    
      }
      for (int i = index; i < numLeds; i++){                              // Then change the Index # led, and those after it to red
        ledStrip[i] = CHSV(0, 255, ledsBrightness);    
      }
    }
  }

  if (blendAmount > 1) {
    for (int i = 0; i < numLeds; i++){                                    // Step through the LEDs one by one
      ledStrip[i] = blend(ledStrip[i], ledsWhite[i], blendAmount);        // Copy the colors from Temp Array (and/or blend to white) into the real LED Array.
    }
  }
    
}

//##################################################
//################### RUN LIGHTS ###################
//##################################################

void runLights() {

  static int lightIndex = 0;                                                                                  // Used to step through the leds in the Xmas Pattern
  static bool colorSwap = false;                                                                              // Changes which color is used in the Xmas Pattern
  
  switch (lightPattern) {
    case 0:
      lightsWatery(ledsFrontLeft, NUM_LEDS_FRONT, mainBright, blendAmountMain, 0);                            // Run the Watery Effect for the Front Left
      lightsWatery(ledsFrontRight, NUM_LEDS_FRONT, mainBright, blendAmountMain, 3000);                        // Run the Watery Effect for the Front Right
      lightsWatery(ledsBackLeft, NUM_LEDS_BACK, mainBright, 0, 6000);                                         // Run the Watery Effect for the Back Left
      lightsWatery(ledsBackRight, NUM_LEDS_BACK, mainBright, 0, 12000);                                       // Run the Watery Effect for the Back Right
      lightsWatery(ledsAttic, NUM_LEDS_ATTIC, atticBright, blendAmountAttic, 0);                              // Run the Watery Effect for the Attic
      break;
    case 1:
      lightsXmas(ledsFrontLeft, NUM_LEDS_FRONT, mainBright, blendAmountMain, 0, lightIndex, colorSwap);       // Run the Xmas Effect for the Front Left
      lightsXmas(ledsFrontRight, NUM_LEDS_FRONT, mainBright, blendAmountMain, 1, lightIndex, colorSwap);      // Run the Xmas Effect for the Front Right
      lightsXmas(ledsBackLeft, NUM_LEDS_BACK, mainBright, 0, 1, lightIndex, colorSwap);                       // Run the Xmas Effect for the Back Left
      lightsXmas(ledsBackRight, NUM_LEDS_BACK, mainBright, 0, 0, lightIndex, colorSwap);                      // Run the Xmas Effect for the Back Right
      lightsXmas(ledsAttic, NUM_LEDS_ATTIC, atticBright, blendAmountAttic, 0, lightIndex, colorSwap);         // Run the Xmas Effect for the Attic
      break;
  }

  EVERY_N_MILLISECONDS(100) {
    lightIndex++;                                                                                             // Once we've run through all of the strips, we increment the index before running again.
  }

  if (lightIndex >= NUM_LEDS_MAX) {                                                                           // If the Index goes beyond our largest number of LEDs
    lightIndex = 0;                                                                                           // Reset the index to 0
    colorSwap = !colorSwap;                                                                                   // and Change colors
  }
}



//#############################################
//################### PHOTO ###################
//#############################################

void ambientLightCheck(){

  static int photoIndex = 0;                                                    // Used to save photo readings into the next slot in the array
  int photoLevel = analogRead(A0);                                              // Temporarily stores the photoresistor sample level
  static int photoReadings[10] = {photoLevel, photoLevel, photoLevel, photoLevel, photoLevel, photoLevel, photoLevel, photoLevel, photoLevel, photoLevel};                                                 // Array to hold the 10 most recent photoresistor samples
  
  int photoSum = 0;                                                             // Used to total the contents of the array
  static int photoAvg;                                                          // Average of the 10 light samplees stored in photoReadings[]
  
  photoReadings[photoIndex] = photoLevel;                                       // Insert that reading into the next slot of the array

  for(int i=0; i<10; i++){                                                      // Total up the current contents of the array
    photoSum = (photoSum + photoReadings[i]);
  }

  photoAvg = photoSum/10;                                                       // Average the total of the array
  photoSum = 0;                                                                 // Reset the total of the array, so it recounts from 0 next time it rolls through  photoIndex++;      
  photoIndex++;                                                                 // Move the index up so the next time we go through, we put the new reading in the next slot.

  if (photoIndex > 9) {                                                         // Loop photoIndex from 9-0
    photoIndex = 0;                                                            
  }

  if (photoAvg < AMBIENT_DARK){                                                 // If the ambient light is below a threshold
    itsDark = true;                                                             // It's Dark!
  } else {                                                                      // Otherwise
    itsDark = false;                                                            // It's not Dark
    lastLight = millis();                                                       // And we update a variable to track the last time it was light.
  }
  
  if (debug) {
    EVERY_N_MILLISECONDS(debugDelay) {
      Serial.println("=======================");
      Serial.print("Photo Index: ");
      Serial.println(photoIndex);
      Serial.print("Photo Average: ");
      Serial.println(photoAvg);
      Serial.print("Photo Readings: ");
      for(int j=0; j<10; j++){
        Serial.print(photoReadings[j]);
        Serial.print(", ");
      }
      Serial.println("=======================");
      Serial.println("");
    }
  }
}


//############################################
//################### LOOP ###################
//############################################
 
void loop () {

  timeNow = millis();                                                                       // What time is it right now?

//#### Sample the Photoresistor and keep time as long as it's bright
  EVERY_N_SECONDS(AMBIENT_LIGHT_SAMPLE_TIME){                                               // Only sample the lighting conditions every 30 seconds or so)
    ambientLightCheck();                                                                    // Run the Photoresistor Function       

    if (itsDark){                                                                           // If it's Dark
      if ((timeNow - lastLight) < DUSK_TIMER) {                                             // If the last time it was light is longer ago than the Dusk Timer
        itsDusk = true;                                                                     // It's Dusk!
        idleBright = 128;                                                                   // Keep the mood lights on when the doors are closed
      } else {                                                                              // Otherwise
        itsDusk = false;                                                                    // It ain't!
        idleBright = 0;                                                                     // Turn off the lights when the doors are shut.
      }
      activeBright = 255;                                                                   // Set the active brightness to max
    } else {                                                                                // Otherwise (if it's not dark)
      itsDusk = false;                                                                      // Then it's also not dusk.
      idleBright = 0;                                                                       // Set the idle brightness to 0
      activeBright = 0;                                                                     // And set the Active brightness to 0
    }
  }
  
//#### Sample the Switches ####
  EVERY_N_MILLISECONDS(SWITCH_DEBOUNCE){                                                    // Debounce the switches
    switchLeft = digitalRead(SWITCH_PIN_LEFT);                                              // Sample the Left Door Switch
    switchRight = digitalRead(SWITCH_PIN_RIGHT);                                            // Sample the Right Door Switch
    switchAttic = digitalRead(SWITCH_PIN_ATTIC);                                            // Sample the Attic Door Switch
                                                                                            //
    if ((switchLeft == LOW) || (switchRight == LOW)){                                       // If one or the other front door is open
      doorMain = true;
      lastOpened = timeNow;                                                                 // Record the last time one of the main doors was opened
    } else {
      doorMain = false;
    }

    if (switchAttic == LOW){                                                                // If the attic door is open
      doorAttic = true;
    } else {
      doorAttic = false;
    }
  }

//#### Are we in Linger mode? ####  
  if (((timeNow - lastOpened) < LINGER_TIMER) && (mainBright >= activeBright)) {            // If the last time the doors were opened is less than the Linger Timer
    lightLinger = true;                                                                     // Then we be lingerin'
  } else {                                                                                  // Otherwise
    lightLinger = false;                                                                    // Don't Linger
  }

//#### Set the Brightness ####
  setBright(lightLinger);                                                                   // Run the setBright Function, and tell it if we're lingering or not.

//#### Run the lights - 0 = Watery ####
  runLights();                                                                             // Use the Watery Pattern (Default)

//#### Show it all off ####
  FastLED.show();                                                                           // Aziz, Light!

//#### Debug Shiz ####
  if (debug){
    EVERY_N_MILLISECONDS(debugDelay) {
      if (itsDark) {
        Serial.println("It's Dark.");
      } else {
        Serial.println("It's Light.");
      }
      if (itsDusk) {
        Serial.print("It's Dusk for another ");
        Serial.print((lastLight + DUSK_TIMER) - timeNow);
        Serial.println(" milliseconds.");
      } else {
        Serial.println("It's NOT Dusk.");
      }
      if (lightLinger) {
        Serial.print("Lingering for another ");
        Serial.print((lastOpened + LINGER_TIMER) - timeNow);
        Serial.println(" milliseconds.");
      }
      Serial.println("");
      Serial.println("-------------------------");
      Serial.println("");
    }
  }
}

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.