8 Channel Aquarium Led Lighting Controller Powered by BLYNK

Thanks to the recent addition of the Time Input Widget, I was able to rescue this particular project from the dust bin. I created it last July to be a simple way to demonstrate the Blynk apps ability to control ESP8266 I/O pins directly, using the ESP’s native 10 bit PWM to control 8 Meanwell LDD-H series Led Drivers. Now that some time has passed and the Time Input widget has become available, I realized that this project could be re-vamped into an actual standalone Aquarium lighting controller. I’ve designed and built dozens of similar projects using other commercially available aquarium lighting controllers over the last few years, but this one is special… thanks to BLYNK.

Mind you, I’m not a coder, I’m not even a Hardware Engineer, I’m just a guy that’s passionate for DIY with just enough tenacity to learn new things. My coding skills suck and I make the occasional mistake with my hardware designs, but I keep at it until it works. This particular project functions just fine hardware wise, but the software needs a little help. The software works fine as it is now, but crashes if WiFiManager is included. I’m still trying to sort that issue out.

Here’s a photo of the bare PcB-

Here’s a photo of the PcB with all the surface mounted components soldered on-

Here’s a photo of the completed PcB with most of it’s secondary components mounted.

This PcB uses the Wemos D1 Mini for the brains of the operation. There’s an Atmega 328p -AU soldered to the board that’s programmed to read any of the ESP’s 8 outputs and convert the signal to a 25Khz copy of the original. This 25Khz signal is then used to drive up to 3 PC cooling fans without the annoying whine normally associated with using low frequency PWM.
The Meanwell LDD-H constant current Led drivers are fed from a 48 - 56V power supply. The high voltage needed to drive long strings of leds is also fed to a couple Meanwell SCW08C-12 “DC to DC” converters. The resulting 12V is used to power the PC cooling fans and feed a 5V/1amp regulator connected to the ESP’s and Atmega 328’s 5V input. From my testing, the 5V supply appears to be more than adequate to drive the ESP’s 3V3 regulator.

Here’s the code that I’m using. Mind you, for now the WiFiManager portion needs to stay commented out.
I know this code could definitely be condensed into Arrays and what not, so don’t be too cruel…I haven’t learned to do that yet. It’s overly cumbersome but it does work.


/**************************************************************
   
   EXPERIMENTAL WEMOS D1 MINI (ESP8266) ANALOG  DIMMING CODE WITH 8 CHANNELS.
   For Use with the O2Surplus ESP8266 8 Channel PcB.
 **************************************************************/
//#include <FS.h> // needs to be first in includes.
#define BLYNK_PRINT Serial    // Comment this out to disable prints and save space
#include <BlynkSimpleEsp8266.h>
#include <SimpleTimer.h>
#include <ArduinoOTA.h>
#include <TimeLib.h>
#include <WidgetRTC.h>
/*
//included libraries for WiFiManager - AutoConnectWithFSParameters
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h>          //https://github.com/tzapu/WiFiManager
#include <ArduinoJson.h>
*/
// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
char auth[] = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

// Your WiFi credentials. Set password to "" for open networks.
char ssid[] = "xxxxxxxx";
char pass[] = "xxxxxxxx";
/*
char blynk_token[34] = "YOUR_BLYNK_TOKEN";//added from WiFiManager - AutoConnectWithFSParameters
//flag for saving data
bool shouldSaveConfig = false;

//callback notifying the need to save config
void saveConfigCallback () {
  Serial.println("Should save config");
  shouldSaveConfig = true;
}
*/

char Date[16];
char Time[16];
long startseconds = 0;         // start time in seconds
long stopseconds = 0;          // stop  time in seconds
long nowseconds = 0;           // time  now  in seconds
bool isFirstConnect = true;

int fadetime = 0;
long fadetimeseconds = 0;
long fadetimemillis = 0;

int minPWM = 1;// variable for min PWM value. keep at 1 to avoid crashing the ledFade()
byte fadeIncrement = 1; //How smooth to fade? Uses all 4095 steps available.




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 led0  D1
#define led1  D2
#define led2  D3
#define led3  D4
#define led4  D5
#define led5  D6
#define led6  D7
#define led7  D8

WidgetRTC rtc;
SimpleTimer timer;

// divide your desired dimming time duration(in millis) by the maxPWM variable value / fadeIncrement variable value to
// get the stepWaitTime variable value needed.
// EXAMPLE: maxPWM of 1023/fadeIncrement of 1 to dim over 1 hour is a stepWaitTime of 3,519 millis.


void setLed() {

  stepWaitTime0 = (fadetimemillis / maxPWM0);
  stepWaitTime1 = (fadetimemillis / maxPWM1);
  stepWaitTime2 = (fadetimemillis / maxPWM2);
  stepWaitTime3 = (fadetimemillis / maxPWM3);
  stepWaitTime4 = (fadetimemillis / maxPWM4);
  stepWaitTime5 = (fadetimemillis / maxPWM5);
  stepWaitTime6 = (fadetimemillis / maxPWM6);
  stepWaitTime7 = (fadetimemillis / maxPWM7);

}

