Natural Reef Aquarium Lighting Controller

This section of the code was replaced by the followoing variables so it can be unique for each string;

PHP:
float BlueFull[]            =       {25, 25};          // Value in degrees (sun angle) that each Blue string will be at max output
float WhiteFull[]           =       {37.5, 37.5};      // Value in degrees (sun angle) that each White string will be at max output
float UVFull[]              =       {30};              // Value in degrees (sun angle) that each UV string will be at max output

I will remove the fullSun variable from my future releases.

Hi!
I just wonder if the first line "//float fullSun...." should be comment out? I see that in the earlier version you have made that line i comment out.
Maybe thats the reason why I have problem with the code.

//Patrik
 
I think I might have a fix for the light going to 100% before and after the light cycle.

Please let me know if this works.

PHP:
// Natural Reef Aquarium Lighting V2.4
// 16/06/2013
// Developed by J. Harp (nUm - RTAW Forums, Numlock10 - Reef Central Forums)
// Formulas based off of information from NOAA website for sunrise / sunset times.
// Includes Lunar Simulation.
// Compiled in Arduino 1.5.2
//
// Testing;
// Additonal colour channels
// Unique "fullsun" values for each string
// Fix for 100% power on light start and light stop
//
// Future Development:
// Weather Simulation
//
// Please feel free to use this and modify as you see fit, if you have any comments or suggestions please let me know via messages on the forums listed above.
//

#include <math.h>
#include <Wire.h>
#define DS1307_I2C_ADDRESS 0x68

// RTC variables
byte second, rtcMins, oldMins, rtcHrs, oldHrs, dayOfWeek, dayOfMonth, month, year, psecond;

// LED variables (Change to match your needs)
byte bluePins[]      =  {3, 9};      // PWM pins for blues
byte whitePins[]     =  {10, 11};    // PWM pins for whites
byte uvPins[]        =  {5};         // PWM pins for UVs
byte moonPins[]      =  {6};            // PWM pins for moonlights

byte blueChannels    =        2;    // how many PWMs for blues (count from above)
byte whiteChannels   =        2;    // how many PWMs for whites (count from above)
byte uvChannels      =        1;    // how many PWMs for uv (count from above)
byte moonChannels    =        1;    // how many PWMs from moon (count from above)

byte BluePWMHigh[]          =       {255, 255};        // High value for Blue PWM each vale is for each string - if your values are noraml this is 255, if your values are inverted this is 0
byte BluePWMLow[]           =       {0, 0};            // Low value for Blue PWM - if your values are noraml this is 0, if your values are inverted this is 255
float BlueFull[]            =       {25, 25};          // Value in degrees (sun angle) that each Blue string will be at max output
byte WhitePWMHigh[]         =       {255, 255};        // High value for White PWM - if your values are noraml this is 255, if your values are inverted this is 0
byte WhitePWMLow[]          =       {0, 0};            // Low value for White PWM - if your values are noraml this is 0, if your values are inverted this is 255
float WhiteFull[]           =       {37.5, 37.5};      // Value in degrees (sun angle) that each White string will be at max output
byte UVPWMHigh[]            =       {255};             // High value for UV PWM - if your values are noraml this is 255, if your values are inverted this is 0
byte UVPWMLow[]             =       {0};               // Low value for UV PWM - if your values are noraml this is 0, if your values are inverted this is 255
float UVFull[]              =       {30};              // Value in degrees (sun angle) that each UV string will be at max output
byte MoonPWMHigh[]          =       {255};             // High value for Moon PWM - if your values are noraml this is 255, if your values are inverted this is 0
byte MoonPWMLow[]           =       {0};               // Low value for Moon PWM - if your values are noraml this is 0, if your values are inverted this is 255

// Set for the location of the world you want to replicate.

float latitude = -19.770621;   // + to N  Defualt - (-19.770621) Heart Reef, Great Barrier Reef, QLD, Australia 
float longitude = 149.238532;  // + to E  Defualt - (149.238532)
int TimeZone = 10;             // + to E  Defulat - (10)

// Julian Century Varaiable

float JC;

// Sunlight Variables

//float fullSun = 37.5;  // sun elevation in deg that we will assume full sunlight values (Larger = more sunlight)
int delayTime = 0;     // start time delay in minutes,  - will push the day back, + will bring the day forward


int SunLight (byte _ledPin, byte _ledHigh, byte _ledLow, float _fullSun, byte _year, byte _month, byte _day, byte _hour, byte _min, byte _sec)
{
  float a = floor((14 - _month)/12);
  float y = _year + 4800 - a;
  float m = _month + (12 * a) - 3;
  float AH;
  int result;
  
  JC = (((_day + floor(((153.0 * m) + 2.0) / 5.0) + (365.0 * y) + floor(y / 4.0) - floor(y / 100.0) + floor(y / 400.0) - 32045.0) + ((_hour / 24.0) + (_min / 1444.0) + (_sec / 86400.0))) - 2451556.08) / 36525.0;
  
  float GMLS = fmod(280.46646+JC*(36000.76983 + JC * 0.0003032),360);
  
  float GMAS = 357.52911 + JC * (35999.05029 - 0.0001537 * JC);
  
  float EEO = 0.016708634 - JC * (0.000042037 + 0.0000001267 * JC);
  
  float SEoC = sin((GMAS * M_PI)/180)*(1.914602 - JC * (0.004817 + 0.000014 * JC)) + sin(((2 * GMAS) * M_PI) / 180) * (0.019993 - 0.000101 * JC) + sin(((3 * JC) * M_PI) / 180) * 0.000289;
  
  float STL = GMLS + SEoC;
  
  float STA = GMAS + SEoC;
  
  float SRV = (1.000001018 * (1 - EEO * EEO)) / (1 + EEO * cos((STA * M_PI) / 180));
  
  float SAL = STL - 0.00569 - 0.00478 * sin(((125.04 - 1934.136 * JC) * M_PI) / 180);
  
  float MOE = 23 + (26 + ((21.448 - JC * (46.815 + JC * (0.00059 - JC * 0.001813)))) / 60) / 60;
  
  float OC = MOE + 0.00256 * cos(((215.04 - 1934.136 * JC) * M_PI) / 180);
  
  float SD = (asin(sin((OC * M_PI) / 180) * sin((SAL * M_PI) / 180))) * (180 / M_PI);
  
  float vy = tan(((OC / 2) * M_PI) / 180) * tan(((OC / 2) * M_PI) / 180);
  
  float EQoT = (4 * (vy * (sin(2 * ((GMLS * M_PI) / 180)) - 2 * EEO * sin((GMAS * M_PI) / 180) + 4 * EEO * vy * sin((GMAS * M_PI) / 180) * cos( 2 * ((GMLS * M_PI) / 180)) - 0.5 * vy * vy * sin(4 * ((GMLS * M_PI) / 180)) - 1.25 * EEO * EEO * sin(2 * ((GMAS * M_PI) / 180))))) * (180 / M_PI);
  
  float HAS = acos(cos((90.833 * M_PI) / 180) / (cos((latitude * M_PI) / 180) * cos((SD * M_PI) / 180)) - tan((latitude * M_PI) / 180) * tan((SD * M_PI) / 180)) * (180 / M_PI);

  float SN = (720 - 4 * longitude - EQoT + TimeZone * 60);

  float SR = SN - HAS * 4;

  float SS = SN + HAS * 4;
 
  float STD = 8 * HAS;
  
  float TST = fmod((((_hour) + (_min / 60.0) + (_sec / 3600.0)) / 24.0)*1440 + EQoT + 4 * longitude - 60 * TimeZone,1440)+delayTime;
 
  if (TST / 4 < 0)
  {
  AH = ((TST / 4.0) + 180);
  }
  else
  {
  AH = ((TST / 4.0) - 180);  
  }
  
  float SZA = (acos(sin((latitude * M_PI) / 180) * sin((SD * M_PI) / 180) + cos((latitude * M_PI) / 180) * cos((SD * M_PI) / 180) * cos((AH * M_PI) / 180))) * (180 / M_PI);
  
  int SEA = 90 - SZA;
  
  if (SEA <= 0)  
  {
   result = _ledLow;    
  }
  
  if (SEA > 0 && SEA < _fullSun)
  {
  result = map(SEA,0,_fullSun,_ledLow,_ledHigh);
  }
  
  if (SEA >= _fullSun)  
  {
  result = _ledHigh;
  }
  
  analogWrite(_ledPin, result);  
  return result;
  
}

