Arduino Aquarium Lighting - Fade using RTC

I am working on an Aquarium controller for some custom LEDs I have built for my fish tank.
Please see my previous post: https://forum.arduino.cc/index.php?topic=389915.0
I have hit yet another wall so after hours of researching i decided to turn to help again!

This is my first project using Arduino so please excuse any mistakes/messy code but this is what i have so far:

// Aquarium Control // Dean Cohen //

// v0.1 Testing PWM control of LED Driver
// v0.2 Added DS3231 RTC, Configuring date/time to show in serial monitor (Thanks to http://www.rinkydinkelectronics.com/library.php?id=73)
// v0.3 Configured to use real time instead of unix time (Thanks to sterretje)
// v0.4 Set to turn LEDs on/off at set times

//Connect 'Dim' wire from LED Driver to pin 10 
//Connect Driver GND input to arduino GND (same side as pin 10)
//Connect (RTC-Arduino): GND-GND, VCC-3.3v, SDA-A4, SCL-A5

  #include <DS3231.h>
// Init the DS3231 using the hardware interface
  DS3231  rtc(A4, A5);

  int led = 10;
//  int fan = 11;
  int brightness = 0;
  int fadeqty = 20;
  
  void setup() {
  pinMode(led, OUTPUT);
  pinMode(fan, OUTPUT);
  Serial.begin(9600);
  rtc.begin();

  // The following lines can be uncommented to set the date and time
  //rtc.setDOW(WEDNESDAY);       // Set Day-of-Week to SUNDAY
  //rtc.setTime(23, 07, 00);     // Set the time to 12:00:00 (24hr format)
  //rtc.setDate(30, 03, 2016);   // Set the date to January 1st, 2014
  }

  void loop()
  {
  // Send Day-of-Week
  Serial.print(rtc.getDOWStr());
  Serial.print(" ");
  
  // Send date
  Serial.print(rtc.getDateStr());
  Serial.print(" -- ");

  // Send time
  Serial.println(rtc.getTimeStr());

  // pointer to a time string
  char *strTime;
  // Get formatted Time 
  strTime = rtc.getTimeStr(FORMAT_LONG);
  
  //LEDs turn on if given time is met
  if(strcmp(strTime, "07:30:00") == 0) {
  Serial.print("***LED ON***");
  Serial.print('\n');
  analogWrite(led, 255);
  }
  //LEDs turn off if given time is met
  if(strcmp(strTime, "17:00:00") == 0) {
  Serial.print("***LED OFF***");
  Serial.print('\n');
  analogWrite(led, 0);
  }

  // fade LEDs on/off
  //analogWrite(led, brightness);
  //if(strcmp(strTime, "23:03:15") == 0) {
  //brightness = brightness + fadeqty;
  //}
  //if (brightness == 255) { 
  //brightness == 255;
  //Serial.print("BRIGHTNESS: "); 
  //Serial.print(brightness);
  //Serial.print('\n');
  //delay (500);
  //}
  
  delay (1000);
}

//  Not Yet Used - Set fan to 100% if exceeds Temp
//  if(rtc.getTemp() > "VALUE")
//  Serial.print("***FAN ON***");
//  analogWrite(fan, 255);  

//  Not Yet Used - PWM LED code
//  analogWrite(led, 64);
//  delay(1000);
//  analogWrite(led, 127);
//  delay(1000);
//  analogWrite(led, 191);
//  delay(1000);
//  analogWrite(led, 255);
//  delay(1000);

//  Not Used - Print RTC built-in Temp
//  // RTC Temp
//  Serial.print("RTC Temperature: ");
//  Serial.print(rtc.getTemp());
//  Serial.println(" C");

//  Not Used - Print Unix time to serial (useful for code below)
//  //Send Unix Time
//  Serial.print("Unix Time: ");
//  Serial.print(rtc.getUnixTime(rtc.getTime()));
//  Serial.print('\n');
  
//  Not used - if (Unix time) = (defined time) print ***LED ON***
//  if (rtc.getUnixTime(rtc.getTime()) == 1459255200)
//  Serial.print("***LED ON***");
//  Serial.print('\n');

