/*
------------------- FERTIGATION PROJECT -------------------------------
wokwi link:
https://wokwi.com/projects/380819825982997505
github link:
https://github.com/nevchits/fertiG/blob/main/SW/fertiG/fertiG.ino
-------- CHANGELOG ----------------------------------------------------
17 Dec 2023, 17:02 -->
- back up previous code,
- rewrite the whole code to use the timelib
23 Nov 2023 -->
- TODO: work on the timer settings and actual functionality.
- TODO: set it so that we have an on and off timer cycle.
- TODO: put one on preset number 3 (15 minutes off, 3 minutes on)
- TODO: disable the timer by setting fertigation state to IDLE (preset 0)
BUILD 18Nov23:
- Fixed Screen Navigation issues where it cycles through all the screens
BUG 20 Nov 2023 1403:
- Trying to fix the issue where the program bounces back to IDLE even after pressing a preset. seems to only happen in hardware
- FIXED?
20 Nov 2023, 15:11
- beautified Time Display... removed lines coz of refresh rate
- added project to github.
TODO:
1. add timer (on and off) irrigation as a preset (i.e. preset number 3) --> maybe make that the default? no?
2. fix continuous dosing issue
3. Alarms?
4. Logging?
*/
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
#include <TimeLib.h>
String lines = "--------------------";
String versionNumber = "0.8b181123"; //total of 11 spaces
//-------------------------------- I/O-------------------------------
#define CONDUCTIVITY A2
//TODO add PH later
#define DOSERMOTOR 2
#define IRRIGATORMOTOR 3
#define FERTIGATORMOTOR 4 //till we get a new pin
//---------------- PARAMETRIC VALUES -------------------------------
float pHValue = 7.0;
float conductivityValue = 2.0;
float moistureContent = 12.0;
float temperatureValue = 32.0;
float humidityValue = 55.2;
//-----------Fertigation states booleans and directives--------------
String fertigationState = "IDLE";
bool isIdle = true;
bool isDosing = false;
bool isIrrigating = false;
bool isFertigating = false;
int previousFertigationState = 0;
int currentFertigationState = 0;
#define IDLE 0
#define DOSING 1
#define IRRIGATING 2
#define FERTIGATING 3
//------------------------- screen number directives -----------------
#define HOME_SCREEN 1
#define MENU1 2
#define MENU2 3
#define MENU3 4
#define RUNTIME_PH 5
#define RUNTIME_TIMER 6
#define RUNTIME_MOISTURE 7
#define RUNTIME_TEMP_HUM 8
#define ABOUT1 9
#define ABOUT2 10
#define MENU_SETDATETIME1 11
#define MENU_SETDATETIME2 12
#define MENU_SETDATETIME3 13
#define MENU_SETDATETIME4 14
#define MENU_SETDATETIME5 15
#define MENU_SETDATETIME6 16
#define MENU_SETDATETIME7 17
//--------------------------- FAKE RTC VARIABLES -----------------------
int RTCHour = 23;
int RTCMinute = 59;
int RTCSecond = 40;
int flag = 0;
int TIME = 0;
//millis controllers
int prevSecond;
//timer values
int timerONHour = 0;
int timerONMinute = 2;
int timerONSecond = 0;
int timerOFFHour = 0;
int timerOFFMinute = 2;
int timerOFFSecond = 0;
int prevTimerSecond;
bool isTimerSet = false;
bool isTimerDosing = false;
bool isTimerIrrigating = false;
bool isTimerFertigating = false;
int timerSetHour = 0;
int timerSetMinute = 1;
int timerSetSecond = 30;
//------------------------------- SCREEN VARIABLES ----------------------
int screenNum = 1;
int currentScreen = 1;
bool isFooterHome = false;
bool isRuntimeScreen = false;
bool mustRefreshScreen = true;
//date time variables. TODO: handle them properly
/* Keypad setup */
const byte KEYPAD_ROWS = 4;
const byte KEYPAD_COLS = 4;
byte rowPins[KEYPAD_ROWS] = {12, 11, 10, 9};
byte colPins[KEYPAD_COLS] = {8, 7, 6, 5};
char keys[KEYPAD_ROWS][KEYPAD_COLS] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, KEYPAD_ROWS, KEYPAD_COLS);
LiquidCrystal_I2C lcd(0x27, 20, 4); // I2C address 0x27, 20 column and 4 rows
//----------- SCREEN METHODS ----------------------------------------
void testScreen(){
screenSelector(screenNum);
screenNum++;
if (screenNum >= 4) screenNum = 1;
delay(2000);
}
void footerHome(){
lcd.setCursor(0,3);
lcd.print("* <-Home | # ->Next");
}
void footerBack(){
lcd.setCursor(0,3);
lcd.print("* <-Back | # ->Next");
}
void runtimeHeader(){
lcd.clear();
lcd.setCursor(0,1);
lcd.print("STATE: ");
checkFertigationState();
lcd.setCursor(7,1);
lcd.print(fertigationState);
}
//old time header
void printTimeHeader_old(){
prevSecond = (millis()/1000)%60;
RTCSecond = prevSecond;
lcd.setCursor(0,0);
lcd.print(lines);
lcd.setCursor(9,0);
lcd.print('|');
lcd.setCursor(10,0);
if (RTCHour < 10) lcd.print("0");
lcd.print(RTCHour);
lcd.print(":");
lcd.setCursor(13,0);
//print leading 0 if necessary
if (RTCMinute < 10) lcd.print("0");
lcd.print(RTCMinute);
lcd.print(":");
lcd.setCursor(16,0);
if (RTCSecond < 10) lcd.print("0");
lcd.print(RTCSecond);
lcd.setCursor(18,0);
lcd.print('|');
}
//new one using timeLib
void printTimeHeader(){
lcd.setCursor(0,0);
lcd.print(lines);
lcd.setCursor(9,0);
lcd.print('|');
lcd.setCursor(10,0);
lcd.print(__TIME__);
lcd.print('|');
}
void correctTime(){
//print leading 0 if necessary
lcd.clear();
lcd.setCursor(0,0);
lcd.print("TIME >");
lcd.setCursor(10,0);
lcd.print("hh");
lcd.print(":");
lcd.print("mm");
lcd.print(":");
lcd.print("ss");
//no need to correct seconds
// lcd.setCursor(11,0);
// lcd.print("--");
//starting with hours:
int i = 0; //to count number of keys pressed. expecting 6
int j = 0; //to move the cursor to the right position
String keys = "";
int timevals[6];
while (keys.length() < 6){
keys += getKeyInput();
if(i == 2) j = 1; //move it to the correct position
if ( i == 4) j = 2; //move it to correct position for seconds too.
lcd.setCursor((i + j + 10),0);
lcd.print(keys[i]);
//convert to int
timevals[i] = keys[i] - '0';
i++;
}
lcd.setCursor(0,1);
//untidy combination into the actual time: and lazy wrap around of time:
RTCHour = (timevals[0])*10 + timevals[1];
if (RTCHour >= 24) RTCHour -= 24;
RTCMinute = (timevals[2])*10 + timevals[3];
if (RTCMinute >= 60) RTCMinute -=60;
RTCSecond = (timevals[4])*10 + timevals[5];
//set time method now:
setTime(RTCHour, RTCMinute, RTCSecond, 1, 1, 23);
}
//---------------------------- TIMER SETUP ----------------------------------------
void setTimer(){
//TODO: add * as backspace function
//lets ignore seconds for now, deal with hours and minutes only
lcd.clear();
lcd.setCursor(0,1);
lcd.print("TIME ON >");
lcd.setCursor(10,1);
lcd.print("hh");
lcd.print(":");
lcd.print("mm");
lcd.setCursor(0,2);
lcd.print("TIME OFF>");
lcd.setCursor(10,2);
lcd.print("hh");
lcd.print(":");
lcd.print("mm");
//starting with hours:
unsigned int i = 0; //to count number of keys pressed. expecting 8
int j = 0; //to move the cursor to the right position
unsigned int k = 1; // k for the row on the lcd.
// String keys = "";
char keys[4]; //let's try to use a char array
int timervals[4];
// while (keys.length() < 4){
//lcd.blink();
while (i < 8){
//keys += getKeyInput(); //was using this with the keys.length clause
keys[i] = getKeyInput();
if(i == 2) j = 1; //move it to the correct position, coz the cursor is supposed to jump the ":" character
if (i == 4) {
j = -4;
k = 2;
}
if (i == 6) {
j = -3;
k = 2;
}
lcd.setCursor((i + j + 10),k);
lcd.blink();
lcd.print(keys[i]);
//convert to int
timervals[i] = keys[i] - '0';
i++;
}
lcd.setCursor(0,1);
//untidy combination into the actual time: and lazy wrap around of time:
timerONHour = (timervals[0])*10 + timervals[1];
if (timerONHour >= 24) timerONHour -= 24;
timerONMinute = (timervals[2])*10 + timervals[3];
if (timerONMinute >= 60) timerONMinute -=60;
//untidy combination into the actual time: and lazy wrap around of time:
timerOFFHour = (timervals[0])*10 + timervals[1];
if (timerOFFHour >= 24) timerOFFHour -= 24;
timerOFFMinute = (timervals[2])*10 + timervals[3];
if (timerOFFMinute >= 60) timerOFFMinute -=60;
//TODO: match the timer mintes to the realtime:
//start the Timer cycle
//startTimerCycle();
lcd.noBlink();
}
//update the RTC and the timer values
//old update method.
void updateLCDTime_old(){
RTCSecond = (millis()/1000)%60;
if (flag == 24) flag = 0;
//only change the necessary fields
//if (RTCSecond > prevSecond){ //until we solve the 0 issue
if (RTCSecond != prevSecond) {
prevSecond = RTCSecond;
//minutes
if (RTCSecond == 0)
{
RTCMinute ++;
}
if (RTCMinute >= 60)
{
RTCMinute = 0;
RTCHour = RTCHour + 1;
flag = flag + 1;
}
if (RTCHour >= 24)
{
RTCHour = 0;
}
//also get parametric values while you are here
getConductivity();
//then fertigate is conductivity is below 2.5
if (conductivityValue < 2.5){
if (previousFertigationState != DOSING) previousFertigationState = currentFertigationState; //it will change coz it is contantly checking
setFertigationState(DOSING);
}
//POSSIBLE BUG: causes the program to fall back to idle on the actual hardware... --> Fixed?
// else if (previousFertigationState != DOSING){ //so that it doesnt bounce back to dosing. Commenting out this 'elseif' fixes #1
//go back to previous fertigation state
// setFertigationState(previousFertigationState); //which should be "IDLE" on initiation, right?
// }
getpH();
//only print if we are showing the runtime screen:
if (isRuntimeScreen){
//runtime header, except the screen clear part
lcd.setCursor(0,1);
lcd.print("STATE: ");
checkFertigationState();
lcd.setCursor(7,1);
lcd.print(fertigationState);
//RTC printing
//print leading 0 if necessary
lcd.setCursor(0,0);
//lcd.print(lines);
lcd.setCursor(8,0);
lcd.print("| ");
lcd.setCursor(10,0);
if (RTCHour < 10) lcd.print("0");
lcd.print(RTCHour);
lcd.print(":");
lcd.setCursor(13,0);
//print leading 0 if necessary
if (RTCMinute < 10) lcd.print("0");
lcd.print(RTCMinute);
lcd.print(":");
lcd.setCursor(16,0);
//print leading 0 if necessary
if (RTCSecond < 10) lcd.print("0");
lcd.print(RTCSecond);
lcd.setCursor(18,0);
lcd.print(" |");
//display timer stuff too... under the timer screen
//BUG: now the screen only shows the timer and the clock... --> runtime header was clearing the screen
if (screenNum == RUNTIME_TIMER){
lcd.setCursor(8,2);
//print leading 0 if necessary
if (timerONHour < 10) lcd.print("0");
lcd.print(timerONHour);
lcd.print(':');
if (timerONMinute < 10) lcd.print("0");
lcd.print(timerONMinute);
lcd.print(':');
if (timerONSecond < 10) lcd.print("0");
lcd.print(timerONSecond);
}
if(screenNum == RUNTIME_PH){
//update the ph and conductivity also
lcd.setCursor(3,2);
lcd.print(pHValue);
lcd.setCursor(16,2);
lcd.print(conductivityValue);
}
}
}
//timer stuff
if (isTimerSet && isRuntimeScreen){
timerONSecond = 60 - (millis()/1000)%60;
if (timerONSecond != prevTimerSecond){
prevTimerSecond = timerONSecond;
if(timerONSecond == 60) timerONSecond = 0; //kuti isanyore 60
if (timerONSecond == 0 && timerONMinute > 0){
timerONMinute --;
}
if (timerONMinute == 0 && timerONHour > 0){
timerONHour --; //we'll fix the resetting to 60 later on
}
//do something when timer runs out
if (timerONHour == 0 && timerONMinute == 0 && timerONSecond == 0){
//let's irrigate for now
setFertigationState(IRRIGATING);
isTimerSet = false;
}
}
// timer debug:
Serial.print("ON timer=");
Serial.print(timerONHour);
Serial.print(":");
Serial.print(timerONMinute);
Serial.print(":");
Serial.println(timerONSecond);
Serial.print("OFF timer=");
Serial.print(timerOFFHour);
Serial.print(":");
Serial.print(timerOFFMinute);
Serial.print(":");
Serial.println(timerOFFSecond);
}
}
//new update method using timelib
void updateLCDTime(){
//also get parametric values while you are here
getConductivity();
//then fertigate is conductivity is below 2.5
if (conductivityValue < 2.5){
if (previousFertigationState != DOSING) previousFertigationState = currentFertigationState; //it will change coz it is contantly checking
setFertigationState(DOSING);
}
getpH();
//only print if we are showing the runtime screen:
if (isRuntimeScreen){
//runtime header, except the screen clear part
lcd.setCursor(0,1);
lcd.print("STATE: ");
checkFertigationState();
lcd.setCursor(7,1);
lcd.print(fertigationState);
//RTC printing
//print leading 0 if necessary
lcd.setCursor(0,0);
//lcd.print(lines);
lcd.setCursor(8,0);
lcd.print("| ");
lcd.setCursor(10,0);
if (hour() < 10) lcd.print("0");
lcd.print(hour());
lcd.print(":");
lcd.setCursor(13,0);
//print leading 0 if necessary
if (minute() < 10) lcd.print("0");
lcd.print(minute());
lcd.print(":");
lcd.setCursor(16,0);
//print leading 0 if necessary
if (second() < 10) lcd.print("0");
lcd.print(second());
lcd.setCursor(18,0);
lcd.print(" |");
//display timer stuff too... under the timer screen
//BUG: now the screen only shows the timer and the clock... --> runtime header was clearing the screen
if (screenNum == RUNTIME_TIMER){
lcd.setCursor(8,2);
//print leading 0 if necessary
if (timerONHour < 10) lcd.print("0");
lcd.print(timerONHour);
lcd.print(':');
if (timerONMinute < 10) lcd.print("0");
lcd.print(timerONMinute);
lcd.print(':');
if (timerONSecond < 10) lcd.print("0");
lcd.print(timerONSecond);
}
if(screenNum == RUNTIME_PH){
//update the ph and conductivity also
lcd.setCursor(3,2);
lcd.print(pHValue);
lcd.setCursor(16,2);
lcd.print(conductivityValue);
}
}
//timer stuff
if (isTimerSet && isRuntimeScreen){
timerONSecond = 60 - (millis()/1000)%60;
if (timerONSecond != prevTimerSecond){
prevTimerSecond = timerONSecond;
if(timerONSecond == 60) timerONSecond = 0; //kuti isanyore 60
if (timerONSecond == 0 && timerONMinute > 0){
timerONMinute --;
}
if (timerONMinute == 0 && timerONHour > 0){
timerONHour --; //we'll fix the resetting to 60 later on
}
//do something when timer runs out
if (timerONHour == 0 && timerONMinute == 0 && timerONSecond == 0){
//let's irrigate for now
setFertigationState(IRRIGATING);
isTimerSet = false;
}
}
// timer debug:
// Serial.print("ON timer=");
// Serial.print(timerONHour);
// Serial.print(":");
// Serial.print(timerONMinute);
// Serial.print(":");
// Serial.println(timerONSecond);
// Serial.print("OFF timer=");
// Serial.print(timerOFFHour);
// Serial.print(":");
// Serial.print(timerOFFMinute);
// Serial.print(":");
// Serial.println(timerOFFSecond);
}
}
// ---------------------------- ACTUAL SCREENS --------------------------
void homeScreen(){
isRuntimeScreen = false;
lcd.clear();
lcd.setCursor(0,0);
lcd.print(lines);
lcd.setCursor(4,0);
lcd.print("FERTIGATION");
lcd.setCursor(0,1);
lcd.print("A> Runtime");
lcd.setCursor(0,2);
lcd.print("B> Menu");
lcd.setCursor(0,3);
lcd.print("C> About");
}
void menu1(){
isRuntimeScreen = false;
lcd.clear();
lcd.setCursor(0,0);
lcd.print(lines);
lcd.setCursor(8,0);
lcd.print("MENU");
lcd.setCursor(0,1);
lcd.print("A> Set Date/Time");
lcd.setCursor(0,2);
lcd.print("B> Set ON/OFF Timer");
isFooterHome = true;
footerHome();
}
void menu2(){
isRuntimeScreen = false;
lcd.clear();
lcd.setCursor(0,0);
lcd.print(lines);
lcd.setCursor(8,0);
lcd.print("MENU");
lcd.setCursor(0,1);
lcd.print("C> Set pH");
lcd.setCursor(0,2);
lcd.print("D> Set Conductivity");
isFooterHome = false;
footerBack();
}
void menu3(){
isRuntimeScreen = false;
lcd.clear();
lcd.setCursor(0,0);
lcd.print(lines);
lcd.setCursor(8,0);
lcd.print("MENU");
lcd.setCursor(0,1);
lcd.print("0 > Reset Defaults");
lcd.setCursor(0,2);
lcd.print("1..9> Presets");
isFooterHome = false;
footerBack();
}
void runtimePH(){
isRuntimeScreen = true;
runtimeHeader();
updateLCDTime();
//pH and Conductivity Values
lcd.setCursor(0,2);
lcd.print("pH=");
lcd.setCursor(3,2);
lcd.print(pHValue);
lcd.setCursor(8,2);
lcd.print(" us/cm=");
lcd.setCursor(16,2);
lcd.print(conductivityValue);
isFooterHome = true;
footerHome();
}
// screen 6
void runtimeTimer(){
//ned to update this to show ON-OFF timer values
isRuntimeScreen = true;
runtimeHeader();
updateLCDTime();
//dosing or irrigating timer
lcd.setCursor(0,2);
lcd.print("Timer =");
lcd.setCursor(8,2);
//print leading 0 if necessary
if (timerONHour < 10) lcd.print("0");
lcd.print(timerONHour);
lcd.print(':');
if (timerONMinute < 10) lcd.print("0");
lcd.print(timerONMinute);
lcd.print(':');
if (timerONSecond < 10) lcd.print("0");
lcd.print(timerONSecond);
isFooterHome = false;
footerBack();
}
// screen 7
void runtimeMoisture(){
isRuntimeScreen = true;
runtimeHeader();
updateLCDTime();
//Moisture Content
lcd.setCursor(0,2);
lcd.print("Moisture =");
lcd.setCursor(11,2);
lcd.print(moistureContent); //TODO replace with actual timer values
lcd.setCursor(17,2);
lcd.print("%");
isFooterHome = false;
footerBack();
}
// screen 8
void runtimeTempHum(){
isRuntimeScreen = true;
runtimeHeader();
updateLCDTime();
//Temp and Humidity
lcd.setCursor(0,2);
lcd.print("T =");
lcd.setCursor(3,2);
lcd.print(temperatureValue); //TODO replace with actual timer values
lcd.setCursor(7,2);
lcd.print((char)223); //degree symbol
lcd.print("C");
lcd.setCursor(11,2);
lcd.print("H =");
lcd.setCursor(15,2);
lcd.print(humidityValue);
lcd.setCursor(19,2);
lcd.print("%");
isFooterHome = false;
footerBack();
}
//screen 9 --ABOUT
void about1(){
isRuntimeScreen = false;
lcd.clear();
lcd.setCursor(0,0);
lcd.print(lines);
lcd.setCursor(7,0);
lcd.print("ABOUT");
lcd.setCursor(1,1);
lcd.print("Fertigation System");
lcd.setCursor(0,2);
lcd.print("version ");
lcd.print(versionNumber);
isFooterHome = true;
footerHome();
}
//screen 9 --ABOUT
void about2(){
isRuntimeScreen = false;
lcd.clear();
lcd.setCursor(0,0);
lcd.print(lines);
lcd.setCursor(7,0);
lcd.print("ABOUT");
lcd.setCursor(3,1);
lcd.print("BY ECI, SIRDC");
lcd.setCursor(2,2);
lcd.print("[email protected]");
isFooterHome = true;
footerHome();
}
//screen 10
//------------------------------------------------------------
char getKeyInput(){
char key = 0;
//add a timeout. let's start with 5 seconds
int startTimeout = millis();
int endTimeout;
while (key == 0) {
updateLCDTime(); //ewwwww
key = keypad.getKey();
if (key >= '0' && key <= '9') {
//lcd.print(key);
}
//timeout
endTimeout = millis();
//if (endTimeout - startTimeout > 500) break;
}
return key;
}
//---------------------------------- SCREEN STUFF----------------------------
// starting with fertigation states ----------
void checkFertigationState(){
//11 spaces munhu wese
if (isIdle) fertigationState = "IDLE ";
else if (isDosing) fertigationState = "DOSING ";
else if (isFertigating) fertigationState = "FERTIGATING";
else if (isIrrigating) fertigationState = "IRRIGATING ";
}
void setFertigationState(int fertigationStateValue){
currentFertigationState = fertigationStateValue;
// set the previous fertigation state for history... should not be changable by conductivity... hmmm
//previousFertigationState = fertigationStateValue;
// reset all of them
isIdle = false;
isDosing = false;
isIrrigating = false;
isFertigating = false;
//also reset timers if timer is set
if (isTimerSet){
isTimerDosing = false;
isTimerIrrigating = false;
isTimerFertigating = false;
}
// change only one depending on the state value
switch (fertigationStateValue){
case 0:
isIdle = true;
digitalWrite(DOSERMOTOR, LOW);
digitalWrite(IRRIGATORMOTOR, LOW);
digitalWrite(FERTIGATORMOTOR, LOW);
break;
case 1:
isDosing = true;
if (isTimerSet) isTimerDosing = true;
digitalWrite(DOSERMOTOR, HIGH);
digitalWrite(IRRIGATORMOTOR, LOW);
digitalWrite(FERTIGATORMOTOR, LOW);
break;
case 2:
isIrrigating = true;
if (isTimerSet) isTimerIrrigating = true;
digitalWrite(DOSERMOTOR, LOW);
digitalWrite(IRRIGATORMOTOR, HIGH);
digitalWrite(FERTIGATORMOTOR, LOW);
break;
case 3:
isFertigating = true;
if (isTimerSet) isTimerFertigating = true;
digitalWrite(DOSERMOTOR, LOW);
digitalWrite(IRRIGATORMOTOR, LOW);
digitalWrite(FERTIGATORMOTOR, HIGH);
break;
default:
isIdle = true;
digitalWrite(DOSERMOTOR, LOW);
digitalWrite(IRRIGATORMOTOR, LOW);
digitalWrite(FERTIGATORMOTOR, LOW);
break;
}
}
//toggle timer
void toggleTimer(){
if (isTimerSet) {
isTimerSet = false;
}
else {
isTimerSet = true;
prevTimerSecond = (millis()/1000)%60;
timerONSecond = prevTimerSecond;
}
}
//start timer
void startTimerCycle(){
isTimerSet = true;
prevTimerSecond = (millis()/1000)%60;
timerONSecond = prevTimerSecond;
}
// stop timer
void stopTimerCycle(){
isTimerSet = false;
}
// read conductivity and pH
void getConductivity(){
conductivityValue = (float)(analogRead(CONDUCTIVITY))/1024 * 5.0;
//debug:
Serial.print("Conductivity=");
Serial.println(conductivityValue);
}
void getpH(){
//nothing yet
}
//--- then screen selector ---
void screenSelector(int screenNumber){
switch(screenNumber){
case 1:
homeScreen();
break;
case 2:
menu1();
break;
case 3:
menu2();
break;
case 4:
menu3();
break;
case 5:
runtimePH();
break;
case 6:
runtimeTimer();
break;
case 7:
runtimeMoisture();
break;
case 8:
runtimeTempHum();
break;
case 9:
about1();
break;
case 10:
about2();
break;
default:
screenNum = 1;
homeScreen();
break;
}
}
int navigator(char keyinput){
currentScreen = screenNum;
//next and back and home controls...
//TODO: if you are in runtime, just cycle between runtime screens only...
//TODO: same with Menu and About screens
// for footerHome
if (isFooterHome){
if (keyinput =='*') screenNum = HOME_SCREEN;
else if (keyinput == '#') {
//check the screen number to make sure you don't cycle into a different group.
if (screenNum == HOME_SCREEN) {} //do't do anything
else if (screenNum == MENU3) screenNum = MENU1;
else if(screenNum == RUNTIME_TEMP_HUM) screenNum = RUNTIME_PH;
else if(screenNum == ABOUT2) screenNum = ABOUT1;
//add the other new screens you design here
else screenNum ++ ;
}
}
//for footerBack
else{
if (keyinput =='*') screenNum --;
else if (keyinput == '#') {
if (screenNum == HOME_SCREEN) {} //do't do anything
else if (screenNum == MENU3) screenNum = MENU1;
else if(screenNum == RUNTIME_TEMP_HUM) screenNum = RUNTIME_PH;
else if(screenNum == ABOUT2) screenNum = ABOUT1;
//add the other new screens you design here
else screenNum ++ ;
}
}
//add A, B and C for Home Screen
if(currentScreen == HOME_SCREEN){
if (keyinput =='A') screenNum = RUNTIME_PH;
else if (keyinput == 'B') screenNum = MENU1;
else if (keyinput == 'C') screenNum = ABOUT1;
}
//add A, B, C and D for Setup Screen (Menu 1 and 2)
if(currentScreen == MENU1 || currentScreen == MENU2){
if (keyinput =='A') {
screenNum = RUNTIME_PH;
// TODO: this is a screen and should be listed with other screens
correctTime();
}
else if (keyinput == 'B') {
setTimer();
//toggleTimer();
startTimerCycle();
//...and go to the timer screen
screenNum = RUNTIME_TIMER;
}
else if (keyinput == 'C') screenNum = ABOUT1;
else if (keyinput == 'D') screenNum = ABOUT1;
}
//screen for presets --> shouldnt matter which screen you are on...
//if(currentScreen == MENU3) {
if (keyinput =='0') {
setFertigationState(IDLE);
stopTimerCycle();
screenNum = RUNTIME_PH; //might need to keep the screen wherever it is...
}
else if (keyinput == '1') {
setFertigationState(DOSING);
screenNum = RUNTIME_PH;
}
else if (keyinput == '2') {
setFertigationState(IRRIGATING);
screenNum = RUNTIME_PH;
}
else if (keyinput == '3') {
setFertigationState(FERTIGATING);
screenNum = RUNTIME_PH;
}
//}
return screenNum;
}
//----------------------- SETUP AND LOOP -----------------------------------------------------------
void setup() {
//set up motors
pinMode(DOSERMOTOR, OUTPUT);
pinMode(IRRIGATORMOTOR, OUTPUT);
pinMode(FERTIGATORMOTOR, OUTPUT);
//inputs
pinMode(CONDUCTIVITY, INPUT);
lcd.init(); // initialize the lcd
lcd.backlight();
screenNum = HOME_SCREEN;
screenSelector(screenNum);
//serial
Serial.begin(9600);
}
// -------------------------------------------------------------------------------------------------
void loop() {
screenSelector(navigator(getKeyInput())); //BUG: we are stuck in here coz keypad is a blocking call --> FIXED by placing the LCD refresh inside the getKeyInput method
}
//-------------------------------- END ------------------------------------------------------------