void ledFade0(unsigned long thisMillis0) {
  if (nowseconds < startseconds) {
    currentFadePosition0 = minPWM;
  }
  if (nowseconds > startseconds && nowseconds < stopseconds) {
    // is it time to start the Sunrise?
    // if not, nothing happens
    if (thisMillis0 - previousFadeMillis0 >= stepWaitTime0) {
      currentFadePosition0 = currentFadePosition0 + fadeIncrement;
      if (currentFadePosition0 >= maxPWM0) {
        // At max limit stop the fade
        currentFadePosition0 = maxPWM0;
      }
      // put actionable () here.
      analogWrite(led0, currentFadePosition0);
      // reset millis for the next iteration (fade timer only)
      previousFadeMillis0 = thisMillis0;
    }
  }
  if (nowseconds > stopseconds) {
    // is it time to start the Sunset yet?
    // if not, nothing happens
    if (thisMillis0 - previousFadeMillis0 >= stepWaitTime0) {
      currentFadePosition0 = currentFadePosition0 - fadeIncrement;
      if (currentFadePosition0 <= minPWM) {
        // At min limit stop the fade
        currentFadePosition0 = minPWM;
      }
      // put actionable () here
      analogWrite(led0, currentFadePosition0);
      // reset millis for the next iteration (fade timer only)
      previousFadeMillis0 = thisMillis0;
    }
  }
}
void ledFade1(unsigned long thisMillis1) {
  if (nowseconds < startseconds) {
    currentFadePosition1 = minPWM;
  }
  if (nowseconds > startseconds && nowseconds < stopseconds) {
    // is it time to start the Sunrise?
    // if not, nothing happens
    if (thisMillis1 - previousFadeMillis1 >= stepWaitTime1) {
      currentFadePosition1 = currentFadePosition1 + fadeIncrement;
      if (currentFadePosition1 >= maxPWM1) {
        // At max limit stop the fade
        currentFadePosition1 = maxPWM1;
      }
      // put actionable () here.
      analogWrite(led1, currentFadePosition1);
      // reset millis for the next iteration (fade timer only)
      previousFadeMillis1 = thisMillis1;
    }
  }
  if (nowseconds > stopseconds) {
    // is it time to start the Sunset yet?
    // if not, nothing happens
    if (thisMillis1 - previousFadeMillis1 >= stepWaitTime1) {
      currentFadePosition1 = currentFadePosition1 - fadeIncrement;
      if (currentFadePosition1 <= minPWM) {
        // At min limit stop the fade
        currentFadePosition1 = minPWM;
      }
      // put actionable () here
      analogWrite(led1, currentFadePosition1);
      // reset millis for the next iteration (fade timer only)
      previousFadeMillis1 = thisMillis1;
    }
  }
}
void ledFade2(unsigned long thisMillis2) {
  if (nowseconds < startseconds) {
    currentFadePosition2 = minPWM;
  }
  if (nowseconds > startseconds && nowseconds < stopseconds) {
    // is it time to start the Sunrise?
    // if not, nothing happens
    if (thisMillis2 - previousFadeMillis2 >= stepWaitTime2) {
      currentFadePosition2 = currentFadePosition2 + fadeIncrement;
      if (currentFadePosition2 >= maxPWM2) {
        // At max limit stop the fade
        currentFadePosition2 = maxPWM2;
      }
      // put actionable () here.
      analogWrite(led2, currentFadePosition2);
      // reset millis for the next iteration (fade timer only)
      previousFadeMillis2 = thisMillis2;
    }
  }
  if (nowseconds > stopseconds) {
    // is it time to start the Sunset yet?
    // if not, nothing happens
    if (thisMillis2 - previousFadeMillis2 >= stepWaitTime2) {
      currentFadePosition2 = currentFadePosition2 - fadeIncrement;
      if (currentFadePosition2 <= minPWM) {
        // At min limit stop the fade
        currentFadePosition2 = minPWM;
      }
      // put actionable () here
      analogWrite(led2, currentFadePosition2);
      // reset millis for the next iteration (fade timer only)
      previousFadeMillis2 = thisMillis2;
    }
  }
}
void ledFade3(unsigned long thisMillis3) {
  if (nowseconds < startseconds) {
    currentFadePosition3 = minPWM;
  }
  if (nowseconds > startseconds && nowseconds < stopseconds) {
    // is it time to start the Sunrise?
    // if not, nothing happens
    if (thisMillis3 - previousFadeMillis3 >= stepWaitTime3) {
      currentFadePosition3 = currentFadePosition3 + fadeIncrement;
      if (currentFadePosition3 >= maxPWM3) {
        // At max limit stop the fade
        currentFadePosition3 = maxPWM3;
      }
      // put actionable () here.
      analogWrite(led3, currentFadePosition3);
      // reset millis for the next iteration (fade timer only)
      previousFadeMillis3 = thisMillis3;
    }
  }
  if (nowseconds > stopseconds) {
    // is it time to start the Sunset yet?
    // if not, nothing happens
    if (thisMillis3 - previousFadeMillis3 >= stepWaitTime3) {
      currentFadePosition3 = currentFadePosition3 - fadeIncrement;
      if (currentFadePosition3 <= minPWM) {
        // At min limit stop the fade
        currentFadePosition3 = minPWM;
      }
      // put actionable () here
      analogWrite(led3, currentFadePosition3);
      // reset millis for the next iteration (fade timer only)
      previousFadeMillis3 = thisMillis3;
    }
  }
}
void ledFade4(unsigned long thisMillis4) {
  if (nowseconds < startseconds) {
    currentFadePosition4 = minPWM;
  }
  if (nowseconds > startseconds && nowseconds < stopseconds) {
    // is it time to start the Sunrise?
    // if not, nothing happens
    if (thisMillis4 - previousFadeMillis4 >= stepWaitTime4) {
      currentFadePosition4 = currentFadePosition4 + fadeIncrement;
      if (currentFadePosition4 >= maxPWM4) {
        // At max limit stop the fade
        currentFadePosition4 = maxPWM4;
      }
      // put actionable () here.
      analogWrite(led4, currentFadePosition4);
      // reset millis for the next iteration (fade timer only)
      previousFadeMillis4 = thisMillis4;
    }
  }
  if (nowseconds > stopseconds) {
    // is it time to start the Sunset yet?
    // if not, nothing happens
    if (thisMillis4 - previousFadeMillis4 >= stepWaitTime4) {
      currentFadePosition4 = currentFadePosition4 - fadeIncrement;
      if (currentFadePosition4 <= minPWM) {
        // At min limit stop the fade
        currentFadePosition4 = minPWM;
      }
      // put actionable () here
      analogWrite(led4, currentFadePosition4);
      // reset millis for the next iteration (fade timer only)
      previousFadeMillis4 = thisMillis4;
    }
  }
}
void ledFade5(unsigned long thisMillis5) {
  if (nowseconds < startseconds) {
    currentFadePosition5 = minPWM;
  }
  if (nowseconds > startseconds && nowseconds < stopseconds) {
    // is it time to start the Sunrise?
    // if not, nothing happens
    if (thisMillis5 - previousFadeMillis5 >= stepWaitTime5) {
      currentFadePosition5 = currentFadePosition5 + fadeIncrement;
      if (currentFadePosition5 >= maxPWM5) {
        // At max limit stop the fade
        currentFadePosition5 = maxPWM5;
      }
      // put actionable () here.
      analogWrite(led5, currentFadePosition5);
      // reset millis for the next iteration (fade timer only)
      previousFadeMillis5 = thisMillis5;
    }
  }
  if (nowseconds > stopseconds) {
    // is it time to start the Sunset yet?
    // if not, nothing happens
    if (thisMillis5 - previousFadeMillis5 >= stepWaitTime5) {
      currentFadePosition5 = currentFadePosition5 - fadeIncrement;
      if (currentFadePosition5 <= minPWM) {
        // At min limit stop the fade
        currentFadePosition5 = minPWM;
      }
      // put actionable () here
      analogWrite(led5, currentFadePosition5);
      // reset millis for the next iteration (fade timer only)
      previousFadeMillis5 = thisMillis5;
    }
  }
}
void ledFade6(unsigned long thisMillis6) {
  if (nowseconds < startseconds) {
    currentFadePosition6 = minPWM;
  }
  if (nowseconds > startseconds && nowseconds < stopseconds) {
    // is it time to start the Sunrise?
    // if not, nothing happens
    if (thisMillis6 - previousFadeMillis6 >= stepWaitTime6) {
      currentFadePosition6 = currentFadePosition6 + fadeIncrement;
      if (currentFadePosition6 >= maxPWM6) {
        // At max limit stop the fade
        currentFadePosition6 = maxPWM6;
      }
      // put actionable () here.
      analogWrite(led6, currentFadePosition6);
      // reset millis for the next iteration (fade timer only)
      previousFadeMillis6 = thisMillis6;
    }
  }
  if (nowseconds > stopseconds) {
    // is it time to start the Sunset yet?
    // if not, nothing happens
    if (thisMillis6 - previousFadeMillis6 >= stepWaitTime6) {
      currentFadePosition6 = currentFadePosition6 - fadeIncrement;
      if (currentFadePosition6 <= minPWM) {
        // At min limit stop the fade
        currentFadePosition6 = minPWM;
      }
      // put actionable () here
      analogWrite(led6, currentFadePosition6);
      // reset millis for the next iteration (fade timer only)
      previousFadeMillis6 = thisMillis6;
    }
  }
}
void ledFade7(unsigned long thisMillis7) {
  if (nowseconds < startseconds) {
    currentFadePosition7 = minPWM;
  }
  if (nowseconds > startseconds && nowseconds < stopseconds) {
    // is it time to start the Sunrise?
    // if not, nothing happens
    if (thisMillis7 - previousFadeMillis7 >= stepWaitTime7) {
      currentFadePosition7 = currentFadePosition7 + fadeIncrement;
      if (currentFadePosition7 >= maxPWM7) {
        // At max limit stop the fade
        currentFadePosition7 = maxPWM7;
      }
      // put actionable () here.
      analogWrite(led7, currentFadePosition7);
      // reset millis for the next iteration (fade timer only)
      previousFadeMillis7 = thisMillis7;
    }
  }
  if (nowseconds > stopseconds) {
    // is it time to start the Sunset yet?
    // if not, nothing happens
    if (thisMillis7 - previousFadeMillis7 >= stepWaitTime7) {
      currentFadePosition7 = currentFadePosition7 - fadeIncrement;
      if (currentFadePosition7 <= minPWM) {
        // At min limit stop the fade
        currentFadePosition7 = minPWM;
      }
      // put actionable () here
      analogWrite(led7, currentFadePosition7);
      // reset millis for the next iteration (fade timer only)
      previousFadeMillis7 = thisMillis7;
    }
  }
}


