/*
reefLED v1.0
der_will_zur_macht
05 Nov 2009
Arduino LED lighting controller for reef aquariums
//** Current Functionality
// **paramterized LED lighting control for reef aquariums
// Goal: control 3 banks of LED lighting - east, center, and west
// fade the banks to simulate the sun rising, traversing the sky, and setting
// Implementation: use a DS1307 RTC to kick off lighting schedules
// trigger a master pin "on" when the preset start time is reached
// then, fade each PWM pin up and down accordingly
//** Future Functionality
// trigger "random" storms:
// lights fade down from side to side to imitate cloud cover
// during cloud cover, randomly strobe a bank of LEDs to imitate lightening
// run wavemaker powerheads at higher-than-normal levels to simulate increased
// wave action
//
// control heater based on one-wire sensor
// On hold due to apparent conflicts between one-wire and I2C
//
// control LED moonlight
// fade an LED moonlight according to lunar schedule
//
// control Tunze or other variable-speed powerhead to simulate wave action.
// tie into storm simulation as noted above
// tie into other functionality as appropriate
//** Circuit
//
// PWM LED pins described below connected to dimming circuits on drivers
// ledMaster pin below connected to a 120V AC relay to turn the LED drivers on and off
// grounds from drivers connected to arduino ground
// DS1307 RTC connected via I2C
//
//
//
*/
// Pins to control LEDs
int eastLed = 9; // LED PWM channel for east end
int centerLed = 10; // LED PWM channel for center
int westLed = 11; // LED PWM channel for west end
int ledMaster = 8; // Master channel to control LED powersupply
// Set up RTC
#include "Wire.h"
#define DS1307_I2C_ADDRESS 0x68
// RTC variables
byte second, rtcMins, oldMins, rtcHrs, oldHrs, dayOfWeek, dayOfMonth, month, year;
// Other variables. These control the behavior of lighting.
int minCounter = 0; // counter that resets at midnight
int ledStartMins = 480; // minute to start lights
int photoPeriod = 510; // photoperiod in minutes
int photoStagger = 60; // minutes to stagger photoperiods for each bank
void setup() {
pinMode(ledMaster, OUTPUT); // Set the LED master pin as output
// init I2C
Wire.begin();
// if you will be using the print commands below for debugging, uncomment next line
// Serial.begin(9600);
// Change these values and uncomment to set RTC.
// format is: second, minute, hour, dayOfWeek, dayOfMonth, month, year
// setDateDs1307(10, 30, 18, 3, 22, 9, 9);
}
/****** LED Functions ******/
/***************************/
//function to set LED brightness according to time of day
//function has three equal phases - ramp up, hold, and ramp down
void setLed(int mins, int ledPin, int start, int period) {
if (mins > start && mins <= start + (period / 3) ) {
analogWrite(ledPin, map(mins - start, 0, period/3, 0, 255));
}
if (mins > start + (period / 3) && mins <= start + 2*(period / 3)) {
analogWrite(ledPin, 255);
}
if (mins > start + 2*(period / 3) && mins <= start + period) {
analogWrite(ledPin, map(mins - (start + 2*(period/3)), 0, (period/3), 255, 0));
}
}
/***** 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) );
}
// 1) Sets the date and time on the ds1307
// 2) Start the clock
// 3) Set hour mode to 24 hour clock
void setDateDs1307(byte second, // 0-59
byte minute, // 0-59
byte hour, // 1-23
byte dayOfWeek, // 1-7
byte dayOfMonth, // 1-28/29/30/31
byte month, // 1-12
byte year) // 0-99
{
Wire.beginTransmission(DS1307_I2C_ADDRESS);
Wire.send(0);
Wire.send(decToBcd(second));
Wire.send(decToBcd(minute));
Wire.send(decToBcd(hour));
Wire.send(decToBcd(dayOfWeek));
Wire.send(decToBcd(dayOfMonth));
Wire.send(decToBcd(month));
Wire.send(decToBcd(year));
Wire.endTransmission();
}
// Get 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.send(0);
Wire.endTransmission();
Wire.requestFrom(DS1307_I2C_ADDRESS, 7);
*second = bcdToDec(Wire.receive() & 0x7f);
*minute = bcdToDec(Wire.receive());
*hour = bcdToDec(Wire.receive() & 0x3f);
*dayOfWeek = bcdToDec(Wire.receive());
*dayOfMonth = bcdToDec(Wire.receive());
*month = bcdToDec(Wire.receive());
*year = bcdToDec(Wire.receive());
}
/***** Main Loop ***********/
/***************************/
void loop() {
// get time from RTC and put in hrs and mins variables
getDateDs1307(&second, &rtcMins, &rtcHrs, &dayOfWeek, &dayOfMonth, &month, &year);
minCounter = rtcHrs * 60 + rtcMins;
//uncomment these print commands for debugging. Useful to verify that the clock is set correctly
/* Serial.print(rtcHrs, DEC);
Serial.print(":");
Serial.print(rtcMins, DEC);
Serial.print(":");
Serial.print(second, DEC);
Serial.print(" ");
Serial.print(dayOfMonth, DEC);
Serial.print("/");
Serial.print(month, DEC);
Serial.print("/");
Serial.print(year, DEC);
Serial.print(" ");
Serial.print("Start At: ");
Serial.print(ledStartMins);
Serial.print(" Counter: ");
Serial.print(minCounter);
Serial.print(" End: ");
Serial.println(ledStartMins + photoPeriod + 2*photoStagger);
*/
// determine if it is day or night, and act accordingly
if (minCounter > ledStartMins && minCounter < ledStartMins + photoPeriod + 2*photoStagger) { //day
// set LED states
digitalWrite(ledMaster, HIGH);
setLed(minCounter, eastLed, ledStartMins, photoPeriod);
setLed(minCounter, centerLed, ledStartMins + photoStagger, photoPeriod);
setLed(minCounter, westLed, ledStartMins + 2*photoStagger, photoPeriod);
}
else { //night
digitalWrite(ledMaster, LOW);
analogWrite(eastLed, 0);
analogWrite(centerLed, 0);
analogWrite(westLed, 0);
}
delay(1000);
}