Introduction: Soil Water Level Status Using ESP8266

Hi friends, in this instructable we will learn to get the status of the water content of the soil in which the plant is growing. We will send an E-Mail which will display the water content in the soil. Here, we will be using the ESP8266-01, because it does not need any additional breakout boards or shields. Also, it is less expensive and very small in size. So lets start making the project !!!

Step 1: Materials Required -

1) ESP8266-01.

2) Soil moisture sensor.

3) FT232RL USB to UART breakout board.

4) Wires.

5) Mini USB cable.

6) A laptop with Arduino IDE pre-installed.

7) A G-Mail account.

Step 2: G-Mail Setup -

After you have created your own Gmail account, sign in and click on the small circle which shows your account's logo.

Now click on the button which shows My Account. A new page opens. Now click on Sign-In and Security and enable "Allow less secure apps" at the bottom of the page.

This mean apps only need your email and password when login to your gmail account.

If you are concerned about security, just use different account.

Step 3: The Schematic -


















Step 4: The Code -

The Setup -

1) For uploading the code, first you will have to include the json file to include the ESP boards in the boards section. For that, copy the following text (Select the text and click Ctrl + C), open the Arduino IDE and go to Files menu, click on preferences, go to Additional Boards Manager URLs and paste (Click on the white box and click Ctrl + V) the copied text and then click the OK button.

Now to check if the ESP boards are added, go to Tools menu, boards and then select the respective ESP board. Also select the correct port of the computer to which the FTDI Breakout Board is connected.

The Code -

Gsender.cpp and Gsender.h files are being used from the instructable - "ESP8266 G-Mail Sender" by Borya.

Open the Arduino IDE and copy the following code -

#include <ESP8266WiFi.h>
#include "Gsender.h"

#define dry 0 #define wet 1

boolean initialState = dry; boolean currentState = dry;

#pragma region Globals const char* ssid = ""; // WIFI network name const char* password = ""; // WIFI network password uint8_t connection_state = 0; // Connected to WIFI or not uint16_t reconnect_interval = 10000; // If not connected wait time to try again #pragma endregion Globals

uint8_t WiFiConnect(const char* nSSID = nullptr, const char* nPassword = nullptr) { static uint16_t attempt = 0; Serial.print("Connecting to "); if(nSSID) { WiFi.begin(nSSID, nPassword); Serial.println(nSSID); } else { WiFi.begin(ssid, password); Serial.println(ssid); }

uint8_t i = 0; while(WiFi.status()!= WL_CONNECTED && i++ < 50) { delay(200); Serial.print("."); } ++attempt; Serial.println(""); if(i == 51) { Serial.print("Connection: TIMEOUT on attempt: "); Serial.println(attempt); if(attempt % 2 == 0) Serial.println("Check if access point available or SSID and Password\r\n"); return false; } Serial.println("Connection: ESTABLISHED"); Serial.print("Got IP address: "); Serial.println(WiFi.localIP()); return true; }

void Awaits() { uint32_t ts = millis(); while(!connection_state) { delay(50); if(millis() > (ts + reconnect_interval) && !connection_state){ connection_state = WiFiConnect(); ts = millis(); } } }

