Automated Gardening Project

Recently, I have been working on a automated gardening/data logging project. I am using a 12 volt pump and relay connected to a arduino mega to water the garden. To log data, I have 3 moisture sensors, a dht11, a photoresistor, a rtc module (DS3231), and an sd card shield. I also have one through hole status neopixel. I would like my arduino to log data to the sd card every hour and turn on the relay for the pump when the average soil reading is above the threshold I have set. My neopixel displays a color based on what task the arduino is performing. I have just recently gotten back into using my arduino and programming. Will my code work as planned? Any suggestions?

Garduino_Datalogger.ino (6.61 KB)

diyguy3030: Does my code correctly accomplish my goal?

Um, what code? Does it do what you want it to do?

Whoops! I have attached the code.

OP’s code posted properly for him.

EDIT: I also formatted that mess for him.

OP, if you want others to read your code and try to help, you should at least try to make the code readable. All you gotta do is hit control-T in the IDE and it does it for you. It’s not hard. If you had read the forum instructions you would know all this. Reading the instructions first is CRUCIAL to success in this hobby.

/*
  Automated Gardening / Datalogging Project By Scott Powers
  (June 2018)
*/


#include <RTClib.h>
#include <Wire.h>
#include <SPI.h>
#include "DHT.h"
#include <SD.h>
#include <Adafruit_NeoPixel.h>

DateTime now;

#define DHTTYPE DHT11

float humidity = 0; //Relative humidity (%)
float airTemp = 0; //Air temp (degrees F)
float heatIndex = 0; //Heat index (degrees F)
const int waterThreshold = 700;
const int cycleTime = 20; //in seconds
const int chipSelect = 53;
const int soilMoisturePin1 = A13;
const int soilMoisturePower1 = 42;
const int soilMoisturePin2 = A9;
const int soilMoisturePower2 = 51;
const int soilMoisturePin3 = A11;
const int soilMoisturePower3 = 37;
const int sunlightPin = A5;
const int dhtPin = 5;
const int manualButton = 10;
const int neopixelPin = 8;
const int relayPin = 3;

int RawMoisture1 = 0;
int mapMoisture1 = 0;
int RawMoisture2 = 0;
int mapMoisture2 = 0;
int RawMoisture3 = 0;
int mapMoisture3 = 0;
int averageMoisture = 0;

int RawLight = 0;
int maplight = 0;


File logfile;

float moistureAvrg = 0;

bool manualButtonUsed = false;

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(1, neopixelPin, NEO_GRB + NEO_KHZ800);
DHT dht(dhtPin, DHTTYPE);
RTC_DS3231 rtc;


void error(char error[]) {

  Serial.print("Error:");
  Serial.println(error);

  pixels.setPixelColor(0, pixels.Color(0, 255, 0)); //Set Neopixel led to Red to display error
  pixels.show();
  while (1);
}


void setup() {
  Serial.begin(9600);

  pinMode(soilMoisturePower1, OUTPUT);
  digitalWrite(soilMoisturePower1, LOW);
  pinMode(soilMoisturePower2, OUTPUT);
  digitalWrite(soilMoisturePower2, LOW);
  pinMode(soilMoisturePower3, OUTPUT);
  digitalWrite(soilMoisturePower3, LOW);
  pinMode(chipSelect, OUTPUT);
  pinMode(manualButton, INPUT_PULLUP);

  pinMode(relayPin, OUTPUT);
  digitalWrite(relayPin, HIGH); //Make sure the relay is off - low level trigger

  pixels.begin();
  dht.begin();

  if (!SD.begin(chipSelect)) {

    error("Card failed, or not present");
    DateTime now = rtc.now();
  }
  // create a new file
  logfile = SD.open("DataLog.csv", FILE_WRITE);


  if (! logfile) {
    error("couldnt create file");
  }
  // following line sets the RTC to the date & time this sketch was compiled
  rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));

  //cycle Led colors to signal startup
  pixels.setPixelColor(0, pixels.Color(0, 0, 255)); //Blue
  pixels.show();// Moderately bright green color.
  delay(500);
  pixels.setPixelColor(0, pixels.Color(255, 255, 255)); //White
  pixels.show(); // This sends the updated pixel color to the hardware.
  delay(500);
  pixels.setPixelColor(0, pixels.Color(255, 0, 0)); //Green
  pixels.show();
  delay(500);
  pixels.setPixelColor(0, pixels.Color(0, 255, 0)); //Red
  pixels.show();
  delay(500);
  pixels.setPixelColor(0, pixels.Color(255, 255, 255)); //White
  pixels.show();

  logfile.println("Unix Time (s), Air Temp (F),Soil Moisture Average (%),Humidity (%),Heat Index (F),Sunlight Analog Value");
  Serial.println("Unix Time (s), Air Temp (F),Soil Moisture Average (%),Humidity (%),Heat Index (F),Sunlight Analog Value");
}

