Système d'irrigation Automatique

Principe du projet

Le Projet consiste à l'arrosage automatique d'un jardin connecté, c'est une nouvelle manière de piloter et gérer un système d'arrosage d'une manière intelligente en permettant l'économie d'eau.
Il peut être géré via un smartphone, une tablette ou un ordinateur. Vous pouvez contrôler l'arrosage même lorsque vous n'êtes pas chez vous. En étant connecté, vous avez accès à une interface web/App ,permettant de contrôler votre Système d'arrosage programmé ; horaire et durée, la météo (température/humidité de l'air, taux d'humidité du sol).
Vous pouvez aussi lancer les arrosages manuellement et consulter l'historique de vos arrosages. Un Arrosage sur Mesure, avec des quantités exactes, trop facile a utiliser au quotidien

Matériel utilisé

ESP 8266

Ce microcontrôleur qui dispose d’une connexion WiFi permettant de créer de très nombreux projets IoT et domotiques à faible coût.
 
 

Capteur analogique d’humidité du sol

C’est un capteur qui utilise la variation de capacité pour déterminer l’humidité du sol.
 

Un Relais

Un relais est un interrupteur à commande électrique. Il utilise un électroaimant (bobine) pour faire fonctionner son mécanisme de commutation interne (contacts).
 
Pompe immergée 6V

Schéma

 

 

Partie 1: Pilotage depuis une page web

       
 
                  Dans cette partie ,les paramètres du sol et de l’air sont affichées sur une page web qui contiendra 2 boutons (mise en route ou l’arrêt de la pompe).
L’ESP 8266 servira de point d’accés WiFi et de serveur Web.Dans le programme, vous devez modifier le nom de votre réseau WiFi (mon_ssid), ainsi que le mot de passe (mon_mot_de_passe). 
Pour accéder à la page Web, connectez vous à votre réseau wifi puis indiquez dans un navigateur l’adresse IP de votre esp a savoir :192.168.17.8
 

Voici le programme pour la carte Arduino :

#include « DHT.h »

#define DHTPIN 12//D6

#define DHTTYPE DHT11

int PinAnalogiqueHumidite=A0;     

int PinRelai=2;    // D4

DHT dht(DHTPIN, DHTTYPE);

int hsol;  //Humidite su sol

float temp ;//température

float hum;//humidity 

#include<ESP8266WebServer.h>

#include<ESP8266WiFi.h>

const char *ssid= »mon_ssid »;

const char *password= »mon_mot_de_passe »;


IPAddress IP(192,168,17,8);

IPAddress gateway(192,168,17,1);

IPAddress subnet(255,255,255,0);

  

ESP8266WebServer ServerWeb(80);



const char index_html []PROGMEM = R »=====(

<!– Contenu de la page Web –>

<!doctype html>

<html lang= »fr »>

  <head>

    <meta charset= »utf-8″>

    <title>Irrigation</title>

  

    <!– mise en forme de la page web (css)–>

    <style>

      html 

      {

        font-size: 16px;

        margin-top: 50px;

      }

      h1 {

        color: #696969;

        text-align: center;

      }

      a {

        text-align: center;

      }

      a.btn {

        text-decoration: none;

        font-size: 1.7rem;

        color: #fff;

        padding: 13px;

        border-radius: 10px;

        margin: 0 20px 0;

        background-color: #97CC04;

      }

      .ak_container {

        width: 80%;

        margin: 0 auto;

      }

      .wrapper {

        margin-bottom: 70px;

        text-align: center;

      }

      

     </style>

  </head>


  <body class= »ak_container »>

    <div class= »wrapper »>

      <h1>%hsol%</h1> 

      <h1>%temp%</h1>

      <h1>%hum%</h1>

    </div>

    

    <div class= »wrapper »>

      <h1>Irrigation</h1>

      <h2>Etat de la Pompe</h2>

        <a class= »btn » href= »/SwitchIrrigOn »>Marche</a>

        <a class= »btn » href= »/SwitchIrrigOff »>Arret</a>

      <h2>%PinRelai%</h2> 

    </div>

  </body>

</html>

)===== »;


      

 void SwitchIrrigOn()

{

  digitalWrite(PinRelai,HIGH);

  handleRoot();

}

 void SwitchIrrigOff()

{

  digitalWrite(PinRelai,LOW);

  handleRoot();

}

