DateTime, values, and multiple comparison operator

I’m trying to change a PWM value up and down over the course of the day. I saw another project in the forum doing essentially the same thing using map, ie map(minute, 0,59,0,255) but as I understand it, that constrains the fading to within a single hour. I’d like to start and stop the value changes at different times, overlapping hours.

When I try this it works fine, value1 goes up at 10am to 255, taking 59 minutes to do so based on time1, then at 9pm it goes back down to 0 and stays there until the next time 10am rolls around.

 unsigned long time1 = 0;
 int value1 = 0;
 int redled = 9;

{...
   ...


  if(millis()>time1){

     time1 = millis()+13800;

    if (((DateTime.Hour >= 10) && (DateTime.Minute >=0)) && ((DateTime.Hour <= 10) && (DateTime.Minute <=59))) value1+=1;
    if (value1>255) (value1=255);

    if (((DateTime.Hour >= 21) && (DateTime.Minute >=0)) && ((DateTime.Hour <= 21) && (DateTime.Minute <=59))) value1-=1;
    if (value1<0) (value1=0);

    analogWrite(redled, value1);
  }
}

But when I try the half hours like this

...
    if (((DateTime.Hour >= 10) && (DateTime.Minute >=30)) && ((DateTime.Hour <= 11) && (DateTime.Minute <=29))) value1+=1;
    if (value1>255) (value1=255);

    if (((DateTime.Hour >= 21) && (DateTime.Minute >=30)) && ((DateTime.Hour <= 21) && (DateTime.Minute <=29))) value1-=1;
    if (value1<0) (value1=0);
...

value1 remains 0

If I try this

...
    if (((DateTime.Hour >= 10) && (DateTime.Minute >=29)) && ((DateTime.Hour <= 11) && (DateTime.Minute <=39))) value1+=1;
    if (value1>255) (value1=255);

    if (((DateTime.Hour >= 21) && (DateTime.Minute >=29)) && ((DateTime.Hour <= 21) && (DateTime.Minute <=39))) value1-=1;
    if (value1<0) (value1=0);
...

value 1 only changes when the minutes are 29 and 30, so I can see that these comparisons are conflicting, and it probably (obviously?) owes to my lack of understanding of syntax. I’ve spent dozens of hours scouring the forum and playground, and I think it really speaks to the success of Arduino platform and its community that as a complete novice I can go from 0 experience to a mostly working project in such a short time, but I’m stuck on this. I think I’ve tried every variation except for the correct one.

Is this a feasible way to start an increment/decrement of a value and control the rate? How can I start an increment/decrement at 10:30?

Here is a sketch that I think has similar functionality to what you are looking for. It using the DateTime library from the playground and a companion DateTimeAlarm library you can get in this thread: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1217881285/15

to use the DateTimeAlarms library you need to create a new directory called DateTimeAlarms in the library directory and copy the files in the above thread into DateTimeAlarms.cpp and DateTimeAlarms.h

// this sketch demonstrates the DateTimeAlarm function by fading up an led on pin 9 at 9:30 and down at 21:30
// the fade time in seconds is by the variable fadeDuration

#include <DateTime.h>
#include <DateTimeAlarms.h>

#define TIME_MSG_LEN  11   // time sync to PC is HEADER followed by unix time_t as ten ascii digits
#define TIME_HEADER  'T'   // Header tag for serial time sync message 

AlarmID_t fadeUpAlarm, fadeDownAlarm; // the fading alarms
time_t fadeStartTime; // the time fading started
unsigned long fadeDuration = 60; // the number of SECONDS to fade all the way up or down;
typedef enum  { notFading, fadingUp, fadingDown} fadeState_t;  // the fading state 
fadeState_t State;
int redled = 9;

void setup(){
  Serial.begin(19200);  
  pinMode(13,OUTPUT); // we flash the LED each second
  Serial.println("Set clock by sendt T followed by 10 digit unix time");  
  while( getPCtime() == false) 
        ;  // wait in this while loop until clock is set        
  Serial.print("Clock set at ");      
  digitalClockDisplay();
  registerAlarms();  
}

void registerAlarms(){
   fadeUpAlarm = dtAlarms.createAlarm(  AlarmHMS(9, 30, 0), &OnAlarm);  // set the times here
   fadeDownAlarm = dtAlarms.createAlarm( AlarmHMS(21, 30, 0), &OnAlarm);
}