// Digital clock display of the time
void clockDisplay()
{
  // You can call hour(), minute(), ... at any time
  // Please see Time library examples for details

  String currentTime = String(hour()) + ":" + minute() + ":" + second();
  String currentDate = String(month()) + " " + day() + " " + year();
  nowseconds = ((hour() * 3600) + (minute() * 60) + second());
  Serial.print("Time =");
  Serial.println(currentTime);
  Serial.print("Nowseconds =");
  Serial.println(nowseconds);
  Serial.print("Start = ");
  Serial.println(startseconds);
  Serial.print("Stop = ");
  Serial.println(stopseconds);
  Serial.println();
  Blynk.virtualWrite(V8, currentTime);
}


BLYNK_WRITE(V0) {// slider widget to set the maximum led level from the Blynk App.
  desiredledLevel0 = param.asInt();// channel 1
  maxPWM0 = map(desiredledLevel0, 0, 100, minPWM, 1023);
}
BLYNK_WRITE(V1) {// slider widget to set the maximum led level from the Blynk App.
  desiredledLevel1 = param.asInt();// channel 2
  maxPWM1 = map(desiredledLevel1, 0, 100, minPWM, 1023);
}
BLYNK_WRITE(V2) {// slider widget to set the maximum led level from the Blynk App.
  desiredledLevel2 = param.asInt();// channel 3
  maxPWM2 = map(desiredledLevel2, 0, 100, minPWM, 1023);
}
BLYNK_WRITE(V3) {// slider widget to set the maximum led level from the Blynk App.
  desiredledLevel3 = param.asInt();// channel 4
  maxPWM3 = map(desiredledLevel3, 0, 100, minPWM, 1023);
}
BLYNK_WRITE(V4) {// slider widget to set the maximum led level from the Blynk App.
  desiredledLevel4 = param.asInt();// channel 5
  maxPWM4 = map(desiredledLevel4, 0, 100, minPWM, 1023);
}
BLYNK_WRITE(V5) {// slider widget to set the maximum led level from the Blynk App.
  desiredledLevel5 = param.asInt();// channel 6
  maxPWM5 = map(desiredledLevel5, 0, 100, minPWM, 1023);
}
BLYNK_WRITE(V6) {// slider widget to set the maximum led level from the Blynk App.
  desiredledLevel6 = param.asInt();// channel 7
  maxPWM6 = map(desiredledLevel6, 0, 100, minPWM, 1023);
}
BLYNK_WRITE(V7) {// slider widget to set the maximum led level from the Blynk App.
  desiredledLevel7 = param.asInt();// channel 8
  maxPWM7 = map(desiredledLevel7, 0, 100, minPWM, 1023);
}


BLYNK_WRITE(V9) {// slider widget to set the led fade duration up tp 3 hours.
  fadetime = param.asInt();
  fadetimeseconds = map(fadetime, 0, 180, 1, 10800);// 3 hour fade duration is max
  fadetimemillis  = map(fadetime, 0, 180, 1, 10800000);// 3 hour fade duration is max
  Serial.print("Fade Time in seconds =");
  Serial.println(fadetimeseconds);
}

void activetoday() {       // check if schedule should run today
  if (year() != 1970) {
    Blynk.syncVirtual(V3); // sync timeinput widget
    sprintf(Date, "%02d/%02d/%04d",  day(), month(), year());
    sprintf(Time, "%02d:%02d:%02d", hour(), minute(), second());
    nowseconds = ((hour() * 3600) + (minute() * 60) + second());
  }
}

BLYNK_WRITE(V10) {

  TimeInputParam t(param);
  Serial.print("Checked schedule at: ");
  Serial.println(Time);
  int dayadjustment = -1;
  if (weekday() == 1) {
    dayadjustment =  6; // needed for Sunday, Time library is day 1 and Blynk is day 7
  }
  if (t.isWeekdaySelected((weekday() + dayadjustment))) { //Time library starts week on Sunday, Blynk on Monday
    Serial.println("Schedule ACTIVE today");
    nowseconds = ((hour() * 3600) + (minute() * 60) + second());
    startseconds = (t.getStartHour() * 3600) + (t.getStartMinute() * 60);
    if (nowseconds >= startseconds) {

      if (nowseconds <= startseconds + 90) {  // 90s on 60s timer ensures 1 trigger command is sent
        // code here

      }
    }
    else {
      Serial.println("Relay not on");// nothing more to do here, waiting for relay to be turned on later today
    }
    stopseconds = (t.getStopHour() * 3600) + (t.getStopMinute() * 60);
    if (nowseconds >= stopseconds) {
      // 90s on 60s timer ensures 1 trigger command is sent
      if (nowseconds <= stopseconds + 90) {
        // code here

      }
    }
    else {
      if (nowseconds >= startseconds) { // only show if motor has already started today
        Serial.println("Relay is still ON");
        // nothing more to do here, waiting for motor to be turned off later today
      }
    }
  }
  else {
    Serial.println("Schedule INACTIVE today");
    // nothing to do today, check again in 1 minutes time
  }
  Serial.println();
}

