Natural Reef Aquarium Lighting Controller

Hi Jason!
I've been trying your code now for a couple of weeks and everything works just perfect except the moon light. It seems that the moonlight never change intensity. It's the same intensity every day. Do you have any ide about what could be wrong?

//Patrik
 
Forgot the code I'm using. It's the v. 2.5

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[]      =  {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)
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, 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)
byte MoonPWMHigh[]          =       {50};             // 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 = -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 _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();
  }
}

//Patrik
 
PHP:
// Natural Reef Aquarium Lighting V2.5.1
// 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[]      =  {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) 
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, 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) 
byte MoonPWMHigh[]          =       {50};             // 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 = -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 _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 ++) 
  { 
  value = MoonLight(JC, moonPins[i],MoonPWMHigh[i],MoonPWMLow[i]); 
  Serial.print(map(value,MoonPWMLow[i],MoonPWMHigh[i],0,100)); 
  Serial.print("% "); 
  } 
  Serial.println(); 
  } 
}

Try the above and let me know if that works
 
PHP:
// Natural Reef Aquarium Lighting V2.5.1
// 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[]      =  {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) 
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, 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) 
byte MoonPWMHigh[]          =       {50};             // 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 = -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 _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 ++) 
  { 
  value = MoonLight(JC, moonPins[i],MoonPWMHigh[i],MoonPWMLow[i]); 
  Serial.print(map(value,MoonPWMLow[i],MoonPWMHigh[i],0,100)); 
  Serial.print("% "); 
  } 
  Serial.println(); 
  } 
}

Try the above and let me know if that works


Hi, I have uploaded the sketch now and will come back in a couple of days to let you know how it works!

//Patrik
 
Hi Jason!
I've been trying the code for a couple of days now. Unfortunately, the moon light does not work. It got stuck at 8 % and has been so for a week now.

//Patrik
 
Just an update to see if I can get the moon cycle working correctly. If anyone is still trying this please let me know if it works.

PHP:
// Natural Reef Aquarium Lighting V2.5.2
// 11/09/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)
// Moon was not changing intensity, rework of moon code to see if this fixes the problem.
//
// 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 moon = fmod((2456318.69458333 - JC), 29.530589);

	if (moon <= 14.7518)
	{
		result = map(moon, 0, 14.7518, _ledHigh, _ledLow);
	}

	if (moon > 14.7518)
	{
		result = map(moon, 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;
	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++)
		{
			value = MoonLight(JC, moonPins[i], MoonPWMHigh[i], MoonPWMLow[i]);
			Serial.print(map(value, MoonPWMLow[i], MoonPWMHigh[i], 0, 100));
			Serial.print("% ");
		}
		Serial.println();
	}
}

Cheers,
 
Just an update to see if I can get the moon cycle working correctly. If anyone is still trying this please let me know if it works.

PHP:
// Natural Reef Aquarium Lighting V2.5.2
// 11/09/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)
// Moon was not changing intensity, rework of moon code to see if this fixes the problem.
//
// 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 moon = fmod((2456318.69458333 - JC), 29.530589);

	if (moon <= 14.7518)
	{
		result = map(moon, 0, 14.7518, _ledHigh, _ledLow);
	}

	if (moon > 14.7518)
	{
		result = map(moon, 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;
	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++)
		{
			value = MoonLight(JC, moonPins[i], MoonPWMHigh[i], MoonPWMLow[i]);
			Serial.print(map(value, MoonPWMLow[i], MoonPWMHigh[i], 0, 100));
			Serial.print("% ");
		}
		Serial.println();
	}
}

Cheers,

Hi!
I've been trying the code for 3 days now and there is still problem with the moonlight intensity. Now, it's stuck on 13 %. Before this new code it was stuck at 8 %.

//Patrik
 
btw, here is the code I'm using

PHP:
// Natural Reef Aquarium Lighting V2.5.2 
// 11/09/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) 
// Moon was not changing intensity, rework of moon code to see if this fixes the problem. 
// 
// 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) 
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, 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) 
byte MoonPWMHigh[] = { 15 };             // 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 = -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 _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 moon = fmod((2456318.69458333 - JC), 29.530589); 

    if (moon <= 14.7518) 
    { 
        result = map(moon, 0, 14.7518, _ledHigh, _ledLow); 
    } 

    if (moon > 14.7518) 
    { 
        result = map(moon, 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; 
    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++) 
        { 
            value = MoonLight(JC, moonPins[i], MoonPWMHigh[i], MoonPWMLow[i]); 
            Serial.print(map(value, MoonPWMLow[i], MoonPWMHigh[i], 0, 100)); 
            Serial.print("% "); 
        } 
        Serial.println(); 
    } 
}

