ساخت سیستم آبیاری هوشمند مبتنی بر IoT با استفاده از سنسور رطوبت خاک و ESP8266 NodeMCU

الکترونیک و رباتیک -> ماژول ها و سنسور ها 4490 2 کاربر آکادمی پارتینه

دستیابی به گوشه و کنار اراضی بزرگ کشاورزی به صورت همزمان برای کشاورزان یک چالش بزرگ است. به همین دلیل احتمال آبیاری نامیزان زمین های زراعی وجود دارد. در نتیجه محصولاتی با کیفیت نامطلوب برداشت شده که منجر به ایجاد خسارات مالی می‌شود. در این پروژه یک سیستم آبیاری هوشمند با استفاده از آخرین فناوری IoT به منظور سهولت در امر کشاورزی طراحی شده است.سیستم آبیاری هوشمند از قابلیت گسترده ای برای خودکارسازی کامل  سیستم آبیاری برخوردار است.

 در این پروژه روش ساخت یک سیستم آبیاری مبتنی بر اینترنت اشیا با استفاده از ماژول ESP8266 NodeMCU و سنسور دما و روطوبت DHT11 مورد بررسی قرار می‌گیرد. این سیستم نه تنها به صورت خودکار و بر اساس سطح رطوبت موجود در خاک زمین را آبیاری می‌کند، بلکه داده را به سرور ThingSpeak ارسال کرده تا وضعیت زمین در هر جای دنیا بر روی اینترنت قابل مشاهده باشد.ThingSpeak  نیز یک منبع عالی برای نمایش داده‌ها به صورت آنلاین است که می‌توان در هر زمان و مکانی به وسیله‌ی آن به این داده‌ها دسترسی پیدا کرد.

این سیستم شامل یک پمپ آب خواهد بود که بسته به شرایط محیطی زمین مانند رطوبت ، دما  برای پاشش آب  مورد استفاده قرار می‌گیرد. لازم به ذکر است که محصولات زراعی مختلف به میزان مختلفی از رطوبت و دما برای رشد نیاز دارند. در این آموزش  محصولاتی مد نظر هستند که به رطوبتی  حدود 50-55٪ نیاز دارد. بنابراین وقتی که رطوبت خاک کمتر از 50٪ شد ، موتور پمپ به صورت اتوماتیک به منظور پاشش آب روشن می‌شود و زمانی که میزان رطوبت از 55٪ بالاتر رود، پمپ خاموش شود. داده‌های سنسور در بازه زمانی مشخص به سرور ThingSpeak ارسال شده تا بتوان از هر نقطه در جهان به این آن‌ها دست یافت.

مرحله 1 : اتصالات و دیاگرام مداری

دیاگرام مداری سیستم آبیاری هوشمند مبتنی به صورت تصاویری است که مشاهده می‌کنید.

مرحله 2 : کدنویسی و تنظیمات نرم‌افزاری

برای برنامه نویسی ماژول ESP8266 NodeMCU ، فقط از کتابخانه سنسور DHT11 به عنوان کتابخانه خارجی استفاده می شود. سنسور رطوبت دارای خروجی آنالوگ است که می توان از طریق پین آنالوگ ESP8266 NodeMCU آن را دریافت کرد. به دلیل اینکه سطح ولتاژ منطقی  NodeMCUحداکثر 3.3 ولت است، از یک ماژول رله برای راه اندازی ماژول پمپ با ولتاژ ورودی 5 ولت و همچنین برای تغذیه‌ی سنسور رطوبت و سنسور DHT11 از یک منبع تغذیه خارجی 5 ولت نیز استفاده می شود. کد کامل و فیلم پروژه در انتهای آموزش قرار داده شده است.

برای شروع کتابخانه های مورد نیاز را فراخوانی کنید.

#include <DHT.h>
#include <ESP8266WiFi.h>


برای برقرای ارتباط با سرور ThingSpeak وجود  API Key لازم است . برای دانستن چگونگی دستیابی به API Key از ThingSpeak می‌توانید به آموزش قبلی در مورد نظارت بلادرنگ بر دما و رطوبت در ThingSpeakمراجعه کنید.

String apiKey = "X5AQ445IKMBYW31H

const char* server = "api.thingspeak.com"; 

