Am I trying to use a variable or pass a value by reference or by value?

Hello, I am working on a code for PWM fading LEDS that uses addpoints to call the pwm pin to an intensity 0-255. I have the code uploaded and it runs fine when I use real numbers for the time, but I would like the points to be determined off of a “set_on” time that can be set by pushing buttons. I was able to write code for setting the on time, but can’t figure out how to set the off time as a function of the on time. i.e. turn off 16 hours after set_on. When I upload the code, set on works but off shows 2 hours after the initial programmed time of 20 regardless of what I set the on time to via the buttons

How do I use the value of set_on as a reference later in the script? i.e. turn lights on 30 min after set_on
I would also like to reference the value of intensity to display as a % and also trigger different .gifs based on intensity value on an OLED. If I ever get that far, lol.
I had tried searching google and found the variables page on the arduino site and also a link talking about passing a value as a reference or by using foo(). Its all very confusing to me

The code and supporting files are attached as they are too long to post, but here are some snippets of the parts in question
in this section when I upload this test in the code, the light comes on at 20:23 even if I set the on time to 19,21 etc. and the voltage coming out of pin 9 seems really small when its picking a random number like the first instance where I put random(70-100) I should be getting 30-40%
of 5v so 1.5-2v but Im seeing .15v but when I put in an actual number like 230 after it I am seeing 3v is that because Im using a small LED with a resister as opposed to my meanwell and its external power supply? Even then, if 3V is my max 30-40% of that would be .9-1.2V

/////////////////////////Schedule////////////////////////////
  //* /Test: comment this out and uncomment //Run: to run full schedule
  int channelNo = 0;
  int pin = 9;
  Channels[0] = Channel(pin, MaxPoints, fademode_exponential, Points[channelNo]);            // Initialize channel and choose FadeMode
  //--Channel-#-/Add event(----Hours---,----Minutes----,----Intensity----);--//--------Description----------------------------//
  Channels[0].AddPoint (   (set_on)    ,     20        ,         0       );  // start of day (dawn) light should be off
  Channels[0].AddPoint (   (set_on)    ,     23        , random(70-100)  );  // fades light up to 33-40% in the first 3 minutes
  Channels[0].AddPoint (   (set_on)    ,     26        ,       230       );  // fades light up to 90%  over the next 3 min
  Channels[0].AddPoint (   (set_on)    ,     28        , random(30-60)   );  // fades light down to 15-25% @ 8 min elapsed time
  Channels[0].AddPoint (   (set_on)    ,     30        , random(170-230) );  // fades light up to 66-90% 10 min et.
  Channels[0].AddPoint (   (set_on)    ,     32        ,         0       );  // fades light down to 0% (off) over the next 2 min

Thanks.

MultiChannel_PWM_LED_light_control.ino (11.3 KB)

ChannelManager.cpp (5.33 KB)

ChannelManager.h (1.23 KB)

Look at the AddPoint() method. You invoke the Point constructor to create an object, p. When the function ends, p goes out of scope.

Yet, you have passed p to SetPoint, which assumes that it will persist in memory.

You need to decide whether you want to deal with pointers to dynamic memory OR static objects, and NOT try to use them interchangeably.

In AddPoint():

    Point *p = new Point(h, m, intensity);

Then, you CAN pass p to SetPoint(), after changing the signature for SetPoint().

You'll need to make a lot of other changes, too, to stop allocating memory, statically, for the 2D array of Point objects, etc.

Thank you for the help. So, to clarify, a pointer to dynamic memory will read the value set for set_on and pass that to Setpoint? \Just using:Channels[0].SetPoint (  (set_on)  ,  20  ,  0  ); in the code gives error:

  This report would have more information with
  "Show verbose output during compilation"
  enabled in File > Preferences.
