For the past 2 years I've been putting together a hydroponics controller and adding bits of code as I learn them. If not for the constant failures, I would be extremely proud with the way the project works (when it's actually working), but it seems the RTC can only maintain time for at most 3 days, but it usually fails sooner. Perhaps this isn't even an RTC issue, I don't know how to troubleshoot this to determine exactly what is wrong and how to address that.
My circuit is a Freetronics Ethermega. A DS3231 Chronodot from Adafruit is the RTC, but I'm using the DS1307 library due to difficulties with other libraries. Also connected are 2 DHT22 temp/humidity sensors. There is also a Sainsmart 8 channel relay that is isolated completely from the Arduino as no grounds are shared. Instead, a 5V master lead supplies the optoisolators and the digital pins sink when instructed to do so. Finally, I also have an 8 head peristaltic pump dosing module. Each head is controlled by a TIP120 circuit with flywheel diode and resistor between gate and digital pin.
The networking aspect of my project is completely handled by Blynk. With Blynk, I can control certain things from my smartphone with their free app and really bring out the IoT from Arduino. This is how I can choose between pumps and dosing amounts. I also use the same approach for dosing out reverse osmosis water in 1/4 gallon increments. I also have it set up so all Serial.print type strings are printed to a monitor in the Blynk app with each revolution of a loop.
I don't know exactly how long the EM will run till it fails, but at most is roughly 3 days, all the way down to just a few minutes. When the failure occurs, the relay states remain in the programmed position at the time of failure and the RTC time would simply freeze. However, recently, the RTC began to display weirdly as "153:165:85-PM 165/165/2165". Some times is would display the current time minus a few hours and minutes, day and month as 00, but the correct year. At each failure, I reset power to the MCU and begin watching to see how long the connection remains and what the time will look like when it begins sending again. My first thought was a faulty RTC, so I ordered another from Adafruit and still the same result. During the construction, I may have incorrectly wired some stuff and connected everything to discover nothing happening. Perhaps this damaged the MCU somehow by sending 5 volts and a GND of a device and vice-a-versa? I am of the mind to replace the Ethermega just to rule it out, but another $120 is a steep "what if".
I apologize if this is too wordy, or is lacking in other details. If more information is needed, please ask and I will provide. Here is my sketch.
#include <SPI.h> // Used by Blynk
#include <Ethernet.h> // Used by Blynk
#include <BlynkSimpleEthernet.h> // Used by Blynk
#include <Wire.h> // I2c
#include "DHT.h" // DHT data wire connected to I/O pin with a 10k pullup resistor to 5V
#include <SimpleTimer.h> // used to run functions at preset intervals
#include "RTClib.h" // RealTimeClock Library for DS1307 and DS3231
#define BLYNK_PRINT Serial
// 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 = 70; // temp that triggers heater on
byte lowMinTemp = 60; // temp that triggers heater off
byte hiHum = 55; // High humidity value that triggers dehumidifier on
byte lowHum = 50; // Low humidity value that triggers dehumidifier off
//-Digital Pins - Peristaltic Pump Variables - 00 Series Pins
int pumpPin[8] = { 2, 3, 4, 5, 6, 7, 8, 9 };
uint32_t multiplier[8] = { 858, 827, 872, 865, 887, 895, 913, 843 }; //ms per ml
uint32_t startPump = 0;
uint32_t runCount;
bool pumpRunning = false;
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
BLYNK_WRITE(V4) {
x = param.asInt() - 1;
}
BLYNK_WRITE(V5) {
DOSEml = param.asFloat();
}
BLYNK_WRITE(V6) {
button = param.asInt();
}
//
uint32_t msPerGallon = 34000; //ms per gallon
uint32_t ROstart = 0;
uint32_t countGallons;
bool 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 heatVentA 28 //Relay 7/g
#define heatVentB 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 0 // TURN_ON and TURN_OFF are defined to account for Active LOW relays
#define TURN_OFF 1 // 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)
char auth[] = "PasteAuthKeyBetweenQuotes";
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)
SimpleTimer timer; // SimpleTimer instance named timer
void setup()
{
Serial.begin(9600);
//Serial2.begin() // For other baud rates
//Serial3.begin() // For other baud rates
Blynk.begin(auth);
dhtA.begin();
dhtB.begin();
pinMode(A0, INPUT_PULLUP); // DHT22 use internal 20k pullup resistors
pinMode(A2, INPUT_PULLUP);
Wire.begin();
RTC.begin();
//RTC.adjust(DateTime(__DATE__, __TIME__));
//Uncomment "RTC.adjust" the first time this sketch is uploaded to program the RTC.
//Once done, re-comment that line out, and upload this sketch again.
for (int allRelays = lightA; allRelays <= heatVentB; allRelays++) {
pinMode(allRelays, OUTPUT);
digitalWrite(allRelays, TURN_OFF);
}
for (int p = 0; p <= 7; p++)
{
pinMode(pumpPin[p], OUTPUT);
}
Blynk.virtualWrite(V4, 0);
Blynk.virtualWrite(V5, 0);
Blynk.virtualWrite(V6, 0);
Blynk.virtualWrite(V9, 0);
Blynk.virtualWrite(V10, 0);
Blynk.virtualWrite(V11, 0);
Blynk.virtualWrite(V12, 0);
while (Blynk.connect() == false) {}
timer.setInterval(2000L, timeRoutine); // 2 second intervals between timed routiness
timer.setInterval(5001L, climateRoutine); // 5 second intervals between climate routines
timer.setInterval(207L, dosingPumps); // 0.2 second interval to maintain accuracy (+/- .25)
timer.setInterval(1003L, ROcheck); // 1 second interval between RO pump routines
}
void loop()
{
Blynk.run();
timer.run();
}