/*
************************************
Pump Shed with Struct Data Array
************************************
*/
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <TimeLib.h>
#include <TimeAlarms.h> // https://www.pjrc.com/teensy/td_libs_TimeAlarms.html
// Variables that ** WON'T ** change //////////////////////////////////////////////////////
const float fMult = 1.2; // factor used to compute Flats irrigation time
const int relayCount = 3; // relay count
const int dispCols = 20; // i.e. 20 columns (0-19) addressed in C/R order
const int dispRows = 4; // i.e. 4 rows (0- 3) addressed in C/R order
const byte dispI2CAddress = 0x27; // other addresses possible - 0x20 to 0x27
const int tempDL[2] = {0, 0}; // LCD display location for the RTC temperature
const int timeDL[2] = {12, 0}; // LCD display location for the current time
const int startDL[2] = {12, 1}; // LCD display location for the cycle start time
const int sMinsDL[2] = {13, 2}; // LCD display location for the Sandhill minutes
const int fMinsDL[2] = {17, 2}; // LCD display location for the Flats minutes
const long secondsPerDay = 86400; // 24 * 60 * 60
//////////////////////////////////////// Are all of the above actually used?
// Variables that ** WILL ** change //////////////////////////////////////////////////////
time_t cT, pT; // current & previous time in seconds from 1/1/1970
time_t midnight; // time as at 00:00:00 today
time_t cycleStart = (9 * 3600) +
(6 * 60) +
8; /////////// ultimately transmitted to the pump shed via LoRa
// works to 9:06:07 (32,767 secs), but not at 9:07:08 (2^15)
char HMS[9] = "##:##:##"; // time in string format HH:MM:SS
char YMD[11] = "####-##-##"; // date in string format YYYY-MM-DD
int sMinutes = 300; // Sandhill duration (base) in minutes
int fMins = sMinutes * fMult; // Flats duration (= Sandhill minutes * 1.2)
float rtcTemp; // the temperature as determined by the RTC clock
int pos; // LCD position variable Col = pos % 20, Row = pos / 20
char s[10]; // used to store various sprintf() strings
int ledCounter = 0; // LED to blink
// struct to hold data
struct psData { // holds the Pump Shed program values
char relay[2]; // relay name - "R1", "R3" or "R4"
bool status; // true (= ON) or false (= OFF)
int ardPin; // Arduino (digital) pin for that relay
int dispLoc[2]; // array for data location in LCD display [Col, Row]
byte memLoc; // eeprom memory storage @ location ?????????????????????????????
// stores cycleStart & sMinutes
void print() {
Serial.print(F("{\""));
Serial.print(relay[2]);
Serial.print(F("\""));
Serial.print(status);
Serial.print(F(", "));
Serial.print(ardPin);
Serial.print(F(", "));
Serial.print(dispLoc[2]); ////////// bound to be wrong somewhere
Serial.print(F("\", 0x"));
if (dispLoc[2] < 16) {
Serial.write('0');
}
Serial.print(dispLoc[2], HEX);
Serial.println(F("},"));
}
}
psData[] = {
{"R1", false, 2, { 3, 3}, 0x00}, // Relay1 (Pump) initialised to false (OFF)
// R2 (digital pin 7) not used
{"R3", false, 8, {10, 3}, 0x10}, // Relay2 (Sandhill) initialised to false (OFF)
{"R4", false, 10, {17, 3}, 0x20}, // Relay3 (Flats) initialised to false (OFF)
}; /////////////////////////////////////// Memory locations for R3 & R4 a pure guess at this stage
// set the LCD address to 0x27 for a 20 chars and 4 line display
LiquidCrystal_I2C lcd(dispI2CAddress, dispCols, dispRows);
void setup(){ // *******************************************************************
Serial.begin(9600);
setTime(15,52,50,9,8,2022); ////////// ultimately to come from RTC
pT = 0;
// Set the pin modes
for(int i = 0; i < relayCount; i++){
pinMode(psData[i].ardPin, OUTPUT);
}
// Setup & write the unchanging part of the LCD display
lcd.init();
lcd.backlight();
// write the labels
lcd.setCursor(0, 0);
lcd.print(" C Time: : : ");
lcd.setCursor(0, 1);
lcd.print("Start Time: : : ");
lcd.setCursor(0, 2);
lcd.print("Cycles(min): / ");
lcd.setCursor(0, 3);
lcd.print("R1- R3- R4- ");
delay(500);
// lcd.clear();
// remove ************************************************************************
// turn on all LEDs / relays
for (int i = 0; i < relayCount; i++){
digitalWrite(psData[i].ardPin, HIGH);
}
pinMode(7, OUTPUT);
digitalWrite(7, HIGH);
delay(1000);
// remove ************************************************************************
// sync clock to zero seconds so that alarms trigger on the minute
cT = now();
Serial.print("The current time is ");
Serial.println(getHMS(cT));
Serial.print("Alarms will be synchronise to the even minute in... ");
Serial.print(60 - second(now()));
Serial.println(" seconds");
while (second(now()) != 0){} // wait until the next new minute
Alarm.timerRepeat(60, updateLCD); // update the LCD every minute
}
void loop(){ // *******************************************************************
cT = now(); // Store the current time
// Serial.print(cT);
// Serial.print(" ");
midnight = ((cT / secondsPerDay) * secondsPerDay); // time as at 00:00:00 today
// Serial.print(midnight);
// Serial.print(" ");
// dislpay the relay statuses & write the appropriate pin values
for (int i = 0; i < relayCount; i++){
lcd.setCursor(psData[i].dispLoc[0], psData[i].dispLoc[1]);
if (psData[i].status){
lcd.print(" ON");
digitalWrite(psData[i].ardPin, HIGH);
}
else{
lcd.print("OFF");
digitalWrite(psData[i].ardPin, LOW);
}
}
// update the LCD time every second
if (pT != cT){updateLCDTime();}
// Do not loop
// while(true) {};
}
// functions *******************************************************************
char getHMS(long t){
sprintf (HMS, "%02d:%02d:%02d", hour(t), minute(t), second(t));
return(HMS);
}
char getYMD(long t){
sprintf (YMD, "%04d-%02d-%02d", year(t), month(t), day(t));
return(YMD);
}
void updateLCD(){ // all fields, every minute
// update the LCD with the live data
// dislpay the RTC temperature
lcd.setCursor(0, 0);
rtcTemp = 45.2; // assigned here, but ultimately read from the RTC chip
dtostrf(rtcTemp, 4, 1, s); // dtostrf(floatVar, minStringWidthIncDecimalPoint, numVarsAfterDecimal, charBuf);
lcd.print(s);
// dislpay the current time
lcd.setCursor(timeDL[0],timeDL[1]);
HMS[9] = getHMS(cT);
lcd.print(HMS);
// Serial.print(HMS); // print the time
// Serial.print(" ");
// dislpay the cycle start
lcd.setCursor(startDL[0],startDL[1]);
// Serial.println(cycleStart);
HMS[9] = getHMS(cycleStart);
lcd.print(HMS);
// Serial.print(HMS); // print the cycle start
// dislpay the cycle times
lcd.setCursor(sMinsDL[0],sMinsDL[1]);
lcd.print(sMinutes);
lcd.setCursor(fMinsDL[0],fMinsDL[1]);
lcd.print(fMins);
}
void updateLCDTime(){
lcd.setCursor(timeDL[0],timeDL[1]);
HMS[9] = getHMS(cT);
lcd.print(HMS);
}