void reconnectBlynk() {
  if (!Blynk.connected()) {
    if (Blynk.connect()) {
      BLYNK_LOG("Reconnected");
    }
    else {
      BLYNK_LOG("Not reconnected");
    }
  }
}

void setup()
{
  ArduinoOTA.begin();
  Serial.begin(115200);
  
  Blynk.begin(auth, ssid, pass);
  while (Blynk.connect() == false) {
    // Wait until connected
  }
/*
  //The following code is borrowed from WiFiManager
  //clean FS, for testing
  //SPIFFS.format();

  //read configuration from FS json
  Serial.println("mounting FS...");

  if (SPIFFS.begin()) {
    Serial.println("mounted file system");
    if (SPIFFS.exists("/config.json")) {
      //file exists, reading and loading
      Serial.println("reading config file");
      File configFile = SPIFFS.open("/config.json", "r");
      if (configFile) {
        Serial.println("opened config file");
        size_t size = configFile.size();
        // Allocate a buffer to store contents of the file.
        std::unique_ptr<char[]> buf(new char[size]);

        configFile.readBytes(buf.get(), size);
        DynamicJsonBuffer jsonBuffer;
        JsonObject& json = jsonBuffer.parseObject(buf.get());
        json.printTo(Serial);
        if (json.success()) {
          Serial.println("\nparsed json");
          strcpy(blynk_token, json["blynk_token"]);

        } else {
          Serial.println("failed to load json config");
        }
      }
    }
  } else {
    Serial.println("failed to mount FS");
  }
  //end read
  // The extra parameters to be configured (can be either global or just in the setup)
  // After connecting, parameter.getValue() will get you the configured value
  // id/name placeholder/prompt default length
  WiFiManagerParameter custom_blynk_token("blynk", "blynk token", blynk_token, 34);
  Serial.println(blynk_token);
  //WiFiManager
  //Local intialization. Once its business is done, there is no need to keep it around
  WiFiManager wifiManager;

  //set config save notify callback
  wifiManager.setSaveConfigCallback(saveConfigCallback);

  //add all your parameters here
  wifiManager.addParameter(&custom_blynk_token);

  //reset settings - for testing
  //wifiManager.resetSettings();

  //set minimu quality of signal so it ignores AP's under that quality
  //defaults to 8%
  wifiManager.setMinimumSignalQuality();

  //sets timeout until configuration portal gets turned off
  //useful to make it all retry or go to sleep
  //in seconds
  wifiManager.setTimeout(180);

  //fetches ssid and pass and tries to connect
  //if it does not connect it starts an access point with the specified name
  //here  "8 CH LED CONTROL"
  //and goes into a blocking loop awaiting configuration
  if (!wifiManager.autoConnect("8 CH LED CONTROL")) {
    Serial.println("failed to connect and hit timeout");
    delay(3000);
    //reset and try again, or maybe put it to deep sleep
    ESP.reset();
    delay(5000);
  }

  //if you get here you have connected to the WiFi
  Serial.println("8 CH LED CONTROL connected :)");

  //read updated parameters
  strcpy(blynk_token, custom_blynk_token.getValue());

  //save the custom parameters to FS
  if (shouldSaveConfig) {
    Serial.println("saving config");
    DynamicJsonBuffer jsonBuffer;
    JsonObject& json = jsonBuffer.createObject();
    json["blynk_token"] = blynk_token;

    File configFile = SPIFFS.open("/config.json", "w");
    if (!configFile) {
      Serial.println("failed to open config file for writing");
    }

    json.printTo(Serial);
    json.printTo(configFile);
    configFile.close();
    //end save
  }

  Serial.println("local ip");
  Serial.println(WiFi.localIP());
  Blynk.connect();
  Blynk.config(blynk_token);
  

  if (!blynk_token)
  {
    Serial.println("Failed to connect to Blynk server");
    wifiManager.resetSettings();// reset all settings and spool up the "TERRA HVAC" AP again.

    delay(1000);
  }

  Serial.println("Done");
  */
  Blynk.notify("8 Ch Wemos D1 Mini LDD-H led driver PcB Connected successfully");
  
  rtc.begin();
  
  timer.setInterval(1000L, setLed);
  timer.setInterval(1000L, clockDisplay);     // digital time displayed every second
  timer.setInterval(60000L, activetoday);     // check every minute if schedule should run today
  timer.setInterval(60000L, reconnectBlynk);  // check every 60s if still connected to server

  Blynk.syncAll();
}
void loop()
{
 
  ArduinoOTA.handle();
  timer.run(); // Initiates SimpleTimer
  if (Blynk.connected()) {
    Blynk.run();
  }
// get the current time, for this time around loop
  // all millis() timer checks will use this time stamp
  unsigned long currentMillis0 = millis();
  ledFade0(currentMillis0);
  unsigned long currentMillis1 = millis();
  ledFade1(currentMillis1);
  unsigned long currentMillis2 = millis();
  ledFade2(currentMillis2);
  unsigned long currentMillis3 = millis();
  ledFade3(currentMillis3);
  unsigned long currentMillis4 = millis();
  ledFade4(currentMillis4);
  unsigned long currentMillis5 = millis();
  ledFade5(currentMillis5);
  unsigned long currentMillis6 = millis();
  ledFade6(currentMillis6);
  unsigned long currentMillis7 = millis();
  ledFade7(currentMillis7);

}


Here’s what my Blynk Dash board look like-

Front tab-

Back Tab-

Any comments are welcome!

3 Likes

Update.

I got the WiFiManager problem sorted out. Seems I had the Blynk.config(blynk_token); & Blynk.connect(); in the wrong order, which caused the ESP to crash repeatedly. I’ve posted the corrected code below.
Mind you, you don’t need the fancy PcB that I created to use this code. Simply connect the positive PWM lead of any commercially available 5V PWM dimmable led driver to the Wemos D1 Mini I/O pins(D1 - D8) and make sure that the Mini shares a common ground with the led driver to complete the PWM signal circuit.

Here’s the QR code followed by the working code;

/**************************************************************
   
   WEMOS D1 MINI (ESP8266) ANALOG  DIMMING CODE WITH 8 CHANNELS.
   Controlled by BLYNK
 **************************************************************/
