Natural Reef Aquarium Lighting Controller

Quick update:

I have changed the max. moonlight to 255. When I check the serial monitor it says 7%.
Unfortunately, my multimeter is broke and cant measure the current. I will have to wait for a couple of days before I can buy a new one.
Anyway, when looking at the moonlight, they shine very bright and I don't beleve that's only 7% but until I get a new multimeter, I cant say for sure.

//Patrik
 
Very interesting Numlock10!!

I like the SunLight function, very much indeed. When I get some time I'll try to merge that into my sketch, using it to create the "light curve for the day" instead of calling it every time. I'm imagining I'll create my 10 to 20 step curve with discrete points calculated by SunLight, which would be a good enough approximation to the full curve.

Moonlight seems interesting too.

Cool :beer:
 
Quick update:

I have changed the max. moonlight to 255. When I check the serial monitor it says 7%.
Unfortunately, my multimeter is broke and cant measure the current. I will have to wait for a couple of days before I can buy a new one.
Anyway, when looking at the moonlight, they shine very bright and I don't beleve that's only 7% but until I get a new multimeter, I cant say for sure.

//Patrik

Thanks, once I get back home I will try setting up a test string to try updates on.
 
Doing some reading I think I might have found somthing that is causing problems. I will make some changes after work and post an update.
 
Finlay get a chance to make some changes,

Please let me know how this one works, you should be able to run the moon at 10 rather then 255.

PHP:
// Natural Reef Aquarium Lighting V2.5.4
// 23/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
// Float Map for moonlight
//
// 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