so the part I am working on/stuck on is:

  //LEDs turn on if given time is met
  if(strcmp(strTime, "07:30:00") == 0) {
  Serial.print("***LED ON***");
  Serial.print('\n');
  analogWrite(led, 255);
  }
  //LEDs turn off if given time is met
  if(strcmp(strTime, "17:00:00") == 0) {
  Serial.print("***LED OFF***");
  Serial.print('\n');
  analogWrite(led, 0);

Id like to come up with an if statement to define when to start fading the lights on and off, ive tried a few examples however these use ‘delay’ which doesnt seem to work right with the delay I already have,
my thoughts are that i can link it into the RTC somehow?
a very messy solution would be something like this:

  //LEDs turn on if given time is met
  if(strcmp(strTime, "07:30:00") == 0) {
  Serial.print("***LED ON***");
  Serial.print('\n');
  analogWrite(led, 0); }

  //LEDs turn on if given time is met
  if(strcmp(strTime, "07:31:00") == 0) {
  Serial.print("***LED ON***");
  Serial.print('\n');
  analogWrite(led, 64); }

  //LEDs turn on if given time is met
  if(strcmp(strTime, "07:32:00") == 0) {
  Serial.print("***LED ON***");
  Serial.print('\n');
  analogWrite(led, 127); }

  //LEDs turn on if given time is met
  if(strcmp(strTime, "07:33:00") == 0) {
  Serial.print("***LED ON***");
  Serial.print('\n');
  analogWrite(led, 191); }

  //LEDs turn on if given time is met
  if(strcmp(strTime, "07:34:00") == 0) {
  Serial.print("***LED ON***");
  Serial.print('\n');
  analogWrite(led, 255); }

but I was hoping for a smooth gradual fade over say 30 minutes from 0-255.

I also tried something along the lines of this:

  fade LEDs on/off
  analogWrite(led, brightness);
  if(strcmp(strTime, "23:03:15") == 0) {
  brightness = brightness + fadeqty;
  }
  if (brightness == 255) { 
  brightness == 255;
  Serial.print("BRIGHTNESS: "); 
  Serial.print(brightness);
  Serial.print('\n');
  delay (500);
  //}

But it has the delay and i struggled getting my head around the formula last night.

Thanks!

The relevant parts of the pwm fade routines extracted from my controller program, the code might give you some ideas.

//---SUNRISE/SUNSET/MOONLIGHT PWM LED/S----------------------------------------

byte srON_hh     = 9;       // Sunrise, start time for fade Up
byte srON_mm     =  0;

byte srOFF_hh    = 12;
byte srOFF_mm    =  4;

//-----------------------------------------------------------------------------

byte ssON_hh   = 18;      // Sunset, start time for fade Down
byte ssON_mm   = 0;

byte ssOFF_hh  = 18;
byte ssOFF_mm  = 4;

//-----------------------------------------------------------------------------

byte LEDPWM_MOON     =  0;      // moonlight pwm value 0 - 255

byte LEDPWM_PRELOAD  = 30;      // pwm value at which SunRise leds start to illuminate

byte LEDPWM_INCVALUE =  6;      // number of steps to increment the pwm duty cycle

byte LEDPWM_INCTIME  =  3;      // time in seconds between each in/decrease in pwm

byte LEDPWM_DAYLIGHT =  0;      // leds with main lights, 0 for OFF, Max 255 for ON


float SUNRISE_ON  = (srON_hh +  srON_mm / 60.0f);
float SUNRISE_OFF = (srOFF_hh + srOFF_mm / 60.0f);
float SUNSET_ON   = (ssON_hh +  ssON_mm / 60.0f);
float SUNSET_OFF  = (ssOFF_hh + ssOFF_mm / 60.0f);


// main loop

  ledmoonlight_control();   // call led moon rouitine

  

void ledmoonlight_control () {
  //-----------------------------------------------------------------------------
  //  Sunrise , Sunset and Moonlight Control
  //
  //  In this code all three functions are connected to the same blue LEDS
  //  though easy to modify to control separate leds
  //
  //-----------------------------------------------------------------------------
  //  Sunrise LED PWM control
  //-----------------------------------------------------------------------------
  //
  //  To progressively fade up the leds with the option to switch off or leave on
  //  once th main lights come on

  if ( currentHourMinute >= SUNRISE_ON && currentHourMinute <= SUNRISE_OFF && LEDPWM_VALUE == 0 ){
    LEDPWM_VALUE = LEDPWM_PRELOAD;
  }

  if( currentHourMinute >= SUNRISE_ON && currentHourMinute <= SUNRISE_OFF && LEDPWM_VALUE > 0 && LEDPWM_VALUE+LEDPWM_INCVALUE  <= 255  && U_TIME >= LEDPWM_TIME ){
    LEDPWM_TIME = (U_TIME + LEDPWM_INCTIME);
    LEDPWM_VALUE = (LEDPWM_VALUE + LEDPWM_INCVALUE) ;
  }

  //  After sunrise the leds PWM  is set to the value in LEDPWM_DAYLIGHT
  if (currentHourMinute > SUNRISE_OFF  && currentHourMinute < SUNSET_ON ) {
    LEDPWM_VALUE = LEDPWM_DAYLIGHT;
  }

  //else analogWrite(PWM_LED, PWM_VALUE);



  //-----------------------------------------------------------------------------
  //  Sunset and Moonlight LED PWM control
  //-----------------------------------------------------------------------------

  //  To progressively fade down the leds with the option to set a PWM value for Moonlight

  if ( currentHourMinute >= SUNSET_ON && currentHourMinute <= SUNSET_OFF && LEDPWM_VALUE == 0 ){
    LEDPWM_VALUE = 255;
  }

  if ( currentHourMinute >= SUNSET_ON && currentHourMinute <= SUNSET_OFF && LEDPWM_VALUE > LEDPWM_MOON &&  U_TIME >= LEDPWM_TIME &&  LEDPWM_INCVALUE <= LEDPWM_VALUE){

    LEDPWM_TIME = (U_TIME + LEDPWM_INCTIME) ;
    LEDPWM_VALUE = (LEDPWM_VALUE - LEDPWM_INCVALUE );
  }

  // if Sunset value drops to 0 then increase by 1 to avoid a Sunset restart
  if (LEDPWM_VALUE == 0  && currentHourMinute >= SUNSET_ON && currentHourMinute <= SUNSET_OFF){
    LEDPWM_VALUE = 1;
  }

  // sunset ended so ensure pwm is at Zero unless Moon is on
  if ( currentHourMinute > SUNSET_OFF && LEDPWM_MOON == 0 ) {
    LEDPWM_VALUE = 0;
  }

}//---end of ledmoonlight_control

Thank you for your help, i will look through it now.

Just a few quick questions: the byte functions are defined by you right? so you are telling the arduino that

'srON_hh is 9; for example? and 'LEDPWM_MOON' is 0

i will look into your code a little more and see if i can figure it out more, Thanks!

Hi,

That code is from my controller and all the values/code are my own.

I will try and put it back together as its own sketch with the rtc so you can see it running.

The first 8 "bytes" are the start and end times for the sunrise and sunset and those shown are just default values, within my main program I can change those times and save them in eeprom

In that example the sunrise starts at 09:00 hrs and end at 12:04 hrs

The Floats below then take those times and convert it into a value usable in the main timing loop.

The other "bytes" should are self explaining , the Moonlight default value was 0, but can be set to whatever intensity you like.

The Preload value is the point at which the leds begin to visibly illuminate.

Thanks, i think i should manage to get my head around it a bit better now, im just trying to familiarise myself with all the different ways to do things!

the way you have done things is similar to how I wanted to get it, i just lack the knowledge with which code does what,

I notice you have ‘void ledmoonlight_control ()’ does this mean you can run multiple loops, so say for example in future i can run a separate loop for Temperature control and things like that?

I also assume ‘currentHourMinute’ is defined by your RTC lib?

Thanks:)

Attached is a working sketch of the led sunrise/set/moon, which I have just run with a 330r and led to 0v from pin d3

I have included the serial monitor so you can check your RTC clock is working.

Do not know which RTC/Wire libraies you use, but if it does not work, then the libraries I used are included.

As you say, there are lots of ways to do the same thing, its really all down to your level of experience, I’m also new to C++ , so doubtless others can find fault with my code methods, but everyone has to start somewhere.

Yes, you can use void in several ways, and in my full code I use about 10 separate Functions like Temp, Lights,TopUp, Wavemaker see Arduino - FunctionDeclaration

Also as you can see from the sketch , in the actual moon function, I do not read or write directly to the i/o port, instead I write to a “flag” and that flag is used in “port control” function , so you do not have to go though all your code when you want to change pin assignments

CurrentHourMinute is via the RTC and you will now see it updated in the main loop of the sketch.

Shout if anythings not clear.

demoMoonlight.zip (20.6 KB)

Hey, sorry for the delay (work tends to get in the way)

just a quick question;

byte srON_hh     = 9;       // Sunrise, start time for fade Up
byte srON_mm     =  0;

float SUNRISE_ON  = (srON_hh +  srON_mm / 60.0f);[\code]

what is the 60f? I assume this turns it into a time value? what does the f stand for?

I was hoping i could be clever and try something like this:
byte SunRise_On     = "07:00:00";

and rearrange your formulae a bit, but byte has the be a number so i can see why you did it your way!

Thanks

Expect you can do the run times in different ways, though what you have shown is a String and that would probably need a lot more code to compare against the rtc values.

If I remember rightly, the ‘f’ in 60.0f just denotes the value is a fraction, if just divide by 60 you will see it gives a different result, so you need to specify the '.0 ’ and seems the ‘f’ is just to highlight to you its a fraction.

Eg 09 : 20 becomes 9.3333330154

As you can see in the rest of the code the RTC values are similarly converted so the accuracy is even closer than comparing even by mins and seconds

// get current time

DateTime now = RTC.now();

currentHourMinute = now.hour() + now.minute()/60.0f;

Hello guys, I read your conversation and looks similar of the project I want to develop.

I am an electronics specialist, but I sucks in programming so, I need your help for my project.

I want to make that project run yearly for many years using the RTC to be accurate. Also I want it to recognize the summer and winter time changes (1 hour forward or back).

I need it to operate 24h 365 days, driving mosfets with PWM method under particular times and hours.

I can send you a presentation that I made with all the details of the operation and requirments.

I would be really grateful if you can help!!

Thank you

Nicos

Nicos: Hello guys, I read your conversation and looks similar of the project I want to develop.

[...]

Thank you

Nicos

It's unlikely that those members are paying attention to threads after such a long time. Try PM'ing them.