#include <FS.h> // needs to be first in includes.
#define BLYNK_PRINT Serial    // Comment this out to disable prints and save space
#include <BlynkSimpleEsp8266.h>
#include <SimpleTimer.h>
#include <ArduinoOTA.h>
#include <TimeLib.h>
#include <WidgetRTC.h>

//included libraries for WiFiManager - AutoConnectWithFSParameters
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h>          //https://github.com/tzapu/WiFiManager
#include <ArduinoJson.h>

char blynk_token[34] = "YOUR_BLYNK_TOKEN";//added from WiFiManager - AutoConnectWithFSParameters
//flag for saving data
bool shouldSaveConfig = false;

//callback notifying the need to save config
void saveConfigCallback () {
  Serial.println("Should save config");
  shouldSaveConfig = true;
}


char Date[16];
char Time[16];
long startseconds = 0;         // start time in seconds
long stopseconds = 0;          // stop  time in seconds
long nowseconds = 0;           // time  now  in seconds
bool isFirstConnect = true;

int fadetime = 0;
long fadetimeseconds = 0;
long fadetimemillis = 0;

int minPWM = 1;// variable for min PWM value. keep at 1 to avoid crashing the ledFade()
byte fadeIncrement = 1; //How smooth to fade? Uses all 1023 steps available.




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

WidgetRTC rtc;
SimpleTimer timer;

// divide your desired dimming time duration(in millis) by the maxPWM variable value / fadeIncrement variable value to
// get the stepWaitTime variable value needed.
// EXAMPLE: maxPWM of 1023/fadeIncrement of 1 to dim over 1 hour is a stepWaitTime of 3,519 millis.


void setLed() {
  if(currentFadePosition0 <= 1){
    analogWrite(pwmLED0, 0);
  }
  else{
  stepWaitTime0 = (fadetimemillis / (maxPWM0 / fadeIncrement));
  analogWrite(pwmLED0, currentFadePosition0);
  }
  if(currentFadePosition1 <= 1){
    analogWrite(pwmLED1, 0);
  }
  else{
  stepWaitTime1 = (fadetimemillis / (maxPWM1 / fadeIncrement));
  analogWrite(pwmLED1, currentFadePosition1);
  }
  if(currentFadePosition2 <= 1){
    analogWrite(pwmLED2, 0);
  }
  else{
  stepWaitTime2 = (fadetimemillis / (maxPWM2 / fadeIncrement));
  analogWrite(pwmLED2, currentFadePosition2);
  }
  if(currentFadePosition3 <= 1){
    analogWrite(pwmLED3, 0);
  }
  else{
  stepWaitTime3 = (fadetimemillis / (maxPWM3 / fadeIncrement));
  analogWrite(pwmLED3, currentFadePosition3);
  }
  if(currentFadePosition4 <= 1){
    analogWrite(pwmLED4, 0);
  }
  else{
  stepWaitTime4 = (fadetimemillis / (maxPWM4 / fadeIncrement));
  analogWrite(pwmLED4, currentFadePosition4);
  }
  if(currentFadePosition5 <= 1){
    analogWrite(pwmLED5, 0);
  }
  else{
  stepWaitTime5 = (fadetimemillis / (maxPWM5 / fadeIncrement));
  analogWrite(pwmLED5, currentFadePosition5);
  }
  if(currentFadePosition6 <= 1){
    analogWrite(pwmLED6, 0);
  }
  else{
  stepWaitTime6 = (fadetimemillis / (maxPWM6 / fadeIncrement));
  analogWrite(pwmLED6, currentFadePosition6);
  }
  if(currentFadePosition7 <= 1){
    analogWrite(pwmLED7, 0);
  }
  else{
  stepWaitTime7 = (fadetimemillis / (maxPWM7 / fadeIncrement));
  analogWrite(pwmLED7, currentFadePosition7);
  }
}