void OnAlarm(AlarmID_t Sender){

  if( Sender ==  fadeUpAlarm)
  {
      Serial.println("Starting to fade up");         
      State= fadingUp;

  }
   else  if( Sender ==  fadeDownAlarm) 
   {
      Serial.println("Starting to fade down");   
      State= fadingDown;
   }    
   fadeStartTime = DateTime.now();
}

void doFading(){
int fadeLevel;  
  
  unsigned long elapsedTime = DateTime.now() - fadeStartTime;
  if(elapsedTime > fadeDuration)
     State = notFading;
  else   
      fadeLevel = map(elapsedTime,0, fadeDuration, 0, 255);
  if( State == fadingUp)
  {       
     analogWrite(redled,fadeLevel); 
     Serial.print("Writing value ");
     Serial.println(fadeLevel);
  } 
  if( State == fadingDown)
  {          
     analogWrite(redled,255-fadeLevel); 
     Serial.print("Writing value ");
     Serial.println(255-fadeLevel);
  } 
}


void  loop(){  
  unsigned long  prevtime;

  if( getPCtime()) {  // try to get time sync from pc        
    Serial.print("Clock re-set at ");      
    digitalClockDisplay();   
  }
  dtAlarms.delay(1000); 
  doFading();
  digitalClockDisplay( );   // update digital clock

}

boolean getPCtime() {
  // if time synch available from serial port, update time and return true
  unsigned long pctime;
  char c;
  while(Serial.available() >=  TIME_MSG_LEN ){  // time message consists of a header and ten ascii digits
    if( Serial.read() == TIME_HEADER ) {        
      pctime = 0;
      for(int i=0; i < TIME_MSG_LEN -1; i++){   
        c= Serial.read();          
        if( c >= '0' && c <= '9'){   
          pctime = (10 * pctime) + (c - '0') ; // convert digits to a number    
        }
      }   
      DateTime.sync(pctime);  // Synch local time using added function in wiring.c
      return true;   // return true if time message received on the serial port
    }  
  }
  return false;  //if no message return false
}

void timeDisplay(){
  DateTime.available();
  Serial.print(DateTime.Hour,DEC);  
  printDigits(DateTime.Minute);  
  printDigits(DateTime.Second); 
  Serial.println("");
}

void digitalClockDisplay(){
   DateTime.available(); //refresh the Date and time properties
  // digital clock display of current time
  Serial.print(DateTime.Hour,DEC);  
  printDigits(DateTime.Minute);  
  printDigits(DateTime.Second); 
  Serial.println();
 }

void printDigits(byte digits){
  // utility function for digital clock display: prints preceding colon and leading 0 
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits,DEC);   
}

Nice. I’d tried unsuccessfully to use DateTimeAlarms before, but this worked. However, at the registered alarm times, fadeLevel goes up to 254 and stays there until the fadeDown alarm, where it then goes to 255 and starts going down to 1 where it stays until fadeUp, where it goes to 0 and starts going up. 1 on a scale of 0-255 is not negligible when it’s controlling 96 watts of LEDs :wink:

#include <LiquidCrystal.h>
#include <DateTime.h>
#include <DateTimeAlarms.h>o

#define TIME_MSG_LEN  11   // time sync to PC is HEADER followed by unix time_t as ten ascii digits
#define TIME_HEADER  255   // Header tag for serial time sync message

LiquidCrystal lcd(12, 8, 7, 5, 4, 3, 2);

AlarmID_t fadeUpAlarm, fadeDownAlarm; // the fading alarms
time_t fadeStartTime; // the time fading started
unsigned long fadeDuration = 3600; // the number of SECONDS to fade all the way up or down;
typedef enum  { notFading, fadingUp, fadingDown} fadeState_t;  // the fading state
fadeState_t State;

int redled = 9;

void setup(){

  pinMode(redled, OUTPUT);

  Serial.begin(19200);

  analogWrite(6, 100);  // Backplane LED
      
while( getPCtime() == false);  // wait in this while loop until clock is set
registerAlarms();

}

void registerAlarms(){
   fadeUpAlarm = dtAlarms.createAlarm(  AlarmHMS(10, 30, 0), &OnAlarm);  // set the times here
   fadeDownAlarm = dtAlarms.createAlarm( AlarmHMS(22, 00, 0), &OnAlarm);
}