float floatMap(float x, float in_min, float in_max, int out_min, int out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

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.0 - _month) / 12.0);
	float y = _year + 4800.0 - a;
	float m = _month + (12.0 * a) - 3.0;
	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.0);

	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.0)*(1.914602 - JC * (0.004817 + 0.000014 * JC)) + sin(((2.0 * GMAS) * M_PI) / 180.0) * (0.019993 - 0.000101 * JC) + sin(((3.0 * JC) * M_PI) / 180.0) * 0.000289;

	float STL = GMLS + SEoC;

	float STA = GMAS + SEoC;

	float SRV = (1.000001018 * (1.0 - EEO * EEO)) / (1.0 + EEO * cos((STA * M_PI) / 180.0));

	float SAL = STL - 0.00569 - 0.00478 * sin(((125.04 - 1934.136 * JC) * M_PI) / 180.0);

	float MOE = 23.0 + (26.0 + ((21.448 - JC * (46.815 + JC * (0.00059 - JC * 0.001813)))) / 60.0) / 60.0;

	float OC = MOE + 0.00256 * cos(((215.04 - 1934.136 * JC) * M_PI) / 180.0);

	float SD = (asin(sin((OC * M_PI) / 180.0) * sin((SAL * M_PI) / 180.0))) * (180.0 / M_PI);

	float vy = tan(((OC / 2.0) * M_PI) / 180.0) * tan(((OC / 2.0) * M_PI) / 180.0);

	float EQoT = (4.0 * (vy * (sin(2.0 * ((GMLS * M_PI) / 180.0)) - 2.0 * EEO * sin((GMAS * M_PI) / 180.0) + 4.0 * EEO * vy * sin((GMAS * M_PI) / 180.0) * cos(2.0 * ((GMLS * M_PI) / 180.0)) - 0.5 * vy * vy * sin(4.0 * ((GMLS * M_PI) / 180.0)) - 1.25 * EEO * EEO * sin(2 * ((GMAS * M_PI) / 180))))) * (180 / M_PI);

	float HAS = acos(cos((90.833 * M_PI) / 180.0) / (cos((latitude * M_PI) / 180.0) * cos((SD * M_PI) / 180.0)) - tan((latitude * M_PI) / 180.0) * tan((SD * M_PI) / 180.0)) * (180.0 / M_PI);

	float SN = (720.0 - 4.0 * longitude - EQoT + TimeZone * 60.0);

	float SR = SN - HAS * 4.0;

	float SS = SN + HAS * 4.0;

	float STD = 8.0 * HAS;

	float TST = fmod((((_hour)+(_min / 60.0) + (_sec / 3600.0)) / 24.0) * 1440.0 + EQoT + 4.0 * longitude - 60.0 * TimeZone, 1440.0) + delayTime;

	if (TST / 4 < 0.0)
	{
		AH = ((TST / 4.0) + 180.0);
	}
	else
	{
		AH = ((TST / 4.0) - 180.0);
	}

	float SZA = (acos(sin((latitude * M_PI) / 180.0) * sin((SD * M_PI) / 180.0) + cos((latitude * M_PI) / 180.0) * cos((SD * M_PI) / 180.0) * cos((AH * M_PI) / 180.0))) * (180.0 / M_PI);

	float SEA = 90.0 - SZA;

	if (SEA <= 0.0)
	{
		result = _ledLow;
	}

	if (SEA > 0.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.0 - _month) / 12.0);
	float y = _year + 4800.0 - a;
	float m = _month + (12.0 * a) - 3.0;

        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 = floatMap(moon, 0.0, 14.7652945, _ledHigh, _ledLow);
	}

	if (moon >= 14.7652946)
	{
		result = floatMap(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,
 
Finlay get a chance to make some changes,

Please let me know how this one works, you should be able to run the moon at 10 rather then 255.

PHP:
// Natural Reef Aquarium Lighting V2.5.4
// 23/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
// Float Map for moonlight
//
// 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

float floatMap(float x, float in_min, float in_max, int out_min, int out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

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.0 - _month) / 12.0);
	float y = _year + 4800.0 - a;
	float m = _month + (12.0 * a) - 3.0;
	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.0);

	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.0)*(1.914602 - JC * (0.004817 + 0.000014 * JC)) + sin(((2.0 * GMAS) * M_PI) / 180.0) * (0.019993 - 0.000101 * JC) + sin(((3.0 * JC) * M_PI) / 180.0) * 0.000289;

	float STL = GMLS + SEoC;

	float STA = GMAS + SEoC;

	float SRV = (1.000001018 * (1.0 - EEO * EEO)) / (1.0 + EEO * cos((STA * M_PI) / 180.0));

	float SAL = STL - 0.00569 - 0.00478 * sin(((125.04 - 1934.136 * JC) * M_PI) / 180.0);

	float MOE = 23.0 + (26.0 + ((21.448 - JC * (46.815 + JC * (0.00059 - JC * 0.001813)))) / 60.0) / 60.0;

	float OC = MOE + 0.00256 * cos(((215.04 - 1934.136 * JC) * M_PI) / 180.0);

	float SD = (asin(sin((OC * M_PI) / 180.0) * sin((SAL * M_PI) / 180.0))) * (180.0 / M_PI);

	float vy = tan(((OC / 2.0) * M_PI) / 180.0) * tan(((OC / 2.0) * M_PI) / 180.0);

	float EQoT = (4.0 * (vy * (sin(2.0 * ((GMLS * M_PI) / 180.0)) - 2.0 * EEO * sin((GMAS * M_PI) / 180.0) + 4.0 * EEO * vy * sin((GMAS * M_PI) / 180.0) * cos(2.0 * ((GMLS * M_PI) / 180.0)) - 0.5 * vy * vy * sin(4.0 * ((GMLS * M_PI) / 180.0)) - 1.25 * EEO * EEO * sin(2 * ((GMAS * M_PI) / 180))))) * (180 / M_PI);

	float HAS = acos(cos((90.833 * M_PI) / 180.0) / (cos((latitude * M_PI) / 180.0) * cos((SD * M_PI) / 180.0)) - tan((latitude * M_PI) / 180.0) * tan((SD * M_PI) / 180.0)) * (180.0 / M_PI);

	float SN = (720.0 - 4.0 * longitude - EQoT + TimeZone * 60.0);

	float SR = SN - HAS * 4.0;

	float SS = SN + HAS * 4.0;

	float STD = 8.0 * HAS;

	float TST = fmod((((_hour)+(_min / 60.0) + (_sec / 3600.0)) / 24.0) * 1440.0 + EQoT + 4.0 * longitude - 60.0 * TimeZone, 1440.0) + delayTime;

	if (TST / 4 < 0.0)
	{
		AH = ((TST / 4.0) + 180.0);
	}
	else
	{
		AH = ((TST / 4.0) - 180.0);
	}

	float SZA = (acos(sin((latitude * M_PI) / 180.0) * sin((SD * M_PI) / 180.0) + cos((latitude * M_PI) / 180.0) * cos((SD * M_PI) / 180.0) * cos((AH * M_PI) / 180.0))) * (180.0 / M_PI);

	float SEA = 90.0 - SZA;

	if (SEA <= 0.0)
	{
		result = _ledLow;
	}

	if (SEA > 0.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.0 - _month) / 12.0);
	float y = _year + 4800.0 - a;
	float m = _month + (12.0 * a) - 3.0;

        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 = floatMap(moon, 0.0, 14.7652945, _ledHigh, _ledLow);
	}

	if (moon >= 14.7652946)
	{
		result = floatMap(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,

Hi!
I'm testing it right now. The clock is now 13.00 and when I set the moonlight to 10 the moon output is 0%. If I set the moonligt to 150 it says 6 % output. If I set the moonligt to 255 it says 7% output.

I will run the sketch with setting 10 for the moonlight. I will return tomorrow if I see some changes. Please let me now if you want me to do some more testing, like changing some number or so.

//Patrik
 
..and here is the code I'm using right now

PHP:
// Natural Reef Aquarium Lighting V2.5.4
// 23/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
// Float Map for moonlight
//
// 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

float floatMap(float x, float in_min, float in_max, int out_min, int out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

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.0 - _month) / 12.0);
    float y = _year + 4800.0 - a;
    float m = _month + (12.0 * a) - 3.0;
    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.0);

    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.0)*(1.914602 - JC * (0.004817 + 0.000014 * JC)) + sin(((2.0 * GMAS) * M_PI) / 180.0) * (0.019993 - 0.000101 * JC) + sin(((3.0 * JC) * M_PI) / 180.0) * 0.000289;

    float STL = GMLS + SEoC;

    float STA = GMAS + SEoC;

    float SRV = (1.000001018 * (1.0 - EEO * EEO)) / (1.0 + EEO * cos((STA * M_PI) / 180.0));

    float SAL = STL - 0.00569 - 0.00478 * sin(((125.04 - 1934.136 * JC) * M_PI) / 180.0);

    float MOE = 23.0 + (26.0 + ((21.448 - JC * (46.815 + JC * (0.00059 - JC * 0.001813)))) / 60.0) / 60.0;

    float OC = MOE + 0.00256 * cos(((215.04 - 1934.136 * JC) * M_PI) / 180.0);

    float SD = (asin(sin((OC * M_PI) / 180.0) * sin((SAL * M_PI) / 180.0))) * (180.0 / M_PI);

    float vy = tan(((OC / 2.0) * M_PI) / 180.0) * tan(((OC / 2.0) * M_PI) / 180.0);

    float EQoT = (4.0 * (vy * (sin(2.0 * ((GMLS * M_PI) / 180.0)) - 2.0 * EEO * sin((GMAS * M_PI) / 180.0) + 4.0 * EEO * vy * sin((GMAS * M_PI) / 180.0) * cos(2.0 * ((GMLS * M_PI) / 180.0)) - 0.5 * vy * vy * sin(4.0 * ((GMLS * M_PI) / 180.0)) - 1.25 * EEO * EEO * sin(2 * ((GMAS * M_PI) / 180))))) * (180 / M_PI);

    float HAS = acos(cos((90.833 * M_PI) / 180.0) / (cos((latitude * M_PI) / 180.0) * cos((SD * M_PI) / 180.0)) - tan((latitude * M_PI) / 180.0) * tan((SD * M_PI) / 180.0)) * (180.0 / M_PI);

    float SN = (720.0 - 4.0 * longitude - EQoT + TimeZone * 60.0);

    float SR = SN - HAS * 4.0;

    float SS = SN + HAS * 4.0;

    float STD = 8.0 * HAS;

    float TST = fmod((((_hour)+(_min / 60.0) + (_sec / 3600.0)) / 24.0) * 1440.0 + EQoT + 4.0 * longitude - 60.0 * TimeZone, 1440.0) + delayTime;

    if (TST / 4 < 0.0)
    {
        AH = ((TST / 4.0) + 180.0);
    }
    else
    {
        AH = ((TST / 4.0) - 180.0);
    }

    float SZA = (acos(sin((latitude * M_PI) / 180.0) * sin((SD * M_PI) / 180.0) + cos((latitude * M_PI) / 180.0) * cos((SD * M_PI) / 180.0) * cos((AH * M_PI) / 180.0))) * (180.0 / M_PI);

    float SEA = 90.0 - SZA;

    if (SEA <= 0.0)
    {
        result = _ledLow;
    }

    if (SEA > 0.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.0 - _month) / 12.0);
    float y = _year + 4800.0 - a;
    float m = _month + (12.0 * a) - 3.0;

        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 = floatMap(moon, 0.0, 14.7652945, _ledHigh, _ledLow);
    }

    if (moon >= 14.7652946)
    {
        result = floatMap(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();
    }
}

