Clean Loop

I found this code for an 8 channel LED controller and noted that the author added a time check within the loop. How do you do a similar action without the code being in the Loop?

{
 Blynk.run();
 timer.run(); // Initiates SimpleTimer
}

// get the current time, for this time around loop
// all millis() timer checks will use these time stamps

 unsigned long currentMillis0 = millis();
 ledFade0(currentMillis0);

void fLedFade0(void) {
   unsigned long currentMillis0 = millis();
   ledFade0(currentMillis0);
}

void setup(void) {
   timer.setInterval(1000L, fLedFade0);
}

The trick will be the timer interval. I’ve used one second in my example. I don’t know exactly what the ledFade0() function is doing, how long it takes to execute, how frequently it needs to be invoked, …

I’m also assuming you have eight such ledFadeX() functions. You’ll likely want to dedicate a timer interval to each function. I believe the original sketch uses the SimpleTimer. A SimpleTimer only supports ten intervals. I believe the original sketch already uses four intervals. You can switch to the BlynkTimer which supports 16 intervals. The syntax is identical. Or incorporate a second SimpleTimer dedicated to the ledFadeX() functions.

And by the way, it would be a lot cleaner if the ledFadeX() functions captured the current time. They could be called directly by the timer,

void ledFade0(void) {
   unsigned long thisMillis0 = millis();
   if (nowseconds < startseconds) {
      currentFadePosition0 = minPWM;
   }
   // ...
}

void setup(void) {
   timer.setInterval(1000L, ledFade0);
}

And if you’re more adventurous, you could collapse all eight of the ledFadeX() functions into a single ledFade() function. This …

int maxPWM0 = 0; // variable for max PWM value attached to BLYNK Virtual pin.
int maxPWM1 = 0; // variable for max PWM value attached to BLYNK Virtual pin.
int maxPWM2 = 0; // variable for max PWM value attached to BLYNK Virtual pin.
int maxPWM3 = 0; // variable for max PWM value attached to BLYNK Virtual pin.
int maxPWM4 = 0; // variable for max PWM value attached to BLYNK Virtual pin.
int maxPWM5 = 0; // variable for max PWM value attached to BLYNK Virtual pin.
int maxPWM6 = 0; // variable for max PWM value attached to BLYNK Virtual pin.
int maxPWM7 = 0; // variable for max PWM value attached to BLYNK Virtual pin.

int currentFadePosition0 = 0;// don't change this!
int currentFadePosition1 = 0;// don't change this!
int currentFadePosition2 = 0;// don't change this!
int currentFadePosition3 = 0;// don't change this!
int currentFadePosition4 = 0;// don't change this!
int currentFadePosition5 = 0;// don't change this!
int currentFadePosition6 = 0;// don't change this!
int currentFadePosition7 = 0;// don't change this!

unsigned long previousFadeMillis0;// millis() timing Variable, just for fading
unsigned long previousFadeMillis1;// millis() timing Variable, just for fading
unsigned long previousFadeMillis2;// millis() timing Variable, just for fading
unsigned long previousFadeMillis3;// millis() timing Variable, just for fading
unsigned long previousFadeMillis4;// millis() timing Variable, just for fading
unsigned long previousFadeMillis5;// millis() timing Variable, just for fading
unsigned long previousFadeMillis6;// millis() timing Variable, just for fading
unsigned long previousFadeMillis7;// millis() timing Variable, just for fading

long stepWaitTime0 = 0;  //How long to watch the clock before incrementing to the next step. (time in milliseconds)
long stepWaitTime1 = 0;  //How long to watch the clock before incrementing to the next step. (time in milliseconds)
long stepWaitTime2 = 0;  //How long to watch the clock before incrementing to the next step. (time in milliseconds)
long stepWaitTime3 = 0;  //How long to watch the clock before incrementing to the next step. (time in milliseconds)
long stepWaitTime4 = 0;  //How long to watch the clock before incrementing to the next step. (time in milliseconds)
long stepWaitTime5 = 0;  //How long to watch the clock before incrementing to the next step. (time in milliseconds)
long stepWaitTime6 = 0;  //How long to watch the clock before incrementing to the next step. (time in milliseconds)
long stepWaitTime7 = 0;  //How long to watch the clock before incrementing to the next step. (time in milliseconds)

int desiredledLevel0 = 0;
int desiredledLevel1 = 0;
int desiredledLevel2 = 0;
int desiredledLevel3 = 0;
int desiredledLevel4 = 0;
int desiredledLevel5 = 0;
int desiredledLevel6 = 0;
int desiredledLevel7 = 0;

#define pwmLED0  D1
#define pwmLED1  D2
#define pwmLED2  D3
#define pwmLED3  D4
#define pwmLED4  D5
#define pwmLED5  D6
#define pwmLED6  D7
#define pwmLED7  D8

becomes this,

int maxPWM[] = {0, 0, 0, 0, 0, 0, 0, 0};
int currentFadePosition[] = {0, 0, 0, 0, 0, 0, 0, 0};
unsigned long previousFadeMillis[] = {0, 0, 0, 0, 0, 0, 0, 0};
long stepWaitTime[] = {0, 0, 0, 0, 0, 0, 0, 0};
int desiredledLevel[] = {0, 0, 0, 0, 0, 0, 0, 0};
const int pwmLED[] = {D1, D2, D3, D4, D5, D6, D7, D8};

and the one and only one ledFade() function looks something like this,