int MoonLight (float JC, byte _ledPin, byte _ledHigh, byte _ledLow)
{
 int result;
 
 float MS = fmod((2456318.69458333 - JC),29.530589);
 
 if(MS <= 14.7518)
 {
  result = map(MS,0,14.7518,_ledLow,_ledHigh);
 }
 
 if( MS > 14.7518)
 {
   result = map(MS,14.7518,29.530589,_ledHigh,_ledLow);
 }
 analogWrite(_ledPin, result); 
 return result;
}
 

/***** RTC Functions *******/
/***************************/
// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
  return ( (val/10*16) + (val%10) );
}

// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return ( (val/16*10) + (val%16) );
}

// Gets the date and time from the ds1307
void getDateDs1307(byte *second,
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
byte *year)
{
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write(0);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_I2C_ADDRESS, 7);

  *second     = bcdToDec(Wire.read() & 0x7f);
  *minute     = bcdToDec(Wire.read());
  *hour       = bcdToDec(Wire.read() & 0x3f);
  *dayOfWeek  = bcdToDec(Wire.read());
  *dayOfMonth = bcdToDec(Wire.read());
  *month      = bcdToDec(Wire.read());
  *year       = bcdToDec(Wire.read());
}

void setup() {
delay(500);
Serial.begin(57600);
Wire.begin();
}

void loop() {
  getDateDs1307(&second, &rtcMins, &rtcHrs, &dayOfWeek, &dayOfMonth, &month, &year);
  if (psecond != second){
    psecond = second;
  Serial.print(rtcHrs);
  Serial.print(":");
  Serial.print(rtcMins);
  Serial.print(":");
  Serial.print(second);
  Serial.print(" ");
  Serial.print(dayOfMonth);
  Serial.print("/");
  Serial.print(month);
  Serial.print("/");
  Serial.println(year);
  update_leds();
  }
}

void update_leds ( void ){
  int i;
  byte value;
  int MS;
  Serial.println("Blue LED's");
  for (i = 0; i < blueChannels; i++)
  {
    value = SunLight(bluePins[i],BluePWMHigh[i],BluePWMLow[i],BlueFull[i],year,month,dayOfMonth,rtcHrs,rtcMins,second);
    Serial.print(map(value,BluePWMLow[i],BluePWMHigh[i],0,100));
    Serial.print("% ");
  }
  Serial.println();
  Serial.println("White LED's");
  for (i = 0; i < whiteChannels; i++)
  {
    value = SunLight(whitePins[i],WhitePWMHigh[i],WhitePWMLow[i],WhiteFull[i],year,month,dayOfMonth,rtcHrs,rtcMins,second);
    Serial.print(map(value,WhitePWMLow[i],WhitePWMHigh[i],0,100));
    Serial.print("% ");
  }
  Serial.println();
  Serial.println("UV LED's");
  for (i = 0; i < uvChannels; i++)
  {
    value = SunLight(uvPins[i],UVPWMHigh[i],UVPWMLow[i],UVFull[i],year,month,dayOfMonth,rtcHrs,rtcMins,second);
    Serial.print(map(value,UVPWMLow[i],UVPWMHigh[i],0,100));
    Serial.print("% ");
  }
  Serial.println();
  Serial.println("Moon Value");
  for (i = 0; i < moonChannels; i ++)
  {
  MS = MoonLight(JC, moonPins[i],MoonPWMHigh[i],MoonPWMLow[i]);
  Serial.println(MS);
  Serial.print(map(MS,MoonPWMLow[i],MoonPWMHigh[i],0,100));
  Serial.print("% ");
  }
  Serial.println();
}

Great! I will try when I get home from work. Only 8 hours left.....

//Patrik
 
Hi Jason!
Just wanted to tell you that the code seems to work!!!!! The sunset did work as it should. Don't know about the sunrise but I guess it will work also (I will check on saturday when I'm home)

So, a big thank you for your code and support. It's great!

Now, I only got one more question and it's problably very stupid but I ask anyway (nobody knows me anyway.:crazy1:) Lets say I have 2 string of 445nm leds 1 string of 465nm leds. and they are powered by 3 meanwell ldd 1000h driver (one for each string). I will use pwm pin 6 and 9 and every led should be power by 100%. Now, should the code look like this below:

PHP:
[CODE]byte bluePins[]      =  {6, 9};      // PWM pins for blues


byte blueChannels    =        2;    // how many PWMs for blues (count from above)


byte BluePWMHigh[]          =       {255, 255, 255};        // High value for Blue PWM each vale is for each string - if your values are noraml this is 255, if your values are inverted this is 0
byte BluePWMLow[]           =       {0, 0, 0};            // Low value for Blue PWM - if your values are noraml this is 0, if your values are inverted this is 255
float BlueFull[]            =       {25, 25, 25};          // Value in degrees (sun angle) that each Blue string will be at max output [/CODE]
 
That depends on if you plan to run 2 of the 3 channels on the same pin.

If that is the case then you need somthing like this;

PHP:
byte bluePins[]      =  {6, 9};      // PWM pins for blues 


byte blueChannels    =        2;    // how many PWMs for blues (count from above) 