Arduino: 1.0.6 (Windows NT (unknown)), Board: "Arduino Nano w/ ATmega328"
MultiChannel_PWM_LED_light_control.ino: In function 'void InitializeChannels(int)':
MultiChannel_PWM_LED_light_control:86: error: no matching function for call to 'Channel::SetPoint(int&, int, int)'
C:\Users\Master\Documents\Arduino\libraries\Channelmanager/ChannelManager.h:40: note: candidates are: void Channel::SetPoint(int, int, int, float)
C:\Users\Master\Documents\Arduino\libraries\Channelmanager/ChannelManager.h:41: note:                 void Channel::SetPoint(int, Point)

So, how do I change the channelmanager.h to tell it to read the value of set_on to pass that value to Setpoint?

Channel(int pin, int maxLength, FadeMode fadeMode, Point* m);
    int GetPin();
    void AddPoint(int h, int m, float intensity);
    void SetPoint(int index, int h, int m, float intensity);
    void SetPoint(int index, Point p);
    void ClearPoint(int index);
    Point GetPoint(int index);
    void GoToCurrentPosition(long time);
    void MoveForward();
    int GetLightIntensityInt(long time);
    float CorrectForFadeMode(float intensity);
    void UpdateCurrentLightValue(long time);
    void UpdateData();
    int GetLength();
    void Reset();

private:
    int _pin;
    int _lightValue;
    FadeMode _fadeMode;
    int _currentPosition;
    int _length;
    int _maxLength;
    Point _previous;
    Point _next;
    Point* _storage;
};

So, how do I change the channelmanager.h to tell it to read the value of set_on to pass that value to Setpoint?

The compiler is what is responsible for getting the value from the memory location referred to by the variable named set_on, and passing the value to SetPoint().

But, SetPoint() takes either 2 arguments or 4, not 3. THAT is what the compiler is telling you.

Ok, I think it is starting to make a little more sense now. Please forgive my ignorance, but what exactly are the arguments I am trying to give it?

Please forgive my ignorance, but what exactly are the arguments I am trying to give it?

Either a position in an array (where there is an existing Point object) and a Point object with some data to be copied to the Point object in the array OR a position in an array (where there is an existing Point object) and the time, hours and minutes, when you want something to happen, and the intensity of the LED (presumably at that Point).

Downwardflight: but what exactly are the arguments I am trying to give it?

your class defines two functions for setPoint():

void Channel::SetPoint(int index, int h, int m, float intensity)
{
    SetPoint(index, Point(h, m, intensity));
}

void Channel::SetPoint(int index, Point p)
{
    _storage[index] = p;
}

one takes four arguments one takes two...

the question goes back to you... 1) what arguments are you trying to pass and 2) to which function?

So for: void SetPoint(int index, int h, int m, float intensity); my arguments are 1) int index 2)int h 3) int m 4) float intensity And: void SetPoint(int index, Point p); my arguments are 1) int index 2) Point p So when I tell it: set_on or set_on + 3 it's seeing either 1 or 3 arguments?

I am trying to tell it to use the value for set_on so I can reference all of the points off of what time my photo period starts i.e. (Set_on +3, 0, 255) >set the intensity to 255 3 hours and 0 mins after set_on So the argument I am trying to pass is the set_on time and I am trying to pass it to the intensity function?

Downwardflight: So for: void SetPoint(int index, int h, int m, float intensity); my arguments are 1) int index 2)int h 3) int m 4) float intensity And: void SetPoint(int index, Point p); my arguments are 1) int index 2) Point p So when I tell it: set_on or set_on + 3 it's seeing either 1 or 3 arguments?

I am trying to tell it to use the value for set_on so I can reference all of the points off of what time my photo period starts i.e. (Set_on +3, 0, 255) >set the intensity to 255 3 hours and 0 mins after set_on So the argument I am trying to pass is the set_on time and I am trying to pass it to the intensity function?

have you tried to create a struct? Honestly I read your code but I wasn't able to figure out what you are trying to do... some kind of timer mechanism that triggers Led fading events, maybe?