void handleRoot()

{

  /* conversion des données en chaines de caractères (string)*/ 

  String stringMoisture= « Humidité du sol :  » +String(hsol) + » % »; //Affichage en html de l’humidité du sol

  String stringTemperature= « Température de l’Air :  » +String(temp) + » °C »; //Affichage en html de la température de l’air

  String stringHumidity= « Humidité de l’air :  » +String(hum) + » % »;//L’humidité atmosphérique absolue. Il s’agit de la valeur réelle contenue dans un mètre cube. Son unité de mesure est le g/m³

  

  String temp(reinterpret_cast<const __FlashStringHelper*>(index_html));

  temp.replace(« %hsol% », stringMoisture);

  temp.replace(« %temp% », stringTemperature);

  temp.replace(« %hum% », stringHumidity);


  if(digitalRead(PinRelai)==LOW)

  {

    temp.replace(« %PinRelai% », »Pompe a l’arret »);

  } 

  else 

  {

    temp.replace(« %PinRelai% », »Pompe en marche »);

  }          


  ServerWeb.send(200, »text/html »,temp);

}


void setup() {

  dht.begin();

  Serial.begin(9600);

  pinMode(PinAnalogiqueHumidite, INPUT);       //pin A0 en entrée analogique 

  pinMode(PinRelai, OUTPUT);   //relai_pompe 

  WiFi.softAPConfig(IP,gateway,subnet);

  WiFi.softAP(ssid,password);

  ServerWeb.on(« /SwitchIrrigOn »,SwitchIrrigOn);

  ServerWeb.on(« /SwitchIrrigOff »,SwitchIrrigOff);

  ServerWeb.on(« / »,handleRoot);

  ServerWeb.begin();

   handleRoot();

}



void loop() { 

   

  ServerWeb.handleClient();

  temp = dht.readTemperature();

  hum= dht.readHumidity();

  hsol = analogRead(PinAnalogiqueHumidite);

  hsol=map(hsol,100,700,100,0);


  

  Serial.println(temp); 

  Serial.println(hum);

  Serial.println(hsol); 

  delay(2000); 

  handleRoot();

}


Voici le Résultat :

Partie 2:Affichage et stockage des données

                     (base de donnée)

                  Dans cette partie ,les paramètres du sol et de l’air sont affichées sur une page web (sous forme d’un graphe, comme vous pouvez le voir juste au dessous), mais l’irrigation est automatique cette fois ci, On conservera les données dans une base de donnée de votre choix (Always data dans notre programme)
 Pour accéder à la page Web, copiez le lien .index sur un navigateur 

Voici le programme pour la carte Arduino :

 

Code Arduino:



/*
* Projet station météo dht11 alwaysdata
* Capteur dht 11
* Envoi des données à intervalle régulier sur serveur php
* Rétroaction : allumage leds green et red suivant la temperature captée
*/
#include
#include
#include
#define wifi_ssid « ************ »
#define wifi_pwd « ************* »
#define dhtType DHT11
#define dhtPin 12 //D6
#define ledRedPin 4 //D2
#define ledGreenPin 5 //D1
const int RELAY = 2; //D4
int PinAnalogiqueHumidite=A0;
int moisture;
String staticUrl = « http://jardin-connect.alwaysdata.net/********/*****.php? »;
float temperature;
float humidity;
unsigned long lastTime = 0;
unsigned long currentTime;
// parameter for periodic sensor
const int sensorPeriod = 300000; //each 15 mn
DHT dht(dhtPin, dhtType);
void wifiConnexion()
{
WiFi.begin(wifi_ssid, wifi_pwd);
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(« . »);
delay(1000);
}
Serial.println();
Serial.println(« Connexion WiFi établie »);
}
void sendDatas()
{
currentTime = millis();
if (currentTime == 0)
{
lastTime = 0;
}
if (lastTime == 0 || (currentTime – lastTime) > sensorPeriod)
{
lastTime = currentTime;
moisture = analogRead(PinAnalogiqueHumidite);
moisture = map(moisture,300,800,100,0);
temperature = dht.readTemperature();
humidity = dht.readHumidity();
if (isnan(temperature) || isnan(humidity))
{
Serial.println(« Echec de lecture ! »);
return;
}
WiFiClient client;
HTTPClient http;
String url = staticUrl + »temperature= » +temperature + »&humidity= » +humidity + »&moisture= » +moisture;
http.begin(client, url);
Serial.print(« [HTTP] GET…\n »);
// start connection and send HTTP header. httpcode return the status of the response
int httpCode = http.GET();
if (httpCode > 0) {
// HTTP header has been send and Server response header has been handled
Serial.printf(« [HTTP] GET… code: %d\n », httpCode);
// file found at server
if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
String payload = http.getString();
Serial.println(payload);
if (payload == « 1 ») {
digitalWrite(ledRedPin, HIGH);
digitalWrite(ledGreenPin, LOW);
} else if (payload == « 0 ») {
digitalWrite(ledRedPin, LOW);
digitalWrite(ledGreenPin, HIGH);
}
}
} else {
Serial.printf(« [HTTP] GET… failed, error: %s\n », http.errorToString(httpCode).c_str());
}
http.end();
}
}
void setup()
{
Serial.begin(115200);
wifiConnexion();
dht.begin();
pinMode(RELAY, OUTPUT);
/* pinMode(ledRedPin, OUTPUT);
pinMode(ledGreenPin, OUTPUT);*/
}
void loop()
{
if (moisture < 50 )
{
digitalWrite(RELAY,HIGH);
}
else
{
digitalWrite(RELAY,LOW);
}
if (WiFi.status() != WL_CONNECTED)
wifiConnexion();
}
if (WiFi.isConnected()) {
sendDatas();
}
// Serial.println(moisture);
}

 

 

