Brown outs or reboots

That did the trick. The W5100 didn’t hold things up this time. I tested twice to make sure I was fully awake. I disconnect everything, reinstate power only and within about 5 seconds it gets right out into the loop of timered functions as my relays illuminated their onboard LEDs in accordance with my schedule.


#include <SPI.h>                    // Used by Blynk
#include <Ethernet.h>               // Used by Blynk
#include <BlynkSimpleEthernet.h>    // Used by Blynk
//#include <UIPEthernet.h>
//#include <BlynkSimpleUIPEthernet.h>
#include <Wire.h>                   // I2c
#include <WidgetRTC.h>
#include <DHT.h>                    // DHT data wire connected to I/O pin with a 10k pullup resistor to 5V
#include <RTClib.h>                 // RealTimeClock Library for DS1307 and DS3231
#define BLYNK_PRINT Serial

char auth[] = "AUTH";
unsigned int port = 8442;
byte arduino_mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };    //DE:ED:BA:FE:FE:ED
char server[] =    "blynk-cloud.com"; // can use "blynk-cloud.com" or an IP address
IPAddress arduino_ip ( 10,   0,   0,  120);
IPAddress dns_ip     (  10,   0,   0,   1);
IPAddress gateway_ip ( 10,   0,   0,   1);
IPAddress subnet_mask(255, 255, 255,   0);
unsigned int myEthernetTimeout =   20000;  //  5.0s Ethernet Connection Timeout (ECT)
unsigned int blynkInterval     =  30000;  // 25.0s Check Server Frequency      (CSF)
unsigned long startConnecting = millis();

//  DHT Reference Values - CHANGE THESE TO MANAGE YOUR ROOM'S CLIMATE - //
byte hiMaxTemp = 80;   // temp that triggers heat removal device(s) on
byte lowMaxTemp = 70;  // temp that triggers heat removal device(s) off
byte hiMinTemp = 55;   // temp that triggers heater on
byte lowMinTemp = 65;  // temp that triggers heater off
byte hiHum = 58;       // High humidity value that triggers dehumidifier on
byte lowHum = 40;      // Low humidity value that triggers dehumidifier off