No, I'm not sure where I would start with that, I will read up on structs Yes, more or less, I am trying to make a schedule that will trigger LED fading based off of times throughout a fixed 16 hour photoperiod that I can set up or down via push button switches. So there's a randomish dimming and brightening effect simulating cloud cover throughout the day, or I could even add another channel to have the red LEDS stay brighter longer giving a more of a fall sunset affect.

Downwardflight: No, I'm not sure where I would start with that, I will read up on structs Yes, more or less, I am trying to make a schedule that will trigger LED fading based off of times throughout a fixed 16 hour photoperiod that I can set up or down via push button switches. So there's a randomish dimming and brightening effect simulating cloud cover throughout the day, or I could even add another channel to have the red LEDS stay brighter longer giving a more of a fall sunset affect.

so, you want to fix sunrise and sunset and have clouds fly over randomly during the day...

Yes the sunset would be fixed to 16 hours after sunrise, the sunrise would have a default time and be settable up or down via 2 push button tactile switches. As well as clouds randomly throughout the day

So when I tell it: set_on or set_on + 3 it's seeing either 1 or 3 arguments?

The question doesn't make sense. The variable named set_on contains a single value. set_on + 3 is a single value. "it" is a pronoun with no referent, so we have no idea what you mean by "it". There are no arguments involved in using the variable set_on, except when passing it to a function. Which function are you referring to? Whatever function it is, you are passing the function ONE value when you use either set_on or set_on + 3.

Downwardflight:
Yes the sunset would be fixed to 16 hours after sunrise, the sunrise would have a default time and be settable up or down via 2 push button tactile switches. As well as clouds randomly throughout the day

This isn’t everything you want, but it is a good demo. I wrote a library called DailyTimer, it is here on gitHub.

I had to adapt if for your application but you can see that it is a bit easier with the library that what you are trying to do. this just manages the on-board LED but you should be able to see where to add your specific functions.

.ino:

#include "DailyTimer.h"

#define CLOUD_INTERVAL 60 * 5 // max time between clouds
#define CLOUD_DURATION 60 * 2 // max cloud duration

void sunrise(void);
void sunset(void);
void cloud(void);
void nocloud(void);

const byte ledPin = 13;

DailyTimer sunRiseSunSet(true, 6, 0, 18, 0, EVERY_DAY, FIXED, sunrise, sunset);  //call sunrise() at the start of the timer and sunset() at the end.
DailyTimer randomCloud(true, 0, 0, 0, 0, EVERY_DAY, FIXED, cloud, nocloud);  //call cloud() at the start of the timer and nocloud() at the end.

void setup() 
{
  Serial.begin(9600);
  pinMode(13, OUTPUT);
  setTime(1510563600);
  randomSeed(analogRead(A0));

  sunRiseSunSet.begin();  // syncs the timer, use it here and after calls to setStartTime
  Serial.print("Active days: ");
  Serial.println(sunRiseSunSet.getDays(), BIN);
}

void loop() 
{
  static unsigned long lastTime = 0;
  DailyTimer::update();
  if(millis() - lastTime >= 1000)
  {
    char timeBuffer[32] = "";
    sprintf(timeBuffer, "Time:%2d:%02d:%02d\tDate:%02d/%02d/%4d", hour(), minute(), second(), month(), day(), year());
    Serial.println(timeBuffer);
    lastTime = millis();
  }
}

void sunrise(void)
{
  digitalWrite(13, HIGH);
  setNextCloud();
}

void sunset(void)
{
  digitalWrite(13, LOW);
}

void cloud(void)
{
  Serial.println(F("Cloud"));
  digitalWrite(13, LOW);
}

void nocloud(void)
{
  Serial.println(F("No Cloud"));
  digitalWrite(13, HIGH);
  setNextCloud();
}