گام بعدی نوشتن نام شبکه (Wi-Fi(SSID و رمز عبور است.

const char *ssid =  "Partineh";     

const char *pass =  "xxxxxxxxxxx"; 

در این مرحله پینی که سنسور DHT قرار است به آن متصل شود تعریف کرده و نوع DHT مشخص می‌شود.

#define DHTPIN D3          

DHT dht(DHTPIN, DHT11);

خروجی سنسور رطوبت به پین A0 و خروجی موتور نیز به پین D0 ماژول  ESP8266 NodeMCU متصل می‌شود.

const int moisturePin = A0;

const int motorPin = D0;


از تابع millis برای ارسال داده‌ها پس از هر بازه‌ی زمانی مشخص که در اینجا  10 ثانیه است، استفاده شده است. تابع delay به دلیل اینکه برنامه را برای ایجاد تأخیر مشخص متوقف می‌کند استفاده نشده است.

unsigned long interval = 10000;

unsigned long previousMillis = 0;

پین موتور را به عنوان خروجی تنظیم و در ابتدا موتور خاموش می‌شود. سپس مقادیر سنسور DHT11 خوانده می‌شوند.

pinMode(motorPin, OUTPUT);

digitalWrite(motorPin, LOW); // keep motor off initally

dht.begin();

با استفاده از رمزعبور SSID تعریف شده به Wi-Fi متصل شده و بعد از اتصال مراحل بعدی آغاز می‌شوند.

WiFi.begin(ssid, pass);

  while (WiFi.status() != WL_CONNECTED)

  {

    delay(500);

    Serial.print(".");

  }

  Serial.println("");

  Serial.println("WiFi connected");

}

در این مرحله زمان فعلی شروع برنامه تعریف و در یک متغیر ذخیره شده تا با زمان سپری شده مقایسه شود.

unsigned long currentMillis = millis();

مقادیر دما و رطوبت محیط خوانده  و در دو متغیر ذخیره می‌شوند.

float h = dht.readHumidity();

float t = dht.readTemperature();


اگر DHT متصل شده باشد و ESP8266 NodeMCU قادر به خواندن داده‌ها باشد ، مرحله بعدی آغاز می‌شود. در غیر این صورت باید مراحل قبلی  مجددا تکرار شوند.

در ادامه میزان رطوبت خاک خوانده و نمایش داده می‌شود.

moisturePercentage = ( 100.00 - ( (analogRead(moisturePin) / 1023.00) * 100.00 ) );
  Serial.print("Soil Moisture is  = ");
  Serial.print(moisturePercentage);
  Serial.println("%");

اگر میزان رطوبت خاک بین محدوده تعیین شده باشد پمپ خاموش شده و در صورتی که کمتر از میزان رطوبت تعیین شده باشد، پمپ روشن می‌شود.

if (moisturePercentage < 50) {
    digitalWrite(motorPin, HIGH);
  }
   if (moisturePercentage > 50 && moisturePercentage < 55) {
    digitalWrite(motorPin, HIGH);
  }
 if (moisturePercentage > 56) {
    digitalWrite(motorPin, LOW);
  }


حال هر 10 ثانیه یکبار  تابع ()sendThingspeak را فراخوانی کرده تا داده‌های دریافت شده شامل رطوبت محیط، دما و رطوبت خاک را به سرور ThingSpeak ارسال شوند.

  if ((unsigned long)(currentMillis - previousMillis) >= interval) {
    sendThingspeak();
    previousMillis = millis();
    client.stop();
  }

در تابع () sendThingspeak اتصال سیستم به سرور بررسی شده و مقادیر رطوبت محیط ، دما و رطوبت خاک در یک رشته ذخیره می‌شود. در نهایت این رشته به همراه کد API و آدرس سرور به سرور ThingSpeak ارسال می‌شود.

if (client.connect(server, 80))
    {
      String postStr = apiKey;
      postStr += "&field1=";
      postStr += String(moisturePercentage);
      postStr += "&field2=";
      postStr += String(t);
      postStr += "&field3=";
      postStr += String(h);      
      postStr += "

";

سرانجام داده‌ها با استفاده ازتابع ()client.print که حاوی کد API ، آدرس سرور و اطلاعات سنسورها هستند، به سرور ThingSpeak ارسال می شوند.

client.print("POST /update HTTP/1.1
");
      client.print("Host: api.thingspeak.com
");
      client.print("Connection: close
");
      client.print("X-THINGSPEAKAPIKEY: " + apiKey + "
");
      client.print("Content-Type: application/x-www-form-urlencoded
");
      client.print("Content-Length: ");
      client.print(postStr.length());
      client.print("

");
      client.print(postStr);

در مرحله آخر داده ها در پنل  ThingSpeak به صورت تصویری که در بالا مشاهده می‌کنید، نمایش داده می‌شوند. توجه داشته باشید که خاموش کردن موتور در هنگامی که میزان رطوبت خاک به حد مطلوب میرسد بسیار مهم است. 

کد کامل برنامه:

#include <DHT.h>
#include <ESP8266WiFi.h>
String apiKey = "X5AQ3EGIKMBYW31H";     //  Enter your Write API key here
const char* server = "api.thingspeak.com";
const char *ssid =  "CircuitLoop";     // Enter your WiFi Name
const char *pass =  "circuitdigest101"; // Enter your WiFi Password
#define DHTPIN D3          // GPIO Pin where the dht11 is connected
DHT dht(DHTPIN, DHT11);
WiFiClient client;

const int moisturePin = A0;             // moisteure sensor pin
const int motorPin = D0;
unsigned long interval = 10000;
unsigned long previousMillis = 0;
unsigned long interval1 = 1000;
unsigned long previousMillis1 = 0;
float moisturePercentage;              //moisture reading
float h;                  // humidity reading
float t;                  //temperature reading

void setup()
{
  Serial.begin(115200);
  delay(10);
  pinMode(motorPin, OUTPUT);
  digitalWrite(motorPin, LOW); // keep motor off initally
  dht.begin();
  Serial.println("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, pass);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");              // print ... till not connected
  }
  Serial.println("");
  Serial.println("WiFi connected");
}

void loop()
{
  unsigned long currentMillis = millis(); // grab current time

  h = dht.readHumidity();     // read humiduty
  t = dht.readTemperature();     // read temperature

  if (isnan(h) || isnan(t))
  {
    Serial.println("Failed to read from DHT sensor!");
    return;
  }

  moisturePercentage = ( 100.00 - ( (analogRead(moisturePin) / 1023.00) * 100.00 ) );

  if ((unsigned long)(currentMillis - previousMillis1) >= interval1) {
    Serial.print("Soil Moisture is  = ");
    Serial.print(moisturePercentage);
    Serial.println("%");
    previousMillis1 = millis();
  }

if (moisturePercentage < 50) {
  digitalWrite(motorPin, HIGH);         // tun on motor
}
if (moisturePercentage > 50 && moisturePercentage < 55) {
  digitalWrite(motorPin, HIGH);        //turn on motor pump
}
if (moisturePercentage > 56) {
  digitalWrite(motorPin, LOW);          // turn off mottor
}

if ((unsigned long)(currentMillis - previousMillis) >= interval) {

  sendThingspeak();           //send data to thing speak
  previousMillis = millis();
  client.stop();
}

}

void sendThingspeak() {
  if (client.connect(server, 80))
  {
    String postStr = apiKey;              // add api key in the postStr string
    postStr += "&field1=";
    postStr += String(moisturePercentage);    // add mositure readin
    postStr += "&field2=";
    postStr += String(t);                 // add tempr readin
    postStr += "&field3=";
    postStr += String(h);                  // add humidity readin
    postStr += "\r\n\r\n";

    client.print("POST /update HTTP/1.1\n");
    client.print("Host: api.thingspeak.com\n");
    client.print("Connection: close\n");
    client.print("X-THINGSPEAKAPIKEY: " + apiKey + "\n");
    client.print("Content-Type: application/x-www-form-urlencoded\n");
    client.print("Content-Length: ");
    client.print(postStr.length());           //send lenght of the string
    client.print("\n\n");
    client.print(postStr);                      // send complete string
    Serial.print("Moisture Percentage: ");
    Serial.print(moisturePercentage);
    Serial.print("%. Temperature: ");
    Serial.print(t);
    Serial.print(" C, Humidity: ");
    Serial.print(h);
    Serial.println("%. Sent to Thingspeak.");
  }
}