Numlock10
New member
Hello,
I just wanted to post an updated control program for people that might be interested. There has been an increase in people that seem to be interested in the old code that was posed a few years back.
Since there was some interest I decided to have a look at the code and see if I could improve on it. I pretty much decided to try and do a re-write and have come up with the following;
This code will simulate and natural sunrise and sunset for any location on the planet at a given date.
All you need to provide the code is the Latitude, Longitude and Time Zone for the position on the earth. Along with the RTC it will calculate the lighting times.
Please have a look and let me know what you think? If there is anything you would like to see added or changed, please let me know. I plan to work on the Lunar cycle along with adding weather functions soon....
I just wanted to post an updated control program for people that might be interested. There has been an increase in people that seem to be interested in the old code that was posed a few years back.
Since there was some interest I decided to have a look at the code and see if I could improve on it. I pretty much decided to try and do a re-write and have come up with the following;
This code will simulate and natural sunrise and sunset for any location on the planet at a given date.
All you need to provide the code is the Latitude, Longitude and Time Zone for the position on the earth. Along with the RTC it will calculate the lighting times.
Please have a look and let me know what you think? If there is anything you would like to see added or changed, please let me know. I plan to work on the Lunar cycle along with adding weather functions soon....
PHP:
// Natural Reef Aquarium Lighting V1.0
// 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.
// Compiled in Arduino 1.5.2
//
// Future Development:
// Lunar Cycle
// 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[] = {5, 3, 9}; // PWM pins for blues
byte whitePins[] = {10, 11, 6}; // PWM pins for whites
byte blueChannels = 3; // how many PWMs for blues (count from above)
byte whiteChannels = 3; // how many PWMs for whites (count from above)
int PWMHigh = 255; // High value for PWM - if your values are noraml this is 255, if your values are inverted this is 0
int PWMLow = 0; // Low value for 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)
float fullSun = 37.5; // sun elevation in deg that we will assume full sunlight values
int delayTime = 0; // start time delay in minutes, - will push the day back, + will bring the day forward
int LedLight (byte _ledPin, 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 * m) + 2) / 5) + (365 * y) + floor(y / 4) - floor(y / 100) + floor(y / 400) - 32045) + ((_hour / 24.0) + (_min / 1444.0) + (_sec / 86400.0))) - 2451545) / 36525;
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);
float SEA = 90 - SZA;
if (SEA < 0)
{
result = 0;
}
if (SEA > 0 && SEA < fullSun)
{
result = map(SEA,0,fullSun,PWMLow,PWMHigh);
}
if (SEA > fullSun)
{
result = PWMHigh;
}
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() {
Serial.begin(9600);
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;
Serial.println("Blue LED's");
for (i = 0; i < blueChannels; i++)
{
value = LedLight(bluePins[i],year,month,dayOfMonth,rtcHrs,rtcMins,second);
Serial.print(map(value,PWMLow,PWMHigh,0,100));
Serial.print("% ");
}
Serial.println();
Serial.println("White LED's");
for (i = 0; i < whiteChannels; i++)
{
value = LedLight(whitePins[i],year,month,dayOfMonth,rtcHrs,rtcMins,second);
Serial.print(map(value,PWMLow,PWMHigh,0,100));
Serial.print("% ");
}
Serial.println();
}