void setNextCloud(void)
{
  if(sunRiseSunSet.isActive())
  {
    Serial.println(F("another cloud coming"));
    time_t now = DailyTimer::tmConvert_t(year(), month(), day(), hour(), minute(), second());
    time_t nextCloudStart = now + random(60, CLOUD_INTERVAL);
    time_t nextCloudEnd = nextCloudStart + random(60, CLOUD_DURATION);
    char buffer[32];
    sprintf(buffer, "Start %02d:%02d End %02d:%02d", hour(nextCloudStart), minute(nextCloudStart), hour(nextCloudEnd) , minute(nextCloudEnd));
    Serial.println(buffer);
    randomCloud.setStartTime(hour(nextCloudStart), minute(nextCloudStart));
    randomCloud.setEndTime(hour(nextCloudEnd) , minute(nextCloudEnd));
    randomCloud.begin();
  }
}

header:

#ifndef DailyTimer_h
#define DailyTimer_h

//#include <Time.h>
#include <TimeLib.h>
#include "Arduino.h"

#define MAX_TIMER_INSTANCES 10

enum EventDays{SUNDAYS = 0, MONDAYS, TUESDAYS, WEDNESDAYS, THURSDAYS, FRIDAYS, SATURDAYS, WEEKENDS, WEEKDAYS, EVERY_DAY};
enum RandomType{FIXED, RANDOM, RANDOM_START, RANDOM_END};

const byte dayTemplate[] = {
  /*SMTWTFSS*/   // the bitmask is set with an extra bit for determining off times for days of the week where off time is earlier than on time (i.e. the two values stradle midnight)
  0b10000000,
  0b01000000,
  0b00100000,
  0b00010000,
  0b00001000,
  0b00000100,
  0b00000010,
  0b10000010, // Weekends
  0b01111100, // Weekdays
  0b11111110  // Everyday
};
  
class DailyTimer{
  public:
  
    DailyTimer(byte StartHour, byte StartMinute, EventDays DaysOfTheWeek, RandomType type, void(*_startCallback)());
    DailyTimer(bool syncOnPowerup, byte StartHour, byte StartMinute, byte EndHour, byte EndMinute, EventDays DaysOfTheWeek, RandomType type, void(*_startCallback)(), void(*_endCallback)());

    void setDaysActive(EventDays days);
    void setDaysActive(byte activeDays);
    byte setRandomDays(byte number_Days);
    void setRandomOffset(uint8_t random_minutes, RandomType randomSetting);
    void setStartTime(uint8_t hour, uint8_t minute);
    void setEndTime(uint8_t hour, uint8_t minute);
    int getInstanceCount(void) const;
    bool begin(); 
    uint8_t getDays() const;
    static void update();
    static time_t tmConvert_t(int YYYY, byte MM, byte DD, byte hh, byte mm, byte ss);
    bool isActive();
    static bool isActive(DailyTimer* instance);
    
  protected:
    struct TimerTime{ // bounded 00:00 to 23:59
      uint8_t hour;
      uint8_t minute;
    };
    bool sync();
    void(*startTimeCallback)(); //
    void(*endTimeCallback)();   //
    uint8_t onMask;                // compact ON days storage
    uint8_t offMask;               // compact OFF days storage
    bool state;                 // retains last true/false state of timer
    bool autoSync;              // will run startTimeCallback if timer is in active state when times are changed or powerup
    TimerTime startTime;        //
    TimerTime endTime;          // 
    TimerTime randomStartTime;  // calculated once daily
    TimerTime randomEndTime;    // calculated once daily
    RandomType randomType;            // 
    uint8_t currentDay;          // for comparison of a daily event to randomize the Start and end times
    uint8_t offset;             // minutes of fuzziness for random Starts and Ends

    
    
    static DailyTimer* instanceAddress;
    static uint8_t instanceCount;
};

#endif

.cpp:

#include "DailyTimer.h"

uint8_t DailyTimer::instanceCount = 0;
DailyTimer* instances[MAX_TIMER_INSTANCES] = {nullptr};