void ledFade0(unsigned long thisMillis0) {
  if (nowseconds < startseconds) {
    currentFadePosition0 = minPWM;
  }
  if (nowseconds > startseconds && nowseconds < stopseconds) {
    // is it time to start the Sunrise?
    // if not, nothing happens
    if (thisMillis0 - previousFadeMillis0 >= stepWaitTime0) {
      currentFadePosition0 = currentFadePosition0 + fadeIncrement;
      if (currentFadePosition0 >= maxPWM0) {
        // At max limit stop the fade
        currentFadePosition0 = maxPWM0;
      }
      // put actionable () here.
      //analogWrite(led0, currentFadePosition0);
      // reset millis for the next iteration (fade timer only)
      previousFadeMillis0 = thisMillis0;
    }
  }
  if (nowseconds > stopseconds) {
    // is it time to start the Sunset yet?
    // if not, nothing happens
    if (thisMillis0 - previousFadeMillis0 >= stepWaitTime0) {
      currentFadePosition0 = currentFadePosition0 - fadeIncrement;
      if (currentFadePosition0 <= minPWM) {
        // At min limit stop the fade
        currentFadePosition0 = minPWM;
      }
      // put actionable () here
      //analogWrite(led0, currentFadePosition0);
      // reset millis for the next iteration (fade timer only)
      previousFadeMillis0 = thisMillis0;
    }
  }
}
void ledFade1(unsigned long thisMillis1) {
  if (nowseconds < startseconds) {
    currentFadePosition1 = minPWM;
  }
  if (nowseconds > startseconds && nowseconds < stopseconds) {
    // is it time to start the Sunrise?
    // if not, nothing happens
    if (thisMillis1 - previousFadeMillis1 >= stepWaitTime1) {
      currentFadePosition1 = currentFadePosition1 + fadeIncrement;
      if (currentFadePosition1 >= maxPWM1) {
        // At max limit stop the fade
        currentFadePosition1 = maxPWM1;
      }
      // put actionable () here.
      //analogWrite(led1, currentFadePosition1);
      // reset millis for the next iteration (fade timer only)
      previousFadeMillis1 = thisMillis1;
    }
  }
  if (nowseconds > stopseconds) {
    // is it time to start the Sunset yet?
    // if not, nothing happens
    if (thisMillis1 - previousFadeMillis1 >= stepWaitTime1) {
      currentFadePosition1 = currentFadePosition1 - fadeIncrement;
      if (currentFadePosition1 <= minPWM) {
        // At min limit stop the fade
        currentFadePosition1 = minPWM;
      }
      // put actionable () here
      //analogWrite(led1, currentFadePosition1);
      // reset millis for the next iteration (fade timer only)
      previousFadeMillis1 = thisMillis1;
    }
  }
}
void ledFade2(unsigned long thisMillis2) {
  if (nowseconds < startseconds) {
    currentFadePosition2 = minPWM;
  }
  if (nowseconds > startseconds && nowseconds < stopseconds) {
    // is it time to start the Sunrise?
    // if not, nothing happens
    if (thisMillis2 - previousFadeMillis2 >= stepWaitTime2) {
      currentFadePosition2 = currentFadePosition2 + fadeIncrement;
      if (currentFadePosition2 >= maxPWM2) {
        // At max limit stop the fade
        currentFadePosition2 = maxPWM2;
      }
      // put actionable () here.
      //analogWrite(led2, currentFadePosition2);
      // reset millis for the next iteration (fade timer only)
      previousFadeMillis2 = thisMillis2;
    }
  }
  if (nowseconds > stopseconds) {
    // is it time to start the Sunset yet?
    // if not, nothing happens
    if (thisMillis2 - previousFadeMillis2 >= stepWaitTime2) {
      currentFadePosition2 = currentFadePosition2 - fadeIncrement;
      if (currentFadePosition2 <= minPWM) {
        // At min limit stop the fade
        currentFadePosition2 = minPWM;
      }
      // put actionable () here
      //analogWrite(led2, currentFadePosition2);
      // reset millis for the next iteration (fade timer only)
      previousFadeMillis2 = thisMillis2;
    }
  }
}
void ledFade3(unsigned long thisMillis3) {
  if (nowseconds < startseconds) {
    currentFadePosition3 = minPWM;
  }
  if (nowseconds > startseconds && nowseconds < stopseconds) {
    // is it time to start the Sunrise?
    // if not, nothing happens
    if (thisMillis3 - previousFadeMillis3 >= stepWaitTime3) {
      currentFadePosition3 = currentFadePosition3 + fadeIncrement;
      if (currentFadePosition3 >= maxPWM3) {
        // At max limit stop the fade
        currentFadePosition3 = maxPWM3;
      }
      // put actionable () here.
      //analogWrite(led3, currentFadePosition3);
      // reset millis for the next iteration (fade timer only)
      previousFadeMillis3 = thisMillis3;
    }
  }
  if (nowseconds > stopseconds) {
    // is it time to start the Sunset yet?
    // if not, nothing happens
    if (thisMillis3 - previousFadeMillis3 >= stepWaitTime3) {
      currentFadePosition3 = currentFadePosition3 - fadeIncrement;
      if (currentFadePosition3 <= minPWM) {
        // At min limit stop the fade
        currentFadePosition3 = minPWM;
      }
      // put actionable () here
      //analogWrite(led3, currentFadePosition3);
      // reset millis for the next iteration (fade timer only)
      previousFadeMillis3 = thisMillis3;
    }
  }
}
void ledFade4(unsigned long thisMillis4) {
  if (nowseconds < startseconds) {
    currentFadePosition4 = minPWM;
  }
  if (nowseconds > startseconds && nowseconds < stopseconds) {
    // is it time to start the Sunrise?
    // if not, nothing happens
    if (thisMillis4 - previousFadeMillis4 >= stepWaitTime4) {
      currentFadePosition4 = currentFadePosition4 + fadeIncrement;
      if (currentFadePosition4 >= maxPWM4) {
        // At max limit stop the fade
        currentFadePosition4 = maxPWM4;
      }
      // put actionable () here.
      //analogWrite(led4, currentFadePosition4);
      // reset millis for the next iteration (fade timer only)
      previousFadeMillis4 = thisMillis4;
    }
  }
  if (nowseconds > stopseconds) {
    // is it time to start the Sunset yet?
    // if not, nothing happens
    if (thisMillis4 - previousFadeMillis4 >= stepWaitTime4) {
      currentFadePosition4 = currentFadePosition4 - fadeIncrement;
      if (currentFadePosition4 <= minPWM) {
        // At min limit stop the fade
        currentFadePosition4 = minPWM;
      }
      // put actionable () here
      //analogWrite(led4, currentFadePosition4);
      // reset millis for the next iteration (fade timer only)
      previousFadeMillis4 = thisMillis4;
    }
  }
}
void ledFade5(unsigned long thisMillis5) {
  if (nowseconds < startseconds) {
    currentFadePosition5 = minPWM;
  }
  if (nowseconds > startseconds && nowseconds < stopseconds) {
    // is it time to start the Sunrise?
    // if not, nothing happens
    if (thisMillis5 - previousFadeMillis5 >= stepWaitTime5) {
      currentFadePosition5 = currentFadePosition5 + fadeIncrement;
      if (currentFadePosition5 >= maxPWM5) {
        // At max limit stop the fade
        currentFadePosition5 = maxPWM5;
      }
      // put actionable () here.
      //analogWrite(led5, currentFadePosition5);
      // reset millis for the next iteration (fade timer only)
      previousFadeMillis5 = thisMillis5;
    }
  }
  if (nowseconds > stopseconds) {
    // is it time to start the Sunset yet?
    // if not, nothing happens
    if (thisMillis5 - previousFadeMillis5 >= stepWaitTime5) {
      currentFadePosition5 = currentFadePosition5 - fadeIncrement;
      if (currentFadePosition5 <= minPWM) {
        // At min limit stop the fade
        currentFadePosition5 = minPWM;
      }
      // put actionable () here
      //analogWrite(led5, currentFadePosition5);
      // reset millis for the next iteration (fade timer only)
      previousFadeMillis5 = thisMillis5;
    }
  }
}
void ledFade6(unsigned long thisMillis6) {
  if (nowseconds < startseconds) {
    currentFadePosition6 = minPWM;
  }
  if (nowseconds > startseconds && nowseconds < stopseconds) {
    // is it time to start the Sunrise?
    // if not, nothing happens
    if (thisMillis6 - previousFadeMillis6 >= stepWaitTime6) {
      currentFadePosition6 = currentFadePosition6 + fadeIncrement;
      if (currentFadePosition6 >= maxPWM6) {
        // At max limit stop the fade
        currentFadePosition6 = maxPWM6;
      }
      // put actionable () here.
      //analogWrite(led6, currentFadePosition6);
      // reset millis for the next iteration (fade timer only)
      previousFadeMillis6 = thisMillis6;
    }
  }
  if (nowseconds > stopseconds) {
    // is it time to start the Sunset yet?
    // if not, nothing happens
    if (thisMillis6 - previousFadeMillis6 >= stepWaitTime6) {
      currentFadePosition6 = currentFadePosition6 - fadeIncrement;
      if (currentFadePosition6 <= minPWM) {
        // At min limit stop the fade
        currentFadePosition6 = minPWM;
      }
      // put actionable () here
      //analogWrite(led6, currentFadePosition6);
      // reset millis for the next iteration (fade timer only)
      previousFadeMillis6 = thisMillis6;
    }
  }
}
void ledFade7(unsigned long thisMillis7) {
  if (nowseconds < startseconds) {
    currentFadePosition7 = minPWM;
  }
  if (nowseconds > startseconds && nowseconds < stopseconds) {
    // is it time to start the Sunrise?
    // if not, nothing happens
    if (thisMillis7 - previousFadeMillis7 >= stepWaitTime7) {
      currentFadePosition7 = currentFadePosition7 + fadeIncrement;
      if (currentFadePosition7 >= maxPWM7) {
        // At max limit stop the fade
        currentFadePosition7 = maxPWM7;
      }
      // put actionable () here.
      //analogWrite(led7, currentFadePosition7);
      // reset millis for the next iteration (fade timer only)
      previousFadeMillis7 = thisMillis7;
    }
  }
  if (nowseconds > stopseconds) {
    // is it time to start the Sunset yet?
    // if not, nothing happens
    if (thisMillis7 - previousFadeMillis7 >= stepWaitTime7) {
      currentFadePosition7 = currentFadePosition7 - fadeIncrement;
      if (currentFadePosition7 <= minPWM) {
        // At min limit stop the fade
        currentFadePosition7 = minPWM;
      }
      // put actionable () here
      //analogWrite(led7, currentFadePosition7);
      // reset millis for the next iteration (fade timer only)
      previousFadeMillis7 = thisMillis7;
    }
  }
}
// Digital clock display of the time
void clockDisplay() {
  String currentDate = String(month()) + " " + day() + " " + year();
  nowseconds = ((hour() * 3600) + (minute() * 60) + second());

  // You can call hour(), minute(), ... at any time
  // Please see Time library examples for details
  if (minute() < 10 && second() < 10) {
    String currentTime = String(hour()) + ":0" + minute() + ":0" + second();
    Blynk.virtualWrite(V8, currentTime);
  }
  if (minute() < 10 && second() > 9 ) {
    String currentTime = String(hour()) + ":0" + minute() + ":" + second();
    Blynk.virtualWrite(V8, currentTime);
  }
  if (minute() > 9 && second() < 10) {
    String currentTime = String(hour()) + ":" + minute() + ":0" + second();
    Blynk.virtualWrite(V8, currentTime);
  }
  if (minute() >= 10 && second() >= 10) {
    String currentTime = String(hour()) + ":" + minute() + ":" + second();
    Blynk.virtualWrite(V8, currentTime);
  }

}

