RTC programming (DS1370)

Hardware:

Arduino MEGA2560 v2
Tiny RTC I2C module (Ebay)
Photo Diode Sensor Module 1-Channel Adjustable (ebay)

History:
Attempted to write sketch to setup a customizable timer to turn lights on/off allowing for daylight saving time, and different On/Off times based on day of week. Final logical test is whether it is dark enough to warrant lights- thus the sensor.

Found that my IQ is too low to decipher the available info on how to reference the RTC library- and there are a bunch of different libraries, so I paid someone $50 on oDesk to write the following code.

Problem:
The lights come on, if the sensor is covered, EVEN though it is before the evening ‘power on’ time.

I have confirmed that the RTC is working (almost) correctly. (no matter what I try, it always reads about 1m45s slower than my system clock)
and the light sensor works great.

Any ideas?

I’d REALLY appreciate help resolving this, and for extra points, how would I change this so that the light sensor is powered off a I/O pin ONLY during ‘light on’ time.

Thanks in advance,
Nathan

ps. For anyone interested, I posted a guide on Ebay about this RTC, since it has an inherent design flaw. (That only took 3 hours to decipher. Sure wish I’d spent a few bucks more for a sparkfun model…)
The Guide is here

http://www.ebay.com/gds/Tiny-RTC-I2C-modules-Arduino-/10000000178398866/g.html

//**************************************************************//
//  Name    : Arduino RTC PWM                               
//  Author  : Iskuzhin Rustem
//  Date    : 27 Apr, 2014                          
//  Version : 1.1                                            
//  Notes   : The sketch controls an LED with PWM. RTC controls time 
//  when LED should be turned on or off. Light sensor is used to 
//  indicate a dark enough condition. 
//  Sketch accommodates daylight saving time 
//  Pacific Daylight Time (PDT) = GMT-7 :
//  2nd Sunday in March - 1st Sunday in November
//  Pacific Standard Time (PST) = GMT-8 :
//  1st Sunday in November - 2nd Sunday in March
//****************************************************************
#include <Wire.h>
#include "RTClib.h"
#define TIME_ON 70 //percent on PWM (50-70%)
#define HOUR_MIN_DAY_MORNING 5 //5 AM Monday - Saturday early hour
#define HOUR_MAX_DAY_MORNING 20 //8 AM Monday - Saturday early hour
#define HOUR_MIN_DAY_EVENING 15 //3:30 PM Monday - Saturday late hour
#define MINUTE_MIN_DAY_EVENING 30 
#define HOUR_MAX_DAY_EVENING 19 //7 PM Monday - Saturday late hour
#define HOUR_MIN_SUNDAY_MORNING 6 //6 AM Sunday early hour
#define HOUR_MAX_SUNDAY_MORNING 8 //8 AM Sunday early hour
#define HOUR_MIN_SUNDAY_EVENING 15 //3:30 PM Sunday late hour
#define MINUTE_MIN_SUNDAY_EVENING 30
#define HOUR_MAX_SUNDAY_EVENING 16 //4 PM Sunday late hour
const int LEDPin = 12;//output LED
const int SensorPin = 3;//input light sensor
int val = 0;//value of light sensor input (0 or 1)

RTC_DS1307 RTC; // class RTC define

void setup() {
  pinMode(LEDPin, OUTPUT); //define pin output
  pinMode(SensorPin, INPUT);//define pin input
  Wire.begin();//initialize I2C
  RTC.begin(); //initialize RTC
  Serial.begin(9600);//initialize serial port
}