DailyTimer::DailyTimer(byte StartHour, byte StartMinute, EventDays DaysOfTheWeek, RandomType type, void(*StartTimeCallback)())
{
  autoSync = false;
  startTime.hour = StartHour > 23 ? 23 : StartHour; 
  startTime.minute = StartMinute > 59 ? 59 : StartMinute; 
  endTime.hour = startTime.hour;
  endTime.minute = startTime.minute;
  setDaysActive(dayTemplate[static_cast<int>(DaysOfTheWeek)]);
  randomType = type;
  offset = 15;
  startTimeCallback = StartTimeCallback;
  endTimeCallback = NULL;
  instances[instanceCount] = this;
  instanceCount++;
}

DailyTimer::DailyTimer(bool syncOnPowerup, byte StartHour, byte StartMinute, byte EndHour, byte EndMinute, EventDays DaysOfTheWeek, RandomType type, void(*StartTimeCallback)(), void(*EndTimeCallback)())
{
  autoSync = syncOnPowerup;
  startTime.hour = StartHour > 23 ? 23 : StartHour; 
  startTime.minute = StartMinute > 59 ? 59 : StartMinute; 
  endTime.hour = EndHour > 23 ? 23 : EndHour;
  endTime.minute = EndMinute > 59 ? 59 : EndMinute;
  setDaysActive(dayTemplate[static_cast<int>(DaysOfTheWeek)]);
  randomType = type;
  offset = 15;
  startTimeCallback = StartTimeCallback;
  endTimeCallback = EndTimeCallback;
  instances[instanceCount++] = this;
}

int DailyTimer::getInstanceCount(void) const
{
  return instanceCount;
}

bool DailyTimer::begin()
{
  return sync();
}

void DailyTimer::setDaysActive(EventDays days)
{
  onMask = dayTemplate[static_cast<int>(days)];
  time_t now_time = now();
  if(tmConvert_t(year(now_time), month(now_time), day(now_time), startTime.hour, startTime.minute, 0) > tmConvert_t(year(now_time), month(now_time), day(now_time), endTime.hour, endTime.minute, 0))
  {
    offMask = onMask >> 1;
  }
  else
  {
    offMask = onMask;
  }
  (void)sync();
}

void DailyTimer::setDaysActive(byte activeDays)
{
  onMask = activeDays;
  time_t now_time = now();
  if(tmConvert_t(year(now_time), month(now_time), day(now_time), startTime.hour, startTime.minute, 0) > tmConvert_t(year(now_time), month(now_time), day(now_time), endTime.hour, endTime.minute, 0))
  {
    offMask = onMask >> 1;
  }
  else
  {
    offMask = onMask;
  }
  (void)sync();
}

void DailyTimer::setRandomOffset(uint8_t random_minutes, RandomType type)
{
  offset = random_minutes > 59 ? 59 : random_minutes;
  if (offset == 0)
  {
    randomType = FIXED;
  }
  else
  {
    randomType = type;
  }
}

void DailyTimer::setStartTime(uint8_t hour, uint8_t minute)
{
  startTime.hour = hour > 23 ? 23 : hour; 
  startTime.minute = minute > 59 ? 59 : minute; 
  setDaysActive(onMask);
  (void)sync();
}

void DailyTimer::setEndTime(uint8_t hour, uint8_t minute)
{
  endTime.hour = hour > 23 ? 23 : hour;
  endTime.minute = minute > 59 ? 59 : minute;
  setDaysActive(onMask);
  (void)sync();
}


uint8_t DailyTimer::setRandomDays(uint8_t number_Days)
{
  randomSeed(now() + micros());
  uint8_t mask = 0;
  uint8_t array[8] = {0};
  for (int i = 0; i < number_Days; i++)
  {
    array[i] = 1;
  }
  for(int i = 0; i < 7; i++)
  {
    uint8_t index = random(i, 7);
    uint8_t temp = array[i];
    array[i] = array[index];
    array[index] = temp;
  }
  for (int i = 0; i < 7; i++)
  {
    mask |= (array[i] << i);
  }
  onMask = mask << 1;
  (void)sync();
  return onMask;
}