BLYNK_WRITE(V0) {// slider widget to set the maximum led level from the Blynk App.
  desiredledLevel0 = param.asInt();// channel 1
  maxPWM0 = map(desiredledLevel0, 0, 100, minPWM, 1023);
}
BLYNK_WRITE(V1) {// slider widget to set the maximum led level from the Blynk App.
  desiredledLevel1 = param.asInt();// channel 2
  maxPWM1 = map(desiredledLevel1, 0, 100, minPWM, 1023);
}
BLYNK_WRITE(V2) {// slider widget to set the maximum led level from the Blynk App.
  desiredledLevel2 = param.asInt();// channel 3
  maxPWM2 = map(desiredledLevel2, 0, 100, minPWM, 1023);
}
BLYNK_WRITE(V3) {// slider widget to set the maximum led level from the Blynk App.
  desiredledLevel3 = param.asInt();// channel 4
  maxPWM3 = map(desiredledLevel3, 0, 100, minPWM, 1023);
}
BLYNK_WRITE(V4) {// slider widget to set the maximum led level from the Blynk App.
  desiredledLevel4 = param.asInt();// channel 5
  maxPWM4 = map(desiredledLevel4, 0, 100, minPWM, 1023);
}
BLYNK_WRITE(V5) {// slider widget to set the maximum led level from the Blynk App.
  desiredledLevel5 = param.asInt();// channel 6
  maxPWM5 = map(desiredledLevel5, 0, 100, minPWM, 1023);
}
BLYNK_WRITE(V6) {// slider widget to set the maximum led level from the Blynk App.
  desiredledLevel6 = param.asInt();// channel 7
  maxPWM6 = map(desiredledLevel6, 0, 100, minPWM, 1023);
}
BLYNK_WRITE(V7) {// slider widget to set the maximum led level from the Blynk App.
  desiredledLevel7 = param.asInt();// channel 8
  maxPWM7 = map(desiredledLevel7, 0, 100, minPWM, 1023);
}


BLYNK_WRITE(V9) {// slider widget to set the led fade duration up tp 3 hours.
  fadetime = param.asInt();
  fadetimeseconds = map(fadetime, 0, 180, 1, 10800);// 3 hour fade duration is max
  fadetimemillis  = map(fadetime, 0, 180, 1, 10800000);// 3 hour fade duration is max
  Serial.print("Fade Time in seconds =");
  Serial.println(fadetimeseconds);
}

void activetoday() {       // check if schedule should run today
  if (year() != 1970) {
    Blynk.syncVirtual(V3); // sync timeinput widget
    sprintf(Date, "%02d/%02d/%04d",  day(), month(), year());
    sprintf(Time, "%02d:%02d:%02d", hour(), minute(), second());
    nowseconds = ((hour() * 3600) + (minute() * 60) + second());
  }
}

BLYNK_WRITE(V10) {

  TimeInputParam t(param);
  Serial.print("Checked schedule at: ");
  Serial.println(Time);
  int dayadjustment = -1;
  if (weekday() == 1) {
    dayadjustment =  6; // needed for Sunday, Time library is day 1 and Blynk is day 7
  }
  if (t.isWeekdaySelected((weekday() + dayadjustment))) { //Time library starts week on Sunday, Blynk on Monday
    Serial.println("Schedule ACTIVE today");
    nowseconds = ((hour() * 3600) + (minute() * 60) + second());
    startseconds = (t.getStartHour() * 3600) + (t.getStartMinute() * 60);
    if (nowseconds >= startseconds) {

      if (nowseconds <= startseconds + 90) {  // 90s on 60s timer ensures 1 trigger command is sent
        // code here

      }
    }
    else {
      Serial.println("Relay not on");// nothing more to do here, waiting for relay to be turned on later today
    }
    stopseconds = (t.getStopHour() * 3600) + (t.getStopMinute() * 60);
    if (nowseconds >= stopseconds) {
      // 90s on 60s timer ensures 1 trigger command is sent
      if (nowseconds <= stopseconds + 90) {
        // code here

      }
    }
    else {
      if (nowseconds >= startseconds) { // only show if motor has already started today
        Serial.println("Relay is still ON");
        // nothing more to do here, waiting for motor to be turned off later today
      }
    }
  }
  else {
    Serial.println("Schedule INACTIVE today");
    // nothing to do today, check again in 1 minutes time
  }
  Serial.println();
}

void reconnectBlynk() {
  if (!Blynk.connected()) {
    if (Blynk.connect()) {
      BLYNK_LOG("Reconnected");
    }
    else {
      BLYNK_LOG("Not reconnected");
    }
  }
}