void readMoisture1() {
  pixels.setPixelColor(0, pixels.Color(255, 0, 0)); //Green
  pixels.show();
  RawMoisture1 = 0;
  for (int i = 0; i <= 2; i++) {
    delay(50);
    digitalWrite(soilMoisturePower1, HIGH);//turn D7 "On"
    delay(10);//wait 10 milliseconds
    RawMoisture1 += analogRead(soilMoisturePin1);//Read the SIG value form sensor
    digitalWrite(soilMoisturePower1, LOW);//turn D7 "Off"
  }
  RawMoisture1 = RawMoisture1 / 3;

}


void readMoisture2() {
  RawMoisture2 = 0;
  for (int i = 0; i <= 2; i++) {
    delay(50);
    digitalWrite(soilMoisturePower2, HIGH);//turn D7 "On"
    delay(10);//wait 10 milliseconds
    RawMoisture2 += analogRead(soilMoisturePin2);//Read the SIG value form sensor
    digitalWrite(soilMoisturePower2, LOW);//turn D7 "Off"
  }
  RawMoisture2 = RawMoisture2 / 3;


}


void readMoisture3() {
  RawMoisture3 = 0;
  for (int i = 0; i <= 2; i++) {
    delay(50);
    digitalWrite(soilMoisturePower3, HIGH);//turn D7 "On"
    delay(10);//wait 10 milliseconds
    RawMoisture2 += analogRead(soilMoisturePin3);//Read the SIG value form sensor
    digitalWrite(soilMoisturePower3, LOW);//turn D7 "Off"
  }
  RawMoisture3 = RawMoisture3 / 3;

}

void loop() {
  digitalWrite(relayPin, HIGH);

  // put your main code here, to run repeatedly:
  if (!(now.day() == rtc.now().day())) {

    manualButtonUsed = false;
  }
  DateTime now = rtc.now();
  if (now.minute() == 0) {
    pixels.setPixelColor(0, pixels.Color(0, 0, 255)); //Blue
    pixels.show();
    readMoisture1();
    readMoisture2();
    readMoisture3();

    RawLight = analogRead(sunlightPin);

    moistureAvrg = (RawMoisture1 + RawMoisture2 + RawMoisture3) / 3;

    humidity = dht.readHumidity();
    delay(20);

    airTemp = dht.readTemperature(true);
    delay(20);

    heatIndex = dht.computeHeatIndex(airTemp, humidity, true);
    delay(20);

    logfile.print(now.unixtime()); // seconds since 2000
    logfile.print(",");
    logfile.print(now.year(), DEC);
    logfile.print("/");
    logfile.print(now.month(), DEC);
    logfile.print("/");
    logfile.print(now.day(), DEC);
    logfile.print(" ");
    logfile.print(now.hour(), DEC);
    logfile.print(":");
    logfile.print(now.minute(), DEC);
    logfile.print(":");
    logfile.print(now.second(), DEC);
    logfile.print(",");


    delay (50);
    logfile.print(airTemp);
    logfile.print(",");
    logfile.print(moistureAvrg);
    logfile.print(",");
    logfile.print(humidity);
    logfile.print(",");
    logfile.print(heatIndex);
    logfile.print(",");
    logfile.print(RawLight);
    logfile.print(",");


    if (moistureAvrg >= waterThreshold && !RawLight <= 200) {
      pixels.setPixelColor(0, pixels.Color(255, 255, 255)); //White
      pixels.show(); // This sends the updated pixel color to the hardware.
      logfile.print("WATERING");
      digitalWrite(relayPin, LOW);
      delay(cycleTime * 1000);
      digitalWrite(relayPin, HIGH);


    }

    logfile.println();
  }
  if (digitalRead(manualButton) == HIGH) {
    if (!manualButtonUsed) {
      pixels.setPixelColor(0, pixels.Color(255, 255, 255)); //White
      pixels.show(); // This sends the updated pixel color to the hardware.
      logfile.print("WATERING");
      digitalWrite(relayPin, LOW);
      delay(cycleTime * 1000);
      digitalWrite(relayPin, HIGH);
      manualButtonUsed = true;
    }
  }
}