{
CodePHP:
 
 

api.php:

 
<?php

 

require_once ‘pdo.php’;

 

$askedDay = str_replace(« / », «  », $_GET[‘day’]);
$year = substr($askedDay, 4, 4);
$month = substr($askedDay, 2, 2);
$day = substr($askedDay, 0, 2);
$currentDate = $year.$month.$day; //Ymd for request

 

$sql = « SELECT sent_at, temperature, humidity, moisture from capture WHERE YEAR(sent_at) = YEAR($currentDate) AND DAYOFYEAR(sent_at) = DAYOFYEAR($currentDate);« ;

 

$stmt = $pdo->prepare($sql);
$stmt->execute();
$res = $stmt->fetchAll(PDO::FETCH_ASSOC);

 

$table = [];

 

$table[‘cols’] = [
        [
            ‘label’ => ‘Date Time’,
            ‘type’ => ‘string’
        ],
        [
            ‘label’ => ‘Température’,
            ‘type’ => ‘number’
        ],
        [
            ‘label’ => ‘Humidité’,
            ‘type’ => ‘number’
        ],
        [
            ‘label’ => ‘Humidité du Sol’,
            ‘type’ => ‘number’
        ]
    ];

 

$rows = [];
while ($item = array_shift($res)) {
    $datetime = new DateTime($item[‘sent_at’]);
    $hour = $datetime->format(‘H:i’);

 

    $row = [];
    $row[] = [
        ‘v’ => $hour
    ];
    $row[] = [
        ‘v’ => $item[‘temperature’]
    ];
    $row[] = [
        ‘v’ => $item[‘humidity’]
    ];
    $row[] = [
        ‘v’ => $item[‘moisture’]
    ];
    $rows[] = [
        ‘c’ => $row
    ];
}
$table[‘rows’] = $rows;

 

$jsonData = json_encode($table);
echo $jsonData;

 

 

capture.php:

 
<?php

 

require_once ‘pdo.php’;

 

$temperature = $_GET[‘temperature’];
$humidity = $_GET[‘humidity’];
$moisture =  $_GET[‘moisture’];

 

$now = new DateTime(‘NOW’, new DateTimeZone(‘Europe/Paris’));
$sent_at = $now->format(‘Y-m-d H:i:s’);

 

$sql = « INSERT INTO capture(temperature, humidity, sent_at, moisture) VALUES(:temperature, :humidity, :sent_at, :moisture)« ;
$stmt = $pdo->prepare($sql);
$stmt->bindValue(‘:temperature’, $temperature);
$stmt->bindValue(‘:humidity’, $humidity);
$stmt->bindValue(‘:sent_at’, $sent_at);
$stmt->bindValue(‘:moisture’, $moisture);
$stmt->execute();

 

require_once ‘retroaction.php’;

 

 
index.php:

<?php
    $datetime = new DateTime(‘NOW’);
    $askedDay = empty($_POST[‘submit_day’]) ? $datetime->format(‘d/m/Y’) : $_POST[‘day_choice’];
?>

 

<!DOCTYPE html>
<html lang=« fr »>
<head>
    <meta charset=« UTF-8 »>
    <meta name=« viewport » content=« width=device-width, initial-scale=1.0 »>
    <title>Document</title>

 

    <link rel=« stylesheet » href=« style.css »>
    <link rel=« stylesheet » href=« //code.jquery.com/ui/1.13.0/themes/Black-Tie/jquery-ui.css »>

 

    <script type=« text/javascript » src=« https://www.gstatic.com/charts/loader.js »></script>
    <script type=« text/javascript »>
        <?php echo « var askedDay = ‘$askedDay‘; »; ?>
        console.log(askedDay);

 

        google.charts.load(‘current’, {‘packages’:[‘corechart’]});
        google.charts.setOnLoadCallback(drawChart);

 

        function drawChart() {
            ajaxCall();
            setInterval(ajaxCall, 900000); //900000 MS == 15 minutes
            function ajaxCall() {
                var jsonData = $.ajax({
                  url: « http://jardin-connect.alwaysdata.net/********/api.php?day= » +askedDay,
                  dataType: « json »,
                  async: false
                }).responseText;

 

                var data = new google.visualization.DataTable(jsonData);

 

                var options = {
                    title:‘Irrigation’,
                    curveType: ‘function’,
                    legend:{position:‘bottom’},
                    chartArea:{
                        width:‘90%’,
                        height:‘65%’
                    },
                    animation:{
                        duration: 1000,
                        easing: ‘out’,
                    },
                    hAxis:{
                        gridlines:{
                            color:‘red’,
                            format: ‘scientific’
                        }
                    },
                    vAxis: {
                        maxValue: 100,
                        minValue:20
                    },
                    pointShape: ‘circle’,
                    pointSize: 10,
                    lineWidth: 3,
                    colors: [‘#ff9b00’,‘#138cff’, ‘#008000’],
                    backgroundColor:{
                        fill:‘#fcfcfc’
                    },
                    crosshair:{
                        color:‘#000’
                    }
                }

 

                var chart = new google.visualization.LineChart(document.getElementById(‘chart_display’));
                chart.draw(data, options);
            }
        }
    </script>

 

</head>
<body>
    <main class=« ak_container »>
        <div id=« homepage_page »>
            <a href=«  »>Aujourd’ui</a>

 

            <form id=« asked_date_form » action=«  » method=« POST »>
                <label for=« datepicker »>Jour</label>
                <input id=« datepicker » name=« day_choice » type=« text » autocomplete=« off » value=«  »>

 

                <input type=« submit » id=« submit_day » name=« submit_day » value=« Afficher »>
            </form>

 

            <p id=« today »>
                <?php echo $askedDay ?>
            </p>
            <div id=« chart_display »></div>
        </div>
    </main>
 
    <script src=« https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js » integrity=« sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ== » crossorigin=« anonymous » referrerpolicy=« no-referrer »></script>
    <script src=« https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js » integrity=« sha512-uto9mlQzrs59VwILcLiRYeLKPPbS/bT71da/OEBYEwcdNUk8jYIy+D176RYoop1Da+f9mvkYrmj5MCLZWEtQuA== » crossorigin=« anonymous » referrerpolicy=« no-referrer »></script>
    <script type=« text/javascript »>
        $( function() {
            $( « #datepicker » ).datepicker({
                altField: « #datepicker »,
                closeText: ‘Fermer’,
                prevText: ‘Précédent’,
                nextText: ‘Suivant’,
                currentText: ‘Aujourd\’hui’,
                monthNames: [‘Janvier’, ‘Février’, ‘Mars’, ‘Avril’, ‘Mai’, ‘Juin’, ‘Juillet’, ‘Août’, ‘Septembre’, ‘Octobre’, ‘Novembre’, ‘Décembre’],
                monthNamesShort: [‘Janv.’, ‘Févr.’, ‘Mars’, ‘Avril’, ‘Mai’, ‘Juin’, ‘Juil.’, ‘Août’, ‘Sept.’, ‘Oct.’, ‘Nov.’, ‘Déc.’],
                dayNames: [‘Dimanche’, ‘Lundi’, ‘Mardi’, ‘Mercredi’, ‘Jeudi’, ‘Vendredi’, ‘Samedi’],
                dayNamesShort: [‘Dim.’, ‘Lun.’, ‘Mar.’, ‘Mer.’, ‘Jeu.’, ‘Ven.’, ‘Sam.’],
                dayNamesMin: [‘D’, ‘L’, ‘M’, ‘M’, ‘J’, ‘V’, ‘S’],
                weekHeader: ‘Sem.’,
                dateFormat: ‘dd/mm/yy’
            });
        });
    </script>
</body>
</html>

 

 
 
 

 

pdo.php:

<?php
    $dsn = « mysql:host=mysql-jardin-connect.alwaysdata.net;dbname=jardin-connect_********;charset=utf8 »;
    $dbuser = « ********** »;
    $dbpwd = « *********** »;

 

    $pdo = new PDO($dsn, $dbuser, $dbpwd, []);
 
 
 
retroaction.php:
 
<?php

 

$sql = « SELECT moisture from capture WHERE id=(SELECT max(id) FROM capture)« ;
$stmt = $pdo->query($sql);
$res = $stmt->fetch();
$moisture = $res[‘moisture’];

 

if ($moisture > 50) {
    echo ‘1’;
} else {
    echo ‘0’;
}

 

 
style.css:
 
html {
    font-size: 16px;
}
a {
    text-decoration: none;
    font-size: 1.7rem;
    color: #97CC04;
}
.ui-datepicker {
    font-size: 17px !important;
}
.ui-state-default {
    font-size: 1.2rem;
}
.ak_container {
    width: 80%;
    margin: 0 auto;
}
#homepage_page #today {
    margin: 10px 0 0;
    font-size: 2rem;
    color: #1C2321;
    margin-bottom: 50px;
    text-align: center;
}
#homepage_page #chart_display {
    margin: 0 auto;
    width: 80%;
    height: 600px;
}
#homepage_page form#asked_date_form {
    margin-top: 15px;
    height: 50px;
}
#homepage_page form#asked_date_form label {
    font-size: 1.1rem;
}
#homepage_page form#asked_date_form input#datepicker {
    text-align: center;
    width: 70px;
    height: 30px;
    border-radius: 10px;
    border: 1px solid #97CC04;
    background: #fff;
}
#homepage_page form#asked_date_form input#submit_day {
    width: 90px;
    height: 30px;
    border-radius: 10px;
    border: 1px solid #97CC04;
    font-size: 1rem;
    color: #1C2321;
    background:#fff;

 

}