void setup()
{
  ArduinoOTA.begin();
  Serial.begin(115200);
  
  //The following code is borrowed from WiFiManager
  //clean FS, for testing
  //SPIFFS.format();

  //read configuration from FS json
  Serial.println("mounting FS...");

  if (SPIFFS.begin()) {
    Serial.println("mounted file system");
    if (SPIFFS.exists("/config.json")) {
      //file exists, reading and loading
      Serial.println("reading config file");
      File configFile = SPIFFS.open("/config.json", "r");
      if (configFile) {
        Serial.println("opened config file");
        size_t size = configFile.size();
        // Allocate a buffer to store contents of the file.
        std::unique_ptr<char[]> buf(new char[size]);

        configFile.readBytes(buf.get(), size);
        DynamicJsonBuffer jsonBuffer;
        JsonObject& json = jsonBuffer.parseObject(buf.get());
        json.printTo(Serial);
        if (json.success()) {
          Serial.println("\nparsed json");
          strcpy(blynk_token, json["blynk_token"]);

        } else {
          Serial.println("failed to load json config");
        }
      }
    }
  } else {
    Serial.println("failed to mount FS");
  }
  //end read
  // The extra parameters to be configured (can be either global or just in the setup)
  // After connecting, parameter.getValue() will get you the configured value
  // id/name placeholder/prompt default length
  WiFiManagerParameter custom_blynk_token("blynk", "blynk token", blynk_token, 34);
  Serial.println(blynk_token);
  //WiFiManager
  //Local intialization. Once its business is done, there is no need to keep it around
  WiFiManager wifiManager;

  //set config save notify callback
  wifiManager.setSaveConfigCallback(saveConfigCallback);

  //add all your parameters here
  wifiManager.addParameter(&custom_blynk_token);

  //reset settings - for testing
  //wifiManager.resetSettings();

  //set minimu quality of signal so it ignores AP's under that quality
  //defaults to 8%
  wifiManager.setMinimumSignalQuality();

  //sets timeout until configuration portal gets turned off
  //useful to make it all retry or go to sleep
  //in seconds
  wifiManager.setTimeout(180);

  //fetches ssid and pass and tries to connect
  //if it does not connect it starts an access point with the specified name
  //here  "8 CH LED CONTROL"
  //and goes into a blocking loop awaiting configuration
  if (!wifiManager.autoConnect("8 CH LED CONTROL")) {
    Serial.println("failed to connect and hit timeout");
    delay(3000);
    //reset and try again, or maybe put it to deep sleep
    ESP.reset();
    delay(5000);
  }

  //if you get here you have connected to the WiFi
  Serial.println("8 CH LED CONTROL connected :)");

  //read updated parameters
  strcpy(blynk_token, custom_blynk_token.getValue());

  //save the custom parameters to FS
  if (shouldSaveConfig) {
    Serial.println("saving config");
    DynamicJsonBuffer jsonBuffer;
    JsonObject& json = jsonBuffer.createObject();
    json["blynk_token"] = blynk_token;

    File configFile = SPIFFS.open("/config.json", "w");
    if (!configFile) {
      Serial.println("failed to open config file for writing");
    }

    json.printTo(Serial);
    json.printTo(configFile);
    configFile.close();
    //end save
  }

  Serial.println("local ip");
  Serial.println(WiFi.localIP());
  Blynk.config(blynk_token);
  Blynk.connect();
  Blynk.syncAll();
  if (!blynk_token)
  {
    Serial.println("Failed to connect to Blynk server");
    wifiManager.resetSettings();// reset all settings and spool up the "8 CH LED Contoller" AP again.

    delay(1000);
  }

  Serial.println("Done");
  
  Blynk.notify("8 Ch LDD-H led PcB ONLINE");
  
  rtc.begin();
  
  timer.setInterval(1000L, setLed);
  timer.setInterval(1000L, clockDisplay);     // digital time displayed every second
  timer.setInterval(60000L, activetoday);     // check every minute if schedule should run today
  timer.setInterval(60000L, reconnectBlynk);  // check every 60s if still connected to server

  Blynk.syncAll();
}
void loop()
{
 
  ArduinoOTA.handle();
  timer.run(); // Initiates SimpleTimer
  if (Blynk.connected()) {
    Blynk.run();
  }
// get the current time, for this time around loop
  // all millis() timer checks will use these time stamps
  unsigned long currentMillis0 = millis();
  ledFade0(currentMillis0);
  unsigned long currentMillis1 = millis();
  ledFade1(currentMillis1);
  unsigned long currentMillis2 = millis();
  ledFade2(currentMillis2);
  unsigned long currentMillis3 = millis();
  ledFade3(currentMillis3);
  unsigned long currentMillis4 = millis();
  ledFade4(currentMillis4);
  unsigned long currentMillis5 = millis();
  ledFade5(currentMillis5);
  unsigned long currentMillis6 = millis();
  ledFade6(currentMillis6);
  unsigned long currentMillis7 = millis();
  ledFade7(currentMillis7);

}

3 Likes

I can get this uploaded to my Wemos just fine, blynk recognises the board, it all connects perfectly, but it will not output any PWM at all, and therefore will not dim the lights. all the controls respond on the app, the sliders work, etc, It just does not seem to put out any signal. What could be wrong? I’m using the Wemos D1 mini, and it works with other sketches just fine…

Did you follow this step? What is the LED driver you are using? Remember the shared ground?

1 Like

Yup. Tied in the grounds correctly, and tried on each of the output pins. I’ve tried the LDD300-L and LDD300-H drivers, They drive the LED correctly, but do not dim. Grounding PWM dim pin of the LDD shuts off the LEDs correctly, as does leaving a 10k pull down resistor on the pin.

I’m not great with code, but I can’t see any glaring issues…

I’m using meanwell LDD drivers to dimm my led aquarium lamp.

Some hints:

  1. The Vin- have to be connected to ESP gnd.
  2. Use a regular power supply to power the LDDs. A switching power supply it’s recommended.
  3. The Vout- hasn’t be connected to gnd! Is just for the LED circuit.
  4. I use a 4.7Kohm pull down resistor for all the ESP pwm outputs connected to the LDD pwm inputs.

And my dimming works great.

Did you tried to change defines to the IO number?

#define pwmLED0 5
#define pwmLED1 4

Should I be editing the code with those changes?

Also, yes, I have everything connected as described, I’ve tried both 10k and 4.7k pulldown resistors, tied the ground of both the esp and the -vin of the mean well together. Nothing.

I Suggest that

I’m currently trying to use this code on my arduino mega. It starts to brighten but then appears to crash out. If I move the brightness slider along, it seems the lights get lighter and darker several times before reachs 100 on the slider. Would anyone know why it’s doing this