byte BluePWMHigh[]          =       {255, 255};        // High value for Blue PWM each vale is for each string - if your values are noraml this is 255, if your values are inverted this is 0 
byte BluePWMLow[]           =       {0, 0};            // Low value for Blue PWM - if your values are noraml this is 0, if your values are inverted this is 255 
float BlueFull[]            =       {25, 25};          // Value in degrees (sun angle) that each Blue string will be at max output

If you want all 3 on different pins then you need;

PHP:
byte bluePins[]      =  {6, 9, another pin #};      // PWM pins for blues 


byte blueChannels    =        3;    // how many PWMs for blues (count from above) 


byte BluePWMHigh[]          =       {255, 255, 255};        // High value for Blue PWM each vale is for each string - if your values are noraml this is 255, if your values are inverted this is 0 
byte BluePWMLow[]           =       {0, 0, 0};            // Low value for Blue PWM - if your values are noraml this is 0, if your values are inverted this is 255 
float BlueFull[]            =       {25, 25, 25};          // Value in degrees (sun angle) that each Blue string will be at max output

The important thing is that you need the total pins, channels and values to all contain the same number of objects.

Cheers,

Jason
 
That depends on if you plan to run 2 of the 3 channels on the same pin.

If that is the case then you need somthing like this;

PHP:
byte bluePins[]      =  {6, 9};      // PWM pins for blues 


byte blueChannels    =        2;    // how many PWMs for blues (count from above) 


byte BluePWMHigh[]          =       {255, 255};        // High value for Blue PWM each vale is for each string - if your values are noraml this is 255, if your values are inverted this is 0 
byte BluePWMLow[]           =       {0, 0};            // Low value for Blue PWM - if your values are noraml this is 0, if your values are inverted this is 255 
float BlueFull[]            =       {25, 25};          // Value in degrees (sun angle) that each Blue string will be at max output

If you want all 3 on different pins then you need;

PHP:
byte bluePins[]      =  {6, 9, another pin #};      // PWM pins for blues 


byte blueChannels    =        3;    // how many PWMs for blues (count from above) 


byte BluePWMHigh[]          =       {255, 255, 255};        // High value for Blue PWM each vale is for each string - if your values are noraml this is 255, if your values are inverted this is 0 
byte BluePWMLow[]           =       {0, 0, 0};            // Low value for Blue PWM - if your values are noraml this is 0, if your values are inverted this is 255 
float BlueFull[]            =       {25, 25, 25};          // Value in degrees (sun angle) that each Blue string will be at max output

The important thing is that you need the total pins, channels and values to all contain the same number of objects.

Cheers,

Jason

Thanks!
//Patrik
 
Hi!
Just wanted to let you to know that the sunrise is also working now. The only thing that seems to a bit strange is that it starts about 20 minutes later than it should (i've choosen castaway island, Fiji, as my place to replicate). It's not a big deal but I thought I should let you know about it. The coordinates I'm using is -17.350638,177.086792. timezon:12

//Patrik
 
Thanks,

I'll have a look some time soon.

I have made a few revisions we are up to v2.5 now;

Corrected the issue with the moon being inverted, new moon was at 100% full moon was at 0%
Will not calculate string values for Channel colours that are not in use.

PHP:
// Natural Reef Aquarium Lighting V2.5
// 16/06/2013
// Developed by J. Harp (nUm - RTAW Forums, Numlock10 - Reef Central Forums)
// Formulas based off of information from NOAA website for sunrise / sunset times.
// Includes Lunar Simulation.
// Compiled in Arduino 1.5.2
//
// Testing;
// Moon Correction (was inverted)
// Will not calculate string values if Channel count is 0 to save on processor time
//
// Future Development:
// Weather Simulation
//
// Please feel free to use this and modify as you see fit, if you have any comments or suggestions please let me know via messages on the forums listed above.
//

#include <math.h>
#include <Wire.h>
#define DS1307_I2C_ADDRESS 0x68

// RTC variables
byte second, rtcMins, oldMins, rtcHrs, oldHrs, dayOfWeek, dayOfMonth, month, year, psecond;

// LED variables (Change to match your needs)
byte bluePins[]      =  {3, 9};      // PWM pins for blues
byte whitePins[]     =  {10, 11};    // PWM pins for whites
byte uvPins[]        =  {5};         // PWM pins for UVs
byte moonPins[]      =  {6};         // PWM pins for moonlights

byte blueChannels    =        2;    // how many PWMs for blues (count from above)
byte whiteChannels   =        2;    // how many PWMs for whites (count from above)
byte uvChannels      =        1;    // how many PWMs for uv (count from above)
byte moonChannels    =        1;    // how many PWMs from moon (count from above)

byte BluePWMHigh[]          =       {255, 255};        // High value for Blue PWM each vale is for each string - if your values are noraml this is 255, if your values are inverted this is 0
byte BluePWMLow[]           =       {0, 0};            // Low value for Blue PWM - if your values are noraml this is 0, if your values are inverted this is 255
float BlueFull[]            =       {25, 25};          // Value in degrees (sun angle) that each Blue string will be at max output (Larger = more sunlight)
byte WhitePWMHigh[]         =       {255, 255};        // High value for White PWM - if your values are noraml this is 255, if your values are inverted this is 0
byte WhitePWMLow[]          =       {0, 0};            // Low value for White PWM - if your values are noraml this is 0, if your values are inverted this is 255
float WhiteFull[]           =       {37.5, 37.5};      // Value in degrees (sun angle) that each White string will be at max output (Larger = more sunlight)
byte UVPWMHigh[]            =       {255};             // High value for UV PWM - if your values are noraml this is 255, if your values are inverted this is 0
byte UVPWMLow[]             =       {0};               // Low value for UV PWM - if your values are noraml this is 0, if your values are inverted this is 255
float UVFull[]              =       {30};              // Value in degrees (sun angle) that each UV string will be at max output (Larger = more sunlight)
byte MoonPWMHigh[]          =       {255};             // High value for Moon PWM - if your values are noraml this is 255, if your values are inverted this is 0
byte MoonPWMLow[]           =       {0};               // Low value for Moon PWM - if your values are noraml this is 0, if your values are inverted this is 255

// Set for the location of the world you want to replicate.

float latitude = -19.770621;   // + to N  Defualt - (-19.770621) Heart Reef, Great Barrier Reef, QLD, Australia 
float longitude = 149.238532;  // + to E  Defualt - (149.238532)
int TimeZone = 10;             // + to E  Defulat - (10)

// Julian Century Varaiable

float JC;

// Sunlight Variables

int delayTime = 0;     // start time delay in minutes,  - will push the day back, + will bring the day forward


int SunLight (byte _ledPin, byte _ledHigh, byte _ledLow, float _fullSun, byte _year, byte _month, byte _day, byte _hour, byte _min, byte _sec)
{
  float a = floor((14 - _month)/12);
  float y = _year + 4800 - a;
  float m = _month + (12 * a) - 3;
  float AH;
  int result;
  
  JC = (((_day + floor(((153.0 * m) + 2.0) / 5.0) + (365.0 * y) + floor(y / 4.0) - floor(y / 100.0) + floor(y / 400.0) - 32045.0) + ((_hour / 24.0) + (_min / 1444.0) + (_sec / 86400.0))) - 2451556.08) / 36525.0;
  
  float GMLS = fmod(280.46646+JC*(36000.76983 + JC * 0.0003032),360);
  
  float GMAS = 357.52911 + JC * (35999.05029 - 0.0001537 * JC);
  
  float EEO = 0.016708634 - JC * (0.000042037 + 0.0000001267 * JC);
  
  float SEoC = sin((GMAS * M_PI)/180)*(1.914602 - JC * (0.004817 + 0.000014 * JC)) + sin(((2 * GMAS) * M_PI) / 180) * (0.019993 - 0.000101 * JC) + sin(((3 * JC) * M_PI) / 180) * 0.000289;
  
  float STL = GMLS + SEoC;
  
  float STA = GMAS + SEoC;
  
  float SRV = (1.000001018 * (1 - EEO * EEO)) / (1 + EEO * cos((STA * M_PI) / 180));
  
  float SAL = STL - 0.00569 - 0.00478 * sin(((125.04 - 1934.136 * JC) * M_PI) / 180);
  
  float MOE = 23 + (26 + ((21.448 - JC * (46.815 + JC * (0.00059 - JC * 0.001813)))) / 60) / 60;
  
  float OC = MOE + 0.00256 * cos(((215.04 - 1934.136 * JC) * M_PI) / 180);
  
  float SD = (asin(sin((OC * M_PI) / 180) * sin((SAL * M_PI) / 180))) * (180 / M_PI);
  
  float vy = tan(((OC / 2) * M_PI) / 180) * tan(((OC / 2) * M_PI) / 180);
  
  float EQoT = (4 * (vy * (sin(2 * ((GMLS * M_PI) / 180)) - 2 * EEO * sin((GMAS * M_PI) / 180) + 4 * EEO * vy * sin((GMAS * M_PI) / 180) * cos( 2 * ((GMLS * M_PI) / 180)) - 0.5 * vy * vy * sin(4 * ((GMLS * M_PI) / 180)) - 1.25 * EEO * EEO * sin(2 * ((GMAS * M_PI) / 180))))) * (180 / M_PI);
  
  float HAS = acos(cos((90.833 * M_PI) / 180) / (cos((latitude * M_PI) / 180) * cos((SD * M_PI) / 180)) - tan((latitude * M_PI) / 180) * tan((SD * M_PI) / 180)) * (180 / M_PI);

  float SN = (720 - 4 * longitude - EQoT + TimeZone * 60);

  float SR = SN - HAS * 4;

  float SS = SN + HAS * 4;
 
  float STD = 8 * HAS;
  
  float TST = fmod((((_hour) + (_min / 60.0) + (_sec / 3600.0)) / 24.0)*1440 + EQoT + 4 * longitude - 60 * TimeZone,1440)+delayTime;
 
  if (TST / 4 < 0)
  {
  AH = ((TST / 4.0) + 180);
  }
  else
  {
  AH = ((TST / 4.0) - 180);  
  }
  
  float SZA = (acos(sin((latitude * M_PI) / 180) * sin((SD * M_PI) / 180) + cos((latitude * M_PI) / 180) * cos((SD * M_PI) / 180) * cos((AH * M_PI) / 180))) * (180 / M_PI);
  
  int SEA = 90 - SZA;
  
  if (SEA <= 0)  
  {
   result = _ledLow;    
  }
  
  if (SEA > 0 && SEA < _fullSun)
  {
  result = map(SEA,0,_fullSun,_ledLow,_ledHigh);
  }
  
  if (SEA >= _fullSun)  
  {
  result = _ledHigh;
  }
  
  analogWrite(_ledPin, result);  
  return result;
  
}

int MoonLight (float JC, byte _ledPin, byte _ledHigh, byte _ledLow)
{
 int result;
 
 float MS = fmod((2456318.69458333 - JC),29.530589);
 
 if(MS <= 14.7518)
 {
  result = map(MS,0,14.7518,_ledHigh,_ledLow);
 }
 
 if( MS > 14.7518)
 {
   result = map(MS,14.7518,29.530589,_ledLow,_ledHigh);
 }
 analogWrite(_ledPin, result); 
 return result;
}
 

/***** RTC Functions *******/
/***************************/
// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
  return ( (val/10*16) + (val%10) );
}

// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return ( (val/16*10) + (val%16) );
}

// Gets the date and time from the ds1307
void getDateDs1307(byte *second,
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
byte *year)
{
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write(0);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_I2C_ADDRESS, 7);

  *second     = bcdToDec(Wire.read() & 0x7f);
  *minute     = bcdToDec(Wire.read());
  *hour       = bcdToDec(Wire.read() & 0x3f);
  *dayOfWeek  = bcdToDec(Wire.read());
  *dayOfMonth = bcdToDec(Wire.read());
  *month      = bcdToDec(Wire.read());
  *year       = bcdToDec(Wire.read());
}

