Hi guys,
A friend of mine mentioned wanting to collect some data from his lawn. The idea is to determine based on soil moisture, temperature, sub-surface temperature and humidity, time of day and duration, when is the best time of the day to water the lawn and for how long in order to get the best efficiency out of his water usage. We both realize this is something that is being studied by actual scientists, but it sounded like a fun project to both of us. So I started building and programming a device we can use to gather and log data that can be easily reconfigured depending on what is needed. I'm still working on my code and have a lot of other things I still want to add, but I thought I would share what I have so far because I'm after opinions, improvement ideas, additional features that I can add. And maybe somebody finds something useful for their own projects. So here's what I have so far. It takes up 59% of program memory currently, down from 73%. You might recognize bits of code you have seen in examples online, It's literally come from all over the place. Currently very heavy on comments to make it clear to myself referring back to it later what everything is doing.
//////////////////////////Libraries//////////////////////////
#include <SD.h> //Library for SD card reader
#include <SPI.h> //Serial Peripheral Interface library
#include <DS3231.h> //Library for DS3231 Real time clock (Specifically from rinkydinkelectronics)
#include <Wire.h> //I2C Communication library
#include <LiquidCrystal_I2C.h> //I2C based LCD display library
#include "DHT.h" //Supports DHT digital sensors like the DHT22
//////////////////////////Libraries//////////////////////////
/////////////////////////Definitions/////////////////////////
#define DHTpin 5 //Digital pin connected to DHT sensor
#define SoilPin A1
#define DHTtype DHT22 //Tells the DHT library what sensor to use
/////////////////////////Definitions/////////////////////////
const int ChipSelect = 4; //Arduino pin used for SD card chip select
const int TMP1 = 0; //This is the pin the digital thermometer is connected to
Time t; //Time-data structure (See example code)
/*----------------Initialize-the-RTC--------------------------*/
DS3231 RTC(SDA, SCL);; //This initializes the RTC using I2C bus
/*----------Define-the-LCD-address,-rows,-columns-------------*/
LiquidCrystal_I2C lcd(0x27, 16, 2); //(<Device address>, <Columns>, <Rows>)
/*----Initializing-the-DHT-Sensor------Comment-out-if-not-used*/
DHT dht(DHTpin,DHTtype);
void setup()
{
lcd.init(); //Initialize the LCD diaplay with the pre-defined settings from above
lcd.backlight(); //Initialize the LCD backlight
Serial.begin(115200); //Start the serial interface with given baud rate
RTC.begin(); //Start the real time clock
/*---------This-is-used-for-calibrating-your-RTC-if-needed---*/
/*
rtc.setDow(Friday); //Set day of the week
rtc.setTime(07, 28, 0); //Set hours, minutes, seconds
rtc.setDate(06, 27, 2018) //Set day, month, year
*/
/*-------------Checking-if-we-can-access-the-SD-card---------*/
Serial.println("Initializing SD card..");
if (!SD.begin(ChipSelect))
{
Serial.println("SD card not detected");
return;
}
Serial.println("SD card initialized");
}
void loop()
{
t = RTC.getTime(); //Get "Time" from the RTC and store in "t"
int seconds = (t.sec); //Take only the seconds from RTC and copy to "seconds"
if (seconds % 5 == 0) //This is the interval timer.
//Seconds % 5 == 0 means if seconds divides by 5 with no remainder.
{
LCDtime(0,0); //Calls LCDtime to print time to the LCD
//The two variables specify cursor position
LCDanalogTemp(0,1); //Same as above, but for temperature
// Serial.println(TempString()); //Print temperature string
// Serial.println(TimeString()); //print current time
// Serial.println(SoilMoisture());
WriteSD(DataString()); //This calls WriteSD and passes it DataString by calling it directly.
delay(1000); //Wait until "seconds" is not divisible by 5
}
}
int SoilMoisture()
{
int Read = analogRead(SoilPin); //Read from soil sensor
Read = map(Read,1024,510,0,100); //Number drops as moisture increases.
//Calibrate the second number based on your local water
//by submerging the probe and taking the raw value.
if (Read > 100) //Jus in case the value goes slightly below 510, we wont get 102%
{
Read = 100;
}
return Read; //Return soil moisture as percent.
}
float DHTsensor(int i) //Returns data from an array
{
float DHumidity = dht.readHumidity();
float DTempF = dht.readTemperature(true); //The addition of "true" means we get fahrenheit
float DIndex = dht.computeHeatIndex(DTempF,DHumidity); //Calculate heat index from temp and humidity
float DHTdata[3] = {DHumidity, DTempF, DIndex}; //Put it all in the array
//Usage examples: Serial.print(DHTsensor(2)); or X = (DHTsensor(2));
return DHTdata[i];
}
void LCDanalogTemp (int X, int Y) //Sends LCD formatted temp to specified position on LCD
{
String temp = ("Temp: ");
String Degf = (" *F");
String line1 = temp + (AnalogTemp()) + Degf;
lcd.setCursor(X,Y);
lcd.print(line1);
Serial.print("Sent to LCD: ");Serial.println(line1);
return;
}
void LCDtime (int X, int Y) //Sends LCD formatted time to specified position on LCD
{
String Clock = ("Time: ");
String line1 = Clock + (RTC.getTimeStr());
lcd.setCursor(X,Y);
lcd.print(line1);
Serial.print("Sent to LCD: ");Serial.println(line1);
return;
}
void WriteSD(String SDcardData) //This function writes to the SD card
{
File LogDat = SD.open("log.csv",FILE_WRITE); //Assumes file already exists
if(LogDat)
{
Serial.println("Writing to SD");
LogDat.println(SDcardData);
LogDat.close();
}
}
String DataString() //This function builds the data string that will be written to the SD card.
{
float TF = AnalogTemp();
String TM = RTC.getTimeStr();
String CS = ","; //The character delimiter used in our CSV data file
String StringOut = (TM) + (CS) + (TF);
return StringOut;
}
String TimeString() //Returns only clock time as a string. Format "00:00:00" (8 characters)
{
String tm = RTC.getTimeStr(); //This will give Hour:minute:second
return tm;
}
String TempString() //To be used exclusively with AnalogTemp function
{
float Temp = AnalogTemp(); //Copy temperature data from function AnalogTemp
String TMP = "Temperature: ";
String F = (" *F");
String TempOut = (TMP) + (Temp) + (F); //Build the output string
return TempOut; //Return the built string to calling function
}
float AnalogTemp() //Use this function to get temperature from analog temp sensors
{
float volts, degC, degF, result; //Some floats that will be used to hold our data
volts = getVolts(TMP1); //Get voltage from the temp sensor
degC = (volts -0.5) * 100.0; //Convert voltage to degrees Celsius
degF = degC * (9.0/5.0) + 32; //Convert Celcius to Fahrenheit
result = degF; //Copy the floating point number in "degF" to "Temp"
return result; //Return "Temp" to the function that called it
}
float getVolts(int pin)
{
return (analogRead(pin)*0.004882814); //Calculates analog voltage from specified pin and converts to 0-5.
}