void setup() { Serial.begin(115200); Serial.println("Reading"); connection_state = WiFiConnect(); if(!connection_state) // if not connected to WIFI Awaits(); // constantly trying to connect }

void loop(){ Gsender *gsender = Gsender::Instance(); // Getting pointer to class instance String subject = "Plant Status."; int analogValue = analogRead(2); delay(1000);

if(analogValue <= 300){ currentState = dry; } if((analogValue > 300) && (analogValue < 950)){ currentState = wet; }

if(currentState != initialState){ if((analogValue > 300) && (analogValue < 950)){ //Humid soil if(gsender->Subject(subject)->Send("***your e-mail address***", "Water content in the soil is appropriate. Plants are very happy.")) { Serial.println("Message send."); } else { Serial.print("Error sending message: "); Serial.println(gsender->getError()); } } if(analogValue <= 300) && (analogValue < 950)){ //Dry soil if(gsender->Subject(subject)->Send("***your e-mail address***", "Water content in the soil is very less. Plants are very unhappy.")) { Serial.println("Message send."); } else { Serial.print("Error sending message: "); Serial.println(gsender->getError()); } } } initialState = currentState; }

Now open a new tab by clicking on the downward pointing arrow in the right corner and selecting the New Tab option and give it a name as Gsender.cpp and paste the following code in that tab -

#include "Gsender.h"
Gsender* Gsender::_instance = 0; Gsender::Gsender(){} Gsender* Gsender::Instance() { if (_instance == 0) _instance = new Gsender; return _instance; }

Gsender* Gsender::Subject(const char* subject) { delete [] _subject; _subject = new char[strlen(subject)+1]; strcpy(_subject, subject); return _instance; } Gsender* Gsender::Subject(const String &subject) { return Subject(subject.c_str()); }

bool Gsender::AwaitSMTPResponse(WiFiClientSecure &client, const String &resp, uint16_t timeOut) { uint32_t ts = millis(); while (!client.available()) { if(millis() > (ts + timeOut)) { _error = "SMTP Response TIMEOUT!"; return false; } } _serverResponce = client.readStringUntil('\n'); #if defined(GS_SERIAL_LOG_1) || defined(GS_SERIAL_LOG_2) Serial.println(_serverResponce); #endif if (resp && _serverResponce.indexOf(resp) == -1) return false; return true; }

String Gsender::getLastResponce() { return _serverResponce; }

const char* Gsender::getError() { return _error; }

bool Gsender::Send(const String &to, const String &message) { WiFiClientSecure client; #if defined(GS_SERIAL_LOG_2) Serial.print("Connecting to :"); Serial.println(SMTP_SERVER); #endif if(!client.connect(SMTP_SERVER, SMTP_PORT)) { _error = "Could not connect to mail server"; return false; } if(!AwaitSMTPResponse(client, "220")) { _error = "Connection Error"; return false; }

#if defined(GS_SERIAL_LOG_2) Serial.println("HELO friend:"); #endif client.println("HELO friend"); if(!AwaitSMTPResponse(client, "250")){ _error = "identification error"; return false; }

#if defined(GS_SERIAL_LOG_2) Serial.println("AUTH LOGIN:"); #endif client.println("AUTH LOGIN"); AwaitSMTPResponse(client);

#if defined(GS_SERIAL_LOG_2) Serial.println("EMAILBASE64_LOGIN:"); #endif client.println(EMAILBASE64_LOGIN); AwaitSMTPResponse(client);

#if defined(GS_SERIAL_LOG_2) Serial.println("EMAILBASE64_PASSWORD:"); #endif client.println(EMAILBASE64_PASSWORD); if (!AwaitSMTPResponse(client, "235")) { _error = "SMTP AUTH error"; return false; } String mailFrom = "MAIL FROM: <" + String(FROM) + '>'; #if defined(GS_SERIAL_LOG_2) Serial.println(mailFrom); #endif client.println(mailFrom); AwaitSMTPResponse(client);

String rcpt = "RCPT TO: <" + to + '>'; #if defined(GS_SERIAL_LOG_2) Serial.println(rcpt); #endif client.println(rcpt); AwaitSMTPResponse(client);

#if defined(GS_SERIAL_LOG_2) Serial.println("DATA:"); #endif client.println("DATA"); if(!AwaitSMTPResponse(client, "354")) { _error = "SMTP DATA error"; return false; } client.println("From: <" + String(FROM) + '>'); client.println("To: <" + to + '>'); client.print("Subject: "); client.println(_subject); client.println("Mime-Version: 1.0"); client.println("Content-Type: text/html; charset=\"UTF-8\""); client.println("Content-Transfer-Encoding: 7bit"); client.println(); String body = " " + message + "

"; client.println(body); client.println("."); if (!AwaitSMTPResponse(client, "250")) { _error = "Sending message error"; return false; } client.println("QUIT"); if (!AwaitSMTPResponse(client, "221")) { _error = "SMTP QUIT error"; return false; } return true; }

Open another new tab and give it a name as Gsender.h and paste the following code in that tab -

#ifndef G_SENDER #define G_SENDER #define GS_SERIAL_LOG_1 // Print to Serial only server responce //#define GS_SERIAL_LOG_2 // Print to Serial client commands and server responce #include <WiFiClientSecure.h>

class Gsender { protected: Gsender(); private: const int SMTP_PORT = 465; const char* SMTP_SERVER = ""; const char* EMAILBASE64_LOGIN = ""; // E-Mail address converted into Base64 format const char* EMAILBASE64_PASSWORD = ""; // E-Mail address password converted into Base64 format const char* FROM = ""; // E-Mail address const char* _error = nullptr; char* _subject = nullptr; String _serverResponce; static Gsender* _instance; bool AwaitSMTPResponse(WiFiClientSecure &client, const String &resp = "", uint16_t timeOut = 10000);

public: static Gsender* Instance(); Gsender* Subject(const char* subject); Gsender* Subject(const String &subject); bool Send(const String &to, const String &message); String getLastResponce(); const char* getError(); }; #endif // G_SENDER

Now upload the code in the ESP8266. After uploading the code, disconnect the GPIO 0 pin connected to GND.

Step 5: Editing of the Code -

1) When you look at the main code, at the beginning of the code, fill up the spaces which are left blank to fill the WiFi network name and the password of the WiFi network.

2) When you scroll down the code and reach the end of the code, erase the area where it is written ***your e-mail address*** with your email address.

3) When you open the tab Gsender.h, erase the blank spaces at the beginning of the code and write your E-Mail address and E-Mail account password converted into Base64 format.

4) In the same tab, fill the " of const char* FROM = "; with your E-Mail address.

Step 6: The Installation -

First check the water content in the soil by uploading the following code -

void setup(){
void loop(){
  sensorValue = analogRead(2);

If the analog value shown in Serial monitor is below 300, supply water to the plants and continue supplying water till the range comes between 300 to 950. Once done, again upload the main code and insert the sensor in the soil.

Now whenever the water content in the soil decreases, you will get an E-Mail on your Gmail account. Ensure that wherever you have installed the system, there should be a continuous internet connection to which your ESP board is connected wirelessly.



ewoks made it!(author)2017-05-06

Not too many details, especially about hardware, schematic, step3 clarifications... pity, cause it can be nice project

soardr made it!(author)2017-05-06

Thanks for your comment, but I have given all the required details that are needed to build the project. Still I have verified the connections as given. If still you can find any mistakes, then please comment the mistakes.

TomcatS1 made it!(author)2017-05-06
TomcatS1 made it!(author)2017-05-06

Resistance as soil moisture
The type of sensor we are building in this module is a resistive sensor.The resistive type of moisture sensor is the most crude.
It uses the two probes to pass current through the soil, and then we
read that resistance to get the moisture level. More water makes the
soil conduct electricity more easily (less resistance), while dry soil
conducts electricity more poorly (more resistance).

One problem with resistive sensors is that the resistance of a material changes
with temperature. So when the sun beats on the soil and the soil warms
up, the resistance changes. This will produce a false "dry" read. For
this reason, we employ the soil temperature sensor
so GardenBot can use that data to warp the soil moisture to remove the
false reading -- i.e. on the chart, the line looks straight.

One other problem we encounter is due to our use of Direct Current.
The problem is that if you have DC current (constantly flowing
electricity in one direction) going between two pieces of metal (like
the exposed probe tips) then etching will take place. This process is
called electrolysis,
and it is bad for the probes -- it means that they will be eaten away
slowly by the action of the electricity. We solve this by only turning
the current on when we want to take a reading. Look at staged processing on the brain module page.

By the way, electro-etching can be a very cool effect, if you need
it. It can be used to do metal etching for a variety of purposes
(artistic or otherwise).

diy_bloke made it!(author)2017-05-06

Several errors pop up in your code.
at my end the library is caleld ESP8266WiFi.h rather than 'ESP8266Wifi.h'

Also your bodystring gives an error (missing terminator). I will probably figure it out but you may want to check your code

diy_bloke made it!(author)2017-05-06

ah yes, I see, there is an error in your Gsend.h since you have chosen to just paste it as code...... always gets screwed up by websites when you use fishhooks

soardr made it!(author)2017-05-06

I have uploaded the correct code. The recent code is properly working.

diy_bloke made it!(author)2017-05-06

tnx. Had fixed it already. Alwas a problem with those pesky fish hooks

diy_bloke made it!(author)2017-05-06

Step 5 suggests you have to change the

**** Your E-mail Account name*****

in the ino code, but in fact it is in the '.h' code

Borya made it!(author)2017-04-30

You are using content and code from my Instructable

without mentioning it.

soardr made it!(author)2017-04-30

Thanks for mentioning. I had used part of your content and code thinking they are third party(gmail) content and code(standard library). However I will be removing it from my instructable immediately and replacing parts of my code and content with my own.