byte DailyTimer::getDays() const
{
  return onMask;
}

bool DailyTimer::sync()
{
  bool currentState = isActive(this);
  if(currentState && autoSync)
  {
    startTimeCallback();
  }
  return state = currentState;
}

void DailyTimer::update()
{
  for(int i = 0; i < instanceCount; i++)
  {
    bool lastState = instances[i]->state;
    instances[i]->state = isActive(instances[i]);
    if(lastState != instances[i]->state)
    {
      if(instances[i]->state == true)
      {
        if(instances[i]->startTimeCallback) instances[i]->startTimeCallback();
      }
      else
      {
        if(instances[i]->endTimeCallback) instances[i]->endTimeCallback();
      }
    }
  }
}

bool DailyTimer::isActive()
{
  isActive(this);
}

bool DailyTimer::isActive(DailyTimer* instance)
{
  if (instance->currentDay != weekday() && instance->randomType) // once a day, generate new random offsets
  {
    randomSeed(now() + micros());
    if (instance->randomType == RANDOM  || instance->randomType == RANDOM_START)
    {
      int hrs = instance->startTime.hour * 60 + instance->startTime.minute;
      hrs += constrain(random(-1 * instance->offset, instance->offset), 1, (24 * 60) - 1);
      instance->randomStartTime.minute = hrs % 60;
      instance->randomStartTime.hour = hrs / 60;
    }
    if (instance->randomType == RANDOM || instance->randomType == RANDOM_END)
    {
      int hrs = instance->endTime.hour * 60 + instance->endTime.minute;
      hrs += constrain(random(-1 * instance->offset, instance->offset), 1, (24 * 60) - 1);
      instance->randomEndTime.minute = hrs % 60;
      instance->randomEndTime.hour = hrs / 60;
    }
    instance->currentDay = weekday();
  }
  time_t now_time = now();
  time_t on_time = tmConvert_t(year(now_time), month(now_time), day(now_time), (instance->randomType == RANDOM || instance->randomType == RANDOM_START) ? instance->randomStartTime.hour : instance->startTime.hour, (instance->randomType == RANDOM || instance->randomType == RANDOM_START) ? instance->randomStartTime.minute : instance->startTime.minute, /*second(now_time)*/ 0);
  time_t off_time = tmConvert_t(year(now_time), month(now_time), day(now_time), (instance->randomType == RANDOM || instance->randomType == RANDOM_END) ? instance->randomEndTime.hour : instance->endTime.hour, (instance->randomType == RANDOM || instance->randomType == RANDOM_END) ? instance->randomEndTime.minute : instance->endTime.minute, /*second(now_time));*/ 0);
  byte weekDay = weekday(now_time);
  byte today = 0b00000001 << (8 - weekDay);
  if (today & dayTemplate[SUNDAYS])
  {
    today |= 0b00000001;
  }
  if ((today & instance->onMask) && (today & instance->offMask))  // if it is supposed to turn both on and off today
  {
    if (on_time < off_time)
    {
      return (now_time > on_time && now_time < off_time);
    }
    else if (off_time < on_time)
    {
      return (now_time > on_time || now_time < off_time);
    }
//    else 
//    {
//      return false;
//    }
    else if(on_time == off_time) // single edge event
    {
      if( now_time == on_time)
      {
        return true;
      }
    }
    return false;
  }
  else if (today & instance->onMask) // if it is supposed to turn only on today
  {
    if (on_time < off_time)
    {
      return (now_time > on_time && now_time < off_time);
    }
    else
    {
      return (now_time > on_time);
    }
  }
  else if (today & instance->offMask)  // if it is supposed to turn only off today
  {
    return now_time < off_time;
  }
  else // if 
  {
    return false;
  }
}