void setup() {
delay(500);
Serial.begin(57600);
Wire.begin();
}

void loop() {
  getDateDs1307(&second, &rtcMins, &rtcHrs, &dayOfWeek, &dayOfMonth, &month, &year);
  if (psecond != second){
    psecond = second;
  Serial.print(rtcHrs);
  Serial.print(":");
  Serial.print(rtcMins);
  Serial.print(":");
  Serial.print(second);
  Serial.print(" ");
  Serial.print(dayOfMonth);
  Serial.print("/");
  Serial.print(month);
  Serial.print("/");
  Serial.println(year);
  update_leds();
  }
}

void update_leds ( void ){
  int i;
  byte value;
  int MS;
  if(blueChannels > 0){
  Serial.println("Blue LED's");
  for (i = 0; i < blueChannels; i++)
  {
    value = SunLight(bluePins[i],BluePWMHigh[i],BluePWMLow[i],BlueFull[i],year,month,dayOfMonth,rtcHrs,rtcMins,second);
    Serial.print(map(value,BluePWMLow[i],BluePWMHigh[i],0,100));
    Serial.print("% ");
  }
  Serial.println();
  }
  if(whiteChannels > 0){
  Serial.println("White LED's");
  for (i = 0; i < whiteChannels; i++)
  {
    value = SunLight(whitePins[i],WhitePWMHigh[i],WhitePWMLow[i],WhiteFull[i],year,month,dayOfMonth,rtcHrs,rtcMins,second);
    Serial.print(map(value,WhitePWMLow[i],WhitePWMHigh[i],0,100));
    Serial.print("% ");
  }
  Serial.println();
  }
  if(uvChannels > 0){
  Serial.println("UV LED's");
  for (i = 0; i < uvChannels; i++)
  {
    value = SunLight(uvPins[i],UVPWMHigh[i],UVPWMLow[i],UVFull[i],year,month,dayOfMonth,rtcHrs,rtcMins,second);
    Serial.print(map(value,UVPWMLow[i],UVPWMHigh[i],0,100));
    Serial.print("% ");
  }
  Serial.println();
  }
  if(moonChannels > 0){
  Serial.println("Moon Value");
  for (i = 0; i < moonChannels; i ++)
  {
  MS = MoonLight(JC, moonPins[i],MoonPWMHigh[i],MoonPWMLow[i]);
  Serial.print(map(MS,MoonPWMLow[i],MoonPWMHigh[i],0,100));
  Serial.print("% ");
  }
  Serial.println();
  }
}
 
