#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
byte rowPins[ROWS] = {9, 8, 7, 6};
byte colPins[COLS] = {5, 4, 3, 2};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
const int Relay = 10;
bool RelayState = HIGH;
uint16_t wateringTime;
uint16_t wateringInterval;
enum state {GET_INTERVAL, GET_WATERING_TIME, GET_INSTRUCTION, WAITING, WATERING};
state currentState; // Current state
boolean initialiseState = false; // Gets set when we first change state, so we initialise.
unsigned long stateStartTime; // Timestamp when this state started.
void setup()
{
pinMode(Relay, OUTPUT);
digitalWrite(Relay, HIGH);
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Hello, take care");
lcd.setCursor(0, 1);
lcd.print("of your plants!");
delay(3000);
currentState = changeState(GET_INTERVAL);
}
void loop()
{
char key = NO_KEY;
switch (currentState)
{
case GET_INTERVAL: // Get a value from the keypad, for the interval between watering.
{
if (initialiseState)
{
wateringInterval = 0;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Interval [s]:");
lcd.setCursor(0, 1);
initialiseState = false;
}
key = keypad.getKey();
if (key >= '0' && key <= '9')
{
lcd.print(key);
wateringInterval = (wateringInterval * 10) + key - '0';
}
else if (key == '#')
currentState = changeState(GET_WATERING_TIME);
break;
}
case GET_WATERING_TIME: // Get a value from the keypad, for how long we water.
{
if (initialiseState)
{
wateringTime = 0;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Watering [s]:");
lcd.setCursor(0, 1);
initialiseState = false;
}
key = keypad.getKey();
if (key >= '0' && key <= '9')
{
lcd.print(key);
wateringTime = (wateringTime * 10) + key - '0';
}
else if (key == '#')
currentState = changeState(GET_INSTRUCTION);
break;
}
case GET_INSTRUCTION: // Get A, B, or C to tell us what to do.
{
if (initialiseState)
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("A timer, B water");
lcd.setCursor(0, 1);
lcd.print("now, C restart ");
initialiseState = false;
}
key = keypad.getKey();
if (key == 'A')
currentState = changeState(WAITING);
else if (key == 'B')
currentState = changeState(WATERING);
else if (key == 'C')
currentState = changeState(GET_INTERVAL);
break;
}
case WAITING: // Timer has been started, and we are waiting for interval to complete.
{
if (initialiseState) // First time through
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Wait :)");
initialiseState = false;
}
if (millis() - stateStartTime > wateringInterval * 1000UL)
currentState = changeState(WATERING);
if (keypad.getKey() == 'C')
currentState = changeState(GET_INTERVAL);
break;
}
case WATERING: // We are watering.
{
if (initialiseState)
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Watering :)");
initialiseState = false;
}
if (millis() - stateStartTime > wateringTime * 1000UL)
currentState = changeState(WAITING);
if (keypad.getKey() == 'C')
currentState = changeState(GET_INTERVAL);
break;
}
};
}
state changeState(state newState)
{
initialiseState = true;
stateStartTime = millis();
return newState;
}