//Patrik
 
Just a quick update!
the moonlight does not work. The moonlight does not start at all (0% output) if I choose 10 as max output. It does not changes.

//Patrik
 
Ok, back home again and have had a look at the code. Haven't changed much but have actually measured the output from my Arduino with a multimeter and everything is working correctly. Please let me know if you have any luck with this one.

I have tested your code that you have posted earlier and also get the correct voltage out of my Arudino. Is it possible for you to try changing your pin for the moon?

PHP:
// Natural Reef Aquarium Lighting V2.5.5
// 30/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
// Float Map for moonlight
//
// 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

float floatMap(float x, float in_min, float in_max, float out_min, float out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

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.0 - _month) / 12.0);
	float y = _year + 4800.0 - a;
	float m = _month + (12.0 * a) - 3.0;
	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.0);

	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.0)*(1.914602 - JC * (0.004817 + 0.000014 * JC)) + sin(((2.0 * GMAS) * M_PI) / 180.0) * (0.019993 - 0.000101 * JC) + sin(((3.0 * JC) * M_PI) / 180.0) * 0.000289;

	float STL = GMLS + SEoC;

	float STA = GMAS + SEoC;

	float SRV = (1.000001018 * (1.0 - EEO * EEO)) / (1.0 + EEO * cos((STA * M_PI) / 180.0));

	float SAL = STL - 0.00569 - 0.00478 * sin(((125.04 - 1934.136 * JC) * M_PI) / 180.0);

	float MOE = 23.0 + (26.0 + ((21.448 - JC * (46.815 + JC * (0.00059 - JC * 0.001813)))) / 60.0) / 60.0;

	float OC = MOE + 0.00256 * cos(((215.04 - 1934.136 * JC) * M_PI) / 180.0);

	float SD = (asin(sin((OC * M_PI) / 180.0) * sin((SAL * M_PI) / 180.0))) * (180.0 / M_PI);

	float vy = tan(((OC / 2.0) * M_PI) / 180.0) * tan(((OC / 2.0) * M_PI) / 180.0);

	float EQoT = (4.0 * (vy * (sin(2.0 * ((GMLS * M_PI) / 180.0)) - 2.0 * EEO * sin((GMAS * M_PI) / 180.0) + 4.0 * EEO * vy * sin((GMAS * M_PI) / 180.0) * cos(2.0 * ((GMLS * M_PI) / 180.0)) - 0.5 * vy * vy * sin(4.0 * ((GMLS * M_PI) / 180.0)) - 1.25 * EEO * EEO * sin(2 * ((GMAS * M_PI) / 180))))) * (180 / M_PI);

	float HAS = acos(cos((90.833 * M_PI) / 180.0) / (cos((latitude * M_PI) / 180.0) * cos((SD * M_PI) / 180.0)) - tan((latitude * M_PI) / 180.0) * tan((SD * M_PI) / 180.0)) * (180.0 / M_PI);

	float SN = (720.0 - 4.0 * longitude - EQoT + TimeZone * 60.0);

	float SR = SN - HAS * 4.0;

	float SS = SN + HAS * 4.0;

	float STD = 8.0 * HAS;

	float TST = fmod((((_hour)+(_min / 60.0) + (_sec / 3600.0)) / 24.0) * 1440.0 + EQoT + 4.0 * longitude - 60.0 * TimeZone, 1440.0) + delayTime;

	if (TST / 4 < 0.0)
	{
		AH = ((TST / 4.0) + 180.0);
	}
	else
	{
		AH = ((TST / 4.0) - 180.0);
	}

	float SZA = (acos(sin((latitude * M_PI) / 180.0) * sin((SD * M_PI) / 180.0) + cos((latitude * M_PI) / 180.0) * cos((SD * M_PI) / 180.0) * cos((AH * M_PI) / 180.0))) * (180.0 / M_PI);

	float SEA = 90.0 - SZA;

	if (SEA <= 0.0)
	{
		result = _ledLow;
	}

	if (SEA > 0.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.0 - _month) / 12.0);
	float y = _year + 4800.0 - a;
	float m = _month + (12.0 * a) - 3.0;

        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 = floatMap(moon, 0.0, 14.7652945, _ledHigh, _ledLow);
	}

	if (moon >= 14.7652946)
	{
		result = floatMap(moon, 14.7652946, 29.530589, _ledLow, _ledHigh);
	}
        Serial.print(moon);
        Serial.println();
        Serial.print(result);
        Serial.println();
	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();
                update_moon();
	}
}

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();
	}
}