time_t DailyTimer::tmConvert_t(int YYYY, byte MM, byte DD, byte hh, byte mm, byte ss)
{
  tmElements_t tmSet;
  tmSet.Year = YYYY - 1970;
  tmSet.Month = MM;
  tmSet.Day = DD;
  tmSet.Hour = hh;
  tmSet.Minute = mm;
  tmSet.Second = ss;
  return makeTime(tmSet);
}

The question doesn't make sense. The variable named set_on contains a single value. set_on + 3 is a single value. "it" is a pronoun with no referent, so we have no idea what you mean by "it". There are no arguments involved in using the variable set_on, except when passing it to a function. Which function are you referring to? Whatever function it is, you are passing the function ONE value when you use either set_on or set_on + 3.

I'm sorry for the confusion. I suppose by "it" I mean the compiler. My questions could be better worded, but I am having a hard time with the programming language so I am augmenting my ignorance by trying to find a simpler code that I think I understand and modify it to do what I want.

I don't understand how to access or use the value after set_on in the program, or even how the button changes that value for that matter. I just see the number change on the LCD, so I know the button works.

I would like to use the set_on value as a time reference for my setpoint and addpoints in order to change the light intensity to different values based on time after sunrise "set_on" as well as turning the lights off at sunset "set_off" which I want to be 16 hours after "set_on" time

How to I tell the Compiler/Arduino to read the set_on value I am displaying on the LCD and use it to set the intensity of the LEDs via pwm pin(s) using the matrix (hour, minute, intensity)

If set_on is at 8:00 and I want the intensity at 0 expressed (set_on, 00, 0 )

Then, 30 minutes after set_on I can set a point which the intensity is 50% so that the lights fade up like a sunrise to a medium light level. i.e. (set_on, 30, 127)

Next, in the middle of the day, say 7 hours after set_on I can set a point which the intensity is 90% to fade the lights from 50% to 90% i.e. (set_on+7, 00, 230)

Lastly, in the evening say 14-15 hours after set_on (or 1-2 hours before set_off) I can set a point which the intensity is 70% of max to start the fade to sunset (0 intensity) at set_off or 16 hours after set_on i.e. (set_on+14, 00, 178)

With (set_off, 00, 0) or (set_on+16, 00, 0) turning the lights off as well as having a relay turn on and off the power supply for the LED drivers at set_on and set_off times

In addition, adding clouds by fading to a random lesser intensity at random times in between the predetermined sunrise, noon, and sunset points

This isn't everything you want, but it is a good demo. I wrote a library called DailyTimer, it is here on gitHub.

Thank you for going to all the trouble to write out a demo code to get me in a better direction. I will look over it carefully and try to understand what exactly you are telling the compiler to do and how I can add my functions.

Its crazy when I think about the 8+ years I have spent learning the Automotive industry and studying engineering which have a language, hardware and software of their own. To try and delve into programming, with its own languages and way of thinking, has proven quite daunting. I really appreciate you guys helping me out when I have so little knowledge, and even difficulty explaining what I want to do.

Downwardflight: ... try to understand what exactly you are telling the compiler to do and how I can add my functions.

I'm really not able to understand what it is you are trying to do in your code... I'm not sure you can use what I gave you in the construct of your code.

my example was to show you a practical alternative paradigm...

I was under the assumption that the example was showing me a better way to write code for a sunrise sunset and clouds, so I would no longer be using my hacked together code.

