///////////////////////////////////////////////////////////////////////////////////////////////////
//
// This sketch is a test in fading between colors and fading brightness
// It uses the CHSV colorspace.
//
// - To be able to manipulate CHSV values an array is of CHSV objects is used.
// - The array has a CHSV object for each led
// - Every time the loop runs each led is set to the CHSV in the array of CHSV objects
// CRGB leds[NUM_LEDS] is a CRGB arrray
// The CHSV's from the CHSV array are "translated" to CRGB by the library when using leds[i] = arrCurrentCHSV[i];
// A seperate CHSV array is used because, once a CHSV value is written to a led, the CHSV is converted to CRGB
// After that, it is not possible to get the separate H/S/V value from a led and that makes adjusting the
// color and brightness just pretty plain impossible.
#include <FastLED.h>
#include <Streaming.h>
#include <Math.h>
// SETTINGS FOR LEDS
#define DATA_PIN 2
#define LED_TYPE WS2812
#define COLOR_ORDER GRB
#define NUM_LEDS 26
#define BRIGHTNESS 255
// ARRAYS ==========================================================================
// Array of leds
CRGB leds[NUM_LEDS];
// Array of CHSV objects that can be manipulated
// The CHSV values are written to the leds each loop
CHSV arrCurrentCHSV[NUM_LEDS];
// Array of target values
// This is used to fade colors and brightness
CHSV arrTargetCHSV[NUM_LEDS];
// An array of hue values that produce colors that can be used in effects
// saturation and value are always at 255 when showing a color
CHSV arrColors[8]=
{
CHSV( 255, 0, 255), //0 White - white is a special case, saturation has to be set to 0
CHSV( 255, 255, 255), //1 Red
CHSV( 100, 255, 255), //2 Green
CHSV( 160, 255, 255), //3 Blue
CHSV( 50, 255, 255), //4 Yellow
CHSV( 175, 255, 255), //5 Purple
CHSV( 200, 255, 255), //6 Pink
CHSV( 30, 255, 255) //7 Orange
};
// Determine the number of colors in the array
int intLengtharrColors = sizeof(arrColors) / sizeof(arrColors[0]);
// An array in which each row is a colorset
// eacht row must have the same number of entries
// 12 is chosen so that color sets of 2, 3, 4 and 6 can be used
// while keeping the chance of random selection even
int arrColorsets[7][12] = {
{0,3,1,0,3,1,0,3,1,0,3,1}, //0 red white blue
{3,1,2,3,1,2,3,1,2,3,1,2}, //1 red green blue
{0,1,0,1,0,1,0,1,0,1,0,1}, //2 red white
{2,1,2,1,2,1,2,1,2,1,2,1}, //3 red green
{2,1,4,2,1,4,2,1,4,2,1,4}, //4 red yellow green
{2,4,2,4,2,4,2,4,2,4,2,4}, //5 yellow green
{3,5,3,5,3,5,3,5,3,5,3,5} //6 blue purple
};
// Determine the number of elements/colorsets
int intNumberOfColorsets = sizeof(arrColorsets) / sizeof(arrColorsets[0]);
int intCurrentColorset = 0;
// Parameters for fading value (brightness)
uint8_t intValUpperLimit = 250;
uint8_t intValLowerLimit = 40;
uint8_t intValAdjustment = 2; // This should not be greater than the offset of <intValUpperLimit to 255> or offset <intValLowerLimit to 0?
void setup() {
Serial.begin(9600);
delay(3000); // 3 second delay for recovery
// tell FastLED about the LED strip configuration
FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds, NUM_LEDS);
FastLED.setTemperature(0xFF7029);
// set master brightness control
FastLED.setBrightness(BRIGHTNESS);
// Fill arrCurrentCHSV and arrTargetCHSV with a single color
for(int i = 0; i < NUM_LEDS; i++){
arrCurrentCHSV[i]= CHSV( 160, 255, 255);
arrTargetCHSV[i]= CHSV( 160, 255, 255);
}
} // end setup
void loop(){
// vFade in-/decrements all values in arrCurrentCHSV towards arrTargetCHSV
vFade();
// Place all CHSV objects from arrCurrentCHSV into the led array
// NOTE: memcpy is faster but cannot be used because arrCurrentCHSV elements have to be converted to CRGB
for(int i = 0; i < NUM_LEDS; i++){
leds[i] = arrCurrentCHSV[i];
}
FastLED.show();
// Change the target color for a few leds
// Option 1: since there are only 2-3 colors in a color set, the chance that the new target is the current color is high, therefor all leds will get a new target
// Option 2: change a smaller number of leds and make the change interval smaller or random between for example 500-1000 milliseconds
int intNumberOfLedsToChange = NUM_LEDS;
int intChangeInterval = random(1000,4000);
EVERY_N_MILLISECONDS(intChangeInterval){
for(int led = 0; led <= intNumberOfLedsToChange; led++){
int intTargetLed = random(0, NUM_LEDS);
// generate a random int to select a color from one row in array arrColorsets
int intGetRandomColorFromSet = random(0,12);
int intGetColor = arrColorsets[intCurrentColorset][intGetRandomColorFromSet];
// Place the CHSV color into arrTargetCHSV[i]
arrTargetCHSV[intTargetLed] = arrColors[intGetColor];
} //end for
} //end every
EVERY_N_SECONDS(30){
vChangeColorset();
}
} //end loop
void vFade(){
//Serial << "val: " << arrCurrentCHSV[0].val << endl;
//Serial << "start: " << millis() << endl;
// Every time vFade is called arrCurrentCHSV values wil be in-/decremented towards the CHSV values in arrTargetCHSV
CHSV cur;
CHSV tar;
for(int i = 0; i < NUM_LEDS; i++){
cur = arrCurrentCHSV[i];
tar = arrTargetCHSV[i];
// Hue
if(cur.hue < tar.hue && cur.hue < 255){ // if the hue is smaller than the target AND is not 255: increment the hue
arrCurrentCHSV[i].hue++;
}
if(cur.hue > tar.hue && cur.hue > 0){
arrCurrentCHSV[i].hue--;
}
// Saturartion
if(cur.sat < tar.sat && cur.sat < 255){
arrCurrentCHSV[i].sat++;
}
if(cur.sat > tar.sat && cur.sat > 0){
arrCurrentCHSV[i].sat--;
}
// Value
if(cur.val < tar.val && cur.val < intValUpperLimit){
arrCurrentCHSV[i].val += intValAdjustment;
}
if(cur.val > tar.val && cur.val > intValLowerLimit){
arrCurrentCHSV[i].val -= intValAdjustment;
}
} //end for
//Serial << "end: " << millis() << endl;
} //end vFade
void vChangeColorset(){
// When the colorset is to be changed:
// - ALL leds will fade to black
// - When all leds are black:
// New colors for the leds are set in arrCurrentCHSV AND arrTargetCHSV
// Setting a new target includes setting V (brightness) to 255, fading from black to the new target is handled by vFade
// Fading to black ==============================================================================
//a boolean that indicates wether all leds are black
bool bAllBlack = false;
//as long as not all leds are black yet:
while(bAllBlack == false){
//first set bAllBlack to true
bAllBlack = true;
//check all leds, if there is only one led that is NOT black, bAllBlack is set to false
for(int i = 0; i < NUM_LEDS; i++){
if(arrCurrentCHSV[i].val > intValLowerLimit){
bAllBlack = false;
}
}
for(int i = 0; i < NUM_LEDS; i++){
if(arrCurrentCHSV[i].val > intValLowerLimit){
//decrease the brightness
arrCurrentCHSV[i].val-= intValAdjustment;
// place CHSV into leds[] for display
leds[i] = arrCurrentCHSV[i];
}
}
FastLED.show();
} //end while
// Selecting new colors from a colorset ========================================================
// To ensure the random selection of a colorset different from the current:
int intPreviousColorset = intCurrentColorset;
// as long as the randomly chosen set is the same as the previous, pick a new one
while(intCurrentColorset == intPreviousColorset){
intCurrentColorset = random(0,intNumberOfColorsets); //random() excludes the upper limit so ideal to use as array index :)
}
// Fill arrCurrentCHSV and arrTargetCHSV with new target colors
for(int i = 0; i < NUM_LEDS; i++){
//Random number that gets a color in one row of arrColorsets
int intGetRandomColorFromSet = random(0,12);
// intGetColor is picked out of the current set and used to retreive the color from arrColors
int intGetColor = arrColorsets[intCurrentColorset][intGetRandomColorFromSet];
// Set the new color in arrCurrent
arrCurrentCHSV[i] = arrColors[intGetColor];
// Set value to zero(black) because the leds have to fade in again from 0 to 255
arrCurrentCHSV[i].val = 0;
// Set the new color in arrTarget
arrTargetCHSV[i] = arrColors[intGetColor];
// Set the target brightness V to max
arrTargetCHSV[i].val = 255;
} //end for
} //end vChangeColorset