//-Digital Pins - Peristaltic Pump Variables - 00 Series Pins
const int pumpPin[8] = { 2, 3, 4, 5, 6, 7, 8, 9 };
int dosingLEDs[8]  = { V14, V15, V16, V17, V18, V19, V20, V21 };
uint32_t multiplier[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; //ms per ml
uint32_t startPump = 0;
uint32_t runCount;
bool pumpRunning;
const char *nuteType[8] = { "GH Armor Si", "GH Flora Blend", "GH CALiMAGic", "GH Kool Bloom",
                            "GH Flora Gro", "GH Flora Micro", "GH Flora Bloom", "GH pH Down"
                          }; //Text Printed to Terminal Widget^^

float DOSEml;      //Step Widget (0.25 per step, send step/NO, loop values ON)
int button = 0;   //Button Widget set to Switch
int x;           //Correlates Array Positions with Pump Motor Pins
int calibration;

BLYNK_WRITE(V4) {
  x = param.asInt() - 1;
}
BLYNK_WRITE(V5) {
  DOSEml = param.asFloat();
}
BLYNK_WRITE(V6) {
  button = param.asInt();
}
BLYNK_WRITE(V13) {
  calibration = param.asInt();
}
//
uint32_t msPerGallon = 33000; //ms per gallon
uint32_t ROstart = 0;
uint32_t countGallons;
boolean runningRO = false;
int pumpAon;          //Blynk Override to turn pumpA back on
int pumpBon;          //Blynk Override to turn pumpB back on

int ROpumpOn = 0;     //Blynk Triggered RO Pump
float totalGallons;   //Number of RO Gallons Selected in Widget
BLYNK_WRITE(V9) {
  pumpAon = param.asInt();  // pumpA remote
}
BLYNK_WRITE(V10) {
  pumpBon = param.asInt();  // pumpB remote
}
BLYNK_WRITE(V11) {
  ROpumpOn = param.asInt();  // ROpump remote
}
BLYNK_WRITE(V12) {
  totalGallons = param.asFloat();  // ROpump remote
}

// Digital Pin 10 is <RESERVED> for W5100 Wiznet chip
// Digital Pins - 8 Channel Relay Assignments - 20 Series Pins - 120VAC~ switching
#define lightA 22             //Relay 1/a  
#define lightB 23             //Relay 2/b  
#define pumpA 24              //Relay 3/c 
#define pumpB 25              //Relay 4/d  
#define ROpump 26             //Relay 5/e  
#define scrubberFan 27        //Relay 6/f  
#define VentA 28              //Relay 7/g  
#define VentB 29              //Relay 8/h 

//-Digital Pins - 8 Channel Relay Assignments - 30 Series Pins - 120VAC~ switching
// -Dpins 30-37 are reserved for another bank of Relays.

//Digital Pin Valves Assignments - 40 Series Pins - Hi/Lo Solenoid Valves
//const byte valve[13] = { 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52 };

#define TURN_ON LOW // TURN_ON and TURN_OFF are defined to account for Active LOW relays
#define TURN_OFF HIGH // Used to switch relay states for on/off of 120VAC~ devices  

RTC_DS1307 RTC;
float UTCOffset = -5.0;    // Your timezone relative to UTC (http://en.wikipedia.org/wiki/UTC_offset)

WidgetLCD lcdA(V7);  //Set LCD widget to Advanced Mode - Widget to display project clock
WidgetTerminal terminal(V8);
DHT dhtA(A0, DHT22);     // DHT instance named dhtA, (I/O pin, sensor type)
DHT dhtB(A2, DHT22);     // DHT instance named dhtB, (I/O pin, sensor type)
BlynkTimer timer;       // SimpleTimer instance named timer
WidgetRTC rtcWidget;  // requires RTC widget in app

#define W5100_CS  10
#define SDCARD_CS 4

//**********************Functions***************************//
//**********************************************************//
// This is called for all virtual pins that do not have BLYNK_WRITE handler
BLYNK_WRITE_DEFAULT()
{
  Serial.println("BLYNK_WRITE_DEFAULT()");
  terminal.print("BLYNK_WRITE for pin ");
  terminal.print(request.pin);
  terminal.println(" not defined.");
  terminal.println("Values: ");
  for (auto i = param.begin(); i < param.end(); ++i) {
    terminal.print("* ");
    terminal.println(i.asString());
  }
  terminal.flush();
}

// This is called for all virtual pins that do not have BLYNK_READ handler
BLYNK_READ_DEFAULT()
{
  Serial.println("BLYNK_READ_DEFAULT");
  terminal.print("BLYNK_READ for pin ");
  terminal.print(request.pin);
  terminal.println(" not defined.");
  terminal.flush();
}

// This is called when Blynk has successfully connected
BLYNK_CONNECTED()
{
  Serial.println("BLYNK_CONNECTED");
  rtcWidget.begin();      // Synchronize with widget (server) time on connection
  setSyncInterval(5 * 60); // subsequent time sync interval in seconds (5 minutes)

  for (int i = V4; i <= V6; i++)
    for (int j = V9; j <= V21; j++)
    {
      Blynk.virtualWrite(i, j, 0);
    }
}

void myfunction() {
  Serial.println("\tLook, no Blynk  block.");
  if (Blynk.connected()) {
    Serial.println("\tEthernet still  connected.");
    Blynk.virtualWrite(V22, millis() / 1000);
  }
}

void checkBlynk() {
  while (!Blynk.connected()) {
    Blynk.connect();
    if (millis() > startConnecting + myEthernetTimeout) {
      Serial.print("\tUnable to connect to server. ");
      break;
    }
  }
  Serial.println("Checking again in 30s.");
}

void displayDateTime()
{
  Serial.println("displayDateTime");
  DateTime now = RTC.now();          // reads time at beginning of loop
  byte HOUR = now.hour();
  byte twelveHour = now.hour() - 12; // Variable used to display 13+ hours in 12 hour format
  byte zeroHour = 12;                // Variable use to convert "0" zero hour to display it as 12:00+
  byte displayHour;
  byte MIN = now.minute();
  byte SEC = now.second();
  char* meridian;

  if (now.hour() == 0)  // First we test if the hour reads "0"
  {
    displayHour = zeroHour;
    meridian = "AM";
  }
  else if (now.hour() >= 13)  // if no, Second we test if the hour reads "13 or more"
  {
    displayHour = twelveHour;
    meridian = "PM";
  }
  else
  {
    displayHour = now.hour();
    meridian = "AM";
  }
  if (Blynk.connected())
  {
    char stamp[16];
    lcdA.clear();
    sprintf(stamp, "%02d:%02d:%02d-%02s", displayHour, MIN, SEC, meridian);
    lcdA.print(3, 0, stamp);
    sprintf(stamp, "%02d/%02d/%04d", now.month(), now.day(), now.year());
    lcdA.print(3, 1, stamp);
  }
}
// synchronize the RTC hardware device with our server provided date/time values
void syncRTCHardware()
{
  if (!Blynk.connected())
  {
    Serial.println("Blynk not connected. Exiting syncRTCHardware.");
    return;
  }
  Serial.println("syncRTCHardware");
  DateTime now = RTC.now();          // reads time at beginning of loop

  char currentTime[16];
  char currentDate[16];
  sprintf(currentDate, "%02d/%02d/%04d", month(), day(), year());
  sprintf(currentTime, "%02d:%02d:%02d", hour(), minute(), second());
  Serial.print("Server Time: ");
  Serial.print(currentDate);
  Serial.print (" ");
  Serial.println(currentTime);

  // time library is synchronized by the Blynk WidgetRTC
  if (Blynk.connected())
  {
    bool syncClocks;
    if (now.hour() != hour() && now.minute() != minute()) syncClocks = true;
    if (syncClocks == true)
    {
      syncClocks = false;
      Serial.println("Resynching RTC Time...");
      terminal.println("Resynching RTC Time...");
      RTC.adjust(DateTime(year(), month(), day(), hour(), minute(), second()));
      terminal.flush();
    }
  }
}

// checks connection to Blynk server and attempts reconnect if disconnectedd checkBlynkConnection()
void checkBlynkConnection()
{
  Serial.println("Attempting to Connect");
  if (!Blynk.connected())
  {
    Serial.println("checkBlynkConnection");
    Blynk.connect();  // try to connect to server with default timeout
  }
}

void climateRoutine()
{
  byte h1 = dhtA.readHumidity();          // f1 and h1 are fahrenheit and humidity readings
  byte f1 = dhtA.readTemperature(true);   // from DHT/A
  byte h2 = dhtB.readHumidity();          // f2 and h2 are fahrenheit and humidity readings
  byte f2 = dhtB.readTemperature(true);   // from DHT/B
  if (isnan(f1) || isnan(f2) || isnan(h1) || isnan(h2)) {
    terminal.println("Failed to read from a DHT sensor");
    terminal.flush();
    return;
  }
  Blynk.virtualWrite(V0, f1);      //  Set Virtual Pin 0 frequency to PUSH in Blynk app
  Blynk.virtualWrite(V1, h1);      //  Set Virtual Pin 1 frequency to PUSH in Blynk app
  Blynk.virtualWrite(V2, f2);      //  Set Virtual Pin 2 frequency to PUSH in Blynk app
  Blynk.virtualWrite(V3, h2);      //  Set Virtual Pin 3 frequency to PUSH in Blynk app
  //-------------------Bloom A Temp Test---------------------------------------//
  if (f1 >= hiMaxTemp)  //if "f1" is greater than or equal to hiMaxTemp,
  {
    digitalWrite(VentA, TURN_ON);  // TURN_ON heatVentA (fan).
    terminal.println("Exhausting the heat from Bloom A"); //  Text printed to terminal monitor
  }
  else if (f1 <= lowMaxTemp)  //  or else if "f1" is less than or equal to lowMaxTemp
  {
    digitalWrite(VentA, TURN_OFF); //  TURN_OFF relay E.
  }
  //-----------------------Bloom A Humidity Test-------------------------//
  if (h1 >= hiHum)  //if "h2" is greater than or equal to hiHum,
  {
    digitalWrite(VentA, TURN_ON);  // TURN_ON heatVentA (fan).
    terminal.println("Exhausting the RH from Bloom A"); //  Text printed to terminal monitor
  }
  else if (h1 <= lowHum)  //  or else if "h1" is less than or equal to lowHum
  {
    digitalWrite(VentA, TURN_OFF);
  }
  //-----------------------Bloom B Temp Test-----------------------------//
  if (f2 >= hiMaxTemp)  //if "f2" is greater than or equal to hiMaxTemp,
  {
    digitalWrite(VentB, TURN_ON);  // TURN_ON heatVentA (fan).
    terminal.println("Exhausting the heat from Bloom B"); //  Text printed to terminal monitor
  }
  else if (f2 <= lowMaxTemp)  //  or else if "f2" is less than or equal to lowMaxTemp
  {
    digitalWrite(VentB, TURN_OFF);
  }
  //-----------------------Bloom B Humidity Test-------------------------//
  if (h2 >= hiHum)  //if "h2" is greater than or equal to hiHum,
  {
    digitalWrite(scrubberFan, TURN_ON);  // TURN_ON heatVentA (fan).
    terminal.println("Exhausting the RH from Bloom B"); //  Text printed to terminal monitor
  }
  else if (h2 <= lowHum)  //  or else if "h2" is less than or equal to lowHum
  {
    digitalWrite(scrubberFan, TURN_OFF);
  }
  terminal.flush();
}

void timeRoutine()
{
  DateTime now = RTC.now();          // reads time at beginning of loop

  //------------------12/12 BloomA Light - 5AM-5PM
  //Adjust hours and minutes in accordance with 24 hour time format.
  //Create tests where true is ON time and false is OFF time.
  boolean lightAstate = false;
  if (now.hour() >= 5 && now.hour() <= 16) lightAstate = true;
  if (lightAstate == true)
  {
    digitalWrite(lightA, TURN_ON);
    terminal.println("Lights On In Bloom A");  //  Text printed to terminal monitor
  }
  else
  {
    digitalWrite(lightA, TURN_OFF);
  }
  //--------------------12/12 Bloom B Light - 5PM-5AM
  //lightB is lit during the opposing 12 hours to lightA to conserve current draw from HID ballasts.
  boolean lightBstate = false;
  if (lightAstate == false) lightBstate = true;
  if (lightBstate == true)
  {
    digitalWrite(lightB, TURN_ON);
    terminal.println("Lights On In Bloom B");  //  Text printed to terminal monitor
  }
  else
  {
    digitalWrite(lightB, TURN_OFF);
  }
  //---------------Bloom A Feed Times------------------------
  boolean pumpAstate = false;
  if (pumpAon == 1) pumpAstate = true;
  if (now.hour() == 6 && now.minute() >= 0 && now.minute() < 10) pumpAstate = true;    //6:00 am - 10 mins
  if (now.hour() == 8 && now.minute() >= 30 && now.minute() < 40) pumpAstate = true;  //8:30 am - 10 mins
  if (now.hour() == 11 && now.minute() >= 00 && now.minute() < 10) pumpAstate = true;  //11:00 am - 10 mins
  if (now.hour() == 13 && now.minute() >= 30 && now.minute() < 40) pumpAstate = true;  //1:30 pm - 10 mins
  if (now.hour() == 16 && now.minute() >= 0 && now.minute() < 10) pumpAstate = true;  //4:00 pm - 10 mins
  if (pumpAstate == true)
  {
    Blynk.virtualWrite(V9, 1);
    digitalWrite(pumpA, TURN_ON);
    terminal.println("Pump A Is On");  //  Text printed to terminal monitor
  }
  else
  {
    pumpAon = 0;
    Blynk.virtualWrite(V9, 0);
    digitalWrite(pumpA, TURN_OFF);
  }
  //---------------------------Bloom B Feed Times-------------------------------------
  boolean pumpBstate = false;
  if (pumpBon == 1) pumpBstate = true;
  if (now.hour() == 18 && now.minute() >= 0 && now.minute() < 10) pumpBstate = true;     //6:00 pm - 10 mins -//- 1 hour after light on
  if (now.hour() == 20 && now.minute() >= 30 && now.minute() < 40) pumpBstate = true;   //8:30 pm - 10 mins
  if (now.hour() == 23 && now.minute() >= 0 && now.minute() < 10) pumpBstate = true;     //11:00 pm - 10 mins
  if (now.hour() == 1 && now.minute() >= 30 && now.minute() < 40) pumpBstate = true;    //1:30 am - 10 mins
  if (now.hour() == 4 && now.minute() >= 0 && now.minute() < 10) pumpBstate = true;     //4:00 am - 10 mins
  if (pumpBstate == true)
  {
    Blynk.virtualWrite(V10, 1);
    digitalWrite(pumpB, TURN_ON);
    terminal.println("Pump B Is On");  //  Text printed to terminal monitor
  }
  else
  {
    pumpBon = 0;
    Blynk.virtualWrite(V10, 0);
    digitalWrite(pumpB, TURN_OFF);
  }
  terminal.flush();
}

void ROcheck()  //RO Pump = 34 seconds on time per gallon
{
  if (ROpumpOn == 1 && runningRO == false)            // Activates when Blynk button is toggled
  {
    digitalWrite(ROpump, TURN_ON);
    Blynk.virtualWrite(V11, 255);                     // Illuminates Blynk button widget
    runningRO = true;
    ROstart = millis();
    countGallons = msPerGallon * totalGallons;        // Calculates length of runtime for pump
    Blynk.virtualWrite(V12, 0);
    terminal.print("Pumping:");
    terminal.print(totalGallons);
    terminal.println(" Gallons of RO");
  }
  if (millis() - ROstart > countGallons)              // Determines when runtime ends
  {
    ROpumpOn = 0;
    runningRO = false;
    digitalWrite(ROpump, TURN_OFF);
    Blynk.virtualWrite(V11, 0);
    //Blynk.virtualWrite(V22, 0);
  }
  terminal.flush();
}

void dosingPumps()
{
  if (button == 1 && pumpRunning == false)
  {
    multiplier[x] = calibration;                      // Gets the value in [x] position from Blynk
    Blynk.virtualWrite(V4, 0);
    Blynk.virtualWrite(V5, 0);
    Blynk.virtualWrite(V6, 0);                        // Keeps button ON until fully executed
    pumpRunning = true;
    digitalWrite(pumpPin[x], HIGH);
    Blynk.virtualWrite(dosingLEDs[x], 255);           // [x] position Blynk indicator LED
    startPump = millis();
    runCount = DOSEml * multiplier[x];
    terminal.print("Dosing in: ");
    terminal.print(DOSEml);
    terminal.print(" milliliters of ");
    terminal.println(nuteType[x]);
  }
  if (millis() - startPump > runCount)
  {
    digitalWrite(pumpPin[x], LOW);
    Blynk.virtualWrite(dosingLEDs[x], 0);
    pumpRunning = false;
    button = 0;
  }
  terminal.flush();
}

void setup()
{
  Serial.begin(9600);
  Serial.println("setup start...");

  Serial.println("dhtA.begin()...");
  dhtA.begin();

  Serial.println("dhtB.begin()...");
  dhtB.begin();

  Serial.println("setting DHT's...");
  pinMode(A0, INPUT_PULLUP);    // DHT22 use internal 20k pullup resistors
  pinMode(A2, INPUT_PULLUP);

  Serial.println("Wire.begin()...");
  Wire.begin();

  Serial.println("RTC.begin()...");
  RTC.begin();

  Serial.println("turning relays off...");
  for (int allRelays = lightA; allRelays <= VentB; allRelays++)
  {
    pinMode(allRelays, OUTPUT);
    digitalWrite(allRelays, TURN_OFF);
  }

  Serial.println("setting pump pinMode's...");

  for (int p = 0; p <= 7; p++)
  {
    pinMode(pumpPin[p], OUTPUT);
  }
  pinMode(SDCARD_CS, OUTPUT);
  digitalWrite(SDCARD_CS, HIGH); // Deselect the SD card

  Serial.println("setting timers...");
  timer.setInterval(2000L, timeRoutine);      // 2 second intervals between timed routiness
  timer.setInterval(5001L, climateRoutine);   // 5 second intervals between climate routines
  timer.setInterval(15000L, syncRTCHardware);  // synchronize the RTC device with the server time every 15 seconds
  timer.setInterval(5000L, displayDateTime);   // update the LCD Widget every 5 seconds
  timer.setInterval(15000L, checkBlynkConnection); // check Blynk connection every 15 seconds
  timer.setInterval(207L, dosingPumps);       // 0.2 second interval to maintain accuracy (+/- .25)
  timer.setInterval(1003L, ROcheck);          // 1 second interval between RO pump routines
  timer.setInterval(myEthernetTimeout, myfunction);
  timer.setInterval(blynkInterval, checkBlynk);   // check connection to server per blynkInterval

  Serial.println("beginning Blynk...");
  // Blynk stuff after timers
  //Blynk.config(auth, server, port);
  //Blynk.begin(auth, server, port);
  //while (Blynk.connect() == false) {}
  Ethernet.begin(arduino_mac, arduino_ip, dns_ip, gateway_ip, subnet_mask );
  Blynk.config(auth, server);  // this is OK
  Blynk.connect();             // this is OK
  //Blynk.disconnect(); // skip connecting to the Blynk server until checkBlynkConnection timer fires

    Serial.println("setup complete.");  
}

void loop()
{
  // only attempt Blynk-related functions when connected to Blynk
  if (Blynk.connected())
  {
    Blynk.run();
  }
  timer.run();
}

1 Like

Glad we got there in the end. If it only takes 5s then you could drop the 20000 to say 7000 or 8000 etc.

2 Likes

wow! what a great read!

thanks guys!

2 Likes