void update_moon(void)
{
  int i;
	byte value;
	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,

Jason
 
Last edited:
Ok, I found an error in my moon code :headwally:, I have been running this for about an hour or so now and am seeing a change in the value of the moon light.

PHP:
// Natural Reef Aquarium Lighting V2.5.6
// 30/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
// Float Map for moonlight with corrected formula
//
// 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)

// Sunlight Variables

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

float floatMap(float x, float in_min, float in_max, int out_min, int out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

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.0 - _month) / 12.0);
	float y = _year + 4800.0 - a;
	float m = _month + (12.0 * a) - 3.0;
	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.0);

	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.0)*(1.914602 - JC * (0.004817 + 0.000014 * JC)) + sin(((2.0 * GMAS) * M_PI) / 180.0) * (0.019993 - 0.000101 * JC) + sin(((3.0 * JC) * M_PI) / 180.0) * 0.000289;

	float STL = GMLS + SEoC;

	float STA = GMAS + SEoC;

	float SRV = (1.000001018 * (1.0 - EEO * EEO)) / (1.0 + EEO * cos((STA * M_PI) / 180.0));

	float SAL = STL - 0.00569 - 0.00478 * sin(((125.04 - 1934.136 * JC) * M_PI) / 180.0);

	float MOE = 23.0 + (26.0 + ((21.448 - JC * (46.815 + JC * (0.00059 - JC * 0.001813)))) / 60.0) / 60.0;

	float OC = MOE + 0.00256 * cos(((215.04 - 1934.136 * JC) * M_PI) / 180.0);

	float SD = (asin(sin((OC * M_PI) / 180.0) * sin((SAL * M_PI) / 180.0))) * (180.0 / M_PI);

	float vy = tan(((OC / 2.0) * M_PI) / 180.0) * tan(((OC / 2.0) * M_PI) / 180.0);

	float EQoT = (4.0 * (vy * (sin(2.0 * ((GMLS * M_PI) / 180.0)) - 2.0 * EEO * sin((GMAS * M_PI) / 180.0) + 4.0 * EEO * vy * sin((GMAS * M_PI) / 180.0) * cos(2.0 * ((GMLS * M_PI) / 180.0)) - 0.5 * vy * vy * sin(4.0 * ((GMLS * M_PI) / 180.0)) - 1.25 * EEO * EEO * sin(2 * ((GMAS * M_PI) / 180))))) * (180 / M_PI);

	float HAS = acos(cos((90.833 * M_PI) / 180.0) / (cos((latitude * M_PI) / 180.0) * cos((SD * M_PI) / 180.0)) - tan((latitude * M_PI) / 180.0) * tan((SD * M_PI) / 180.0)) * (180.0 / M_PI);

	float SN = (720.0 - 4.0 * longitude - EQoT + TimeZone * 60.0);

	float SR = SN - HAS * 4.0;

	float SS = SN + HAS * 4.0;

	float STD = 8.0 * HAS;

	float TST = fmod((((_hour)+(_min / 60.0) + (_sec / 3600.0)) / 24.0) * 1440.0 + EQoT + 4.0 * longitude - 60.0 * TimeZone, 1440.0) + delayTime;

	if (TST / 4 < 0.0)
	{
		AH = ((TST / 4.0) + 180.0);
	}
	else
	{
		AH = ((TST / 4.0) - 180.0);
	}

	float SZA = (acos(sin((latitude * M_PI) / 180.0) * sin((SD * M_PI) / 180.0) + cos((latitude * M_PI) / 180.0) * cos((SD * M_PI) / 180.0) * cos((AH * M_PI) / 180.0))) * (180.0 / M_PI);

	float SEA = 90.0 - SZA;

	if (SEA <= 0.0)
	{
		result = _ledLow;
	}

	if (SEA > 0.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.0 - _month) / 12.0);
	float y = _year + 4800.0 - a;
	float m = _month + (12.0 * a) - 3.0;
	
        float mJDN = ((_day  + ((153.0 * m + 2.0) / 5.0) + (365.0 * y) + (y / 4.0) - ( y / 100.0) + (y / 400.0) - 32045.0) + 730483.71);

        float mJDR = (_hour / 24.0) + (_min / 1444.0) + (_sec / 86400.0);

        float mJD = mJDN + mJDR;
        
	float moon = fmod((mJD - 2456318.69458333), 29.530589);

	if (moon <= 14.7652945)
	{
		result = floatMap(moon, 0.0, 14.7652945, _ledHigh, _ledLow);
	}

	if (moon >= 14.7652946)
	{
		result = floatMap(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(){
	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();
	}
}

This should work now even with your 10 max PWM, however I would still recommend getting a lower power driver that will at least allow you a larger range as we discussed earlier.

Please let me know how this one goes.

Cheers,
 
Checked again today and the value has now gone from 13% down to 3% which seems to be tracking correctly.

Cheers,
 
Hi Jason!

Finally, it's working for me too. I started the test yesterday evening and from the beginning it sayed 14%. After checking it again a couple of minutes after midnight it sayed 8%. Now, in the morning, its down to 7 %.:bounce3:

Now, you wont here so much from me unless you come with some new function and I guess I will be one of the first to test it.

The sketch is now complete as I see it, I could not which for anything else. I know, after reading a lot about moonlight sketch, that it ain't easy to produce that you just have done. So, I'm really impressed about what you have done.:beer:

//Patrik
 
now to get the moon on the main blue pin.
you didnt think i forgot did you LOL
i thought that was the whole idea for useing ldd drivers to use the mains instead of having seperate moon lights.
but ive been wrong before
thanks for all your work jason. i cant wait to get this running i loaded it to my nano no prob..i need to get the rtc wired up still .
 
ok i think i broke it

PHP:
// Natural Reef Aquarium Lighting V2.5.6
// 30/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
// Float Map for moonlight with corrected formula
//
// 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[] = {  9 };      // PWM pins for blues
byte whitePins[] = {  11 };    // PWM pins for whites
byte uvPins[] = { 5 };         // PWM pins for UVs
byte moonPins[] = { 6 };         // PWM pins for moonlights

byte blueChannels = 1;    // how many PWMs for blues (count from above)
byte whiteChannels = 1;    // how many PWMs for whites (count from above)
byte uvChannels = 0;    // 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 };      // 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 = -28.61243;   // + to N  Defualt - (-19.770621) Heart Reef, Great Barrier Reef, QLD, Australia 
float longitude = -80.80765;  // + to E  Defualt - (149.238532)
int TimeZone = -5;             // + to E  Defulat - (10)

// Sunlight Variables

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

float floatMap(float x, float in_min, float in_max, int out_min, int out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

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.0 - _month) / 12.0);
    float y = _year + 4800.0 - a;
    float m = _month + (12.0 * a) - 3.0;
    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.0);

    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.0)*(1.914602 - JC * (0.004817 + 0.000014 * JC)) + sin(((2.0 * GMAS) * M_PI) / 180.0) * (0.019993 - 0.000101 * JC) + sin(((3.0 * JC) * M_PI) / 180.0) * 0.000289;

    float STL = GMLS + SEoC;

    float STA = GMAS + SEoC;

    float SRV = (1.000001018 * (1.0 - EEO * EEO)) / (1.0 + EEO * cos((STA * M_PI) / 180.0));

    float SAL = STL - 0.00569 - 0.00478 * sin(((125.04 - 1934.136 * JC) * M_PI) / 180.0);

    float MOE = 23.0 + (26.0 + ((21.448 - JC * (46.815 + JC * (0.00059 - JC * 0.001813)))) / 60.0) / 60.0;

    float OC = MOE + 0.00256 * cos(((215.04 - 1934.136 * JC) * M_PI) / 180.0);

    float SD = (asin(sin((OC * M_PI) / 180.0) * sin((SAL * M_PI) / 180.0))) * (180.0 / M_PI);

    float vy = tan(((OC / 2.0) * M_PI) / 180.0) * tan(((OC / 2.0) * M_PI) / 180.0);

    float EQoT = (4.0 * (vy * (sin(2.0 * ((GMLS * M_PI) / 180.0)) - 2.0 * EEO * sin((GMAS * M_PI) / 180.0) + 4.0 * EEO * vy * sin((GMAS * M_PI) / 180.0) * cos(2.0 * ((GMLS * M_PI) / 180.0)) - 0.5 * vy * vy * sin(4.0 * ((GMLS * M_PI) / 180.0)) - 1.25 * EEO * EEO * sin(2 * ((GMAS * M_PI) / 180))))) * (180 / M_PI);

    float HAS = acos(cos((90.833 * M_PI) / 180.0) / (cos((latitude * M_PI) / 180.0) * cos((SD * M_PI) / 180.0)) - tan((latitude * M_PI) / 180.0) * tan((SD * M_PI) / 180.0)) * (180.0 / M_PI);

    float SN = (720.0 - 4.0 * longitude - EQoT + TimeZone * 60.0);

    float SR = SN - HAS * 4.0;

    float SS = SN + HAS * 4.0;

    float STD = 8.0 * HAS;

    float TST = fmod((((_hour)+(_min / 60.0) + (_sec / 3600.0)) / 24.0) * 1440.0 + EQoT + 4.0 * longitude - 60.0 * TimeZone, 1440.0) + delayTime;

    if (TST / 4 < 0.0)
    {
        AH = ((TST / 4.0) + 180.0);
    }
    else
    {
        AH = ((TST / 4.0) - 180.0);
    }

    float SZA = (acos(sin((latitude * M_PI) / 180.0) * sin((SD * M_PI) / 180.0) + cos((latitude * M_PI) / 180.0) * cos((SD * M_PI) / 180.0) * cos((AH * M_PI) / 180.0))) * (180.0 / M_PI);

    float SEA = 90.0 - SZA;

    if (SEA <= 0.0)
    {
        result = _ledLow;
    }

    if (SEA > 0.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.0 - _month) / 12.0);
    float y = _year + 4800.0 - a;
    float m = _month + (12.0 * a) - 3.0;
    
        float mJDN = ((_day  + ((153.0 * m + 2.0) / 5.0) + (365.0 * y) + (y / 4.0) - ( y / 100.0) + (y / 400.0) - 32045.0) + 730483.71);

        float mJDR = (_hour / 24.0) + (_min / 1444.0) + (_sec / 86400.0);

        float mJD = mJDN + mJDR;
        
    float moon = fmod((mJD - 2456318.69458333), 29.530589);

    if (moon <= 14.7652945)
    {
        result = floatMap(moon, 0.0, 14.7652945, _ledHigh, _ledLow);
    }

    if (moon >= 14.7652946)
    {
        result = floatMap(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(){
    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();
    }
}

in the area that you put location i used my home town.in program it says N/E, my coords are N/W does that have somting to do with it ? i get weird time stamps on serial read. time works with default coords
edit: found - in front of first coord seems to be working now...
th_Selection_002.png
[/URL][/IMG]

th_Selection_001.png
[/URL][/IMG]
 
Last edited:
hello all,

Jason i have signed up to this forum to thank u for the code i have been looking for a code that does just this and struggled, specially as im not in a any way a coder! so thanks!

question time now.... (bet u knew this was coming) lol

how would one add an LCD to this, say a 16x2 lcd just to display clock on first line on one side and maybe temp on the other (for monitoring lighting rig temp) and then the second line scrolls theought the %s of each channel? ? ? ? ?

again thank u for giving your time and knowledge to the likes of me (clueless).
 
maybe something like this but to scroll only on the second line
displying the %s the lights are at.... does that make sense?


PHP:
/*
  Marquee
  * this sketch can scroll a very long line of text
 */

#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 8, 7, 4, 2);
const int numRows = 2;
const int numCols = 16;


void setup()
{
  // set up the LCD's number of columns and rows:
  lcd.begin(numCols, numRows);
}

void loop()
{
  marquee("your text here");
  delay(2500);
  lcd.clear();
}

// this version of marquee uses manual scrolling for very long messages
void marquee( char *text)
{
  int length = strlen(text); // the number of characters in the text
  if(length < numCols)
    lcd.print(text);
  else
  {
    int pos;
    for( pos = 0; pos < numCols; pos++)
       lcd.print(text[pos]);
    delay(1000); // allow time to read the first line before scrolling
    pos=1;
    while(pos <= length - numCols)
    {
      lcd.setCursor(0,0);
      for( int i=0; i < numCols; i++)
        lcd.print(text[pos+i]);
      delay(300);
      pos = pos + 1;
    }
  }
}
 
Back
Top