Skip to content

Instantly share code, notes, and snippets.

Created February 7, 2018 15:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/1aa31949462b45e7c985ca19c75708db to your computer and use it in GitHub Desktop.
Save anonymous/1aa31949462b45e7c985ca19c75708db to your computer and use it in GitHub Desktop.
/////////////////////// INCLUDES ///////////////////////////////////
#include <IRremote.h>
#include <EEPROM.h>
// Load RTC Date/Time
#include <Wire.h> // must be included here so that Arduino library object file references work
#include <RtcDS3231.h>
RtcDateTime now; // time provided by RTC
RtcDS3231<TwoWire> Rtc(Wire);
// set up irReciever
const int irReceiverPin = 12;
IRrecv irrecv(irReceiverPin);
decode_results results;
/////////////////////// VARIABLES ///////////////////////////////////
// IMPORTANT REMINDER !!!
// irReciever runs on Timer 1, blocking PWM on pins 3 and 11
//
// This will produce stange colors if you use pins 3 and 11
// Pin 6 is Timer 0 which is shared with the main timer loop,
// which can be flickery when using PWM at times. As we use
// less blues then reds and greens, this is set up to use
// Timer 2 for Red and Green and Timer 0 for Blue. Think twice
// before swaping around these pins.
// LED pins
int rLED = 9;
int gLED = 10;
int bLED = 6;
// last remote code (needs to be an unsigned long
unsigned long remoteCode = 0;
///////////////// TEMPERATURE and BRIGHTNESS OF COLOR
// Color Temperature, In Kelvin
// unsigned long needed for very cold, very blue light temperatures,
// e.g. above 32,700 kelvin (we can do that even if those colors are mostly theortical!)
unsigned long temp = 1800;
// Brightness (0 to 100%)
int bright = 0;
// Saturation for Hue Function (0 to 255 fully)
int saturation = 255;
// Hue for Hue Function (0 to 360)
int hue = 0;
// use int rather then byte, because sometimes the code accidnetially goes negative
int red = 0;
int green = 0;
int blue = 0;
//// bedTime and riseAndShine modes
bool bedTime = false;
bool riseAndShine = false;
//////////////// TIMERS FOR THE LOOP
// Time of Last Loop
unsigned long prevMS = 0;
// Time of Last Button Press
unsigned long buttonMS = 0;
////////////// SPECIAL MODES (e.g. time delay dimming for sleep or rise)
// special mode version -- default is 99 which is off.
int specialMode = 99;
// time elapsed in special mode
unsigned long specialModeMS = 0;
// time elapsed in special mode LOOP
unsigned long specialModeMSLoop = 0;
// what task number are we on in specialMode
int specialModeTK = 1;
unsigned long eepromLastWrite = 0;
/////////////////////// FUNCTIONS ///////////////////////////////////
// Kelvin to RGB Code is roughly based on this javascript that I re-wrote in C#
// http://www.tannerhelland.com/4435/convert-temperature-rgb-algorithm-code/
// unsigned long needed for very cold, very blue light temperatures,
// e.g. above 32,700 kelvin (we can do that even if those colors are mostly theortical!)
// float used for brightness so to avoid truncation of percent
void kRGB (unsigned long kelvin = temp, float brightness = bright) {
int t = kelvin / 100;
if(t <= 66 ){
red = 255;
green = t;
green = 99.4708025861 * log(green) - 161.1195681661;
if( t <= 19){
blue = 0;
}
else {
blue = t-10;
blue = 138.5177312231 * log(blue) - 305.0447927307;
}
}
else if (t < 320) {
red = t - 60;
red = 329.698727446 * pow(red, -0.1332047592);
green = t - 60;
green = 288.1221695283 * pow(green, -0.0755148492 );
blue = 255;
}
else {
// this is mostly made up, just testing
// as original code doesn't look at imaginary colors
// beyond about 32,000 kelvin
// this will create negative numbers at times
// but setColor will just zero out the channels
blue = 255;
red = t - 255;
green = t - 255;
}
// safety values for brightness
if (brightness > 100) {
bright = 100;
brightness = 100;
}
if (brightness < 0) {
bright = 0;
brightness = 0;
}
// dim based on brightness value
red = (int) round(red * (brightness/100));
blue = (int) round(blue * (brightness/100));
green = (int) round(green * (brightness/100));
// safety values for colors
if (red < 0) red = 0;
if (green < 0) green = 0;
if (blue < 0) blue = 0;
if (red > 255) red = 255;
if (blue > 255) blue = 255;
if (green > 255) green = 255;
// set LED outputs
analogWrite(rLED, red);
analogWrite(gLED, green);
analogWrite(bLED, blue);
// debugging output
Serial.print("kelvin=");
Serial.print(kelvin);
Serial.print(", bright=");
Serial.print(bright);
Serial.print(", r=");
Serial.print(red);
Serial.print(", g=");
Serial.print(green);
Serial.print(", b=");
Serial.print(blue);
Serial.print("\n");
}
// set color by hue, brightness, saturation
void hueColor() {
if (saturation == 0) {
// achromatic (grey)
red = green = blue = bright;
}
else
{
unsigned int scaledHue = (hue * 6);
unsigned int sector = scaledHue >> 8; // sector 0 to 5 around the color wheel
unsigned int offsetInSector = scaledHue - (sector << 8); // position within the sector
unsigned int p = (bright * ( 255 - saturation )) >> 8;
unsigned int q = (bright * ( 255 - ((saturation * offsetInSector) >> 8) )) >> 8;
unsigned int t = (bright * ( 255 - ((saturation * ( 255 - offsetInSector )) >> 8) )) >> 8;
switch( sector ) {
case 0:
red = bright;
green = t;
blue = p;
break;
case 1:
red = q;
green = bright;
blue = p;
break;
case 2:
red = p;
green = bright;
blue = t;
break;
case 3:
red = p;
green = q;
blue = bright;
break;
case 4:
red = t;
green = p;
blue = bright;
break;
default: // case 5:
red = bright;
green = p;
blue = q;
break;
}
}
// set LED outputs
analogWrite(rLED, red);
analogWrite(gLED, green);
analogWrite(bLED, blue);
// debugging output
Serial.print("hue=");
Serial.print(hue);
Serial.print(", saturation=");
Serial.print(saturation);
Serial.print(", bright=");
Serial.print(bright);
Serial.print(", r=");
Serial.print(red);
Serial.print(", g=");
Serial.print(green);
Serial.print(", b=");
Serial.print(blue);
Serial.print("\n");
}
// manual color settings
// change red, green, blue before running this function
void setColor () {
// set LED outputs
analogWrite(rLED, red);
analogWrite(gLED, green);
analogWrite(bLED, blue);
// debugging output
Serial.print("manual color setting");
Serial.print(", r=");
Serial.print(red);
Serial.print(", g=");
Serial.print(green);
Serial.print(", b=");
Serial.print(blue);
Serial.print("\n");
}
// Setup Function
void setup() {
// for debugging
Serial.begin(9600);
// load IR pin
irrecv.enableIRIn();
// load pin
pinMode(rLED, OUTPUT);
pinMode(gLED, OUTPUT);
pinMode(bLED, OUTPUT);
// load initial RTC data
Rtc.Begin();
now = Rtc.GetDateTime();
// upon boot (due to power failure), load data from EEPROM
int eeAddress = 0;
EEPROM.get(eeAddress,bright);
eeAddress += sizeof(int);
EEPROM.get(eeAddress,temp);
kRGB();
}
// Loop cycles through the colors
void loop() {
// every 30 seconds write the latest brightness/temperature to eeprom
// don't do this every loop because otherwise we would use up memory lifespan
// by doing this too frequently, especially during dim or brighten
if (millis() - eepromLastWrite >= 30000) {
storeTempEEPROM();
eepromLastWrite = millis();
// also is it time to head to bed or rise and shine?
now = Rtc.GetDateTime();
// Is it 6:54 AM and is the Day of Week Monday = 1 through Friday = 5 ? And Not Already Sunset or Sunsrise
if (now.Hour() == 6 && now.Minute() == 54 && now.DayOfWeek() > 0 && now.DayOfWeek() < 6 && specialMode == 0 && bright == 0) {
remoteCode = 1976685926; // reverse button
}
// Is it 10:30 PM and is the Day of Week Sunday = 0 through Thursday = 4 ? And Not Already Sunset or Sunsrise
if (now.Hour() == 22 && now.Minute() == 30 && now.DayOfWeek() < 5 && specialMode == 0 && bright != 0) {
remoteCode = 3980777284; // forward button
}
// At the top of the hour, blink
if ( now.Minute() == 0 && specialMode == 0) {
specialMode = 8;
}
else if (now.Minute() == 0 && specialMode == 99) {
specialMode = 99; // blink once, do nothing really ..
}
else {
specialMode = 0;
}
}
// check to see if any mode requests have come in
// DELAY is to prevent button bounce
// from somebody holding the button too long
if (millis() - buttonMS >= 500 && irrecv.decode(&results)) {
Serial.println(results.value);
irrecv.resume(); // Receive the next value
remoteCode = results.value;
buttonMS = millis();
}
// every half a second see if user
// has requested any changes
if (millis() - prevMS >= 500) {
// if any remote codes are hit, interrupt any special modes
// reset to default modes before taking next option
if (remoteCode && specialMode) {
specialMode = 0;
specialModeMS = 0;
specialModeTK = 1;
//kRGB(2700,100);
}
// turn light string on or off
if (remoteCode == 4105841032) {
/*
if (bright == 0 || red == 0) {
while (bright < 100) {
bright++;
kRGB();
}
specialMode = 0;
Serial.print("on button activated");
}
else {*/
while (bright > 0) {
bright--;
kRGB();
}
red = 0; green = 0; blue = 0;
setColor();
Serial.print("off button activated");
delay(1500);
//}
}
// lower or raise the brightness
if (remoteCode == 2209452902 ) {
bright -= 3;
//
kRGB();
Serial.print("dim button activated");
}
if (remoteCode == 1752382022) {
bright += 3;
kRGB();
Serial.print("bright button activated");
}
// warm or chill the color temperature
// above 3500 kelvin we make bigger steps
if (remoteCode == 1595074756) {
if (temp < 3000) {
temp += 100;
}
else if (temp < 3500) {
temp += 200;
}
else {
temp += 700;
}
kRGB();
Serial.print("cool button activated");
}
if (remoteCode == 412973352) {
if (temp > 3500) {
temp -= 700;
}
else if (temp > 3000) {
temp -= 200;
}
else if (temp > 100) {
temp -= 100;
}
kRGB();
Serial.print("warm button activated");
}
// color temperature pre-sets
if (remoteCode == 3778927144) {
temp = 500;
kRGB();
Serial.print("one button activated");
}
if (remoteCode == 2908251746) {
temp = 750;
kRGB();
Serial.print("two button activated");
}
if (remoteCode == 657459652) {
temp = 1000;
kRGB();
Serial.print("three button activated");
}
if (remoteCode == 4120482440) {
temp = 1500;
kRGB();
Serial.print("four button activated");
}
if (remoteCode == 1931099650) {
temp = 2000;
kRGB();
Serial.print("five button activated");
}
if (remoteCode == 742730860) {
temp = 2500;
kRGB();
}
if (remoteCode == 1167253836) {
temp = 3000;
kRGB();
Serial.print("seven button activated");
}
if (remoteCode == 1747313982) {
temp = 6000;
kRGB();
Serial.print("eight button activated");
}
if (remoteCode == 2340753640) {
temp = 10000;
kRGB();
Serial.print("nine button activated");
}
if (remoteCode == 3119867746) {
// temp = 5000;
// bright = 100;
while (bright < 100) {
bright++;
kRGB();
}
Serial.print("zero button activated");
}
////////// special modes ////////////
if (remoteCode == 1976685926) {
// special mode 1 - Sunset
specialMode = 1;
specialModeMS = millis();
specialModeTK = 1;
// start as 50% dim, warm yellow light
temp = 1200;
bright = 50;
kRGB();
Serial.print("back button activated");
}
if (remoteCode == 3980777284) {
// special mode 2 - Sunrise
specialMode = 2;
specialModeMS = millis();
specialModeMSLoop = millis();
specialModeTK = 1;
temp = 500;
bright = 20;
kRGB();
Serial.print("forward button activated");
}
if (remoteCode == 1784778242) {
// special mode 3 - Sunset then eight hours later, sunrise
specialMode = 3;
specialModeMS = millis();
specialModeTK = 1;
// start as 50% dim, warm yellow light for the sunset mode
temp = 1200;
bright = 50;
kRGB();
Serial.print("play button activated");
}
if (remoteCode == 3361986248) {
// special mode 4 - Sunset then nine hours later, sunrise
specialMode = 4;
specialModeMS = millis();
specialModeTK = 1;
// start as 40% dim, warm yellow light for the sunset mode
temp = 1200;
bright = 50;
kRGB();
Serial.print("stop button activated");
}
if (remoteCode == 3398220998) {
red = 255;
blue = 255;
green = 0;
setColor();
/*
* holiday season over, disabled
// special mode 5 - Chistmas Colors
specialMode = 5;
specialModeMS = millis();
// start as black
red = 0;
green = 0;
blue = 0;
setColor();
Serial.print("go back button activated");
*/
}
if (remoteCode == 3459683302) {
// special mode 6 - Red, Blue, White Colors blink
specialMode = 6;
specialModeMS = millis();
// start as black
red = 0;
green = 0;
blue = 0;
setColor();
Serial.print("dash button activated");
}
if (remoteCode == 2331063592) {
// special mode 7 - rainbowGo button hit
specialMode = 7;
specialModeMS = millis();
hue = 0;
saturation = 255;
// leave brightness alone, let that be adjusted manually
Serial.print("go button activated");
}
// reset remote code to zero to avoid repeating
// the action and rest the loop timer to zero
remoteCode = 0;
prevMS = millis();
}
/////////// this section is for special timer modes ////////////////////////
if (specialMode == 1 || (specialMode == 3 && millis() - specialModeMS < 10L * 60 * 1000) ||
(specialMode == 4 && millis() - specialModeMS < 10L * 60 * 1000) ) {
// Task 1 for Special Mode 1
// Task 1 for Special Mode 3, 4 (first ten minutes)
//
// Special Mode 1 - Sunset Mode
// Special Mode 2 - Sunset Mode; See Below for Sunrise
//
// oranges and reds, lights fade out to black in 5 minutes
// 50 cycles * 10 seconds = 5 minutes
// initial color set above in "play button activated section"
if (millis() - specialModeMSLoop > 5L * 1000) {
if (bright > 0) {
// fifty cycles
// reduce color temperature by 10 degrees kelvin
// from 1000k to 500k to make a nice warm temperature
temp -= 10;
// reduce from 50 brightness to 0 brightness
// then shut off the unit
bright -= 1;
kRGB();
}
else {
// we are done, make sure fully off
bright = 0;
kRGB();
}
specialModeMSLoop = millis(); // reset LOOP timer
}
}
if (specialMode == 2 || (specialMode == 3 && millis() - specialModeMS > 8L * 60 * 60 * 1000) ||
(specialMode == 4 && millis() - specialModeMS > 9L * 60 * 60 * 1000)) {
// Task 1 for Special Mode 2
// Task 2 for Special Mode 3 (eight hours later)
// Task 2 for Special Mode 4 (nine hours later)
//
// Special Mode 2 - Sunrise Mode
// Special Mode 3 and Special Mode 4, Task 2 - Sunrise in the Morning Mode
//
// 500 kelvin light driven at 20%, incremented 100 kelvin for 95 times
// to bring us up to 9,900 kelvin at 100% brightness
//
// Once we reach 10,000 kelvin, we pull up the blue channel (bC) at a rate of
// 10/256th or 4% each ten seconds until we reach 255 (full brightness).
//
// Then to reach full brightness, which is less blue and more light
// we pull up the red (rC) and green chanels at a rate of
// 10/256th or 4% each ten seconds until we reach 255 (full brightness all channels).
//
// 95 cycles * 6 seconds = 570 seconds or 9 1/2 minutes to
// full brightness
// initial color set above in "play button activated section"
if (millis() - specialModeMSLoop > 6L * 1000) {
if (temp < 10000) {
// keep increasing color until we reach 10,000 kelvin, very blue
temp += 100;
// increase up to 100%
if (bright < 100) {
bright++;
}
else {
bright = 100;
}
kRGB();
}
else {
/*
if (blue < 255) {
blue++;
}
setColor();*/
}
specialModeMSLoop = millis();
}
}
if (specialMode == 5) {
// delightful christmas color fade red to white to green
// seasons greetings!
// we just use the sluggish microprocess to limit speed here
if (red >= 0 && red < 255 && blue == 0 && green == 0) red++;
if (red == 255 && blue < 255) { blue++; green++; }
if (red && blue == red) { blue--; red--; }
if (red == 0 && green != 0) { green--; }
setColor();
}
if (specialMode == 6) {
/*
// blinky christmas mode, more festive and obnoxious!
if (millis() - specialModeMS > 200) {
if (red == 0 && blue == 0 && green == 0) { red = 127; blue = 0; green = 0; }
else if (red == 127 && blue == 0 && green == 0) { red = 255; blue = 0; green = 0; }
else if (red == 255 && blue == 0 && green == 0) { red = 255; blue = 127; green = 127; }
else if (red == 255 && blue == 0 && green == 0) { red = 255; blue = 127; green = 127; }
else if (red == 255 && blue == 127 && green == 127) { red = 255; blue = 255; green = 255; }
else if (red == 255 && blue == 255 && green == 255) { red = 127; blue = 127; green = 255; }
else if (red == 127 && blue == 127 && green == 255) { red = 0; blue = 0; green = 255; }
else if (red == 0 && blue == 0 && green == 255) { red = 0; blue = 0; green = 127; }
else { red = 127; blue = 0; green = 0; }
setColor();
specialModeMS = millis();
}
*/
// blinky patrotic mode, more festive and obnoxious!
if (millis() - specialModeMS > 200) {
if (red == 0 && blue == 0 && green == 0) { red = 127; blue = 0; green = 0; }
else if (red == 127 && blue == 0 && green == 0) { red = 255; blue = 0; green = 0; }
else if (red == 255 && blue == 0 && green == 0) { red = 255; blue = 127; green = 127; }
else if (red == 255 && blue == 0 && green == 0) { red = 255; blue = 127; green = 127; }
else if (red == 255 && blue == 127 && green == 127) { red = 255; blue = 255; green = 255; }
else if (red == 255 && blue == 255 && green == 255) { red = 127; blue = 255; green = 127; }
else if (red == 127 && blue == 255 && green == 127) { red = 0; blue = 255; green = 0; }
else if (red == 0 && blue == 255 && green == 0) { red = 0; blue = 127; green = 0; }
else { red = 127; blue = 0; green = 0; }
setColor();
specialModeMS = millis();
}
}
if (specialMode == 7) {
// hue changing mode
//if (millis() - specialModeMS > 200) {
if (hue < 360) {
hue++;
}
else {
hue = 0;
}
saturation = 255;
bright = 100;
hueColor();
// specialModeMS = millis();
//}
}
if (specialMode == 8) {
// At the top of the hour briefly shut off, go bright
// then restore to current brightness
uint8_t i = bright;
bright = 10;
kRGB();
delay(500);
bright = 100;
kRGB();
delay(500);
bright = i;
kRGB();
specialMode = 99; // blink once, prevent this from loading over and over again
}
}
// store color temperature and brightness in eprom in case of power reset
// by using the update feature, it only writes when the data changes
void storeTempEEPROM() {
int eeAddress = 0;
EEPROM.put(eeAddress, bright);
eeAddress += sizeof(int);
EEPROM.put(eeAddress, temp);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment