jameslzhu
11/4/2017 - 5:59 PM

sunset.ino

#include<math.h>
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
  #include <avr/power.h>
#endif

#define LED_PIN 0
#define NUM_LEDS 60

#define BRIGHTNESS 127
#define MAX_TEMP 6600
#define MIN_TEMP 1000

#define TIMESTEP 5 // ms

Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800);

double t;

void setup() {
  // This is for Trinket 5V 16MHz
  #if defined (__AVR_ATtiny85__)
    if (F_CPU == 16000000) clock_prescale_set(clock_div_1);
  #endif
  // Clear LED strip
  strip.begin();
  strip.setBrightness(127);
  strip.show();

  t = 0.0;
}

void loop() {
  double sin_value = sin(t);
  
  int temp = lround(sin_value * sin_value * (MAX_TEMP - MIN_TEMP) + MIN_TEMP);

  uint32_t rgb = color(temp);

  setAllPixels(rgb);
  
  t += TIMESTEP / 1000.0;
  delay(TIMESTEP);
}

void setAllPixels(uint32_t rgb) {
  for (uint16_t i = 0; i < strip.numPixels(); i++) {
    strip.setPixelColor(i, rgb);
  }
  strip.show();
}

// Kelvin color curve
// based from http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/
// and http://www.zombieprototypes.com/?p=210
uint32_t color(int temp) {
  double red = 0;
  if (temp < 6600) {
    red = 255;
  } else {
    // a + b x + c Log[x] /.
    // {a -> 351.97690566805693`,
    // b -> 0.114206453784165`,
    // c -> -40.25366309332127
    //x -> (kelvin/100) - 55}
    red = temp / 100 - 55;
    red = 351.97690566805693 + 0.114206453784165 * red - 40.25366309332127 * log(red);
    if (red < 0) {
      red = 0;
    }
    if (red > 255) {
      red = 255;
    }
  }

  /* Calculate green */
  double green = 0;
  if (temp < 6600) {
    // a + b x + c Log[x] /.
    // {a -> -155.25485562709179`,
    // b -> -0.44596950469579133`,
    // c -> 104.49216199393888`,
    // x -> (kelvin/100) - 2}
    green = temp / 100 - 2;
    green = -155.25485562709179 - 0.44596950469579133 * green + 104.49216199393888 * log(green);
    if (green < 0) green = 0;
    if (green > 255) green = 255;

  } else {

    // a + b x + c Log[x] /.
    // {a -> 325.4494125711974`,
    // b -> 0.07943456536662342`,
    // c -> -28.0852963507957`,
    // x -> (kelvin/100) - 50}
    green = temp / 100 - 50;
    green = 325.4494125711974 + 0.07943456536662342 * green - 28.0852963507957 * log(green);
    if (green < 0) green = 0;
    if (green > 255) green = 255;

  }

  /* Calculate blue */
  double blue = 0;
  if (temp >= 6600) {
    blue = 255;
  } else {
    if (temp <= 2000) {
      blue = 0;
    } else {
      // a + b x + c Log[x] /.
      // {a -> -254.76935184120902`,
      // b -> 0.8274096064007395`,
      // c -> 115.67994401066147`,
      // x -> kelvin/100 - 10}
      blue = temp / 100 - 10;
      blue = -254.76935184120902 + 0.8274096064007395 * blue + 115.67994401066147 * log(blue);
      if (blue < 0) blue = 0;
      if (blue > 255) blue = 255;
    }
  }

  // Combine colors and return
  return strip.Color(lround(red), lround(green), lround(blue));
}