void loop() {
  int hour_max_mor, hour_min_mor, hour_min_ev, hour_max_ev, minute_min_ev;
  int brightness=255*TIME_ON/100; //define value of PWM
  uint8_t hh, mm, dayofweek, month, day, n=0;
  DateTime now = RTC.now(); //read now time and date
  month=now.month();//take number of month
  day=now.day(); //take number of day
  dayofweek=now.dayOfWeek();//take number of day of week
  hh=now.hour();//take number of hour
  mm=now.minute();//take number of minutes
  if ((month==3)&&(dayofweek==0)&&(day>=8)&&(hh>=2))//verify is it 2nd Sunday in March
  {
    n=0;//use hours as defined
  }
  if ((month==11)&&(dayofweek==0)&&(hh>=2))//verify is it 1st Sunday in November
  {
    n=1; //use hours with offset minus one hour
  }  
  if (dayofweek==0) //verify if Sunday
  {
    hour_min_mor=HOUR_MIN_SUNDAY_MORNING-n; //set early hour
    hour_max_mor=HOUR_MAX_SUNDAY_MORNING-n;//set late hour
    hour_min_ev=HOUR_MIN_SUNDAY_EVENING-n; //set early hour
    hour_max_ev=HOUR_MAX_SUNDAY_EVENING-n; //set late hour
    minute_min_ev=MINUTE_MIN_SUNDAY_EVENING; //set early minutes
  }
  else
  {
    hour_min_mor=HOUR_MIN_DAY_MORNING-n;  //set early hour
    hour_max_mor=HOUR_MAX_DAY_MORNING-n; //set late hour
    hour_min_ev=HOUR_MIN_DAY_EVENING-n; //set early hour
    hour_max_ev=HOUR_MAX_DAY_EVENING-n; //set late hour
    minute_min_ev=MINUTE_MIN_DAY_EVENING; //set early minutes
  }
  val = digitalRead(SensorPin);  //read sensor value
  Serial.print(val); //check sensor in serial monitor
  Serial.print(' ');
  
  if ((hh<hour_max_mor)&&(hh>hour_min_mor)&&(val==1))//verify is it morning
  {
    analogWrite(LEDPin, brightness); //turn on LED with PWM
  }
  else if((hh<hour_max_ev)&&(hh>hour_min_ev)&&(val==1)) //verify is it evening
  {
    if (hh==hour_min_ev) //verify is it 3 PM
    {
      if (mm>minute_min_ev)//verify is it 3:30 PM
      {
        analogWrite(LEDPin, brightness); //turn on LED with PWM
        Serial.print("LED turn on");
        Serial.println();
      }
      else
      {
        analogWrite(LEDPin, 0); // turn off PWM
        Serial.print("LED turn off");
        Serial.println();
      }
    }
    else
    {
      analogWrite(LEDPin, brightness); //turn on LED with PWM
      Serial.print("LED turn on");
      Serial.println();
    }
  }
  else
  {
    analogWrite(LEDPin, 0); // turn off PWM
    Serial.print("LED turn off");
    Serial.println();
  }
  delay(2000);//delay 2 seconds
}

This looks wrong…

#define HOUR_MAX_DAY_MORNING 20 //8 AM Monday - Saturday early hour

This seems wrong:

 if ((hh<hour_max_mor)&&(hh>hour_min_mor)&&(val==1))//verify is it morning
  {
    analogWrite(LEDPin, brightness); //turn on LED with PWM
  }

If it’s morning, you want to turn it off, not on. Try:

 if ((hh<hour_max_mor)&&(hh>hour_min_mor)&&(val==1))//verify is it morning
  {
    analogWrite(LEDPin, 0); //turn off LED
  }

David, Thanks. That made a huge difference!

Henry- thanks for your input too. As I understand it, in the code you quoted the author was testing the time to see if it was in the band of time the sign should be on in the morning. At 48.5 deg latt, and -7UTC our mornings don't get light till after 8am in the mid winter, but are plenty bright by 4:30am in mid summer- so that is why there is such a big range of time that the sign 'might' need to be lit. If within those margins, then the light sensor is sampled to confirm if lighting is really needed.

In other words, that part of the code works fine.

Now, about how to only power the light sensor if the RTC says it is within the possible 'on' times...

You could almost use the same if statements you have already to turn the sensor on and off. Just drop the val == 1 part. However making this change with the current design will make your code even harder to read and maintain. I would suggest a slight design change. Since you are using a DateTime structure to receive the time for the RTC, I would recommend you use the same for defining your time window start and end times. Then define one or more compare functions. You could use a simple time of day compare of two DateTimes that returns 1,0 or -1 depending on if the first DateTime is greater then equal to or less than the second one. This function would ignore the date fields and only compare the time fields. Or you could use a between function that takes three DateTimes as parameters and returns true if the first time is between the second two.

I would suggest you do the same for detecting DST using a time of year comaprarison. The way you have it now, n will only equal 1 for 22 hours on Sundays in November.

David,

Does the end of your last post mean that the DST functionality doesn't work in the winter except for a few hours on Sundays in November?

As I stated in my original post, I really DON'T GET all this stuff about the RTC libraries or how to use them- and where the documentation is for a particular library. I'm not unwilling to learn, but had missed the deadline for this project, that is why I hired it out. If you are saying that part of the code is broken, I'd love to get it fixed. Could you suggest how it should be written, or point me in the right direction? (as I see it, I've got 6 months to learn how to fix this :) )

Thanks so much for your expertise. Someday I hope to pay it forward too.

That's right, your DST detection logic is broken.

  if ((month==3)&&(dayofweek==0)&&(day>=8)&&(hh>=2))//verify is it 2nd Sunday in March
  {
    n=0;//use hours as defined
  }
  if ((month==11)&&(dayofweek==0)&&(hh>=2))//verify is it 1st Sunday in November
  {
    n=1; //use hours with offset minus one hour
  }

You set n=0 at the top of the loop so you don't need the first if statement. Look carefully at the second if statement. It says, if it is November and if it is Sunday and if it is after 2AM then set n=1. At all other times n will be 0. What you want is: if it is after 2AM on the first Sunday in November or before 2AM on the second Sunday in March then set n=1.