Mali (माली) is a Hindi word, commonly used for the person who makes and maintains garden.
Have you tried kitchen gardening but given up after initial confusion and failures? Are you too busy to take care of your plants? Want to go on vacation but fear the worst for your indoor garden?
Having green spaces in our homes the key to maintaining a happy and healthy lifestyle. Plants and flowers demand attention and delicate conditions to be healthy and look beautiful.
Growing plants is a very pleasant experience. But our pace of life gives us little chance to keep the exact rhythm of watering the plants according to their needs. With how busy our lives are, it's sometimes easy to forget to pay a little attention to your thirsty indoor plants until it's too late and you are left with a crusty pile of yellow carcasses. The main reasons for dying plants are over- and under-watering, temperature and light issues. That’s probably happening because plants can’t talk and express directly what they need. They may need very careful and accurate watering. Some of them need more light and some need less. Air temperature and humidity are also highly important.
SmartMali is a smart plant pot that has sensors to detect sunlight, soil moisture, air temperature and humidity. These are the most critical 'vitals' that indicate a plant's well being - does it have enough sunlight, water? They will send you these values on your mobile app and based on that you can take appropriate actions. Using this specialized sensors, it automatically waters and monitors your plants in real time. It is connected to the internet with SparkFun ESP8266 Thing Dev Board.
You never have to worry about dead plants again. This automated smart pot will take care of watering your plants and provide artificial sunlight. The pot has a motor and a reservoir, which you can fill with water once in a while.
Goals for the project:-- Automatically water your plants
- Monitor plant vitals in real time
- Switch ON the grow light when needed
- Upto atleast a month of watering
- App based control on watering. So when you press the 'water' button on your app, it sends the signal to the smart pot, which actuates a motor in it.
- Monitor the level of water in the reservoir
- Timer/Schedule based plant watering.
- ADS1115 ADC Module Interfacing
In this project we have two analog sensors (Light Dependent Resistor and Soil Moisture) to be interfaced with the ESP8266. But ESP8266 has only one 10-bit ADC which can read maximum voltage of 1V. So we are going to use an external ADC like ADS1115 for reading those sensors.
The ADS1115 is a 16 bit Analog Digital Converter that can greatly improve your micro-controller resolution and measurement accuracy. It has four input channels that can be configured for Single Ended, Differential or Comparator Measurements. For our project we have to just read the analog sensors so we are going to use two channels for single ended 16 bit measurement with the ADS1115.
ADS1115 Chip has a base of 7-Bit i2C Address of 0x48 (1001000) and i2c addressing that allow four different addresses using one address (ADR).
Though you see i told you ADS1115 is a 16-bit ADC but the output of the ADS1115 is a signed integer. That means one of the bits in the 16 bit words is going to be used to tell us if it’s a positive or negative value being reported. What this means is that there are 32,768 possible output values, where zero is the first and 32,767 is the last.
2^16 = 65,536. i.e. if the ADC used unsigned integer it would have been able to have 65,536 possible output values, where zero is the first and 65,535 is the last.
The value of a bit is determined by the Programmable Gain Amplifier (PGA) setting as is this setting establishes full scale.
In the default mode, the setting is +/-6.144 volts. Thus the value of 32767 would represent a value of 6.144 volts. Dividing 6.144 volts by 32767 yields a scale factor of 0.1875 mV per bit. The PGA setting of +/- 6.144 range can be a little misleading as it seems to infer that you can measure voltages that high. You can’t.
Instead, the maximum measurable voltage is established by the supply voltage to the chip. Specifically, the maximum measurable voltage is 0.3 volts more than the supply voltage. In fact, exceeding this voltage at your analog input may damage your chip. So that means if you provided VCC of 5V to ADS1115 and have set PGA setting of +/- 6.144 range still the maximum voltage you can apply at the analog input must not be greater than 5.3V (5 + 0.3) .
In our case though we are setting the PGA to +/- 4.096V as our sensors can maximum output 3.3V and not more than that. So that means we will get a scale factor of (4.096/32767) 0.125mV. i.e. 1 bit = 0.125mV.
For your info:-
ADS1115 has following PGA settings available ->
+/- 6.144V, +/- 4.096V, +/- 2.048V, +/- 1.024V, +/- 0.512V, +/- 0.256V
Here is the example code for interfacing ADS1115 with ESP8266:-
{Adafruit ADS1015 library works with ADS1115 too :) }
#include <Wire.h>
#include <Adafruit_ADS1015.h>
Adafruit_ADS1115 ads; /* Use this for the 16-bit version */
void setup(void)
{
Serial.begin(9600);
Serial.println("");
Serial.println("");
Serial.println("Smart Mali Project v1.0 !!");
Serial.println("Getting single-ended readings from AIN0..3");
Serial.println("ADC Range: +/- 4.096V (1 bit = 2mV/ADS1015, 0.125mV/ADS1115)");
// ADS1015 ADS1115
// ------- -------
// ads.setGain(GAIN_TWOTHIRDS); // 2/3x gain +/- 6.144V 1 bit = 3mV 0.1875mV
ads.setGain(GAIN_ONE); // 1x gain +/- 4.096V 1 bit = 2mV 0.125mV
// ads.setGain(GAIN_TWO); // 2x gain +/- 2.048V 1 bit = 1mV 0.0625mV
// ads.setGain(GAIN_FOUR); // 4x gain +/- 1.024V 1 bit = 0.5mV 0.03125mV
// ads.setGain(GAIN_EIGHT); // 8x gain +/- 0.512V 1 bit = 0.25mV 0.015625mV
//ads.setGain(GAIN_SIXTEEN); // 16x gain +/- 0.256V 1 bit = 0.125mV 0.0078125mV
ads.begin();
}
void loop(void)
{
int16_t adc0, adc1, adc2, adc3;
adc0 = ads.readADC_SingleEnded(0);
adc1 = ads.readADC_SingleEnded(1);
adc2 = ads.readADC_SingleEnded(2);
adc3 = ads.readADC_SingleEnded(3);
Serial.print("AIN0: "); Serial.print(adc0);
float voltage0 = (adc0 * 0.125)/1000;
Serial.print("\tVoltage0: "); Serial.println(voltage0, 6);
Serial.print("AIN1: "); Serial.print(adc1);
float voltage1 = (adc1 * 0.125)/1000;
Serial.print("\tVoltage1: "); Serial.println(voltage1, 6);
Serial.print("AIN2: "); Serial.print(adc2);
float voltage2 = (adc2 * 0.125)/1000;
Serial.print("\tVoltage2: "); Serial.println(voltage2, 6);
Serial.print("AIN3: "); Serial.print(adc3);
float voltage3 = (adc3 * 0.125)/1000;
Serial.print("\tVoltage3: "); Serial.println(voltage3, 6);
Serial.println(" ");
delay(1000);
}
- Light Dependent Resistor (LDR) and Soil Moisture Sensor Interfacing
LDR is connected to via voltage divider with A0 of ADS1115 ADC module. While Soil Moisture sensor is connected to A3 of ADS1115 ADC module.
A photoresistor or LDR is a component that is sensitive to light. When light falls upon it then the resistance changes. Values of the resistance of the LDR may change over many orders of magnitude the value of the resistance falling as the level of light increases.It is not uncommon for the values of resistance of an LDR or photoresistor to be several Megaohms in darkness and then to fall to a few hundred ohms in bright light.
The soil moisture sensor is a simple breakout for measuring the moisture in soil and similar materials. The soil moisture sensor is pretty straight forward to use. The two large exposed pads function as probes for the sensor, together acting as a variable resistor. The more water that is in the soil means the better the conductivity between the pads will be and will result in a lower resistance, and a higher SIG out. To get the Soil Moisture Sensor functioning all you will need is to connect the VCC and GND pins to ESP8266 Thing Dev board, you will receive a SIG out which will depend on the amount of water in the soil. One commonly known issue with soil moisture senors is their short lifespan when exposed to a moist environment.
Code for Interfacing LDR and Soil Moisture Sensor:-
/*
* ADS1115 uses I2C for communication
* Also we need Adafruit ADS1115 library for reading the analog pins of ADS1115
*/
#include <Wire.h>
#include <Adafruit_ADS1015.h>
Adafruit_ADS1115 ads; /* Use this for the 16-bit version */
void setup()
{
Serial.begin(9600); //Serial UART Baudrate
Serial.println("");
Serial.println("*************************************************************************************************");
Serial.println("Smart Mali Project v1.0 !!");
Serial.println("Getting single-ended readings from AIN0..3");
Serial.println("ADC Range: +/- 4.096V (1 bit = 2mV/ADS1015, 0.125mV/ADS1115)");
ads.setGain(GAIN_ONE); // 1x gain +/- 4.096V 1 bit = 0.125mV
ads.begin();
Serial.println("*************************************************************************************************");
Serial.println("");
}
void loop()
{
long val = 0;
int light_level = 0, soilMoisture_level = 0;
/*
* Averaging the LDR analog values
*/
for (int number = 0; number < 10; number++)
{
light_level = ads.readADC_SingleEnded(0);
val = val + light_level;
delay(100);
}
Serial.print("LDR Average Value: ");
light_level = val/10;
Serial.print(light_level);
float voltage0 = (light_level * 0.125)/1000;
Serial.print("\t LDR Voltage Output: ");
Serial.println(voltage0, 6);
val = 0;
/*
* Averaging the Soil Moisture analog values
*/
for (int number = 0; number < 10; number++)
{
soilMoisture_level = ads.readADC_SingleEnded(3);
val = val + soilMoisture_level;
delay(100);
}
Serial.print("Soil Moisture Average Value: ");
soilMoisture_level = val/10;
Serial.print(soilMoisture_level);
float voltage3 = (soilMoisture_level * 0.125)/1000;
Serial.print("\t Soil Moisture Voltage Output: ");
Serial.println(voltage3, 6);
Serial.println("*************************************************************************************************");
Serial.println("");
delay(10000);
}
Output in Arduino IDE Serial Monitor (Snapshot):-
Code for storing LDR and Soil Moisture Sensor threshold values in the ESP8266 EEPROM:-
/*
* ADS1115 uses I2C for communication
* Also we need Adafruit ADS1115 library for reading the analog pins of ADS1115
* In ESP8266 EEPROM library uses one sector of flash located just after the SPIFFS.
*/
#include <Wire.h>
#include <Adafruit_ADS1015.h>
#include <EEPROM.h>
/*
* The current address in the EEPROM (i.e. which byte we're going to write to next)
* at address 0 we are going to write light level (LDR) threshold
* at address 20 we are going to write soil moisture sensor threshold
*/
const int ldr_addr = 0;
const int moisture_addr = 20;
Adafruit_ADS1115 ads; /* Use this for the 16-bit version */
/*
* This function reads an integer value in the EEPROM memory
*/
int eepromReadInt(int address){
int value = 0x0000;
value = value | (EEPROM.read(address) << 8);
value = value | EEPROM.read(address+1);
return value;
}
/*
* This function writes an integer value in the EEPROM memory
*/
void eepromWriteInt(int address, int value){
EEPROM.write(address, (value >> 8) & 0xFF );
EEPROM.write(address+1, value & 0xFF);
/*
* EEPROM.write does not write to flash immediately,
* instead you must call EEPROM.commit()
* whenever you wish to save changes to flash.
*/
EEPROM.commit();
}
void setup()
{
Serial.begin(9600); //Serial UART Baudrate
/*
* You need to call EEPROM.begin(size) before you start reading or writing,
* size being the number of bytes you want to use.
* Size can be anywhere between 4 and 4096 bytes.
*/
EEPROM.begin(512);
Serial.println("");
Serial.println("*************************************************************************************************");
Serial.println("Smart Mali Project v1.0 !!");
Serial.println("Getting single-ended readings from AIN0..3");
Serial.println("ADC Range: +/- 4.096V (1 bit = 2mV/ADS1015, 0.125mV/ADS1115)");
ads.setGain(GAIN_ONE); // 1x gain +/- 4.096V 1 bit = 0.125mV
ads.begin();
Serial.println("*************************************************************************************************");
Serial.println("");
}
void loop()
{
long val = 0;
int light_level = 0, soilMoisture_level = 0;
/*
* Averaging the LDR analog values
*/
for (int number = 0; number < 10; number++)
{
light_level = ads.readADC_SingleEnded(0);
val = val + light_level;
delay(100);
}
Serial.print("LDR Average Value: ");
light_level = val/10;
Serial.println(light_level);
/*
* write the value to the appropriate byte of the EEPROM.
* these values will remain there even when the board is turned off.
*/
eepromWriteInt(ldr_addr, light_level);
val = 0;
/*
* Averaging the Soil Moisture analog values
*/
for (int number = 0; number < 10; number++)
{
soilMoisture_level = ads.readADC_SingleEnded(3);
val = val + soilMoisture_level;
delay(100);
}
Serial.print("Soil Moisture Average Value: ");
soilMoisture_level = val/10;
Serial.println(soilMoisture_level);
/*
* write the value to the appropriate byte of the EEPROM.
* these values will remain there even when the board is turned off.
*/
eepromWriteInt(moisture_addr, soilMoisture_level);
int data = eepromReadInt(ldr_addr);
Serial.print("LDR Data EEPROM Read: ");
Serial.println(data);
data = eepromReadInt(moisture_addr);
Serial.print("Soil Moisture Data EEPROM Read: ");
Serial.println(data);
Serial.println(" ");
Serial.println("*************************************************************************************************");
Serial.println("");
delay(10000);
}
Output in Arduino IDE Serial Monitor (Snapshot):-
- Ultrasonic Sensor Interfacing
This economical sensor provides 2cm to 400cm of non-contact measurement functionality with a ranging accuracy that can reach up to 3mm. Each HC-SR04 module includes an ultrasonic transmitter, a receiver and a control circuit.
There are only four pins that you need to worry about on the HC-SR04: VCC (Power - 5V), Trig (Trigger), Echo (Receive), and GND (Ground).
If you are wondering why i have used an ultrasonic sensor in this project because for two things:-
1) I need to know how much amount of water my plant consumes and also how much amount of water is remaining before the water reservoir needs to be refilled.
2) Also because i can't just dry run my R385 High Lift Water Pump, the pump will get damaged. So what i will do if the water level is below the threshold the pump will not start. In my case i have set the threshold as 10mm since the water pipe i have used for the pump is of 6mm.
Note:- I know this HC SR-04 is not water proof but since it was lying around i used it. But let me know which sensor would be better to use in this scenario. The sensors needs to be cheap and accurate atleast in mm range. Also the reservoir i have used in this project is almost cylindrical and of height 9cm and radius 8.5cm. So the sensor also needs to be small and it should have a atleast measurement range of 0 to 20cm.
Code for Interfacing Ultrasonic Sensor with ESP8266:
const int trigPin = 12; //ESP8266 GPIO 12 Connected to Trig pin of HC SR04
const int echoPin = 13; //ESP8266 GPIO 13 Connected to Echo pin of HC SR04
void setup() {
// initialize serial communication:
Serial.begin(9600);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
Serial.println("");
Serial.println("****HCSR04 Ultrasonic demo****\n");
}
void loop()
{
/*
* establish variables for duration of the ping,
* and the distance result in centimeters:
*/
long duration, cm;
/*
* The sensor is triggered by a HIGH pulse of 10 or more microseconds.
* Give a short LOW pulse beforehand to ensure a clean HIGH pulse
*/
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
/*
* Read the signal from the sensor: a HIGH pulse whose
* duration is the time (in microseconds) from the sending
* of the ping to the reception of its echo off of an object.
*/
duration = pulseIn(echoPin, HIGH);
// convert the time into a distance
cm = microsecondsToCentimeters(duration);
Serial.print("Distance:- ");
Serial.print(cm);
Serial.print("cm");
Serial.println();
delay(5000);
}
long microsecondsToCentimeters(long microseconds)
{
/********************************************Ultrasonic sensors******************************************************
Speed of sound = 340 m/s
Now, 1 metre = 100 centimetre and 1 seconds = 1000000 microseconds
Speed of sound = 340 * 100 cm/(1000000 microseconds) = 0.034 cm per us = (1/29.412) cm per us is approx. (1/29) cm per us
The Ultrasonic burst travels out & back.So to find the distance of the object we have to divide the time the echo pin was high by 2
Distance = (Time echo pin was high/2) * speed of sound
= (Time echo pin was high/2) * (1/29)
*********************************************************************************************************************/
return microseconds / 29 / 2;
}
Output in Arduino IDE Serial Monitor (Snapshot):-
- Temperature and Humidity Sensor Interfacing
This is a multifunctional sensor that gives you temperature and relative humidity information at the same time. It utilizes a TH02 sensor that can meet measurement needs of general purposes. It provides reliable readings when environment humidity condition inbetween 0-80% RH, and temperature condition inbetween 0-70°C, covering needs in most home and daily applications that don't contain extreme conditions.
This sensor was added to let us know whether e area where the plant has been placed is decent enough for the plant to survive. Also, in future i will use some mist nozzles and a fan to control the temperature and humidity around the plant.
Code for interfacing the Temperature and Humidity sensor with ESP8266:
/*
* TH02 is a digital Temperature and Humidity sensor that uses I2C for communication
* Also we need Seeedstudio TH02 library for reading this sensor
* Grove – Temperature & Humidity Sensor (High-Accuracy &Mini) –
* https://github.com/Seeed-Studio/Grove_Temper_Humidity_TH02
*/
#include <TH02_dev.h>
#include "Arduino.h"
#include "Wire.h"
void setup()
{
Serial.begin(9600); // start serial for output at 9600 baudrate
Serial.println("");
Serial.println("****TH02_dev demo by seeed studio****\n");
/* Power up,delay 150ms,until voltage is stable */
delay(150);
/* Reset HP20x_dev */
TH02.begin();
delay(100);
/* Determine TH02_dev is available or not */
int TH02_available = TH02.isAvailable();
Serial.print("TH02 Available or not:- ");
Serial.println(TH02_available);
if (TH02_available == 0)
{
Serial.println("TH02_dev is available.\n");
}
else
{
Serial.println("TH02_dev is not available.\n");
}
}
void loop()
{
float temper = TH02.ReadTemperature();
Serial.println("Temperature: ");
Serial.print(temper);
Serial.println("C\r\n");
float humidity = TH02.ReadHumidity();
Serial.println("Humidity: ");
Serial.print(humidity);
Serial.println("%\r\n");
delay(5000);
}
Output in Arduino IDE Serial Monitor (Snapshot):-
- STP55NF06 MOSFET's for controlling Water Pump and LED Grow Light
This is a N-channel 60 V, 0.015 Ω, 50 A Power MOSFET. It is suitable for use as primary switch in advanced high-efficiency isolated DC-DC converters for telecom and computer applications, and applications with low gate charge driving requirements.
Or you can also use 5V Relay Module with Optocoupler Isolation.
Code for controlling Water Pump and LED Grow Light using MOSFET:-
int mosfet1 = 5; //ESP8266 GPIO5 Connected to motor (water pump)
int mosfet2 = 4; //ESP8266 GPIO4 Connected to led grow light
void setup()
{
pinMode(mosfet1, OUTPUT); // Initialize the mosfet1 pin as an output
pinMode(mosfet2, OUTPUT); // Initialize the mosfet2 pin as an output
/*
* The MOSFET circuit designed is Active low
* Means if we provide LOW voltage to mosfet1 or mosfet2 it will turn ON
*/
digitalWrite(mosfet1, HIGH); // Turn the mosfet1 OFF
digitalWrite(mosfet2, HIGH); // Turn the mosfet2 OFF
}
// the loop function runs over and over again forever
void loop()
{
digitalWrite(mosfet1, LOW); // Turn the mosfet1 ON
digitalWrite(mosfet2, LOW); // Turn the mosfet2 ON
delay(2000); // Wait for two second
digitalWrite(mosfet1, HIGH); // Turn the mosfet1 OFF
digitalWrite(mosfet2, HIGH); // Turn the mosfet2 OFF
delay(2000); // Wait for two second
}
Code for controlling Water Pump and LED Grow Light using Relays:-
int relayPin1 = 5; //
int relayPin2 = 4; /
void setup()
{
pinMode(relayPin1, OUTPUT); // Initialize the Relay1 pin as an output
pinMode(relayPin2, OUTPUT); // Initialize the Relay2 pin as an output
}
// the loop function runs over and over again forever
void loop()
{
digitalWrite(relayPin1, LOW); // Turn the Relay1 ON
digitalWrite(relayPin2, LOW); // Turn the Relay2 ON
delay(1000); // Wait for a second
digitalWrite(relayPin1, HIGH); // Turn the Relay1 OFF
digitalWrite(relayPin2, HIGH); // Turn the Relay2 OFF
delay(1000); // Wait for a second
}
Relays are not a great solution for controlling a DC Motor and a DC LED Grow Light. It would be better to use a MOSFET for this job.
STP55NF06 MOSFET i used (was lying around in my components box) was not triggering directly by the GPIO's 3.3V but were working fine with gate voltage more than 4V. So i used 2N2222 transistors as a switch to trigger the MOSFET's.
A good example would be using the below MOSFET:
The NDP6020P is a very common MOSFET with very low on-resistance and a control voltage (aka gate voltage) that is compatible with most 5V and 3.3v micro-controller. This allows you to control high-power devices with very low-power control mechanisms.
- 7805 voltage regulator for ESP8266 Thing Dev Board
7805 IC provides fixed +5 volts regulated power supply with provisions to add heat sink as well. 7805 is not very efficient and has drop out voltage problems. The difference between the input and output voltage appears as heat. A lot of energy is wasted in the form of heat. If you are going to use 7805 then you need to be using a heat sink too.
Heat generated = (input voltage – 5) x output current
If we have a system with input 15 volts and output current required is .5 amperes, we have: (15 – 5) x 0.5 = 10×0.5 =5W;
5W energy is being wasted as heat, hence a decent sized heatsink plate is required to disperse this heat. On the other hand, energy actually being used is:
(5 x 0.5Amp) = 2.5W.
So twice the energy, that is actually utilized is wasted. On the other hand, if 9V is given as input at the same amount of load:
(9-5) x 0.5 = 2W
2W energy will be wasted as heat. So Higher the input voltage, less efficient your 7805 will be.
An estimated efficient input voltage would be over 7.5V. Now in our case since we need 12 volt to drive water pump motor as well as LED grow light we will be using the same to power our ESP8266 Thing Dev Board by step down the 12 volt to 5 volt using 7805. Also, it's cheap and was lying around in my electronic components kit.
Before programming the ESP8266 Thing Dev Board by Sparkfun you will need to install ESP8266 addon for the Arduino IDE.
The following tutorials are great as guide to start working with ESP8266 Thing Dev Board:-
ESP8266 Thing Development Board Hookup Guide
Some Example Sketches for getting started!
Cloud Connection:-In this project i am not using an event currently. I was going to use it to schedule the LED Grow Light time period i.e i want the LED grow light to b switched ON between a specific period which is between 6am to 8pm. So the plant can get a proper sleep between 8pm to 6am. And as we have added a LDR the LED grow light will be switched ON between 6am to 8pm only when the light level is detected low.
Controlling MOSFET's via Cayenne Platform:-
The below will help you to control the relays via the Cayenne platform or Cayenne Mobile App.
/*
*
* Make sure you install the ESP8266 Board Package via the Arduino IDE Board Manager
* and select the correct ESP8266 board before compiling.
* Also make sure all the required libraries are installed before compiling this code
* ADS1115 uses I2C for communication
* Also we need Adafruit ADS1115 library for reading the analog pins of ADS1115
* TH02 is a digital Temperature and Humidity sensor that uses I2C for communication
* Also we need Seeedstudio TH02 library for reading this sensor
* Grove – Temperature & Humidity Sensor (High-Accuracy &Mini) –
* https://github.com/Seeed-Studio/Grove_Temper_Humidity_TH02
* In ESP8266 EEPROM library uses one sector of flash located just after the SPIFFS.
*/
//#define CAYENNE_DEBUG
#define CAYENNE_PRINT Serial
#include <CayenneMQTTESP8266.h>
#include <ESP8266WiFi.h>
#include <Wire.h>
#include <Adafruit_ADS1015.h>
#include <TH02_dev.h>
#include "Arduino.h"
#include <EEPROM.h>
Adafruit_ADS1115 ads; /* Use this for the 16-bit version */
// WiFi network info.
char ssid[] = "Litasddfgchgdart"; //Add your home wifi network ssid
char wifiPassword[] = "Au23ftfdgdfg11"; //Add wifi password
// Cayenne authentication info. This should be obtained from the Cayenne Dashboard.
char username[] = "9c5e0-retrtrr-65c9-f526"; //Add your username
char password[] = "98b38f9dfgdfgdfgdfgc3fd9819be59ddc03c8e"; //Add your password
char clientID[] = "1ccd5ccxgdfgdfgfgff3788e"; //Add your clientID
unsigned long lastMillis = 0;
//GPIO Connections
const int trigPin = 12;
const int echoPin = 13;
const int mosfet1 = 5; //ESP8266 GPIO5 Connected to motor (water pump)
const int mosfet2 = 4; //ESP8266 GPIO4 Connected to led grow light
/*
* The current address in the EEPROM (i.e. which byte we're going to write to next)
* at address 0 we are going to write light level (LDR) threshold
* at address 20 we are going to write soil moisture sensor threshold
*/
//Variables for LDR light level data storage
int lightLevel = 0;
int ldr_addr = 0;
//Variables for soil moisture level data storage
int moistureLevel = 0;
int moisture_addr = 20;
//Variables for water level data storage
int waterLevelcm = 0;
int waterContainerHeight = 90; //in cm water reservoir container's total height
int waterLevelmin = 10;
int motorONTime = 1000; //Motor (Water Pump) will be ON for this amount of time
//Variables for Temperature and Humidity data storage
float temperature = 0;
float humidity = 0;
//WiFi Variables
long wifiRSSI = 0;
/*
* Publish data every 30 seconds (30000 milliseconds).
* Change this value to publish at a different interval.
*/
int uploadInterval = 30000; //in milliseconds
/*
* This function reads an integer value in the EEPROM memory
*/
int eepromReadInt(int address){
int value = 0x0000;
value = value | (EEPROM.read(address) << 8);
value = value | EEPROM.read(address+1);
return value;
}
/*
* This function writes an integer value in the EEPROM memory
*/
void eepromWriteInt(int address, int value){
EEPROM.write(address, (value >> 8) & 0xFF );
EEPROM.write(address+1, value & 0xFF);
/*
* EEPROM.write does not write to flash immediately,
* instead you must call EEPROM.commit()
* whenever you wish to save changes to flash.
*/
EEPROM.commit();
}
void setup() {
//configure GPIO pins as input/output
pinMode(mosfet1, OUTPUT); // Initialize the mosfet1 pin as an output
pinMode(mosfet2, OUTPUT); // Initialize the mosfet2 pin as an output
/*
* The MOSFET circuit designed is Active low
* Means if we provide LOW voltage to mosfet1 or mosfet2 it will turn ON
*/
digitalWrite(mosfet1, HIGH); // Turn the mosfet1 OFF
digitalWrite(mosfet2, HIGH); // Turn the mosfet2 OFF
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
/*
* You need to call EEPROM.begin(size) before you start reading or writing,
* size being the number of bytes you want to use.
* Size can be anywhere between 4 and 4096 bytes.
*/
EEPROM.begin(512); // Initlize EEPROM with 512 Bytes
Serial.begin(9600);
/*
* Power up,delay 150ms,until voltage is stable
*/
delay(150);
Serial.println("");
Serial.println(" ");
Serial.println("------------------------------------------------------------------------ ");
Serial.println("Smart Mali Project - A Smart Plant Pot!");
ads.setGain(GAIN_ONE); // 1x gain +/- 4.096V 1 bit = 0.125mV
ads.begin();
/* Reset HP20x_dev */
TH02.begin();
delay(100);
/* Determine TH02_dev is available or not */
int TH02_available = TH02.isAvailable();
Serial.print("TH02 Available or not:- ");
Serial.println(TH02_available);
if (TH02_available == 0)
{
Serial.println("TH02_dev is available.\n");
}
else
{
Serial.println("TH02_dev is not available.\n");
}
delay(1000); // Wait for a second
Cayenne.begin(username, password, clientID, ssid, wifiPassword);
Serial.println(" ");
Serial.println("------------------------------------------------------------------------ ");
}
void loop() {
Cayenne.loop();
}
long microsecondsToCentimeters(long microseconds)
{
/*
* The speed of sound is 340 m/s or 29 microseconds per centimeter.
* The ping travels out and back, so to find the distance of the
* object we take half of the distance travelled.
*/
/********************************************Ultrasonic sensors******************************************************
Speed of sound = 340 m/s
Now, 1 metre = 100 centimetre and 1 seconds = 1000000 microseconds
Speed of sound = 340 * 100 cm/(1000000 microseconds) = 0.034 cm per us = (1/29.412) cm per us is approx. (1/29) cm per us
The Ultrasonic burst travels out & back.So to find the distance of the object we have to divide the time the echo pin was high by 2
Distance = (Time echo pin was high/2) * speed of sound
= (Time echo pin was high/2) * (1/29)
*********************************************************************************************************************/
return microseconds / 29 / 2;
}
CAYENNE_IN(8)
{
CAYENNE_LOG("CAYENNE_IN_DEFAULT(%u) - %s, %s", request.channel, getValue.getId(), getValue.asString());
/*
* Process message here.
* If there is an error set an error message
* using getValue.setError(), e.g getValue.setError("Error message");
*/
Serial.print("Data Received:-= ");
Serial.println(getValue.asInt());
int data = getValue.asInt();
/*
* The ultrasonic sensor is triggered by a HIGH pulse of 10 or more microseconds.
* Give a short LOW pulse beforehand to ensure a clean HIGH pulse
*/
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
/*
* Read the signal from the sensor: a HIGH pulse whose
* duration is the time (in microseconds) from the sending
* of the ping to the reception of its echo off of an object.
*/
long duration = pulseIn(echoPin, HIGH);
waterLevelcm = waterContainerHeight - int(microsecondsToCentimeters(duration));
Serial.print("Water Level: ");
Serial.println(waterLevelcm);
if ((data == 1) && (waterLevelcm > waterLevelmin))
{
digitalWrite(mosfet1, LOW); // Turn the Relay1 ON
Serial.println("Motor (Water Pump) is turned ON");
Cayenne.virtualWrite(12, 11);
}
else
{
digitalWrite(mosfet1, HIGH); // Turn the Relay1 OFF
Serial.println("Motor (Water Pump) is turned OFF");
Cayenne.virtualWrite(12, 10);
}
}
CAYENNE_IN(9)
{
CAYENNE_LOG("CAYENNE_IN_DEFAULT(%u) - %s, %s", request.channel, getValue.getId(), getValue.asString());
/*
* Process message here.
* If there is an error set an error message
* using getValue.setError(), e.g getValue.setError("Error message");
*/
Serial.print("Data Received:-= ");
Serial.println(getValue.asInt());
int data = getValue.asInt();
if (data == 1)
{
digitalWrite(mosfet2, LOW); // Turn the Relay2 ON
Serial.println("LED GROW LIGHT is turned ON");
Cayenne.virtualWrite(12, 21);
}
else
{
digitalWrite(mosfet2, HIGH); // Turn the Relay2 OFF
Serial.println("LED GROW LIGHT is turned OFF");
Cayenne.virtualWrite(12, 20);
}
}
CAYENNE_IN(10)
{
CAYENNE_LOG("CAYENNE_IN_DEFAULT(%u) - %s, %s", request.channel, getValue.getId(), getValue.asString());
/*
* Process message here.
* If there is an error set an error message
* using getValue.setError(), e.g getValue.setError("Error message");
*/
Serial.print("Data Received:-= ");
Serial.println(getValue.asInt());
int data = 0;
data = getValue.asInt();
if (data == 1)
{
Serial.println("Starting the LDR sampling");
Cayenne.virtualWrite(12, 31);
long val = 0;
for (int number = 0; number < 10; number++)
{
lightLevel = ads.readADC_SingleEnded(0);
val = val + lightLevel;
delay(100);
}
lightLevel = val/10;
/*
* We are doing LDR sampling and then averaging the value
* Then this averaged value will act as the LDR threshold below
* which if Light level falls we will swiitch ON the LED grow light.
* For executing this you just have to press LDR Sample Start button
* on the mobile app or Cayenne Dashboard
* write the value to the appropriate byte of the EEPROM.
* This value will remain there even when the board is turned off.
*/
eepromWriteInt(ldr_addr, lightLevel);
}
}
CAYENNE_IN(11)
{
CAYENNE_LOG("CAYENNE_IN_DEFAULT(%u) - %s, %s", request.channel, getValue.getId(), getValue.asString());
/*
* Process message here.
* If there is an error set an error message
* using getValue.setError(), e.g getValue.setError("Error message");
*/
Serial.print("Data Received:-= ");
Serial.println(getValue.asInt());
int data = 0;
data = getValue.asInt();
if (data == 1)
{
Serial.println("Starting the Soil Moisture sampling");
Cayenne.virtualWrite(12, 41);
long val = 0;
for (int number = 0; number < 10; number++)
{
moistureLevel = ads.readADC_SingleEnded(3);
val = val + moistureLevel;
delay(100);
}
moistureLevel = val/10;
/*
* We are doing soil moisture sampling and then averaging the value
* Then this averaged value will act as the soil moisture threshold below
* which if soil moisture level falls we will swiitch ON the Motor (water pump).
* For executing this you just have to press Soil Moisture Sampling button
* on the mobile app or Cayenne Dashboard
* write the value to the appropriate byte of the EEPROM.
* This value will remain there even when the board is turned off.
*/
eepromWriteInt(moisture_addr, moistureLevel);
}
}
Thank you for reading and comment below if you have any suggestions or doubt!
Comments