My idea is to simulate sunlight during the day. Specifically:
I would like to be able to set the ON time with a separate “up” and “down” tactile switch with a 16 hour photo-period. ON being the start of sunrise and the lights fading from 0%/OFF up to and ideally reaching 90% approximately 7 hours after the set ON time, holding at 90% for approximately 2 hours then fading back down to 0%/OFF after 16 hours
I would like to simulate clouds passing over during the “day” by having random shorter fade periods (from a few minutes to an hour) down to different random intensities (with a threshold to keep the lights from going so low they’re essentially off) from whatever the intensity happens to be at that time, and fading back to the intensity it should be based off the original sunrise/set fading schedule
I would like to also control a relay or device to provide a momentary ground to turn on and off the computer power supply I am using to power the LED drivers so it isn’t on all the time while the drivers are sitting at 0% PWM
Finally I would like to use an LCD to display; the current time, the ON and OFF times as set by the push buttons, and the current light intensity between 0-100%

Ideally I’d like to be able to use a TFT over I2C to display the aforementioned as well as a cloud or sun icon at the appropriate times with the current intensity under it. Also incorporating the set time and future add-ons like CO2 or Humidity displays and controls in a menu so everything can be done via touch screen but I’m trying to do it a little at a time as I have lofty goals from where I am starting.

Downwardflight: My idea is to simulate sunlight during the day. Specifically: I would like to be able to set the ON time with a separate "up" and "down" tactile switch with a 16 hour photo-period. ON being the start of sunrise and the lights fading from 0%/OFF up to and ideally reaching 90% approximately 7 hours after the set ON time, holding at 90% for approximately 2 hours then fading back down to 0%/OFF after 16 hours

my feeling is that the "total ambient light" changes extremely rapidly for the first and last hour (or even 45mins) of each day and hardly any at all (from a "noticeable" perspective) the rest of the day.

Likewise when you fade a led up from zero, most of the perceived change in brightness happens between zero and 125 (8bit resolution). Because persistence of vision, it is harder to notice a change in brightness as teh PWM goes above 125 towards 255.

but throw that all away and get back to your goal...you should be focusing on creating a non-blocking function that would give you the climb and descend rate you want. that is, your target brightness, your current level and your desired period to make a change. Search for non-blocking fading and you will find the prototype for what you want to do.

an update() function in loop should serve to always be moving your PWM towards its target position. your functions would include a setTarget() to define where that climb is.

pseudo:

void loop() 
{
  leds.update();
  if (time == sunrise)
  {
    leds.setTarget(245, 7); // target PWM and time to get there in hours
  }
  else if (time == sunset - 7)
  {
    leds.setTarget(0, 7);  // 
  }
}

another method would be included in update() to add or suppress brightness for periods in during the day (random clouds).

my feeling is that the "total ambient light" changes extremely rapidly for the first and last hour (or even 45mins) of each day and hardly any at all (from a "noticeable" perspective) the rest of the day.

Likewise when you fade a led up from zero, most of the perceived change in brightness happens between zero and 125 (8bit resolution). Because persistence of vision, it is harder to notice a change in brightness as the PWM goes above 125 towards 255.

Your first point is quite valid, I am probably overthinking the whole thing by trying to create a curve that is noticeable in the sense that you would perceive the initial rise in brightness as brighter than it is. To me our eyes react more sensitively to brightness different than dimness. If the observer was present since the sunrise it would seem to gain brightness quickly or walking in to the simulation at 10am it might seem already at full brightness as there is no frame for reference, whereas as the light dims it seems less obvious until a certain point. Like when you are rushing to get a project done outside before dark and don't realize how dark it is until you go inside the house and come back out, lol.

As far as your second point, I guess I didn't think of the perceived change in brightness as being non linear on the PWM side as well

So I am stuck trying to weigh the variables between trying to provide a noticeable difference in brightness without having to observe for large amounts of time and providing adequate light for healthy growth during the photo-period without stressing the plants or fish by blasting them with full light for the whole photo-period. While at the same time, showing that you can provide a healthier photo-period with less or the least amount of light. I figured I would have to do some extensive testing of different fade curves to get the best result which is why it originally made sense to me to use a matrix that I could plug values into the sketch as well as trying to write code to set simple parameters like on and off time by just using push buttons or a touch screen