Is it doing what you want? I'm not going to hunt through that code and try to figure out what you intend. You gotta give us some symptoms of the problem. At least something to go on.

Why do you have three different routines for reading the three different moisture sensors? They’re all the same.

Why does the function for moisture sensor 3 have references to moisture sensor 2 in the body of the function. If you’re going to copy - paste the same function three times to avoid having to learn to give a function a parameter or learning about arrays then you at least need to be careful about your copy-paste editing.

void readMoisture3() {
  RawMoisture3 = 0;
  for (int i = 0; i <= 2; i++) {
    delay(50);
    digitalWrite(soilMoisturePower3, HIGH);//turn D7 "On"
    delay(10);//wait 10 milliseconds
    RawMoisture2 += analogRead(soilMoisturePin3);//Read the SIG value form sensor WRONG SENSOR!!!!!!!
    digitalWrite(soilMoisturePower3, LOW);//turn D7 "Off"
  }
  RawMoisture3 = RawMoisture3 / 3;

}

I thought copy and pasting might be slightly easier. Would you suggest accepting an int (1,2, or 3) as a parameter and using a switch case to determine the sensor or is there a way I could pass the variable names used in each function directly as parameters.

diyguy3030: I thought copy and pasting might be slightly easier. Would you suggest accepting an int (1,2, or 3) as a parameter and using a switch case to determine the sensor or is there a way I could pass the variable names used in each function directly as parameters.

You could pass in the variable names. You could put them in an array and pass in an index. Copy-paste is fine if that's what you want to do, but you do have to be careful about your editing. You apparently missed one here.

Anytime you catch yourself putting numbers on the ends of variable names it should hit you like a clue by four that you need an array.

const byte soilMoisturePins[3] = {A13, A9, A11};
const byte soilMoisturePower[3] = {42, 51, 37};
int rawMoisture[3];
void readMoisture(byte whichSensor) {
  RawMoisture[whichSensor] = 0;
  for (int i = 0; i <= 2; i++) {
    delay(50);
    digitalWrite(soilMoisturePower[whichSensor], HIGH);
    delay(10);//wait 10 milliseconds
    RawMoisture[whichSensor] += analogRead(soilMoisturePin[whichSensor]);
    digitalWrite(soilMoisturePower[whichSensor], LOW);
  }
  RawMoisture[whichSensor] = RawMoisture[whichSensor] / 3;

}

You should also take care to edit comments. This had comments about D7, which is obviously not the pin you’re using. That might make sense to you right now, but to someone reading your code it is confusing and when you come back in a few years to maintain this code it will confuse you too. Comments should be made right or deleted.

diyguy3030: Will my code work as planned? Any suggestions?

Did you simply try it all out already?