Been doing a bit of research, looks like you first start seeing light in the morning when the sun is about -18 degrees breaking the horizon. I could change the code to start at -18, this might fix the problem with the 20min delay.

I could make it go from 0% to 5% in the amount of time it takes the sun to get from -18 to 0 degrees.

That would make for a very slow light-up then normal up to full sun.

Just thinking out loud.
 
This is the code as mentioned above,

Please let me know if anyone tries it and if there are any bugs.

PHP:
// Natural Reef Aquarium Lighting V2.6
// 16/06/2013
// Developed by J. Harp (nUm - RTAW Forums, Numlock10 - Reef Central Forums)
// Formulas based off of information from NOAA website for sunrise / sunset times.
// Includes Lunar Simulation.
// Compiled in Arduino 1.5.2
//
// Testing;
// Moon Correction (was inverted).
// Will not calculate string values if Channel count is 0 to save on processor time.
// Light will start ramping up at set value of degrees below the horizion (-18 is default) this value is custom to each string.
// Light will ramp set value from below horizion line to 0 line in PWM points (12.75 is the default = 10%)
// 
//
// Future Development:
// Weather Simulation
//
// Please feel free to use this and modify as you see fit, if you have any comments or suggestions please let me know via messages on the forums listed above.
//

#include <math.h>
#include <Wire.h>
#define DS1307_I2C_ADDRESS 0x68

// RTC variables
byte second, rtcMins, oldMins, rtcHrs, oldHrs, dayOfWeek, dayOfMonth, month, year, psecond;

// LED variables (Change to match your needs)
byte bluePins[]      =  {3, 9};      // PWM pins for blues
byte whitePins[]     =  {10, 11};    // PWM pins for whites
byte uvPins[]        =  {5};         // PWM pins for UVs
byte moonPins[]      =  {6};         // PWM pins for moonlights

byte blueChannels    =        2;    // how many PWMs for blues (count from above)
byte whiteChannels   =        2;    // how many PWMs for whites (count from above)
byte uvChannels      =        1;    // how many PWMs for uv (count from above)
byte moonChannels    =        1;    // how many PWMs from moon (count from above)

byte BluePWMHigh[]          =       {255, 255};        // High value for Blue PWM each vale is for each string - if your values are noraml this is 255, if your values are inverted this is 0
byte BluePWMLow[]           =       {0, 0};            // Low value for Blue PWM - if your values are noraml this is 0, if your values are inverted this is 255
float BlueFull[]            =       {25, 25};          // Value in degrees (sun angle) that each Blue string will be at max output (Larger = more sunlight)
float BlueLow[]             =       {-18, -18};        // Value in degrees (sun angle) that each Blue string will start
byte WhitePWMHigh[]         =       {255, 255};        // High value for White PWM - if your values are noraml this is 255, if your values are inverted this is 0
byte WhitePWMLow[]          =       {0, 0};            // Low value for White PWM - if your values are noraml this is 0, if your values are inverted this is 255
float WhiteFull[]           =       {37.5, 37.5};      // Value in degrees (sun angle) that each White string will be at max output (Larger = more sunlight)
float WhiteLow[]            =       {-18, -18};        // Value in degrees (sun angle) that each White string will start
byte UVPWMHigh[]            =       {255};             // High value for UV PWM - if your values are noraml this is 255, if your values are inverted this is 0
byte UVPWMLow[]             =       {0};               // Low value for UV PWM - if your values are noraml this is 0, if your values are inverted this is 255
float UVFull[]              =       {30};              // Value in degrees (sun angle) that each UV string will be at max output (Larger = more sunlight)
float UVLow[]               =       {-18};             // Value in degrees (sun angle) that each Blue string will start
byte MoonPWMHigh[]          =       {255};             // High value for Moon PWM - if your values are noraml this is 255, if your values are inverted this is 0
byte MoonPWMLow[]           =       {0};               // Low value for Moon PWM - if your values are noraml this is 0, if your values are inverted this is 255

float LowValue               =       12.75;            // PWM steps to ramp from Low to 0 degrees (12.75 = 10%)

// Set for the location of the world you want to replicate.

float latitude = -19.770621;   // + to N  Defualt - (-19.770621) Heart Reef, Great Barrier Reef, QLD, Australia 
float longitude = 149.238532;  // + to E  Defualt - (149.238532)
int TimeZone = 10;             // + to E  Defulat - (10)

// Julian Century Varaiable

float JC;

// Sunlight Variables

int delayTime = 0;     // start time delay in minutes,  - will push the day back, + will bring the day forward


