#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));
}