void OnAlarm(AlarmID_t Sender){

  if( Sender ==  fadeUpAlarm)
  {
      Serial.println("Starting to fade up");        
      State= fadingUp;

  }
   else  if( Sender ==  fadeDownAlarm)
   {
      Serial.println("Starting to fade down");  
      State= fadingDown;
   }    
   fadeStartTime = DateTime.now();
}

void doFading(){
int fadeLevel;  
  
  unsigned long elapsedTime = DateTime.now() - fadeStartTime;
  if(elapsedTime > fadeDuration)
     State = notFading;
  else  
      fadeLevel = map(elapsedTime,0, fadeDuration, 255, 0);
  if( State == fadingDown)
  {
     analogWrite(redled,fadeLevel);
     Serial.print("Writing value ");
     Serial.println(fadeLevel);
  }
  if( State == fadingUp)
  {          
     analogWrite(redled,255-fadeLevel);
     Serial.print("Writing value ");
     Serial.println(255-fadeLevel);
  }
}

void  loop(){

  unsigned long  prevtime;
  
  getPCtime();
  
  if(DateTime.available()) { // update clocks if time has been synced

    prevtime = DateTime.now();
    while( prevtime == DateTime.now() );  // wait for the second to rollover
    DateTime.available(); //refresh the Date and time properties
    digitalClockDisplay( );   // update digital clock
    Serial.print( TIME_HEADER,BYTE); // this is the header for the current time
    Serial.println(DateTime.now());
  }
  dtAlarms.delay(500);
  doFading();
//  digitalClockDisplay( );
}

boolean getPCtime() {
  // if time sync available from serial port, update time and return true
  while(Serial.available() >=  TIME_MSG_LEN ){  // time message consists of a header and ten ascii digits
    if( Serial.read() == TIME_HEADER ) {        
      time_t pctime = 0;
      for(int i=0; i < TIME_MSG_LEN -1; i++){   
        char c= Serial.read();          
        if( c >= '0' && c <= '9'){   
          pctime = (10 * pctime) + (c - '0') ; // convert digits to a number    
        }
      }   
      DateTime.sync(pctime);   // Sync Arduino clock to the time received on the serial port
      return true;   // return true if time message received on the serial port
    }  
  }
  return false;  //if no message return false
}

void digitalClockDisplay(){
  // digital clock display of current date and time
  lcd.setCursor(0, 0);
  lcd.print(DateTime.Hour,DEC);
  printDigits(DateTime.Minute);
  printDigits(DateTime.Second);
  
}

void printDigits(byte digits){
  // utility function for digital clock display: prints preceding colon and leading 0
  lcd.print(":");
  if(digits < 10)
    lcd.print('0');
  lcd.print(digits,DEC);
}

Thanks mem for the help and the great libraries. Half the projects I have in mind need to know the time. Who needs a $20 RTC unless they have to have a battery backup?

It seems everyone using Arduino already has some knowledge of C, so I’m feeling a little sheepish for asking, but is there a way to do this without DateTimeAlarms? As I originally mentioned, without DateTimeAlarms I can get the fade to occur from say 10 to 11, but is there a way to make it happen between, like 10:20 and 11:50?

It took quite a while but I got it eventually.

This sort of thing was only fading up when the minutes were over thirty

if (((DateTime.Hour >= 10) && (DateTime.Minute >=30)) && ((DateTime.Hour <= 11) && (DateTime.Minute <=30)))value1+=1;

So for those who may find it useful, here it is.

if(millis()>time1){
time1 = millis()+12000; // Sets the rate at which the fade occurs

if ((DateTime.Hour == 10 && DateTime.Minute >=30) || (DateTime.Hour == 11 && DateTime.Minute <=30)) value1+=1;
// Sets the timeframe for the fade up

if ((DateTime.Hour == 22 && DateTime.Minute >=15) || (DateTime.Hour == 13 && DateTime.Minute <=15)) value1-=1;
// Sets the timeframe for the fade down

if (value1>255) (value1=255); // Keeps the LED on, otherwise it cycles through 0 again
if (value1<0) (value1=0); // Keeps the LED off

analogWrite(redled, value1);
}