///Wake_Up_Light_V2 ///Written by Ryan @ RPDesigsn.ca ///December 6, 2017 ///This program will fade in a light over 45 min and keep the light on for approximately 15 minutes before turning out. ///The program communicates with an Android app via Bluetooth. The app can be used to control the LED brightness and set the time for the alarm. unsigned long previousMillis; //Last recorded amount of milliseconds unsigned long currentMillis; //Current amount of milliseconds since program began unsigned long offTime; //Length of time between on times - 1 day (86,400,000 ms). (Light will actually be off for offTime - onTime) unsigned long fadeTime; //Length of time light fades in unsigned long onTime; //Length of time light is on volatile unsigned int lightStatus; //0 is off, 1 is on, 2 is fading in unsigned char n; //used to calculate LED brightness unsigned char n1; //Duty cycle for LED1 unsigned char n2; //Duty cycle for LED2 unsigned char onOffPin; //Digital pin for opening/closing relay to operate LED driver unsigned char a2dPin; //Analog to Digital input pin volatile unsigned int a2d; //Average analog to digital value volatile unsigned int a2dArray[20]; //array to store analog to digital conversion values volatile unsigned int i,j; //index variables for loops const byte snoozePin = 2; //digital input pin to monitor when the switch is turned on or not volatile boolean lightSwitch = false; //boolean to monitor when switch is on or not const byte LED1PWM = 3; //pwm for LED 1 const byte LED2PWM = 6; //pwm for LED 2 volatile unsigned char BTdimOverride = 0; //Acts as a boolean. 0 is false, 1 is true unsigned char BTdimValue = 0; //Ranges from 0-100% unsigned char BTalarmSet = 0; //Acts as a boolean. 0 is false, 1 is true unsigned long BToffTime = 0; //Length of time until the light comes on unsigned char BTalarmHour = 0; //Hour of day that the alarm is set for, in 24hr clock format unsigned char BTalarmMinute = 0; //Minute that the alarm is set for unsigned char BTalarmBrightness = 50; //Ranges from 0-100% unsigned long switchOnTime; //variable to use for switch debouncing void setup() { pinMode(snoozePin,INPUT); //Initialize input for snooze button Serial.begin(9600); //Reset everything everytime the device is plugged in previousMillis = 0; currentMillis = 0; offTime = 86400000; //24 hours fadeTime = 2700000; //45 minutes onTime = 3600000; //60 minutes lightStatus = 0; n1 = 0; n2 = 0; a2dPin = A0; onOffPin = 5; pinMode(onOffPin,OUTPUT); digitalWrite(onOffPin, LOW); pinMode(LED1PWM,OUTPUT); analogWrite(LED1PWM, 0); pinMode(LED2PWM,OUTPUT); analogWrite(LED2PWM, 0); for(j=0; j<20; j++) { a2dArray[j] = 931; //max a2d values cause the LED to be off } } void loop() { currentMillis = millis(); while(Serial.available()) { //If the BT message starts with a "?", it is a request for the alarm set time. if(Serial.peek() == '?') { char x = Serial.read(); //clear anything extra from the buffer //Send the requested alarm time Serial.print(BTalarmSet), Serial.print("|"), Serial.print(BToffTime), Serial.print("|"), Serial.print(BTalarmHour), Serial.print("|"), Serial.println(BTalarmMinute); } //If the BT message starts with a '#', it is an LED dimmer value else if(Serial.peek() == '#') { BTdimOverride = 1; BTdimValue = Serial.parseInt(); char x = Serial.read(); //clear anything extra from the buffer } //If the BT message starts with a '$', it is an alarm brightness value else if(Serial.peek() == '$') { BTalarmBrightness = Serial.parseInt(); char x = Serial.read(); //clear anything extra from the buffer } //If BT message starts with a '!', it is in this format: BTdimOverride,BTdimValue,BTalarmSet,BToffTime,BTalarmHour,BTalarmMinute,BTalarmBrightness else if(Serial.peek() == '!') { //Parse the received data into variables BTdimOverride = Serial.parseInt(); if(BTalarmSet == 0) { BTalarmSet = Serial.parseInt(); if(BTalarmSet == 1) { previousMillis = currentMillis; //Set the previousMillis variable to restart the interval } } else { BTalarmSet = Serial.parseInt(); } BToffTime = Serial.parseInt(); offTime = BToffTime; //Variables to store the alarm time. Bluetooth can send a command to retrieve this value to display the set alarm time to user on phone. Save as HHMM BTalarmHour = Serial.parseInt(); BTalarmMinute = Serial.parseInt(); } else { char x = Serial.read(); } } //If BT becomes disconnected, reset BT dimmer override variables but keep alarm variables set if(!Serial) { BTdimOverride = 0; } /********************************* ALARM IS TURNED OFF **********************************************/ if(lightStatus == 0) { if(BTdimOverride == 1) { if(BTdimValue >= 50) { n1 = 130; //130 is an arbitrary number that would provide 100% LED brightness n2 = (BTdimValue - 50) * 127.5/50; } else { n2 = 0; //The following provides a smoother transition when switching between low brightness values if(BTdimValue <= 20) n1 = BTdimValue; else if(BTdimValue > 20 && BTdimValue <= 35) n1 = pow((BTdimValue - 21.0),1.51) + BTdimValue; else n1 = BTdimValue*127.5/50; if(n1 == 0) n1 = 1; } } else { a2dArray[i] = analogRead(a2dPin); //increments the index of the array storing a2d values if (i == 19) i = 0; else i++; a2d = 0; for(j=0; j<20; j++) { a2d += a2dArray[j]; } a2d = a2d/20; //Average the values in the array if(millis() - switchOnTime < 100) //a debounce mechanism for the switch { n1 = 1; } else { if(a2d <= 465) { n1 = 130; n2 = 127.5 - a2d/7.3*2.0; } else { n2 = 0; if(a2d >= 928) n1 = 1; else n1 = 127.5 - (a2d - 466.0)/7.3*2.0; } } //if the light switch is off, keep the PWM output to the LEDs low to prevent a flash when they first turn on if(lightSwitch == false) { a2dArray[i] = 931; n1 = 1; n2 = 0; } } if((digitalRead(snoozePin) == HIGH) && lightSwitch == false) //if the switch was off but has been turned on { lightSwitch = true; switchOnTime = millis(); } else if((digitalRead(snoozePin) == LOW) && lightSwitch == true) //if the switch was on but has been turned off { analogWrite(LED1PWM, 0); //Turn off LED1 analogWrite(LED2PWM, 0); //Turn off LED2 a2d = 931; for(j=0; j<20; j++) { a2dArray[j] = 931; } n1 = 0; n2 = 0; digitalWrite(onOffPin, LOW); //Turn off relay lightStatus = 0; BTdimOverride = 0; lightSwitch = false; } analogWrite(LED1PWM,n1); analogWrite(LED2PWM,n2); if(BTalarmSet == 1) //If the alarm is set, check if it's time for the light to turn on { //If millis() has not rolled over and 1 day has elapsed OR if millis() has rolled over back to zero and 1 day has elapsed if(((currentMillis > previousMillis) && (currentMillis - previousMillis >= offTime)) || ((currentMillis < previousMillis) && (currentMillis + (4294967295 - previousMillis) >= offTime))) { analogWrite(LED1PWM,1); //Reset PWM to a minimum value analogWrite(LED2PWM,0); //Reset PWM to 0 so light does not come on yet digitalWrite(onOffPin, HIGH); offTime = 86400000; //24 hours previousMillis = currentMillis; //Set the previousMillis variable to restart the interval delay(2000); //compensate for switch bouncing lightStatus = 2; //Set the light to begin fading in } } } /********************************* ALARM IS TURNED OFF **********************************************/ /********************************* LIGHT IS FADING IN ***********************************************/ if(lightStatus == 2) { if((digitalRead(snoozePin) == HIGH) && lightSwitch == false) //if the switch was off but has been turned on { lightSwitch = true; switchOnTime = millis(); } else if((digitalRead(snoozePin) == LOW) && lightSwitch == true) //if the switch was on but has been turned off { analogWrite(LED1PWM, 0); //Turn off LED1 analogWrite(LED2PWM, 0); //Turn off LED2 a2d = 931; for(j=0; j<20; j++) { a2dArray[j] = 931; } n1 = 0; n2 = 0; digitalWrite(onOffPin, LOW); //Turn off relay lightStatus = 0; BTdimOverride = 0; lightSwitch = false; } //If millis() HAS NOT rolled over if(currentMillis >= previousMillis) { //Between start time and fadeTime, increase brightness of LED by 1 every fadeTime/255 ms if(currentMillis - previousMillis <= fadeTime) { //Fade in. The value will not change everytime through, only when the math results in the next integer n = (currentMillis - previousMillis) / (fadeTime/255.0) * BTalarmBrightness/100.0; //n increases by 1 every ~10.5 sec when fadeTime = 45 min if(n > 127.5) { n1 = 130; n2 = (n - 127.5); } else { n1 = n; n2 = 0; } if(n1 == 0) n1 = 1; analogWrite(LED1PWM, n1); analogWrite(LED2PWM, n2); } else //After the fadeTime, keep LED fully on { analogWrite(LED1PWM,130 * BTalarmBrightness/100.0); analogWrite(LED2PWM,130 * BTalarmBrightness/100.0); lightStatus = 1; } } //If millis() HAS rolled over if(currentMillis < previousMillis) { //Between start time and fadeTime, increase brightness of LED by 1 every fadeTime/130 ms if(currentMillis + (4294967295 - previousMillis) <= fadeTime) { //Fade in LED over fadeTime n = (currentMillis + (4294967295 - previousMillis)) / (fadeTime/255.0); if(n > 127.5) { n1 = 130; n2 = (n - 127.5); } else { n1 = n; n2 = 0; } analogWrite(LED1PWM, n1); analogWrite(LED2PWM, n2); } else //After the fadeTime, keep LED fully on { analogWrite(LED1PWM,130 * BTalarmBrightness/100.0); analogWrite(LED2PWM,130 * BTalarmBrightness/100.0); lightStatus = 1; } } } /********************************* LIGHT IS FADING IN ***********************************************/ /********************************* LIGHT IS ON ******************************************************/ if(lightStatus == 1) { if((digitalRead(snoozePin) == HIGH) && lightSwitch == false) //if the switch was off but has been turned on { lightSwitch = true; switchOnTime = millis(); } else if((digitalRead(snoozePin) == LOW) && lightSwitch == true) //if the switch was on but has been turned off { analogWrite(LED1PWM, 0); //Turn off LED1 analogWrite(LED2PWM, 0); //Turn off LED2 a2d = 931; for(j=0; j<20; j++) { a2dArray[j] = 931; } n1 = 0; n2 = 0; digitalWrite(onOffPin, LOW); //Turn off relay lightStatus = 0; BTdimOverride = 0; lightSwitch = false; } //if light is ON and if millis() has not rolled over and onTime has elapsed OR if millis() has rolled over back to zero and onTime has elapsed if(((currentMillis > previousMillis) && (currentMillis - previousMillis >= onTime)) || ((currentMillis < previousMillis) && (currentMillis + (4294967295 - previousMillis) >= onTime))) { //Turn off the light digitalWrite(onOffPin, LOW); //Turn off LED relay analogWrite(LED1PWM, 0); analogWrite(LED2PWM, 0); lightStatus = 0; } } /********************************* LIGHT IS ON ******************************************************/ }