//Patrik
 
Thanks for the feedback Patrik,

I have made some bigger changes, please let me know if this has any luck.

PHP:
// Natural Reef Aquarium Lighting V2.5.3
// 14/11/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;

	float 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(byte _ledPin, byte _ledHigh, byte _ledLow, byte _year, byte _month, byte _day, byte _hour, byte _min, byte _sec)
{
	int result;
	float a = floor((14 - _month) / 12);
	float y = _year + 4800 - a;
	float m = _month + (12 * a) - 3;

        float 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 moon = fmod((2456318.69458333 - JC), 29.530589);

	if (moon <= 14.7652945)
	{
		result = map(moon, 0, 14.7652945, _ledHigh, _ledLow);
	}

	if (moon >= 14.7652946)
	{
		result = map(moon, 14.7652946, 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;
	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++)
		{
			value = MoonLight(moonPins[i], MoonPWMHigh[i], MoonPWMLow[i], year, month, dayOfMonth, rtcHrs, rtcMins, second);
			Serial.print(map(value, MoonPWMLow[i], MoonPWMHigh[i], 0, 100));
			Serial.print("% ");
		}
		Serial.println();
	}
}

Cheers,
 
i am doing a small build with just two strings of led's blue violet mixed and white for the tank.
and two strings one for refugium & one ats white.
my ? can i just use the tank light's for the daytime and moonlights instead of running another channel just for the moonlight. i have ldd- drivers dim to 0
thanks
jim
 
Hi!

I'm trying the new code now. Now it says 10% when I measured it at 10.00 in the morning. I will try to test it later at 21.00 if it has changed but if I understand this sketch correct, the code will just change the intensity once a day (00.01), is that correct?

Btw, I'm pretty surprised that no one else is testing this code. Everything, except the moonlight, is working perfect.
One of the biggest reasons that I liked this sketch is because the possibility to add a place to replicate. I choose Fiji island because that way I would have a more even sun cycle, not so big difference between winter and summer times. If going with the original code, which replicate Heart reef, Great Barrier reef, Australia, the sun will be up very long time in the summer but very short in the winter. Just like were I come from, Sweden.

But, the choice is yours! For me, Fiji is perfect!

//Patrik
 
i am doing a small build with just two strings of led's blue violet mixed and white for the tank.
and two strings one for refugium & one ats white.
my ? can i just use the tank light's for the daytime and moonlights instead of running another channel just for the moonlight. i have ldd- drivers dim to 0
thanks
jim

Jim,

The current code does not allow for the use of the same pins for moon and sunlight. Once I get the issue with the moon light resolved I will see if I can make one that will allow a milti-pin for sun and moon.

Cheers,
 
Patrik,

Thanks again for the feedback and really appreciate all of the testing.

The moon light should be updating once every second, it runs in the same loop cycle as the main lights.

cheers,
 
Patrik,

Thanks again for the feedback and really appreciate all of the testing.

The moon light should be updating once every second, it runs in the same loop cycle as the main lights.

cheers,

Hello again!
I think it's just fun to test your sketches. It amazes me how much you can do with these codes and that it works. I also hope that I will be able to contribute something in the future but right now, my kids and my work takes up all my time. I'm completely exhausted in the evenings ...

But, back to the sketcher. One thing that worries me is that it's any of my changes in the sketch that makes the moonlight not working. I hope note.
I will test the original code and only change the led variables and the time. I will come back tomorrow about the result.

Another thing I'm thinking about is: Since I'm totally lost when it comes to coding arduino, I wonder why the "float" thing in moonlight is missing, like this:
PHP:
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

I also wonder why there is a space before and after the numbers in the paragraph. It was not there in earlier sketches but I guess there is a reson for that, right?

Ex:
HTML:
// 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 };

Thanks again for your help and the sketch. I really appreciate that.

//Patrik
 
PHP:
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

There is no float for the moon because I am not trying to calculate the position of the moon in the sky, the floats are the values that sun strings will be at full intensity. The moon does not require that one.

PHP:
// 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 };

The spaces were most likely added when I imported the code into visual studio. They should have no impact on the code.

I had a look at the code you posted and couldn't find anything that you changed that looked like it would be causing trouble... is the most recent one that I have put up still getting stuck as well? How are you reading the values when you say it isn't changing? Do you have a serial LCD?

Cheers,
 
Hi!
It's the most recent code I'm trying and it's stuck at 10%.
I did some test and changed the moonlight max intensity and here is the result:

max moonligt setting / intensity in %