int SunLight (byte _ledPin, byte _ledHigh, byte _ledLow, float _lowSun, float _fullSun, float _lowValue, byte _year, byte _month, byte _day, byte _hour, byte _min, byte _sec)
{
  float a = floor((14 - _month)/12);
  float y = _year + 4800 - a;
  float m = _month + (12 * a) - 3;
  float AH;
  int result;
  
  JC = (((_day + floor(((153.0 * m) + 2.0) / 5.0) + (365.0 * y) + floor(y / 4.0) - floor(y / 100.0) + floor(y / 400.0) - 32045.0) + ((_hour / 24.0) + (_min / 1444.0) + (_sec / 86400.0))) - 2451556.08) / 36525.0;
  
  float GMLS = fmod(280.46646+JC*(36000.76983 + JC * 0.0003032),360);
  
  float GMAS = 357.52911 + JC * (35999.05029 - 0.0001537 * JC);
  
  float EEO = 0.016708634 - JC * (0.000042037 + 0.0000001267 * JC);
  
  float SEoC = sin((GMAS * M_PI)/180)*(1.914602 - JC * (0.004817 + 0.000014 * JC)) + sin(((2 * GMAS) * M_PI) / 180) * (0.019993 - 0.000101 * JC) + sin(((3 * JC) * M_PI) / 180) * 0.000289;
  
  float STL = GMLS + SEoC;
  
  float STA = GMAS + SEoC;
  
  float SRV = (1.000001018 * (1 - EEO * EEO)) / (1 + EEO * cos((STA * M_PI) / 180));
  
  float SAL = STL - 0.00569 - 0.00478 * sin(((125.04 - 1934.136 * JC) * M_PI) / 180);
  
  float MOE = 23 + (26 + ((21.448 - JC * (46.815 + JC * (0.00059 - JC * 0.001813)))) / 60) / 60;
  
  float OC = MOE + 0.00256 * cos(((215.04 - 1934.136 * JC) * M_PI) / 180);
  
  float SD = (asin(sin((OC * M_PI) / 180) * sin((SAL * M_PI) / 180))) * (180 / M_PI);
  
  float vy = tan(((OC / 2) * M_PI) / 180) * tan(((OC / 2) * M_PI) / 180);
  
  float EQoT = (4 * (vy * (sin(2 * ((GMLS * M_PI) / 180)) - 2 * EEO * sin((GMAS * M_PI) / 180) + 4 * EEO * vy * sin((GMAS * M_PI) / 180) * cos( 2 * ((GMLS * M_PI) / 180)) - 0.5 * vy * vy * sin(4 * ((GMLS * M_PI) / 180)) - 1.25 * EEO * EEO * sin(2 * ((GMAS * M_PI) / 180))))) * (180 / M_PI);
  
  float HAS = acos(cos((90.833 * M_PI) / 180) / (cos((latitude * M_PI) / 180) * cos((SD * M_PI) / 180)) - tan((latitude * M_PI) / 180) * tan((SD * M_PI) / 180)) * (180 / M_PI);

  float SN = (720 - 4 * longitude - EQoT + TimeZone * 60);

  float SR = SN - HAS * 4;

  float SS = SN + HAS * 4;
 
  float STD = 8 * HAS;
  
  float TST = fmod((((_hour) + (_min / 60.0) + (_sec / 3600.0)) / 24.0)*1440 + EQoT + 4 * longitude - 60 * TimeZone,1440)+delayTime;
 
  if (TST / 4 < 0)
  {
  AH = ((TST / 4.0) + 180);
  }
  else
  {
  AH = ((TST / 4.0) - 180);  
  }
  
  float SZA = (acos(sin((latitude * M_PI) / 180) * sin((SD * M_PI) / 180) + cos((latitude * M_PI) / 180) * cos((SD * M_PI) / 180) * cos((AH * M_PI) / 180))) * (180 / M_PI);
  
  int SEA = 90 - SZA;
  
  if (SEA <= _lowSun)  
  {
   result = _ledLow;    
  }
  
  if (SEA > _lowSun && SEA <= 0)
  {
  result = map(SEA,_lowSun,0,_ledLow,(_ledLow + _lowValue));
  }
  
  if (SEA > 0)
  {
  result = map(SEA,0,_fullSun,(_ledLow + _lowValue),_fullSun);
  }
  
  if (SEA >= _fullSun)  
  {
  result = _ledHigh;
  }
  
  analogWrite(_ledPin, result);  
  return result;
  
}

int MoonLight (float JC, byte _ledPin, byte _ledHigh, byte _ledLow)
{
 int result;
 
 float MS = fmod((2456318.69458333 - JC),29.530589);
 
 if(MS <= 14.7518)
 {
  result = map(MS,0,14.7518,_ledHigh,_ledLow);
 }
 
 if( MS > 14.7518)
 {
   result = map(MS,14.7518,29.530589,_ledLow,_ledHigh);
 }
 analogWrite(_ledPin, result); 
 return result;
}
 

/***** RTC Functions *******/
/***************************/
// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
  return ( (val/10*16) + (val%10) );
}

// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return ( (val/16*10) + (val%16) );
}

// Gets the date and time from the ds1307
void getDateDs1307(byte *second,
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
byte *year)
{
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write(0);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_I2C_ADDRESS, 7);

  *second     = bcdToDec(Wire.read() & 0x7f);
  *minute     = bcdToDec(Wire.read());
  *hour       = bcdToDec(Wire.read() & 0x3f);
  *dayOfWeek  = bcdToDec(Wire.read());
  *dayOfMonth = bcdToDec(Wire.read());
  *month      = bcdToDec(Wire.read());
  *year       = bcdToDec(Wire.read());
}

void setup() {
delay(500);
Serial.begin(57600);
Wire.begin();
}

void loop() {
  getDateDs1307(&second, &rtcMins, &rtcHrs, &dayOfWeek, &dayOfMonth, &month, &year);
  if (psecond != second){
    psecond = second;
  Serial.print(rtcHrs);
  Serial.print(":");
  Serial.print(rtcMins);
  Serial.print(":");
  Serial.print(second);
  Serial.print(" ");
  Serial.print(dayOfMonth);
  Serial.print("/");
  Serial.print(month);
  Serial.print("/");
  Serial.println(year);
  update_leds();
  }
}

void update_leds ( void ){
  int i;
  byte value;
  int MS;
  if(blueChannels > 0){
  Serial.println("Blue LED's");
  for (i = 0; i < blueChannels; i++)
  {
    value = SunLight(bluePins[i],BluePWMHigh[i],BluePWMLow[i],BlueLow[i],BlueFull[i],LowValue,year,month,dayOfMonth,rtcHrs,rtcMins,second);
    Serial.print(map(value,BluePWMLow[i],BluePWMHigh[i],0,100));
    Serial.print("% ");
  }
  Serial.println();
  }
  if(whiteChannels > 0){
  Serial.println("White LED's");
  for (i = 0; i < whiteChannels; i++)
  {
    value = SunLight(whitePins[i],WhitePWMHigh[i],WhitePWMLow[i],WhiteLow[i],WhiteFull[i],LowValue,year,month,dayOfMonth,rtcHrs,rtcMins,second);
    Serial.print(map(value,WhitePWMLow[i],WhitePWMHigh[i],0,100));
    Serial.print("% ");
  }
  Serial.println();
  }
  if(uvChannels > 0){
  Serial.println("UV LED's");
  for (i = 0; i < uvChannels; i++)
  {
    value = SunLight(uvPins[i],UVPWMHigh[i],UVPWMLow[i],UVLow[i],UVFull[i],LowValue,year,month,dayOfMonth,rtcHrs,rtcMins,second);
    Serial.print(map(value,UVPWMLow[i],UVPWMHigh[i],0,100));
    Serial.print("% ");
  }
  Serial.println();
  }
  if(moonChannels > 0){
  Serial.println("Moon Value");
  for (i = 0; i < moonChannels; i ++)
  {
  MS = MoonLight(JC, moonPins[i],MoonPWMHigh[i],MoonPWMLow[i]);
  Serial.print(map(MS,MoonPWMLow[i],MoonPWMHigh[i],0,100));
  Serial.print("% ");
  }
  Serial.println();
  }
}

Cheers,
 
Hi!
I'm testing your new code right now. Getting back tomorrow about how it works. First thing I notice, now, when its 2 h 20 min left to sunset is that the whites does not shine as much as before so I have to adjust the max value for them a little bit.

And here is the code I'm using:

PHP:
// Natural Reef Aquarium Lighting V2.6
// 16/06/2013
// Developed by J. Harp (nUm - RTAW Forums, Numlock10 - Reef Central Forums)
// Formulas based off of information from NOAA website for sunrise / sunset times.
// Includes Lunar Simulation.
// Compiled in Arduino 1.5.2
//
// Testing;
// Moon Correction (was inverted).
// Will not calculate string values if Channel count is 0 to save on processor time.
// Light will start ramping up at set value of degrees below the horizion (-18 is default) this value is custom to each string.
// Light will ramp set value from below horizion line to 0 line in PWM points (12.75 is the default = 10%)
// 
//
// Future Development:
// Weather Simulation
//
// Please feel free to use this and modify as you see fit, if you have any comments or suggestions please let me know via messages on the forums listed above.
//

#include <math.h>
#include <Wire.h>
#define DS1307_I2C_ADDRESS 0x68

// RTC variables
byte second, rtcMins, oldMins, rtcHrs, oldHrs, dayOfWeek, dayOfMonth, month, year, psecond;

// LED variables (Change to match your needs)
byte bluePins[]      =  {6};      // PWM pins for blues
byte whitePins[]     =  {10, 11};    // PWM pins for whites
byte uvPins[]        =  {5, 9};         // PWM pins for UVs
byte moonPins[]      =  {3};         // PWM pins for moonlights

byte blueChannels    =        1;    // how many PWMs for blues (count from above)
byte whiteChannels   =        2;    // how many PWMs for whites (count from above)
byte uvChannels      =        2;    // how many PWMs for uv (count from above)
byte moonChannels    =        1;    // how many PWMs from moon (count from above)

byte BluePWMHigh[]          =       {255};        // High value for Blue PWM each vale is for each string - if your values are noraml this is 255, if your values are inverted this is 0
byte BluePWMLow[]           =       {0};            // Low value for Blue PWM - if your values are noraml this is 0, if your values are inverted this is 255
float BlueFull[]            =       {25};          // Value in degrees (sun angle) that each Blue string will be at max output (Larger = more sunlight)
float BlueLow[]             =       {-18};        // Value in degrees (sun angle) that each Blue string will start
byte WhitePWMHigh[]         =       {200, 200};        // High value for White PWM - if your values are noraml this is 255, if your values are inverted this is 0
byte WhitePWMLow[]          =       {0, 0};            // Low value for White PWM - if your values are noraml this is 0, if your values are inverted this is 255
float WhiteFull[]           =       {37.5, 37.5};      // Value in degrees (sun angle) that each White string will be at max output (Larger = more sunlight)
float WhiteLow[]            =       {-18, -18};        // Value in degrees (sun angle) that each White string will start
byte UVPWMHigh[]            =       {255, 255};             // High value for UV PWM - if your values are noraml this is 255, if your values are inverted this is 0
byte UVPWMLow[]             =       {0, 0};               // Low value for UV PWM - if your values are noraml this is 0, if your values are inverted this is 255
float UVFull[]              =       {30, 30};              // Value in degrees (sun angle) that each UV string will be at max output (Larger = more sunlight)
float UVLow[]               =       {-18, -18};             // Value in degrees (sun angle) that each Blue string will start
byte MoonPWMHigh[]          =       {75};             // High value for Moon PWM - if your values are noraml this is 255, if your values are inverted this is 0
byte MoonPWMLow[]           =       {0};               // Low value for Moon PWM - if your values are noraml this is 0, if your values are inverted this is 255

float LowValue               =       12.75;            // PWM steps to ramp from Low to 0 degrees (12.75 = 10%)

// Set for the location of the world you want to replicate.

float latitude = -17.730211;   // + to N  Defualt - (-19.770621) Heart Reef, Great Barrier Reef, QLD, Australia 
float longitude = 177.127218;  // + to E  Defualt - (149.238532)
int TimeZone = 12;             // + to E  Defulat - (10)

// Julian Century Varaiable

float JC;

// Sunlight Variables

int delayTime = -150;     // start time delay in minutes,  - will push the day back, + will bring the day forward


int SunLight (byte _ledPin, byte _ledHigh, byte _ledLow, float _lowSun, float _fullSun, float _lowValue, byte _year, byte _month, byte _day, byte _hour, byte _min, byte _sec)
{
  float a = floor((14 - _month)/12);
  float y = _year + 4800 - a;
  float m = _month + (12 * a) - 3;
  float AH;
  int result;
  
  JC = (((_day + floor(((153.0 * m) + 2.0) / 5.0) + (365.0 * y) + floor(y / 4.0) - floor(y / 100.0) + floor(y / 400.0) - 32045.0) + ((_hour / 24.0) + (_min / 1444.0) + (_sec / 86400.0))) - 2451556.08) / 36525.0;
  
  float GMLS = fmod(280.46646+JC*(36000.76983 + JC * 0.0003032),360);
  
  float GMAS = 357.52911 + JC * (35999.05029 - 0.0001537 * JC);
  
  float EEO = 0.016708634 - JC * (0.000042037 + 0.0000001267 * JC);
  
  float SEoC = sin((GMAS * M_PI)/180)*(1.914602 - JC * (0.004817 + 0.000014 * JC)) + sin(((2 * GMAS) * M_PI) / 180) * (0.019993 - 0.000101 * JC) + sin(((3 * JC) * M_PI) / 180) * 0.000289;
  
  float STL = GMLS + SEoC;
  
  float STA = GMAS + SEoC;
  
  float SRV = (1.000001018 * (1 - EEO * EEO)) / (1 + EEO * cos((STA * M_PI) / 180));
  
  float SAL = STL - 0.00569 - 0.00478 * sin(((125.04 - 1934.136 * JC) * M_PI) / 180);
  
  float MOE = 23 + (26 + ((21.448 - JC * (46.815 + JC * (0.00059 - JC * 0.001813)))) / 60) / 60;
  
  float OC = MOE + 0.00256 * cos(((215.04 - 1934.136 * JC) * M_PI) / 180);
  
  float SD = (asin(sin((OC * M_PI) / 180) * sin((SAL * M_PI) / 180))) * (180 / M_PI);
  
  float vy = tan(((OC / 2) * M_PI) / 180) * tan(((OC / 2) * M_PI) / 180);
  
  float EQoT = (4 * (vy * (sin(2 * ((GMLS * M_PI) / 180)) - 2 * EEO * sin((GMAS * M_PI) / 180) + 4 * EEO * vy * sin((GMAS * M_PI) / 180) * cos( 2 * ((GMLS * M_PI) / 180)) - 0.5 * vy * vy * sin(4 * ((GMLS * M_PI) / 180)) - 1.25 * EEO * EEO * sin(2 * ((GMAS * M_PI) / 180))))) * (180 / M_PI);
  
  float HAS = acos(cos((90.833 * M_PI) / 180) / (cos((latitude * M_PI) / 180) * cos((SD * M_PI) / 180)) - tan((latitude * M_PI) / 180) * tan((SD * M_PI) / 180)) * (180 / M_PI);

  float SN = (720 - 4 * longitude - EQoT + TimeZone * 60);

  float SR = SN - HAS * 4;

  float SS = SN + HAS * 4;
 
  float STD = 8 * HAS;
  
  float TST = fmod((((_hour) + (_min / 60.0) + (_sec / 3600.0)) / 24.0)*1440 + EQoT + 4 * longitude - 60 * TimeZone,1440)+delayTime;
 
  if (TST / 4 < 0)
  {
  AH = ((TST / 4.0) + 180);
  }
  else
  {
  AH = ((TST / 4.0) - 180);  
  }
  
  float SZA = (acos(sin((latitude * M_PI) / 180) * sin((SD * M_PI) / 180) + cos((latitude * M_PI) / 180) * cos((SD * M_PI) / 180) * cos((AH * M_PI) / 180))) * (180 / M_PI);
  
  int SEA = 90 - SZA;
  
  if (SEA <= _lowSun)  
  {
   result = _ledLow;    
  }
  
  if (SEA > _lowSun && SEA <= 0)
  {
  result = map(SEA,_lowSun,0,_ledLow,(_ledLow + _lowValue));
  }
  
  if (SEA > 0)
  {
  result = map(SEA,0,_fullSun,(_ledLow + _lowValue),_fullSun);
  }
  
  if (SEA >= _fullSun)  
  {
  result = _ledHigh;
  }
  
  analogWrite(_ledPin, result);  
  return result;
  
}

