Hello all...
In this project I am going to discuss ,how to build a Smart irrigation Project using Raspberry Pi
Smart Irrigation system essentially means to measure the water content in the soil continuously and with the help of a Soil Moisture sensor,
(The Soil Moisture Sensor is used to measure the volumetric water content of soil. This makes it ideal for performing experiments in courses such as soil science, agricultural science, environmental science, horticulture, botany, and biology.)
This Project has 2 modes Automatic as well as manual,In Automatic mode after comparing with a threshold if the soil moisture is less ,it will turn ON a solenoid valve,for watering and vice versa.In Manual mode the user has the right to turn ON/OFF voluntarily.Semaphores concept in Linux OS is used in this project in order to avoid the overlapping of Manual and Auto modes .In this project i have also maintained a log file to monitor the activity of my project.(Time of ON/OFF,Status and the Mode).The time and date fetched using ctime() function .A solenoid valve is also connected in order to control the flow of water.All these components are connected to a Raspberry pi .
This is how the log looks like,
Use the Soil Moisture Sensor to:
• Measure the loss of moisture over time due to evaporation and plant uptake.
• Evaluate optimum soil moisture contents for various species of plants.
• Monitor soil moisture content to control irrigation in greenhouses.
• Enhance your Bottle Biology experiments.
How to use the Soil Moisture Sensor
The prongs should be oriented horizontally, but rotated onto their side – like a knife poised to cut food – so that water does not pool on the flat surface of the prongs. The horizontal orientation of the sensor ensures the measurement is made at a particular soil depth. The entire sensor can be placed vertically, but because soil moisture often varies by depth, this is not usually the desired orientation. To position the sensor, use a thin implement such as a trenching shovel to make a pilot hole in the soil. Place the sensor into the hole, making sure the entire length of the sensor is covered. Press down on the soil along either side of the sensor with your fingers. Continue to compact the soil around the sensor by pressing down on the soil with your fingers until you have made at least five passes along the sensor. This step is important, as the soil adjacent to the sensor surface has the strongest influence on the sensor reading.
CHECK OUT MY REVIEW ABOUT THE SOIL MOISTURE SENSOR
You will get every products at cheap rate at our store, check the link below:
http://www.embeddedstudy.com/p/shop-gadgets.html
Components Required
- Raspberry Pi 3
The Raspberry Pi 3 is the third-generation Raspberry Pi. It replaced the Raspberry Pi 2 Model B in February 2016. Quad Core 1.2GHz Broadcom BCM2837 64bit CPU. 1GB RAM. BCM43438 wireless LAN and Bluetooth Low Energy (BLE) on board.2.Soil Sensor Module
I used a 86062 humidity and soil moisture sensor.Controlling the potentiometer we can adjust the sensitivity of the sensor .it has also got led indications over it.
3.JUMPER WIRES
We require Male-Female and Female-Female Jumper wires for connection.
4.MCP 3204(ADC)
MCP3204/3208 devices are successive approximation 12-bit Analog- to-Digital (A/D) Converters with on-board sample and hold circuitry. ... Differential Nonlinearity (DNL) is speci- fied at ±1 LSB, while Integral Nonlinearity (INL) is offered in ±1LSB (MCP3204/3208-B) and ±2LSB (MCP3204/3208-C) versions.
We have already said how to set up the Raspberry Pi and create the pubnub accountin the IoT Based Smart Home on Raspberry Pi
if you have missed that go through it.
CONNECTION DIAGRAM:
check pinout.xyz for Raspberry Pi pins,All pins mentioned here are WiringPi pins.
Connect everything as follows:
PROJECT CODE SNIPPET:
The Project Code is divided in to 2 files you need to make another file other than listen.c ie adc.h for adc interfacing to soil sensor(I use MCP 3204 ADC) this is for getting precise analog sensor values.
So first create adc.h and include it in the listen.c file.
you can also download whole code zip filesDOWNLOAD
#include<stdint.h>
#include<wiringPiSPI.h>
float mcp3204_read(int ch_num)
{
uint8_t buff[3];
int adc;
float vol=0;
if((ch_num>3)||(ch_num<0))
return -1;
buff[0]=0x06;
buff[1]=ch_num<<6;
buff[2]=0;
wiringPiSPIDataRW(0,buff,3);
adc=((buff[1]&0x0f)<<8)+buff[2];
//printf("%d adc val\n,",adc);
vol=((float)adc*5)/4096;
return vol;
}
code explanation
mcp 3204 uses spi protocol to communicate with Raspberri Pi,mcp3204_read()returns float values of measured moisture.
listen.h file code
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include<wiringPi.h>
#include"adc.h"
#include<sys/sem.h>
#include<sys/ipc.h>
#include<sys/types.h>
#include <json.h>
#include "pubnub.h"
#include "pubnub-sync.h"
#define PUBLISH_KEY "pub-c-c30824bb-bc31-463b-a395-XXXXXXXXXXXX"
#define SUBSCRIBE_KEY "sub-c-cfa511de-660a-11e7-b272-XXXXXXXXXXXX" //use your Publish and Subscribe keys
#define IR 1
#define LED 2
#define CHAN 0
#define LED1 25
struct pubnub_sync *_sync;
struct pubnub *p;
json_object *msg;
char *buff;
int flag=0;
char * readPubnub ()
{
/* Subscribe */
/* 1 */ const char *channels[] = { "ch1", "ch2" };
/* 2 */ pubnub_subscribe_multi(
/* struct pubnub */ p,
/* list of channels */ channels,
/* number of listed channels */ 2,
/* default timeout */ -1,
/* callback; sync needs NULL! */ NULL,
/* callback data */ NULL);
if (pubnub_sync_last_result(_sync) != PNR_OK)
return EXIT_FAILURE;
msg = pubnub_sync_last_response(_sync);
if (json_object_array_length(msg) == 0) {
printf("pubnub subscribe ok, no news\n");
} else {
char **msg_channels = pubnub_sync_last_channels(_sync);
for (int i = 0; i < json_object_array_length(msg); i++) {
json_object *msg1 = json_object_array_get_idx(msg, i);
if(strcmp(channels[i],msg_channels[i])==0)
printf("%s\n",msg_channels[i]);
else
printf("%s\n",msg_channels[i]);
printf("pubnub subscribe [%s]: %s\n", msg_channels[i], buff = (char *)json_object_get_string(msg1));
}
}
return buff;
}
void PubNubInit ()
{
_sync = pubnub_sync_init();
p = pubnub_init(
/* publish_key */ PUBLISH_KEY,
/* subscribe_key */ SUBSCRIBE_KEY,
/* pubnub_callbacks */ &pubnub_sync_callbacks,
/* pubnub_callbacks data */ _sync);
}
void main(void)
{
char *on="MOTOR ON";
char *off="MOTOR OFF";
FILE *fp;
wiringPiSetup();
pinMode(LED,OUTPUT);
digitalWrite(LED,LOW);
fp=fopen("log","a+");
if(fp<0)
{
perror("fopen");
}
fprintf(fp,"%s\t%s\t\t%s\n","Mode","Status","Time");
fclose(fp);
struct sembuf v;
char *readbuff;
int id=semget(5,1,IPC_CREAT|0644);
if(id<0)
{
perror("semget");
return;
}
semctl(id,0,SETVAL,0);
time_t t1;
if(fork()==0)
{
//manual code
float f;
PubNubInit ();
v.sem_num=0;
v.sem_op=0;
v.sem_flg=0;
if(wiringPiSPISetup(0,1000000)<0)
printf("no\n");
else
printf("done");
while(1){
readbuff = readPubnub ();
printf ("readbuff = %s\n",readbuff);
if(strstr(readbuff,"MOTOR ON"))
{
f=mcp3204_read(CHAN);
printf("Manual :%f\n",f);
semop(id,&v,1);
if(f>3.8)
{
fp=fopen("log","a+");
semctl(id,0,SETVAL,1);
digitalWrite(LED,LOW);//low moisture on the motor
printf("Manual On \n");
t1=time(0);
fprintf(fp,"%s\t%s \t %s \n","Manu: ",on,ctime(&t1));
fclose(fp);
}
else
{
printf("no need\n");
}
}
else if(strstr(readbuff,"MOTOR OFF"))
{
fp=fopen("log","a+");
t1=time(0);
fprintf(fp,"%s\t%s\t %s \n","Manu: ",off,ctime(&t1));
digitalWrite(LED,HIGH);
printf("Manual off\n");
sleep(5);
fclose(fp);
semctl(id,0,SETVAL,0);
}
}
}
else
{
float f;
if(wiringPiSPISetup(0,1000000)<0)
printf("ADC Enabled in auto mode \n");
struct sembuf v;
v.sem_num=0;
v.sem_op=0;
v.sem_flg=0;
while(1)
{
f=mcp3204_read(CHAN);
printf("Auto mode detection :: voltage level : %f\n",f);
delay(2000);
semop(id,&v,1);
if(f>3.8)
{
fp=fopen("log","a+");
t1=time(0);
fprintf(fp,"%s\t%s\t %s \n","Auto: ",on,ctime(&t1));
semctl(id,0,SETVAL,1);
digitalWrite(LED,LOW);
printf("Automatic mode motor is switching on fr 40 sec\n");
delay(40000);
digitalWrite(LED,HIGH);
t1=time(0);
fprintf(fp,"%s\t%s\t %s \n","Auto: ",off,ctime(&t1));
fclose(fp);
printf("Auto mode is switching off\n");
semctl(id,0,SETVAL,0);
}
else
;
}
}
}
//end of main
Read Pubnub,Write Pubnub ,Pubnub Init and declarations are explained in the smart home project (it is almost same..go through it...),so we are only discussing about the main() code.
#include"adc.h"
#include<sys/sem.h>
#include<sys/ipc.h>
#include<sys/types.h>
are added additionally for adc and semaphore operations
#define LED 2
#define CHAN 0
#define LED1 25
Main Function
char *on="MOTOR ON";
char *off="MOTOR OFF";
FILE *fp;
wiringPiSetup();
pinMode(LED,OUTPUT);
digitalWrite(LED,LOW);
fp=fopen("log","a+");
if(fp<0)
{
perror("fopen");
}
fprintf(fp,"%s\t%s\t\t%s\n","Mode","Status","Time");
fclose(fp);
Declaring 2 strings one for Motor ON and one for OFF,Declaring a file pointer for log
Declaring LED pin and definig it as output(wiring pi pin 2).check pinout.xyz
Writing MODE Status and Time to Log file.
struct sembuf v;
char *readbuff;
int id=semget(5,1,IPC_CREAT|0644);
if(id<0)
{
perror("semget");
return;
}
semctl(id,0,SETVAL,0);
time_t t1;
if(fork()==0)
{
//manual code
float f;
PubNubInit ();
v.sem_num=0;
v.sem_op=0;
v.sem_flg=0;
if(wiringPiSPISetup(0,1000000)<0)
printf("no\n");
else
printf("done");
while(1){
readbuff = readPubnub ();
printf ("readbuff = %s\n",readbuff);
if(strstr(readbuff,"MOTOR ON"))
{
f=mcp3204_read(CHAN);
printf("Manual :%f\n",f);
semop(id,&v,1);
if(f>3.8)
{
fp=fopen("log","a+");
semctl(id,0,SETVAL,1);
digitalWrite(LED,LOW);//low moisture on the motor
printf("Manual On \n");
t1=time(0);
fprintf(fp,"%s\t%s \t %s \n","Manu: ",on,ctime(&t1));
fclose(fp);
}
else
{
printf("no need\n");
}
}
else if(strstr(readbuff,"MOTOR OFF"))
{
fp=fopen("log","a+");
t1=time(0);
fprintf(fp,"%s\t%s\t %s \n","Manu: ",off,ctime(&t1));
digitalWrite(LED,HIGH);
printf("Manual off\n");
sleep(5);
fclose(fp);
semctl(id,0,SETVAL,0);
}
}
}
Creating semaphore for resource locking and forking child to create MANUAL mode.
if(strstr(readbuff,"MOTOR ON"))
Comparing the string sent from Pubnub with "MOTOR ON",then moisture value is read from ADC to a float variable 'f' ,and if value is greater than a threshold resource is locked (Auto can't access) LED gets ON ,and will print status to log file ,afterwards close the file that is opened in the append mode,In the else part if there is enough water content no action is taken and will print NO Need....Same for MOTOR OFF also LED gets off and will print the status to log file..the resource is released only after Motor is OFF and is made available to AUTO Mode..(Resource here means the Status of Pi's pin connected to Solenoid valve).
else
{
float f;
if(wiringPiSPISetup(0,1000000)<0)
printf("ADC Enabled in auto mode \n");
struct sembuf v;
v.sem_num=0;
v.sem_op=0;
v.sem_flg=0;
while(1)
{
f=mcp3204_read(CHAN);
printf("Auto mode detection :: voltage level : %f\n",f);
delay(2000);
semop(id,&v,1);
if(f>3.8)
{
fp=fopen("log","a+");
t1=time(0);
fprintf(fp,"%s\t%s\t %s \n","Auto: ",on,ctime(&t1));
semctl(id,0,SETVAL,1);
digitalWrite(LED,LOW);
printf("Automatic mode motor is switching on fr 40 sec\n");
delay(40000);
digitalWrite(LED,HIGH);
t1=time(0);
fprintf(fp,"%s\t%s\t %s \n","Auto: ",off,ctime(&t1));
fclose(fp);
printf("Auto mode is switching off\n");
semctl(id,0,SETVAL,0);
}
else
;
}
}
}
AUTO mode is written inside the Parent Code.Parent process has all time control and need to monitor the status every time.
Here also while running in the AUTO mode, MANUAL mode must not interfere so we are locking the resource using semaphores.As in Manual mode here also LED status and LOG file entry is changes.In else code we will do nothing.In Auto mode motor is pre-setted to switch On for 40 sec & then turned OFF.
Thats all for this project,Hope you all liked it... Enjoy....
0 on: "IoT Based Smart Irrigation Project on Raspberry Pi"