5 - 20%
10 - 10%
15 - 13%
20 - 10%
25 - 8%
30 - 10%
35 - 8%
40 - 7%
45 - 8%
50 - 8%

I do not know whether this test may be helpful but I think the result is quite weird. I mean, the intensity should not change whether you changed the max output or not. Right?

Anyway, here is the code I'm using:

PHP:
// Natural Reef Aquarium Lighting V2.5.3 
// 14/11/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[] = { 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) 
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, 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) 
byte MoonPWMHigh[] = {10};             // 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 = -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 _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; 

    float 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(byte _ledPin, byte _ledHigh, byte _ledLow, byte _year, byte _month, byte _day, byte _hour, byte _min, byte _sec) 
{ 
    int result; 
    float a = floor((14 - _month) / 12); 
    float y = _year + 4800 - a; 
    float m = _month + (12 * a) - 3; 

        float 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 moon = fmod((2456318.69458333 - JC), 29.530589); 

    if (moon <= 14.7652945) 
    { 
        result = map(moon, 0, 14.7652945, _ledHigh, _ledLow); 
    } 

    if (moon >= 14.7652946) 
    { 
        result = map(moon, 14.7652946, 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; 
    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++) 
        { 
            value = MoonLight(moonPins[i], MoonPWMHigh[i], MoonPWMLow[i], year, month, dayOfMonth, rtcHrs, rtcMins, second); 
            Serial.print(map(value, MoonPWMLow[i], MoonPWMHigh[i], 0, 100)); 
            Serial.print("% "); 
        } 
        Serial.println(); 
    } 
}

One last thing. I test the output by the computer. I connect the laptop via the usb wire. start the arduino software and click on serial monitor and then read the result.

//Patrik
 
I did one more test and change the max output to 1. Now the intensity was 100% which seems to be correct according to the lunar calender. I will check again tomorrow if it has been changed.

//Patrik
 
I didn't realized that you had the moon output so low, I think that could be one of the reasons we are seeing strange things. What type of driver do you run for your moon LEDs? Is it possible to adjust the current on the driver? If you can manually set the max current to what you want the full moon to be at, we can then use all 255 steps to adjust the level.

I think that the problem that we might be having is that you are only trying to use 10 steps, this will mean that the LEDs will spend a lot of time at the same level.

It takes 14.5 days to go from 10 - 0 and then another 14.5 days to go back from 0 - 10. That means we only will see a change in value of less then 1 step per day.

0.6 steps per day. (PWM is only whole numbers so every other day it might change 1 step)

Day Value Precent
15 10 100%
14 9 93%
13 9 86%
12 8 80%
11 7 73%
10 7 66%
9 6 59%
8 5 53%
7 5 46%
6 4 39%
5 3 32%
4 3 26%
3 2 19%
2 1 12%
1 1 5%
0 0 0%
1 1 5%
2 1 12%
3 2 19%
4 3 26%
5 3 32%
6 4 39%
7 5 46%
8 5 53%
9 6 59%
10 7 66%
11 7 73%
12 8 80%
13 9 86%
14 9 93%
15 10 100%


With the 255 - 0 - 255 we will see a much more frequent change in PWM steps.

18.2 steps per day.

Day Value Precent
15 255 100%
14 238 93%
13 220 86%
12 203 80%
11 186 73%
10 169 66%
9 151 59%
8 134 53%
7 117 46%
6 100 39%
5 82 32%
4 65 26%
3 48 19%
2 30 12%
1 13 5%
0 0 0%
1 13 5%
2 30 12%
3 48 19%
4 65 26%
5 82 32%
6 100 39%
7 117 46%
8 134 53%
9 151 59%
10 169 66%
11 186 73%
12 203 80%
13 220 86%
14 238 93%
15 255 100%


The other thing that might be helpful is to actually read the current on the LED string. The value you see in the serial reader is only a calculated value that should be the same as the output to the LEDs but its possible that they might not be the same.

Please let me know if you need me to explain anything further or need more guidance in the setup or testing.

Cheers,
 
Ok, I think I understand what you are saying. I will test to change the light to 255.

My system is a 720 liter that is powered by about 100 3w leds. 2 of this leds (royal blue, cree) is used as moonlight.
All of the leds is run by Meanwell ldd-h drivers (700 and 1000 mA)
The moonlight is using a ldd-h 1000 driver.

Unfortunately, I don't have any extra driver that I could use. I know that there are 300 mA available and I guess I have to buy one of these.

The problem with using the 1000mA driver at full power is the light output is to bright. (I never thougt 2 3w led could be so bright...) and that is the reason why I choose to set the max. output to only 10.

//Patrik
 
Back
Top