Voici le Résultat :

Partie 3:Utilisation de IOT Cloud Arduino 

       
 
             IOT Cloud Arduino nous donne accès a une interface Web ou une  application nommé « Arduino IOT Cloud Remote »  pour pouvoir afficher/stocker les données (taux d’humidité du sol, température/humidité de l’air ) et de contrôler l’arrosage  via un bouton (marche/arrêt )
 

 

Voici le programme pour la carte Arduino :

 

#include « thingProperties.h »

#define ledG 16 //D2

#include « DHT.h »

#define DHTpin 12//D6

#define DHTTYPE DHT11

DHT dht(DHTpin, DHTTYPE);

int sensor = A0;

int relay = 2; //D4

void setup()

{ Serial.begin(9600);

  delay(1500);

  dht.begin();

  pinMode(ledG, INPUT);

  //pinMode(sensor,INPUT);

  pinMode(relay, OUTPUT);

  initProperties();

  ArduinoCloud.begin(ArduinoIoTPreferredConnection);

  setDebugMessageLevel(2);

  ArduinoCloud.printDebugInfo();

}

void loop()

{

  ArduinoCloud.update();

  temperature = dht.readTemperature();

  humidite = dht.readHumidity();

  humidity = analogRead(sensor);

  humidity = map(humidity, 300, 800, 100, 0);

  onLedBtnChange() ;

 

}

 

void onLedBtnChange()

{

  if (humidity > 50)

  {

    digitalWrite(ledG, HIGH);

  }

  else

  {

    digitalWrite(ledG, LOW);

  }

 

}

 

 

void onRelaisChange()  {

  if (relais)

  {

    digitalWrite(relay, HIGH);

  }

  else

  {

    digitalWrite(relay, LOW);

  }

}

 

Voici le Résultat :

Affichage depuis un site Web :
Affichage avec une application: