/*
Project: Soil Moisture Controller MkII
Description: Keeps soil moisture within a certain range.
If sensor indicates soil is dry
Run pump for PUMP_TIME milliseconds (default 45s)
Wait for SOAK_TIME milliseconds (default 10 mins)
Repeat
NOTE: Initial Flow rate is 1L/3min
Creation date: 10/16/23
Author: AnonEngineering
TO DO:
Sequence pumps so only 1 is on at a time
Set on / off pump cycles
Gregnor — 10/15/23 at 12:10 AM Arduino | #coding-help | "Code check?"
License: https://en.wikipedia.org/wiki/Beerware
*/
#include "SPI.h"
#include "timeObj.h" // LC_baseTools
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"
// uncomment next line for serial
#define SERIAL_DEBUG true
const int TFT_DC = 9;
const int TFT_CS = 10;
const unsigned long SEEP_TIME = 4500; // watering time for pump to be @45sec NOTE: Initial Flow rate is 1ltr/3min measured. Could use recalibration depending on plant.
const unsigned long PUMP_TIME = 1000; // time on a follow up water if soild humidity not reached @10sec.
const int NUM_PLANTS = 5;
const int PUMP_PINS[NUM_PLANTS] = {6, 5, 4, 3, 2};
const int SENSOR_PINS[NUM_PLANTS] = {A4, A3, A2, A1, A0};
const int MOIST_THRESHOLD[NUM_PLANTS][2] = { // dry, wet
{400, 300},
{380, 300},
{380, 300},
{380, 300},
{380, 300}
};
const char PLANT_NAMES[NUM_PLANTS][8] = {
{"Cactus"},
{" Jade"},
{"Rubber"},
{"Spider"},
{" Aloe"}
};
//bool needsWater[NUM_PLANTS];
//int moistReading[NUM_PLANTS];
timeObj pump_run_timer[NUM_PLANTS];
timeObj water_seep_timer[NUM_PLANTS];
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
void setPumps(int sensorVal, int pumpNumber, bool pumpOn) {
static int rowVal = 0;
const int colVal[] = {0, 150, 260};
char msgData[16];
if (pumpNumber == 0) rowVal = 5;
// set color
if (sensorVal >= MOIST_THRESHOLD[pumpNumber][0]) {
tft.setTextColor(0xfe20, 0x0000); // dry, yellow
} else if (sensorVal <= MOIST_THRESHOLD[pumpNumber][1]) {
tft.setTextColor(0x07d9, 0x0000); // wet, blue
} else {
tft.setTextColor(0x8faa, 0x0000); // normal, green
}
// show plant
tft.setCursor(colVal[0], rowVal);
tft.print (PLANT_NAMES[pumpNumber]);
// show value
tft.setCursor(colVal[1], rowVal);
sprintf(msgData, "%4d", sensorVal);
tft.print (msgData);
// show pump
tft.setCursor(colVal[2], rowVal);
tft.print (pumpOn ? "On " : "Off");
rowVal = rowVal + 50;
if (pumpOn) {
pump_run_timer[pumpNumber].start();
digitalWrite(PUMP_PINS[pumpNumber], HIGH);
} else {
digitalWrite(PUMP_PINS[pumpNumber], LOW);
}
}
void setup() {
#ifdef SERIAL_DEBUG
Serial.begin(115200);
#endif
tft.begin();
tft.setRotation(3);
tft.setTextSize(4);
for (int i = 0; i < NUM_PLANTS; i++) {
pinMode(PUMP_PINS[i], OUTPUT);
pinMode(SENSOR_PINS[i], INPUT);
pump_run_timer[i].setTime(PUMP_TIME); // Set the timer for 500 ms. (1/2 second)
//pump_run_timer[i].start(); // Fire up the timer.
water_seep_timer[i].setTime(SEEP_TIME); // Set the timer for 500 ms. (1/2 second)
//water_seep_timer[i].start(); // Fire up the timer.
}
// splash screen
tft.setTextColor(0x53de); // kinda blue 565 color
tft.setCursor(75, 60);
tft.println("Gregnor");
tft.setCursor(100, 100);
tft.println("Hydro");
tft.setCursor(125, 140);
tft.println("System");
delay(5000);
// clear splash
tft.fillScreen(ILI9341_BLACK);
tft.setTextSize(3);
}
void loop() {
bool needsWater[NUM_PLANTS];
int moistReading[NUM_PLANTS];
for (int i = 0; i < NUM_PLANTS; i++) {
moistReading[i] = analogRead(SENSOR_PINS[i]);
if (moistReading[i] < MOIST_THRESHOLD[i][0]) {
needsWater[i] = false;
//digitalWrite(PUMP_PINS[i], LOW);
} else {
needsWater[i] = true;
//digitalWrite(PUMP_PINS[i], HIGH);
}
#ifdef SERIAL_DEBUG
//#ifdef SERIAL_DEBUG
Serial.print(PLANT_NAMES[i]);
Serial.print(" sensor:\t");
Serial.print("Value: ");
Serial.print(moistReading[i]);
//#endif
Serial.print("\tPump ");
Serial.print(i);
Serial.print(" needs to run: ");
Serial.println(needsWater[i] ? "True" : "False");
#endif
setPumps(moistReading[i], i, needsWater[i]);
}
#ifdef SERIAL_DEBUG
Serial.println();
#endif
delay(1000);
}
Drier
Wetter