void ledFade0(void) { ledFade(0); }
void ledFade1(void) { ledFade(1); }
void ledFade2(void) { ledFade(2); }
void ledFade3(void) { ledFade(3); }
void ledFade4(void) { ledFade(4); }
void ledFade5(void) { ledFade(5); }
void ledFade6(void) { ledFade(6); }
void ledFade7(void) { ledFade(7); }
}

void setup(void) {
   timer.setInterval(1000L, ledFade0); delay(50);
   timer.setInterval(1000L, ledFade1); delay(50);
   timer.setInterval(1000L, ledFade2); delay(50);
   timer.setInterval(1000L, ledFade3); delay(50);
   timer.setInterval(1000L, ledFade4); delay(50);
   timer.setInterval(1000L, ledFade5); delay(50);
   timer.setInterval(1000L, ledFade6); delay(50);
   timer.setInterval(1000L, ledFade7); 
}

void ledFade(int count) {
  unsigned long thisMillis = millis();
  if (nowseconds < startseconds) {
    currentFadePosition[count] = minPWM;
  }
  if (nowseconds > startseconds && nowseconds < stopseconds) {
    // is it time to start the Sunrise?
    // if not, nothing happens
    if (thisMillis - previousFadeMillis[count] >= stepWaitTime[count]) {
      currentFadePosition[count] = currentFadePosition[count] + fadeIncrement;
      if (currentFadePosition[count] >= maxPWM[count]) {
        // At max limit stop the fade
        currentFadePosition[count] = maxPWM[count];
      }
      // put actionable () here.
      //analogWrite(led0, currentFadePosition0);
      // reset millis for the next iteration (fade timer only)
      previousFadeMillis[count] = thisMillis;
    }
  }
  if (nowseconds > stopseconds) {
    // is it time to start the Sunset yet?
    // if not, nothing happens
    if (thisMillis - previousFadeMillis[count] >= stepWaitTime[count]) {
      currentFadePosition[count] = currentFadePosition[count] - fadeIncrement;
      if (currentFadePosition[count] <= minPWM) {
        // At min limit stop the fade
        currentFadePosition[count] = minPWM;
      }
      // put actionable () here
      //analogWrite(led0, currentFadePosition0);
      // reset millis for the next iteration (fade timer only)
      previousFadeMillis[count] = thisMillis;
    }
  }
}

To be honest, I really don’t see where the ledFade() function is doing much of anything (in terms of processing time). You could probably get by with one timer interval,

void fLedFade(void) {
   for (int count = 0; count < 8; count++)
      ledFade(count);
}

void setup(void) {
   timer.setInterval(1000L, fLedFade);
}

I’d start with one timer interval. If that doesn’t work, then split it up into eight. I think it’ll be fine with one. This is likely why the original sketch worked (I assume it did). The ledFadeX() functions execute rather quickly. So even while they are invoked in the context of the loop() function, they’re not stealing considerable CPU time. I agree with your original intent to clean up the loop() function.

Thanks for all of that I will certainly try the above, I love the fact you have made the code much shorter.

Is this the version of the code you’re referencing?

If so, I think it would be worthwhile cleaning it up. Maybe someone has already done it and I’m just not looking at the latest code.

Functionality-wise, does this code do exactly what you’re after? Are you looking for an eight-channel lighting controller?

Yes that’s the one. Have you made it?

No, I’ll have to make it vicariously through you. :wink:

Obviously, I’d encourage anyone with hands-on experience to chime in.

I’d certainly be happy to help you restructure the code to clean-up the loop() function. And to consolidate the data structures and functions which were cut-n-pasted eight times. The finished product will be more compact, readable and maintainable.

If I were you, I’d test the firmware as-is. I can only assume it works given that someone posted it to the forum. This way you establish a baseline. Then we can begin to tweak it and tweak it and tweak it, making sure that it continues to work following each tweak.

Perfect. Mine will only have 5 channels for the LED’s but I am introducing heating and cooling and a few timers.

Yes. That’s one of the things I was getting at. I’d suggest we maintain support for a maximum of eight channels and then define a constant specific to your application. For example,

#define NUMBER_OF_CHANNELS 5

void fLedFade(void) {
   for (int count = 0; count < NUMBER_OF_CHANNELS; count++)
      ledFade(count);
}

void setup(void) {
   timer.setInterval(1000L, fLedFade);
}

Note: We can clean up my poor use of function names.

I think I am going to have to reduce the scope of this because my initial aim was to use an ESP32. After purchasing 2 of them and testing both of them out I have found them untrustworthy, mainly they keep disconnecting from the network. I have done some research on the web and it seems to be a common complaint but I have not found a solution, therefore I have to revert back to the more trusty ESP8266, which I have had running for weeks without any connection issues. Anybody has had problems with ESP32 connection issues?

You should probably create a new topic regarding the ESP32 connection issues. However, I assume the connection issues aren’t related to Blynk, correct?

You’re reducing the scope because an ESP8266 doesn’t have the needed GPIO? There are ways to expand the GPIO. And you could always use two (or more) ESP8266’s. You could dedicate one ESP8266 to the five LED channels and a second ESP8266 to heating, cooling and timers. You can “bridge” the ESP8266’s if necessary. In other words, they become somewhat of a “virtual nodeMCU” with two (or three) times the GPIO of a single ESP8266.

1 Like

I will investigate that option and yes the connection issues has nothing to do with Bkynk