Wake-up light, part 2: patterns

By | January 2, 2017

A short update for the wake-up light. Some quick (and dirty?) coding using an Arduino Pro Micro and the Fastled library already gives some nice results:

The code uses the Fastled built-in HSV colorspace (hue, saturation, value). Although originally meant for RGB LEDs, it also seems to work fine for WWA (warm white, cold white, amber) LEDs. In the first pattern, the hue is changed between a value of approx. 95 (deep red) and 215 (natural white). In the second pattern, hue is fixed to 95, and saturation is gradually changed from 255 (pure colour) to 0 (natural white).

Both approaches give approximately the same result, but the first one opens the option to first use hue for colour determination, after which overall brightness can be increased by lowering saturation. This is done in the third pattern. In my opinion, this is already pretty much suitable for the final wake-up light pattern. The fourth pattern shows the Fire2012 example from the Fastled library, just because it looks nice.

Finally, the Arduino code for this example:

#define FASTLED_ALLOW_INTERRUPTS 0
#include "FastLED.h"

const int button = 4;

const int minutes = 30;
const int hueMin = 100;
const int hueMax = 230;

#define NUM_LEDS 60 
//#define DATA_PIN 1
#define DATA_PIN 2
#define FRAMES_PER_SECOND 60

CRGB leds[NUM_LEDS];
CRGBPalette16 gPal;

void setup() 
{
  Serial.begin(115200);
 
  pinMode(button, INPUT);

  LEDS.addLeds<WS2812B,DATA_PIN,RGB>(leds,NUM_LEDS);
  LEDS.setBrightness(255);

  FastLED.clear();
  FastLED.show();



}

void loop() {
  // Change hue between 96 and 214, corresponding to deep red to natural white
  delay(3000);
  for (int i=0; i<NUM_LEDS; i++) {
    int j = 96 + i*2;
    leds[i] = CHSV(j, 255, 255);
    FastLED.show();
    delay(10);
  }
  delay(5000);
  FastLED.clear();
  FastLED.show();
  delay(500);

  // Fix hue, and vary saturation
  for (int i=0; i<NUM_LEDS; i++) {
    int j = (i*255)/NUM_LEDS;
    leds[i] = CHSV(96, 255-j, 255);
    FastLED.show();
    delay(10);
  }
  delay(5000);
  FastLED.clear();
  FastLED.show();
  delay(500);


  // First try for wake-up pattern
  // Slowly go up. Start with deep red colour (hue = 96), and blend to natural white-ish
  for (int i=0; i<NUM_LEDS; i++) {
    int hue = 96 + i*2;
    for (int j=0; j<255; j++) { leds[i] = CHSV(hue, 255, j); //delay(1); FastLED.show(); } } // Once all LEDs are lit, start decreasing hue (blend all colours to natural white) for (int j=255; j>0; j--) {
    for (int i=0; i<NUM_LEDS; i++) {
      int hue = 96 + i*2;
      leds[i] = CHSV(hue, j, 255);
    }
    FastLED.show();
    delay(30);
    if (j<170) delay(70); // First part is faster, brightness starts increasing around this value
  }
  delay(5000);
  FastLED.clear();
  FastLED.show();
  delay(500);


  // Do a fire simulation 
  unsigned long tStart = millis();
  
  random16_add_entropy( random());
  static uint8_t hue = 0;
  hue++;
  CRGB darkcolor  = CHSV(hue,255,192); // pure hue, three-quarters brightness
  CRGB lightcolor = CHSV(hue,128,255); // half 'whitened', full brightness
  gPal = CRGBPalette16( CRGB::Black, darkcolor, lightcolor, CRGB::White);

  while (millis()-tStart-<30000) {
    Fire2012WithPalette(); // run simulation frame, using palette colors
    
    FastLED.show(); // display this frame
    FastLED.delay(1000 / FRAMES_PER_SECOND);
  }
  

}

// Fire2012 by Mark Kriegsman, July 2012
// as part of "Five Elements" shown here: http://youtu.be/knWiGsmgycY
//
// COOLING: How much does the air cool as it rises?
// Less cooling = taller flames.  More cooling = shorter flames.
// Default 55, suggested range 20-100 
#define COOLING  55

// SPARKING: What chance (out of 255) is there that a new spark will be lit?
// Higher chance = more roaring fire.  Lower chance = more flickery fire.
// Default 120, suggested range 50-200.
#define SPARKING 120


void Fire2012WithPalette()
{
// Array of temperature readings at each simulation cell
  static byte heat[NUM_LEDS];

  // Step 1.  Cool down every cell a little
    for( int i = 0; i < NUM_LEDS; i++) { heat[i] = qsub8( heat[i], random8(0, ((COOLING * 10) / NUM_LEDS) + 2)); } // Step 2. Heat from each cell drifts 'up' and diffuses a little for( int k= NUM_LEDS - 1; k >= 2; k--) {
      heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2] ) / 3;
    }
    
    // Step 3.  Randomly ignite new 'sparks' of heat near the bottom
    if( random8() < SPARKING ) {
      int y = random8(7);
      heat[y] = qadd8( heat[y], random8(160,255) );
    }

    // Step 4.  Map from heat cells to LED colors
    for( int j = 0; j < NUM_LEDS; j++) {
      // Scale the heat value from 0-255 down to 0-240
      // for best results with color palettes.
      byte colorindex = scale8( heat[j], 240);
      CRGB color = ColorFromPalette( gPal, colorindex);
      int pixelnumber = j;
      
      leds[pixelnumber] = color;
    }
}
Series Navigation<< Wake-up light, part 1: casing

3 thoughts on “Wake-up light, part 2: patterns

Leave a Reply

Your email address will not be published. Required fields are marked *