int MoonLight (float JC, byte _ledPin, byte _ledHigh, byte _ledLow)
{
 int result;
 
 float MS = fmod((2456318.69458333 - JC),29.530589);
 
 if(MS <= 14.7518)
 {
  result = map(MS,0,14.7518,_ledHigh,_ledLow);
 }
 
 if( MS > 14.7518)
 {
   result = map(MS,14.7518,29.530589,_ledLow,_ledHigh);
 }
 analogWrite(_ledPin, result); 
 return result;
}
 

/***** RTC Functions *******/
/***************************/
// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
  return ( (val/10*16) + (val%10) );
}

// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return ( (val/16*10) + (val%16) );
}

// Gets the date and time from the ds1307
void getDateDs1307(byte *second,
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
byte *year)
{
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write(0);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_I2C_ADDRESS, 7);

  *second     = bcdToDec(Wire.read() & 0x7f);
  *minute     = bcdToDec(Wire.read());
  *hour       = bcdToDec(Wire.read() & 0x3f);
  *dayOfWeek  = bcdToDec(Wire.read());
  *dayOfMonth = bcdToDec(Wire.read());
  *month      = bcdToDec(Wire.read());
  *year       = bcdToDec(Wire.read());
}

void setup() {
delay(500);
Serial.begin(57600);
Wire.begin();
}

void loop() {
  getDateDs1307(&second, &rtcMins, &rtcHrs, &dayOfWeek, &dayOfMonth, &month, &year);
  if (psecond != second){
    psecond = second;
  Serial.print(rtcHrs);
  Serial.print(":");
  Serial.print(rtcMins);
  Serial.print(":");
  Serial.print(second);
  Serial.print(" ");
  Serial.print(dayOfMonth);
  Serial.print("/");
  Serial.print(month);
  Serial.print("/");
  Serial.println(year);
  update_leds();
  }
}

void update_leds ( void ){
  int i;
  byte value;
  int MS;
  if(blueChannels > 0){
  Serial.println("Blue LED's");
  for (i = 0; i < blueChannels; i++)
  {
    value = SunLight(bluePins[i],BluePWMHigh[i],BluePWMLow[i],BlueLow[i],BlueFull[i],LowValue,year,month,dayOfMonth,rtcHrs,rtcMins,second);
    Serial.print(map(value,BluePWMLow[i],BluePWMHigh[i],0,100));
    Serial.print("% ");
  }
  Serial.println();
  }
  if(whiteChannels > 0){
  Serial.println("White LED's");
  for (i = 0; i < whiteChannels; i++)
  {
    value = SunLight(whitePins[i],WhitePWMHigh[i],WhitePWMLow[i],WhiteLow[i],WhiteFull[i],LowValue,year,month,dayOfMonth,rtcHrs,rtcMins,second);
    Serial.print(map(value,WhitePWMLow[i],WhitePWMHigh[i],0,100));
    Serial.print("% ");
  }
  Serial.println();
  }
  if(uvChannels > 0){
  Serial.println("UV LED's");
  for (i = 0; i < uvChannels; i++)
  {
    value = SunLight(uvPins[i],UVPWMHigh[i],UVPWMLow[i],UVLow[i],UVFull[i],LowValue,year,month,dayOfMonth,rtcHrs,rtcMins,second);
    Serial.print(map(value,UVPWMLow[i],UVPWMHigh[i],0,100));
    Serial.print("% ");
  }
  Serial.println();
  }
  if(moonChannels > 0){
  Serial.println("Moon Value");
  for (i = 0; i < moonChannels; i ++)
  {
  MS = MoonLight(JC, moonPins[i],MoonPWMHigh[i],MoonPWMLow[i]);
  Serial.print(map(MS,MoonPWMLow[i],MoonPWMHigh[i],0,100));
  Serial.print("% ");
  }
  Serial.println();
  }
}
 
Just a quick update: After about 20-30 minutes everything went back to normal. It's seems that I don't have change the value of the white leds after all.

//Patrik
 
"Float" is just another term for "decimal" in programming.
A "Double" is like a float, but has twice the precision normally. But in all Arduino boards (except the Due) a double is exactly like a float.

Be careful with this, if your comparing with 0 or any other number..

For example with decimal (2 decimal places) (1 X 1) - 1 = 0

whereas in floating point number your system could calculate (1 x 1) - 1 = 0.0000000001 or -0.000000000001 or something similar, so if you compare your number to 0, it might not be the outcome you expect.
 
Be careful with this, if your comparing with 0 or any other number..

For example with decimal (2 decimal places) (1 X 1) - 1 = 0

whereas in floating point number your system could calculate (1 x 1) - 1 = 0.0000000001 or -0.000000000001 or something similar, so if you compare your number to 0, it might not be the outcome you expect.
Oh yes, that's true. That's why you try to avoid floats whenever possible, or convert them to ints.
Like, to convert 32.75*F into an integer, you use
int = 32.75*100.0.
Whenever you want the specific temperature, you divide by 100.
 
Hi Jason!
I've been trying your code now. The second one you made, to fix the 20 minutes issuse is not working. The problem I got was that the led never turned off at sunset. I waited for 40 minutes but it never turned off. After that I tried your other code and that one is working just perfect!
//Patrik
 
Is any of this code compatible with te arduino due. I have a mega 2560 and a due, I would rather try this set if code in the due for the faster processing speed
 
There isn't any reason that it shouldn't run on the due, you will just need to adjust the pin numbers if they are incorrect. It compiled fine when I tried compiling on the Due (native USB port) settings.
 
Back
Top