Forgive me, but I don’t see how in code the RTC is reading a time stamp from Blynk. In
if(year() != 1970){
rtc.adjust(DateTime(year(), month(), day(), hour(), minute(), second()));
}
… how does the rtc “adjust”?
I already have the elements in the sketch to display these and DHT values on Blynk widgets worked out. Am just trying to refine my use of the RTC by adding a second RTC to the first RTC.
Here’s my project code. I am still learning as I write it, so it’s far from perfect or complete, but the code used in the RTC process to my knowledge is near perfect.
/*
* This code is a functional hydroponics controller. Sensors are measured, preset values are
* executed and devices are turned on and off, but also some devices are on with modulated voltage
* for speed control. The sensors are an internal clock (RTC), atmospheric temperature and humidity
* sensors (DHT22) and the users smartphone (w/Blynk). Water quality sensors are also on the wishlist,
* but this will be added in later. The example code is already written for these other circuits.
* For more info see; https://www.atlas-scientific.com/
* The devices consist of lights, fans, dehumidifiers, water pumps, water valves and
* nutrient dosing pumps. All of the sensors dictate the usage of each device and the program combined
* with Blynk extends the gardener's capability in the garden exponentially!
* */
#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
// DHT Reference Values - CHANGE THESE TO MANAGE YOUR ROOM'S CLIMATE - //
byte hiMaxTemp = 90; // temp that triggers heat removal fan on
byte lowMaxTemp = 75; // temp that triggers heat removal fan off
byte hiMinTemp = 70; // temp that triggers heater on
byte lowMinTemp = 60; // temp that triggers heater off
byte hiHum = 75; // High humidity value that triggers dehumidifier on
byte lowHum = 70; // Low humidity value that triggers dehumidifier off
//Digital Pin Peristaltic Pump Dosing Heads - 00 Series Pins - PWM/12v motors
#define GHfloraGro 2 //Pump 1 - Primary Nutrient - nutePumps[0]
#define GHfloraMicro 3 //Pump 2 - Primary Nutrient - nutePumps[1]
#define GHfloraBloom 4 //Pump 3 - Primary Nutrient - nutePumps[2]
#define GHfloraBlend 5 //Pump 4 - Metabolic Supplement - nutePumps[3]
#define GHarmorSi 6 //Pump 5 - Silica Supplement (raises pH) - nutePumps[4]
#define GHcaliMagic 7 //Pump 6 - Calcium/Magnesium Supplement - nutePumps[5]
#define GHkoolBloom 8 //Pump 7 - Bloom Supplement - nutePumps[6]
#define GHphDown 9 //Pump 8 - pH Lowering Agent - nutePumps[7]
int nutePumps[] {GHfloraGro, GHfloraMicro, GHfloraBloom, GHfloraBlend, GHarmorSi, GHcaliMagic, GHkoolBloom, GHphDown};
//Analong Pin Sensor Assignments - Analog Pins
//#define pH A0
//#define PPM A1
//#define waterTemp A2
#define lightA 22 //Relay 1/a - Relays[0]
#define lightB 23 //Relay 2/b - Relays[1]
#define pumpA 24 //Relay 3/c - Relays[2]
#define pumpB 25 //Relay 4/d - Relays[3]
#define ROpump 26 //Relay 5/e - Relays[4]
#define scrubberFan 27 //Relay 6/f - Relays[5]
#define heatVentA 28 //Relay 7/g - Relays[6]
#define heatVentB 29 //Relay 8/h - Relays[7]
int Relays[] {lightA, lightB, pumpA, pumpB, ROpump, scrubberFan, heatVentA, heatVentB};
//Digital Pin Relay Assignments - 30 Series Pins - 120VAC~ switching
//#define 30 //2nd bank of 8 relays
//#define 31
//#define 32
//#define 33
//#define 34
//#define 35
//#define 36
//#define 37
//int Relays2[8] {30, 31, 32, 33, 34, 35, 36, 37};
//Digital Pin Valves[] array elements - 40 Series Pins - Hi/Lo Solenoid Valves
#define source 40 //waterValve[0]
#define upperProbes 41 //waterValve[1]
#define upperNuteRail 42 //waterValve[2]
#define siteReturnA 43 //waterValve[3]
#define siteReturnB 44 //waterValve[4]
#define lowerProbes 45 //waterValve[5]
#define lowerNuteRail 46 //waterValve[6]
#define betweenRails 47 //waterValve[7]
#define waste 48 //waterValve[8]
#define mainAccessA 49 //waterValve[9]
#define feedPlantA 50 //waterValve[10]
#define mainAccessB 51 //waterValve[11]
#define feedPlantB 52 //waterValve[12]
int Valves[] {source, upperProbes, upperNuteRail, siteReturnA, siteReturnB, lowerProbes, lowerNuteRail, betweenRails, waste, mainAccessA, feedPlantA, mainAccessB, feedPlantB};
#define TURN_ON 0 // TURN_ON and TURN_OFF are defined to account for Active High relays
#define TURN_OFF 1 // Used to switch relay states for on/off of AC devices
RTC_DS1307 RTC;
float UTCOffset = -5.0; // Your timezone relative to UTC (http://en.wikipedia.org/wiki/UTC_offset)
#define BLYNK_PRINT Serial
char auth[] = "PasteEmailedAuthTokenHere";
WidgetLCD lcdA(V2); //Set LCD widget to Advanced Mode - Widget to display project clock
DHT dhtA(A0, DHT22); // DHT instance named dhtA, I/O pin and sensor type
DHT dhtB(A1, DHT22); // DHT instance named dhtB, I/O pin and 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();
Wire.begin();
RTC.begin();
RTC.adjust(DateTime(__DATE__, __TIME__));
//pinMode(nutePumps[8], INPUT_PULLUP);
//pinMode(Valves[13], INPUT_PULLUP);
pinMode(Relays[0, 1, 2, 3, 4, 5, 6, 7], OUTPUT); //
//pinMode(lightA, OUTPUT); //Relay 1/a - Relays[0]
//pinMode(lightB, OUTPUT); //Relay 2/b - Relays[1]
//pinMode(pumpA, OUTPUT); //Relay 3/c - Relays[2]
//pinMode(pumpB, OUTPUT); //Relay 4/d - Relays[3]
//pinMode(ROpump, OUTPUT); //Relay 5/e - Relays[4]
//pinMode(scrubberFan, OUTPUT); //Relay 6/f - Relays[5]
//pinMode(heatVentA, OUTPUT); //Relay 7/g - Relays[6]
//pinMode(heatVentB, OUTPUT);
pinMode(nutePumps[0, 1, 2, 3, 4, 5, 6, 7], OUTPUT);
pinMode(Valves[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], OUTPUT);
while (Blynk.connect() == false) {}
timer.setInterval(10000L, timeRoutine); // 10 second intervals between timed routiness
timer.setInterval(11100L, climateRoutine); // 11.1 second intervals between climate routines
//timer.setInterval(xxxxL, testResB);
//timer.setInterval(xxxxL, testResA);
//timer.setInterval(xxxxL, testResB);
delay(2500);
}
void loop()
{
Blynk.run();
timer.run();
}
//Functions
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
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(V3, f2); // Set Virtual Pin 2 frequency to PUSH in Blynk app
Blynk.virtualWrite(V4, h2); // Set Virtual Pin 3 frequency to PUSH in Blynk app
Serial.println(f1);
Serial.println(h1);
Serial.println(f2);
Serial.println(h2);
// Tests temp & humidity to see if preset values are exceed.
// If exceeded, a relay is trigger high to power an exhaust fan or heater.
//**************************** REMOVING HEAT *************************************//
if (f1 >= hiMaxTemp) //if "f1" is greater than or equal to hiMaxTemp,
{
digitalWrite(heatVentA, TURN_ON); // TURN_ON heatVentA (fan).
Serial.print("\t");
Serial.println(F("Exhausting the heat from A")); // Text printed to serial monitor
Serial.print("\t");
Serial.println();
}
else if (f1 <= lowMaxTemp) // or else if "f1" is less than or equal to lowMaxTemp
{
digitalWrite(heatVentA, TURN_OFF); // TURN_OFF relay E.
}
}
void timeRoutine()
{
DateTime now = RTC.now(); // reads time at beginning of loop
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";
}
char timeStamp[11];
char dateStamp[11];
sprintf(timeStamp, "%02d:%02d:%02d-%02s", displayHour, MIN, SEC, meridian);
sprintf(dateStamp, "%02d/%02d/%04d", now.month(), now.day(), now.year());
String ts;
String ds;
ts = timeStamp;
ds = dateStamp;
lcdA.clear(); //Advanced Mode
lcdA.print(3, 0, ts); //Advanced Mode
lcdA.print(3, 1, ds); //Advanced Mode
Serial.println(ts);
Serial.print(ds);
//*************** 12/12 BloomA Light - 6AM-6PM**********************************//
//***** 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() >= 6 && now.hour() <= 17) lightAstate = true;
if (lightAstate == true)
{
digitalWrite(lightA, TURN_ON);
Serial.print("\t");
Serial.print(F("Bloom A Light On")); // Text printed to serial monitor
Serial.print("\t");
Serial.println();
}
else
{
digitalWrite(lightA, TURN_OFF);
Serial.print("\t");
Serial.println(F("Bloom A Light OFf")); // Text printed to serial monitor
Serial.print("\t");
Serial.println();
}
//*************** 12/12 BloomB Light - 6PM-6AM**********************************//
//***** Adjust hours and minutes in accordance with 24 hour time format. *******//
//***** lightB is lit during the opposing 12 hours to lightA. *****************//
boolean lightBstate = false;
if (lightAstate == false) lightBstate = true;
if (lightBstate == true)
{
digitalWrite(lightB, TURN_ON);
Serial.print("\t");
Serial.print(F("Bloom B Light On")); // Text printed to serial monitor
Serial.print("\t");
Serial.println();
}
else
{
digitalWrite(lightB, TURN_OFF);
Serial.print("\t");
Serial.println(F("Bloom B Light OFf")); // Text printed to serial monitor
Serial.print("\t");
Serial.println();
}
//*********************************** FEED TIMEs - pumpA ******************************************//
// By testing hour once and minute twice, we isolate the "on" time and the duration it is "on". *****//
// If the Boolean becomes true, D32 is HIGH until Boolean becomes false again. **********************//
boolean pumpAstate = false;
if (now.hour() == 9 && now.minute() >= 0 && now.minute() < 10) pumpAstate = true; //9:00 am - 10mins
if (now.hour() == 15 && now.minute() >= 30 && now.minute() < 40) pumpAstate = true; //3:30 pm - 10mins
if (now.hour() == 22 && now.minute() >= 30 && now.minute() < 33) pumpAstate = true; //10:30pm - 03mins
if (pumpAstate == true)
{
digitalWrite(pumpA, TURN_ON);
Serial.print("\t");
Serial.println(F("Feeding PlantA")); // Text printed to serial monitor
Serial.print("\t");
Serial.println();
}
else
{
digitalWrite(pumpA, TURN_OFF);
}
//*******************************Feed Times - pumpB *******************************************//
boolean pumpBstate = false;
if (now.hour() == 9 && now.minute() >= 0 && now.minute() < 10) pumpBstate = true; //9:00 am - 10mins
if (now.hour() == 15 && now.minute() >= 30 && now.minute() < 40) pumpBstate = true; //3:30 pm - 10mins
if (now.hour() == 22 && now.minute() >= 30 && now.minute() < 33) pumpBstate = true; //10:30pm - 03mins
if (pumpBstate == true)
{
digitalWrite(pumpB, TURN_ON);
Serial.print("\t");
Serial.println(F("Feeding PlantB")); // Text printed to serial monitor
Serial.print("\t");
Serial.println();
}
else
{
digitalWrite(pumpB, TURN_OFF);
}
}