Publié le

Serre connectée !

L’hiver arrive et qui dit hiver, dit préparation des semis pour le jardin (et des plantes aussi).

L’an dernier nous avons fait une étagère sur roulette pour pouvoir entreposer les bacs à semis sous la véranda. Je n’en était pas très satisfait car les chiens dormant dans la véranda, on laisse la porte ouverte et donc la nuit descend pas mal (c’est suffisant pour les agrumes qui sont en hors-gel, mais pour faire lever des pieds de tomate il faut au minimum un mois).

Du coup on est parti pour fermer l’étagère-serre avec des plaques de polycarbonate alvéolé de 16mm (les même que nous avions utilisé en 2011 pour faire la véranda.

Bien sur, je n’ai pas voulu m’arrêter là. J’ai une mini-serre depuis 2 ans qui me sert à faire les semis les plus délicats (surtout niveau température) et j’avais un thermomètre digital, mais bon j’avais la température sur le moment, mais pas d’historique.

1. Partie bricolage, conception de la serre :

Bon là pas trop de bla bla, je ne veux pas rentrer dans les détails, une étagère, des plaques de polycarbonate et on ferme le tout ! (Sauf le haut ou j’ai mit de l’aggloméré).

IMG_0563

2. Partie montage de l’électronique :

J’ai percé mes plaque avec une scie cloche pour poser des ventilateurs de PC sur les deuxième et troisième étagère au centre pour faire une circulation d’air, ainsi que sur les cotés pour faire passer mes câbles.

IMG_0560

Pour le haut de la serre j’ai fait une aération avec une plaque de polycarbonate qui glisse en récupérant le chariot d’un vieux lecteur CD de PC. Le voici en action :

Voici la liste des composants que j’ai utilisé :

  • Un Arduino méga,
  • Un shield Ethernet,
  • Quatre DS18B20 (capteur température),
  • Un DHT22 (capteur température et humidité),
  • Un pont en H (SainSmart L298N),
  • Un écran LCD 1602 en I2C,
  • Un transfo 12V,
  • Un régulateur de tension 5V,
  • Un relais,
  • Une boite de dérivation,
  • Une boite de jonction avec façade transparente,
  • Un vieux lecteur CD,
  • Des câbles, des résistances de 4.7kΩ.

Petit avantage du L298N, il permet d’alimenter l’Arduino (et oui j’ai besoin de 12V pour alimenter les ventilos et le chariot du lecteur CD).

Voici le montage :

Serre_bb3

 

3. Programmation de la carte :

Gros programme :

  • Relevé des températures
  • Si la moyenne est supérieure à 30°C => ouverture de la serre
  • Si la température est inférieure à 22°C => On allume le chauffage
  • Envoie des données sur mon site.

Voici le programme (qui est à mon sens encore améliorable :

#include <LiquidCrystal_I2C.h>
#include <SPI.h>
#include <Ethernet.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include "DHT.h"
#include <Wire.h>

//Déclarations de l'écran
LiquidCrystal_I2C lcd(0x27, 16, 2);

// Déclaration des sondes DS18B20
#define ONE_WIRE_MINI_SERRE 22 
#define ONE_WIRE_ETAGE_1 23
#define ONE_WIRE_ETAGE_3 25 
#define ONE_WIRE_VERRANDA 26 

OneWire oneWire1(ONE_WIRE_MINI_SERRE);
OneWire oneWire2(ONE_WIRE_ETAGE_1);
OneWire oneWire3(ONE_WIRE_ETAGE_3);
OneWire oneWire4(ONE_WIRE_VERRANDA);

DallasTemperature mini_serre(&oneWire1);
DallasTemperature etage_1(&oneWire2);
DallasTemperature etage_3(&oneWire3);
DallasTemperature verranda(&oneWire4);

// Déclaration DHT :
#define DHTTYPE DHT22
#define DHTPIN 24

DHT dht(DHTPIN, DHTTYPE);

// Déclaration interrupteur ouverture porte
#define Etat_Ouverture 27

// Déclaration RELAIS chauffage
#define Relais_Chauffage 28
int Etat_chauffage = 0 ;

//Déclaration pins OUVERTURE HAUT :
#define Pin1 29
#define Pin2 30

// Réseau :
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
char server[] = "www.jpg32190.fr";
IPAddress ip(192, 168, 1, 177);
EthernetClient client;


void setup() {
  Serial.begin(9600);
  lcd.begin();
  lcd.backlight();
  mini_serre.begin();
  etage_1.begin();
  etage_3.begin();
  verranda.begin();
  dht.begin();
  pinMode(Etat_Ouverture,INPUT);
  pinMode(Relais_Chauffage,OUTPUT);
  pinMode(Pin1,OUTPUT);
  pinMode(Pin2,OUTPUT);

  // On met le chauffage à zéro :
  digitalWrite(Relais_Chauffage,LOW);

 // LANCEMENT RESEAU
 lcd.print("demarrage");
  if (Ethernet.begin(mac) == 0) {
     Serial.println("Failed to configure Ethernet using DHCP");
     Ethernet.begin(mac, ip);
   }
    delay(1000);
    Serial.println("connecting...");
    Serial.print("My IP address: ");
    String showIP = "";
    lcd.clear();
    for (byte thisByte = 0; thisByte < 4; thisByte++) {
    // print the value of each byte of the IP address:
      Serial.print(Ethernet.localIP()[thisByte], DEC);
    
      lcd.print(Ethernet.localIP()[thisByte], DEC);
      lcd.print(".");
      Serial.print(".");
    }
    Serial.println();
  delay(3000);

  
}

void loop() {
  // Requêtes des DS18B20 :
  mini_serre.requestTemperatures();
  float temp_mini_serre = mini_serre.getTempCByIndex(0);
  while (temp_mini_serre >80 || temp_mini_serre < -50) {
    mini_serre.requestTemperatures();
  float temp_mini_serre = mini_serre.getTempCByIndex(0);
  }
  etage_1.requestTemperatures();
  float temp_etage_1 = etage_1.getTempCByIndex(0);
  while (temp_etage_1 >80 || temp_etage_1 < -50) {
    etage_1.requestTemperatures();
  float temp_etage_1 = etage_1.getTempCByIndex(0);
  }
  etage_3.requestTemperatures();
  float temp_etage_3 = etage_3.getTempCByIndex(0);
  while (temp_etage_3 >80 || temp_etage_3 < -50) {
    etage_3.requestTemperatures();
  float temp_etage_3 = etage_3.getTempCByIndex(0);
  }
  verranda.requestTemperatures();
  float temp_verranda = verranda.getTempCByIndex(0);
  while (temp_verranda >80 || temp_verranda < -50) {
    verranda.requestTemperatures();
  float temp_verranda = verranda.getTempCByIndex(0);
  }
  
  // Requete du DHT22 :
  float temp_etage_2 = dht.readTemperature();
  float humidite = dht.readHumidity();
  

  // AFFICHAGE SUR LE LCD :
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print(temp_etage_1);
  lcd.print("  ");
  lcd.print(temp_etage_2);
  lcd.setCursor(0,1);
  lcd.print(temp_etage_3);
  lcd.print("  ");
  lcd.print(temp_mini_serre);
  

  
  // Commande ouverture / fermeture haut :
  float moyenne_temperature = (temp_etage_1 + temp_etage_2 + temp_etage_3 ) / 3;
  int Etat_Couvercle = digitalRead(Etat_Ouverture);

  if (moyenne_temperature > 30) {
    if (Etat_Couvercle != 1) {
      ouverture();
      }
  }
  else {
    if (Etat_Couvercle != 0) {
      fermeture();
      }
  }

  // Controle du chauffage 

  if (moyenne_temperature < 22) {
    digitalWrite(Relais_Chauffage,HIGH);
    Etat_chauffage = 1;
  }
  else {
    digitalWrite(Relais_Chauffage,LOW);
    Etat_chauffage = 0;
  }
   Serial.println(temp_mini_serre);
// PREPARATION DU PULL SUR LE SITE :
  String url = "GET /meteo/serre_data.php?t_mini_serre=";
  url+=String(temp_mini_serre,2);
  url+="&t_serre_1=";
  url+=String(temp_etage_1,2);
  url+="&t_serre_2=";
  url+=String(temp_etage_2,2);
  url+="&t_serre_3=";
  url+=String(temp_etage_3,2);
  url+="&t_verranda=";
  url+=String(temp_verranda,2);
  url+="&h_serre_2=";
  url+=String(humidite,2);
  url+="&etat_ouverture=";
  url+= Etat_Couvercle;
  url+="&etat_chauffage=";
  url+= Etat_chauffage;
  url+= " HTTP/1.1";

  Serial.println(url);
// Envoi des données : 

  if (client.connect(server, 80)) {
    Serial.println("connected");
    client.println(url);
    client.println("Host: www.jpg32190.fr");
    client.println("Connection: close");
    client.println();
    client.stop();
  }
  else {
    Serial.println("connection failed");
  }

  


  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting.");
   // client.stop();
    //while (true);
  }

  delay(60000);
  
  
}


// Fonctions ouverture et fermeture porte :

void ouverture() {
  Serial.println("OUVERTURE");
      digitalWrite(Pin1,LOW);
      digitalWrite(Pin2,HIGH);
      delay(3000);
      Serial.println("pause");
      digitalWrite(Pin1,LOW);
      digitalWrite(Pin2,LOW);
      delay(7000);
}

void fermeture() {
  digitalWrite(Pin1,HIGH);
      digitalWrite(Pin2,LOW);
      delay(3000);
      Serial.println("pause");
      digitalWrite(Pin1,LOW);
      digitalWrite(Pin2,LOW);
      delay(7000);
}

4. Partie web :

Partie ou je suis le plus novice (je faisais déjà du HTML en 2000, mais c’était pas très esthétique).

Ici j’ai choisit d’utiliser encore une fois Highstock pour faire des graphes liée.

Avant ça, première partie la table de données contenant mes températures. Le fichier serre_data.php me permet d’insérer mes données dans ma table sql :

<?php
  include("connexionDB.php");
   $t_mini_serre = $_GET['t_mini_serre'];
   $t_serre_1 = $_GET['t_serre_1'];
   $t_serre_2 = $_GET['t_serre_2'];
   $t_serre_3 = $_GET['t_serre_3'];
   $t_verranda = $_GET['t_verranda'];
   $h_serre_2 = $_GET['h_serre_2'];
   $etat_ouverture = $_GET['etat_ouverture'];
   $etat_chauffage = $_GET['etat_chauffage'];
   
  
   mysql_query("INSERT INTO serre (t_mini_serre, t_serre_1, t_serre_2, t_serre_3, t_verranda, h_serre_2, etat_ouverture, etat_chauffage ) VALUES ('$t_mini_serre','$t_serre_1','$t_serre_2','$t_serre_3','$t_verranda','$h_serre_2','$etat_ouverture','$etat_chauffage' )");
  
?>

La rien de bien compliqué.

Ensuite je dois formater mes données pour pouvoir faire mes graphes. J’ai repris le modèle que j’avais fait pour récupérer mes données Netatmo en faisant un formatage spécial pour l’heure d’été/hiver. C’est mon fichier temperatureserre.php :

<?php
include('connexionDB.php');

$date = 1445538928*1000;
echo "[";
$i=0;
$sth = mysql_query("SELECT datemesure, t_mini_serre, t_serre_1, t_serre_2, t_serre_3 , t_verranda, h_serre_2, etat_chauffage, etat_ouverture FROM serre ORDER BY datemesure ASC");
$rows = array();

while($r = mysql_fetch_array($sth)) {
    if (date("I",time())==0){
    	
    	$date = (strtotime($r["datemesure"])+3600)*1000 ;
    	if (strtotime($r["datemesure"])<1449595350) {
    		$rows[] = "[".$date.",".$r["t_mini_serre"].",".$r["t_serre_1"].",".$r["t_serre_2"].",".$r["t_serre_3"].",".$r["t_verranda"].",".$r["h_serre_2"].",null,".$r["etat_chauffage"].",".$r["etat_ouverture"]."]";
    		$i = $i +1;
    	}
    	else {
    		$rows[] = "[".$date.",".$r["t_mini_serre"].",".$r["t_serre_1"].",".$r["t_serre_2"].",".$r["t_serre_3"].",".$r["t_verranda"].",".$r["h_serre_2"].",".$r["t_verranda"].",".$r["etat_chauffage"].",".$r["etat_ouverture"]."]";
    		$i = $i +1;
    	}
	}
	else {
		
		$date = (strtotime($r["datemesure"])+3600)*1000 ;	
		$rows[] = "[".$date.",".$r["t_mini_serre"].",".$r["t_serre_1"].",".$r["t_serre_2"].",".$r["t_serre_3"].",".$r["t_verranda"].",".$r["h_serre_2"].",".$r["t_verranda"].",".$r["etat_chauffage"].",".$r["etat_ouverture"]."]";
        $i = $i+1;
	}
}
for ($j = 0 ; $j<$i-1; $j ++){
	echo $rows[$j];
	echo ",";
}
echo $rows[$i-1];
echo "]";

?>

Là aussi, je passe les détails, quelques compétences en php permettent de comprendre le code. Vous pouvez regarder le résultat sur ce lien.

Une fois toutes les données récupérées, il reste juste à faire un jolie page pour afficher nos graphes.

C’est la partie qui m’a pris le plus de temps, voici le code :

<?php 
$page = $_SERVER['PHP_SELF'];
$sec = "30";
include('connexionDB.php');

$req = mysql_query("SELECT * FROM serre ORDER BY datemesure DESC LIMIT 1");
while($row = mysql_fetch_assoc($req)) {
   $t_mini_serre =  $row["t_mini_serre"];
   $t_serre_1 =  $row["t_serre_1"];
   $t_serre_2 =  $row["t_serre_2"];
   $t_serre_3 =  $row["t_serre_3"];
   $t_verranda =  $row["t_verranda"];
   $h_serre =  $row["h_serre_2"];
   $etat_ouverture = $row['etat_ouverture'];
   $etat_chauffage = $row['etat_chauffage'];
   
};



        /* On récupère la date du jour et on crée la plage horaire de la journée */
        $day = date("d");
        $month = date("m");
        $year = date("Y");
        $date_inf = $year."-".$month."-".$day." 00:00:00";
        $date_sup = $year."-".$month."-".$day." 23:59:59";

       
        /* On récupère la Température minimum mini serre*/

        $req2 = mysql_query("SELECT * FROM serre WHERE datemesure BETWEEN '$date_inf' AND '$date_sup' ORDER BY t_mini_serre ASC LIMIT 1");
        $data2 = mysql_fetch_array($req2);
        $temperature_minimale_mini = $data2['t_mini_serre'];

        /* On récupère la Température maximum mini serre*/

        $req3 = mysql_query("SELECT * FROM serre WHERE datemesure BETWEEN '$date_inf' AND '$date_sup' ORDER BY t_mini_serre DESC LIMIT 1");
        $data3 = mysql_fetch_array($req3);
        $temperature_maximale_mini = $data3['t_mini_serre'];
    
        

        /* On récupère le temperature minimum serre 1 */

        $req4 = mysql_query("SELECT * FROM serre WHERE datemesure BETWEEN '$date_inf' AND '$date_sup' ORDER BY t_serre_1 ASC LIMIT 1");
        $data4 = mysql_fetch_array($req4);
        $temperature_minimale_serre_1 =  $data4['t_serre_1']   ;
        

        $req5 = mysql_query("SELECT * FROM serre WHERE datemesure BETWEEN '$date_inf' AND '$date_sup' ORDER BY t_serre_1 DESC LIMIT 1");
        $data5 = mysql_fetch_array($req5);
        $temperature_maximale_serre_1 = $data5['t_serre_1'];
        
        /* On récupère le temperature minimum serre 2 */

        $req4 = mysql_query("SELECT * FROM serre WHERE datemesure BETWEEN '$date_inf' AND '$date_sup' ORDER BY t_serre_2 ASC LIMIT 1");
        $data4 = mysql_fetch_array($req4);
        $temperature_minimale_serre_2 =  $data4['t_serre_2']   ;
        

        $req5 = mysql_query("SELECT * FROM serre WHERE datemesure BETWEEN '$date_inf' AND '$date_sup' ORDER BY t_serre_2 DESC LIMIT 1");
        $data5 = mysql_fetch_array($req5);
        $temperature_maximale_serre_2 = $data5['t_serre_2'];
        
        /* On récupère le temperature minimum serre 3 */

        $req4 = mysql_query("SELECT * FROM serre WHERE datemesure BETWEEN '$date_inf' AND '$date_sup' ORDER BY t_serre_3 ASC LIMIT 1");
        $data4 = mysql_fetch_array($req4);
        $temperature_minimale_serre_3 =  $data4['t_serre_3']   ;
        

        $req5 = mysql_query("SELECT * FROM serre WHERE datemesure BETWEEN '$date_inf' AND '$date_sup' ORDER BY t_serre_3 DESC LIMIT 1");
        $data5 = mysql_fetch_array($req5);
        $temperature_maximale_serre_3 = $data5['t_serre_3'];
        
        
        // Moyenne de la temperature de la serre :
        $temperature_minimale_serre = ( $temperature_minimale_serre_1 + $temperature_minimale_serre_2 + $temperature_minimale_serre_3 ) / 3 ;
        $temperature_maximale_serre = ( $temperature_maximale_serre_1 + $temperature_maximale_serre_2 + $temperature_maximale_serre_3 ) / 3 ;
        
        // Humidité serre MINI
        $req8 = mysql_query("SELECT * FROM serre WHERE datemesure BETWEEN '$date_inf' AND '$date_sup' ORDER BY h_serre_2 ASC LIMIT 1");
        $data8 = mysql_fetch_array($req8);
        $humidite_minimale = $data8["h_serre_2"];
        
        // Humidité serre MAXI
        $req9 = mysql_query("SELECT * FROM serre WHERE datemesure BETWEEN '$date_inf' AND '$date_sup' ORDER BY h_serre_2 DESC LIMIT 1");
        $data9 = mysql_fetch_array($req9);
        $humidite_maximale = $data9["h_serre_2"];
        
        // temperature verranda mini
        $req8 = mysql_query("SELECT * FROM serre WHERE datemesure BETWEEN '$date_inf' AND '$date_sup' ORDER BY t_verranda ASC LIMIT 1");
        $data8 = mysql_fetch_array($req8);
        $temperature_verranda_minimale = $data8["t_verranda"];
        
        // temperature verranda maxi
        $req9 = mysql_query("SELECT * FROM serre WHERE datemesure BETWEEN '$date_inf' AND '$date_sup' ORDER BY t_verranda DESC LIMIT 1");
        $data9 = mysql_fetch_array($req9);
        $temperature_verranda_maximale = $data9["t_verranda"];
        
        // VARIATIONS T  / T-1
        $req = mysql_query("SELECT * FROM serre ORDER BY datemesure DESC LIMIT 2");
            while($row = mysql_fetch_assoc($req)) {
                $t_mini_serre_delta[] =  $row["t_mini_serre"];
                $t_serre_1_delta[] =  $row["t_serre_1"];
                $t_serre_2_delta[] =  $row["t_serre_2"];
                $t_serre_3_delta[] =  $row["t_serre_3"];
                $t_verranda_delta[] =  $row["t_verranda"];
                $h_serre_delta[] =  $row["h_serre_2"];
                $etat_ouverture_delta[] = $row['etat_ouverture'];
                $etat_chauffage_delta[] = $row['etat_chauffage'];
   
            };
            $delta_mini_serre = $t_mini_serre_delta[0] - $t_mini_serre_delta[1];
            $delta_serre_1 = $t_serre_1_delta[0] - $t_serre_1_delta[1];
            $delta_serre_2 = $t_serre_2_delta[0] - $t_serre_2_delta[1];
            $delta_serre_3 = $t_serre_3_delta[0] - $t_serre_3_delta[1];
            $delta_verranda = $t_verranda_delta[0] - $t_verranda_delta[1];
            $delta_humidite = $h_serre_delta[0] - $h_serre_delta[1];

    ?>

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <meta http-equiv="refresh" content="<?php echo $sec?>;URL='<?php echo $page?>'">
        <title>Surveillance Serre</title>
        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
        <link rel="stylesheet" type="text/css" href="css/tableaux.css" media="screen" />
        <link rel="stylesheet" type="text/css" href="css/style.css" />


<script type="text/javascript">





$(function () {
    var highchartsOptions = Highcharts.setOptions(Highcharts.theme);    
Highcharts.setOptions({
lang: {

months: ["Janvier "," Février ","Mars "," Avril "," Mai "," Juin "," Juillet "," Août "," Septembre ",
" Octobre "," Novembre "," Décembre"],
weekdays: ["Dim "," Lun "," Mar "," Mer "," Jeu "," Ven "," Sam"],
shortMonths: ['Jan', 'Fev', 'Mar', 'Avr', 'Mai', 'Juin', 'Juil','Août', 'Sept', 'Oct', 'Nov', 'Déc'],
decimalPoint: ',',
resetZoom: 'Reset zoom',
resetZoomTitle: 'Reset zoom à 1:1',
downloadPNG: "Télécharger au format PNG image",
downloadJPEG: "Télécharger au format JPEG image",
downloadPDF: "Télécharger au format PDF document",
downloadSVG: "Télécharger au format SVG vector image",
exportButtonTitle: "Exporter image ou document",
printChart: "Imprimer le graphique",
loading: "Chargement...",
rangeSelectorFrom: "Du",
rangeSelectorTo: "au"
 }

});
    $.getJSON('temperatureserre.php', function (data) {

        // split the data set into temp_int and temp_ext
        var graph_temp_mini_serre = [],
            graph_t_serre_1 = [],
            graph_t_serre_2 = [],
            graph_t_serre_3 = [],
            graph_h_serre_2 = [],
            graph_t_verranda = [],
            graph_chauffage = [],
            graph_ouverture = [],
            dataLength = data.length,
            // set the allowed units for data grouping
            

            i = 0;

        for (i; i < dataLength; i += 1) {
            graph_temp_mini_serre.push([
                data[i][0], // the date
                data[i][1], // température mini serre
                
            ]);

            graph_t_serre_1.push([
                data[i][0], // the date
                data[i][2] // température serre 1 
            ]);
            
            graph_t_serre_2.push([
                data[i][0], // the date
                data[i][3] // température serre 2 
            ]);
            
            graph_t_serre_3.push([
                data[i][0], // the date
                data[i][4] // température serre 3 
            ]);
            
            
            graph_h_serre_2.push([
                data[i][0], // the date
                data[i][6] // hum 
            ]);

            graph_t_verranda.push([
                data[i][0], // the date
                data[i][7] // hum 
            ]);
            
            graph_chauffage.push([
                data[i][0], // the date
                data[i][8] // état chauffage 
            ]);
            
            graph_ouverture.push([
                data[i][0], // the date
                data[i][9] // état ouverture 
            ]);
            
           
            }


        // create the chart
        $('#container2').highcharts('StockChart', {
            credits: {
            enabled: false
        },
             rangeSelector : {
                buttons : [ {
                    type : 'hour',
                    count : 3,
                    text : '3h'
                },{
                    type : 'hour',
                    count : 12,
                    text : '12h'
                },{
                    type : 'day',
                    count : 1,
                    text : '1j'
                },{
                    type : 'day',
                    count : 7,
                    text : '1s'
                },{
                    type : 'month',
                    count : 1,
                    text : '1m'
                }, {
                    type : 'all',
                    count : 1,
                    text : 'Tout'
                }],
                selected : 1
            },
           
            title: {
                text: 'Surveillance Serre'
            },
            
            yAxis: [{
                
                labels: {
                    align: 'right',
                    x: -3
                },
                title: {
                    text: 'Température'
                },
                height: '50%',
                lineWidth: 2
            }, {
                labels: {
                    align: 'right',
                    x: -3
                },
                title: {
                    text: 'Humidité'
                },
                top: '55%',
                height: '30%',
                offset: 0,
                lineWidth: 2
            },{
                labels: {
                    align: 'right',
                    x: -3
                },
                title: {
                    text: 'État'
                },
                min:-0.25,
                max:1,
                top: '90%',
                height: '10%',
                offset: 0,
                lineWidth: 2
            }],
            xAxis: {
                ordinal: false,
                alternateGridColor: '#F0FFFF'
            },
            tooltip: {
                    xDateFormat: '%a %d %b %H:%M'
                    
                },
            plotOptions: {
                line: {
                    connectNulls: false,
                        }
            },
            series: [{
                name: 'T° mini Serre',
                color:'#58ACFA',
                data: graph_temp_mini_serre,
                tooltip: {
                    valueDecimals: 1,
                    valueSuffix:' °C'
                }
            }, {
                name: 'T° Serre étage 1',
                color:'#CC2EFA',
                data: graph_t_serre_1,
                yAxis:0,
                tooltip: {
                    valueDecimals: 1,
                    valueSuffix:' °C'
                }
            },
            {
                name: 'T° Serre étage 2',
                color: '#FE2E64',
                data: graph_t_serre_2,
                yAxis:0,
                tooltip: {
                    valueDecimals: 1,
                    valueSuffix:' °C'
                }
            },
            {
                name: 'T° Serre étage 3',
                color: '#04B431',
                data: graph_t_serre_3,
                yAxis:0,
                tooltip: {
                    valueDecimals: 1,
                    valueSuffix:' °C'
                }
            },
            {
                name: 'T° Verranda',
                color: '#FE642E',
                data: graph_t_verranda,
                yAxis:0,
                tooltip: {
                    valueDecimals: 1,
                    valueSuffix:' °C'
                }
            },
            
            {
                name: 'Humidité intérieur',
                color: '#5882FA',
                data: graph_h_serre_2,
                yAxis: 1,
                tooltip: {
                    valueDecimals: 1,
                    valueSuffix:' %'
                }
            },
            {
                name: 'Chauffage',
                data: graph_chauffage,
                yAxis:2,
                tooltip: {
                    valueDecimals: 1,
                    valueSuffix:' °C'
                }
            },
            {
                name: 'Ouverture',
                data: graph_ouverture,
                yAxis:2,
                tooltip: {
                    valueDecimals: 1,
                    valueSuffix:' °C'
                }
            }]
        });
    });
});




// Temp mini serre
$(function () {

    $('#temp_mini_serre').highcharts({

        chart: {
            type: 'gauge',
            plotBackgroundColor: null,
            plotBackgroundImage: null,
            plotBorderWidth: 0,
            plotShadow: false
        },

        title: {
            text: '<span style="font-size:14px; color:#58ACFA">Mini Serre :  <?php echo number_format($t_mini_serre,1,',','.'); ?>°C'
        },
        credits: {
            enabled: false
        },

        pane: {
            startAngle: -150,
            endAngle: 150,
            background: [{
                backgroundColor: {
                    linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
                    stops: [
                        [0, '#FFF'],
                        [1, '#333']
                    ]
                },
                borderWidth: 0,
                outerRadius: '109%'
            }, {
                backgroundColor: {
                    linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
                    stops: [
                        [0, '#333'],
                        [1, '#FFF']
                    ]
                },
                borderWidth: 1,
                outerRadius: '107%'
            }, {
                // default background
            }, {
                backgroundColor: '#DDD',
                borderWidth: 0,
                outerRadius: '105%',
                innerRadius: '103%'
            }]
        },

        // the value axis
        yAxis: {
            min: 10,
            max: 40,

            minorTickInterval: 'auto',
            minorTickWidth: 1,
            minorTickLength: 10,
            minorTickPosition: 'inside',
            minorTickColor: '#666',

            tickPixelInterval: 30,
            tickWidth: 2,
            tickPosition: 'inside',
            tickLength: 10,
            tickColor: '#666',
            labels: {
                step: 1,
                rotation: 'auto'
            },
            title: {
                text: '°C'
            },
            plotBands: [{
                from: 10,
                to: 20,
                color: '#55BF3B' // green
            }, {
                from: 20,
                to: 30,
                color: '#DDDF0D' // yellow
            }, {
                from: 30,
                to: 40,
                color: '#DF5353' // red
            }]
        },
        plotOptions: {
            gauge: {
                dataLabels: {
                    enabled: false
                },
                dial: {
                    radius: '100%'
                }
            }
        },
        series: [{
            color:'#58ACFA',
            name: 'Température mini Serre',
            data: [<?php echo $t_mini_serre; ?>],
            tooltip: {
                valueSuffix: ' °C'
            }
        }]

    });
});

// temp etage 1
$(function () {

    $('#temp_serre_etage_1').highcharts({

        chart: {
            type: 'gauge',
            plotBackgroundColor: null,
            plotBackgroundImage: null,
            plotBorderWidth: 0,
            plotShadow: false
        },
        credits: {
            enabled: false
        },

        title: {
            text: '<span style="font-size:14px; color:#CC2EFA">Serre étage 1 :  <?php echo number_format($t_serre_1,1,',','.'); ?> °C'
        },

        pane: {
            startAngle: -150,
            endAngle: 150,
            background: [{
                backgroundColor: {
                    linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
                    stops: [
                        [0, '#FFF'],
                        [1, '#333']
                    ]
                },
                borderWidth: 0,
                outerRadius: '109%'
            }, {
                backgroundColor: {
                    linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
                    stops: [
                        [0, '#333'],
                        [1, '#FFF']
                    ]
                },
                borderWidth: 1,
                outerRadius: '107%'
            }, {
                // default background
            }, {
                backgroundColor: '#DDD',
                borderWidth: 0,
                outerRadius: '105%',
                innerRadius: '103%'
            }]
        },

        // the value axis
        yAxis: {
            min: -10,
            max: 40,

            minorTickInterval: 'auto',
            minorTickWidth: 1,
            minorTickLength: 10,
            minorTickPosition: 'inside',
            minorTickColor: '#666',

            tickPixelInterval: 30,
            tickWidth: 2,
            tickPosition: 'inside',
            tickLength: 10,
            tickColor: '#666',
            labels: {
                step: 2,
                rotation: 'auto'
            },
            title: {
                text: '°C'
            },
            plotBands: [{
                from: -10,
                to: 0,
                color: '#6BDBF7' // blue
            },{
                from: 0,
                to: 20,
                color: '#55BF3B' // green
            }, {
                from: 20,
                to: 30,
                color: '#DDDF0D' // yellow
            }, {
                from: 30,
                to: 40,
                color: '#DF5353' // red
            }]
        },
        plotOptions: {
            gauge: {
                dataLabels: {
                    enabled: false
                },
                dial: {
                    radius: '100%'
                }
            }
        },
        series: [{
            color:'#CC2EFA',
            name: 'Température Serre',
            data: [<?php echo $t_serre_1; ?>],
            tooltip: {
                valueSuffix: ' °C'
            }
        }]

    });
});


// temp etage 2
$(function () {

    $('#temp_serre_etage_2').highcharts({

        chart: {
            type: 'gauge',
            plotBackgroundColor: null,
            plotBackgroundImage: null,
            plotBorderWidth: 0,
            plotShadow: false
        },
        credits: {
            enabled: false
        },
        title: {
            text: '<span style="font-size:14px; color:#FE2E64">Serre étage 2 : <?php echo number_format($t_serre_2,1,',','.'); ?> °C'
        },

        pane: {
            startAngle: -150,
            endAngle: 150,
            background: [{
                backgroundColor: {
                    linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
                    stops: [
                        [0, '#FFF'],
                        [1, '#333']
                    ]
                },
                borderWidth: 0,
                outerRadius: '109%'
            }, {
                backgroundColor: {
                    linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
                    stops: [
                        [0, '#333'],
                        [1, '#FFF']
                    ]
                },
                borderWidth: 1,
                outerRadius: '107%'
            }, {
                // default background
            }, {
                backgroundColor: '#DDD',
                borderWidth: 0,
                outerRadius: '105%',
                innerRadius: '103%'
            }]
        },

        // the value axis
        yAxis: {
            min: -10,
            max: 40,

            minorTickInterval: 'auto',
            minorTickWidth: 1,
            minorTickLength: 10,
            minorTickPosition: 'inside',
            minorTickColor: '#666',

            tickPixelInterval: 30,
            tickWidth: 2,
            tickPosition: 'inside',
            tickLength: 10,
            tickColor: '#666',
            labels: {
                step: 2,
                rotation: 'auto'
            },
            title: {
                text: '°C'
            },
            plotBands: [{
                from: -10,
                to: 0,
                color: '#6BDBF7' // blue
            },{
                from: 0,
                to: 20,
                color: '#55BF3B' // green
            }, {
                from: 20,
                to: 30,
                color: '#DDDF0D' // yellow
            }, {
                from: 30,
                to: 40,
                color: '#DF5353' // red
            }]
        },
        plotOptions: {
            gauge: {
                dataLabels: {
                    enabled: false
                },
                dial: {
                    radius: '100%'
                }
            }
        },
        series: [{
            color:'#FE2E64',
            name: 'Température Serre',
            data: [<?php echo $t_serre_2; ?>],
            tooltip: {
                valueSuffix: ' °C'
            }
        }]

    });
});


// temp etage 3
$(function () {

    $('#temp_serre_etage_3').highcharts({

        chart: {
            type: 'gauge',
            plotBackgroundColor: null,
            plotBackgroundImage: null,
            plotBorderWidth: 0,
            plotShadow: false
        },
        credits: {
            enabled: false
        },
        title: {
            text: '<span style="font-size:14px; color:#04B431">Serre étage 3   : <?php  echo number_format($t_serre_3,1,',','.'); ?> °C'
        },

        pane: {
            startAngle: -150,
            endAngle: 150,
            background: [{
                backgroundColor: {
                    linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
                    stops: [
                        [0, '#FFF'],
                        [1, '#333']
                    ]
                },
                borderWidth: 0,
                outerRadius: '109%'
            }, {
                backgroundColor: {
                    linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
                    stops: [
                        [0, '#333'],
                        [1, '#FFF']
                    ]
                },
                borderWidth: 1,
                outerRadius: '107%'
            }, {
                // default background
            }, {
                backgroundColor: '#DDD',
                borderWidth: 0,
                outerRadius: '105%',
                innerRadius: '103%'
            }]
        },

        // the value axis
        yAxis: {
            min: -10,
            max: 40,

            minorTickInterval: 'auto',
            minorTickWidth: 1,
            minorTickLength: 10,
            minorTickPosition: 'inside',
            minorTickColor: '#666',

            tickPixelInterval: 30,
            tickWidth: 2,
            tickPosition: 'inside',
            tickLength: 10,
            tickColor: '#666',
            labels: {
                step: 2,
                rotation: 'auto'
            },
            title: {
                text: '°C'
            },
            plotBands: [{
                from: -10,
                to: 0,
                color: '#6BDBF7' // blue
            },{
                from: 0,
                to: 20,
                color: '#55BF3B' // green
            }, {
                from: 20,
                to: 30,
                color: '#DDDF0D' // yellow
            }, {
                from: 30,
                to: 40,
                color: '#DF5353' // red
            }]
        },
        plotOptions: {
            gauge: {
                dataLabels: {
                    enabled: false
                },
                dial: {
                    radius: '100%'
                }
            }
        },
        series: [{
            color:'#04B431',
            name: 'Température Serre',
            data: [<?php echo $t_serre_3; ?>],
            tooltip: {
                valueSuffix: ' °C'
            }
        }]

    });
});


// temp verranda
$(function () {

    $('#temp_verranda').highcharts({

        chart: {
            type: 'gauge',
            plotBackgroundColor: null,
            plotBackgroundImage: null,
            plotBorderWidth: 0,
            plotShadow: false
        },
        credits: {
            enabled: false
        },
        title: {
            text: ' <span style="font-size:14px; color:#FE642E"> Verranda :  <?php echo number_format($t_verranda,1,',','.'); ?> °C </span>'
        },

        pane: {
            startAngle: -150,
            endAngle: 150,
            background: [{
                backgroundColor: {
                    linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
                    stops: [
                        [0, '#FFF'],
                        [1, '#333']
                    ]
                },
                borderWidth: 0,
                outerRadius: '109%'
            }, {
                backgroundColor: {
                    linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
                    stops: [
                        [0, '#333'],
                        [1, '#FFF']
                    ]
                },
                borderWidth: 1,
                outerRadius: '107%'
            }, {
                // default background
            }, {
                backgroundColor: '#DDD',
                borderWidth: 0,
                outerRadius: '105%',
                innerRadius: '103%'
            }]
        },

        // the value axis
        yAxis: {
            min: -10,
            max: 40,

            minorTickInterval: 'auto',
            minorTickWidth: 1,
            minorTickLength: 10,
            minorTickPosition: 'inside',
            minorTickColor: '#666',

            tickPixelInterval: 30,
            tickWidth: 2,
            tickPosition: 'inside',
            tickLength: 10,
            tickColor: '#666',
            labels: {
                step: 2,
                rotation: 'auto'
            },
            title: {
                text: '°C'
            },
            plotBands: [{
                from: -10,
                to: 0,
                color: '#6BDBF7' // blue
            },{
                from: 0,
                to: 20,
                color: '#55BF3B' // green
            }, {
                from: 20,
                to: 30,
                color: '#DDDF0D' // yellow
            }, {
                from: 30,
                to: 40,
                color: '#DF5353' // red
            }]
        },
        plotOptions: {
            gauge: {
                dataLabels: {
                    enabled: false
                },
                dial: {
                    radius: '100%'
                }
            }
        },
        series: [{

            color:'#FE642E',
            name: 'Température Verranda',
            data: [<?php echo $t_verranda; ?>],
            tooltip: {
                valueSuffix: ' °C'
            }
        }]

    });
});



//Humidité
$(function () {

    $('#hum_serre').highcharts({

        chart: {
            type: 'gauge',
            plotBackgroundColor: null,
            plotBackgroundImage: null,
            plotBorderWidth: 0,
            plotShadow: false
        },
        credits: {
            enabled: false
        },

        title: {
            text: '<span style="font-size:14px; color:#5882FA"> Humidité Serre : <?php echo number_format($h_serre,0,',','.'); ?> %</span> '
        },

        pane: {
            startAngle: -150,
            endAngle: 150,
            background: [{
                backgroundColor: {
                    linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
                    stops: [
                        [0, '#FFF'],
                        [1, '#333']
                    ]
                },
                borderWidth: 0,
                outerRadius: '109%'
            }, {
                backgroundColor: {
                    linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
                    stops: [
                        [0, '#333'],
                        [1, '#FFF']
                    ]
                },
                borderWidth: 1,
                outerRadius: '107%'
            }, {
                // default background
            }, {
                backgroundColor: '#DDD',
                borderWidth: 0,
                outerRadius: '105%',
                innerRadius: '103%'
            }]
        },

        // the value axis
        yAxis: {
            min: 0,
            max: 100,

            minorTickInterval: 'auto',
            minorTickWidth: 1,
            minorTickLength: 10,
            minorTickPosition: 'inside',
            minorTickColor: '#666',

            tickPixelInterval: 30,
            tickWidth: 2,
            tickPosition: 'inside',
            tickLength: 10,
            tickColor: '#666',
            labels: {
                step: 2,
                rotation: 'auto'
            },
            title: {
                text: '%'
            },
            
        },
        plotOptions: {
            gauge: {
                dataLabels: {
                    enabled: false
                },
                dial: {
                    radius: '100%'
                }
            }
        },
        series: [{
            color:'#5882FA',
            name: 'Humidité Serre',
            data: [<?php echo $h_serre; ?>],
            tooltip: {
                valueSuffix: ' %'
            }
        }]

    });
});

$(function () {

    var gaugeOptions = {

        chart: {
            type: 'solidgauge'
        },

        title: null,

        pane: {
            center: ['50%', '85%'],
            size: '140%',
            startAngle: -90,
            endAngle: 90,
            background: {
                backgroundColor: (Highcharts.theme && Highcharts.theme.background2) || '#DF5353',
                innerRadius: '60%',
                outerRadius: '100%',
                shape: 'arc'
            }
        },

        tooltip: {
            enabled: false
        },

        // the value axis
        yAxis: {
            stops: [
                [0.1, '#DF5353'], // red
                [0.9, '#55BF3B'] // green
            ],
            lineWidth: 0,
            minorTickInterval: null,
            tickPixelInterval: 400,
            tickWidth: 0,
            title: {
                y: -70
            },
            labels: {
                y: 16
            }
        },

        plotOptions: {
            solidgauge: {
                dataLabels: {
                    y: 5,
                    borderWidth: 0,
                    useHTML: true
                }
            }
        }
    };

    // The speed gauge
    $('#aeration').highcharts(Highcharts.merge(gaugeOptions, {
        yAxis: {
            min: 0,
            max: 1,
           
        },

        credits: {
            enabled: false
        },

        series: [{
            name: 'Speed',
            data: [<?php echo $etat_ouverture; ?>],
            dataLabels: {
                format: '<span style="font-size:20px">Aération</span></div>'
            },
            tooltip: {
                valueSuffix: ' km/h'
            }
        }]

    }));

    // The RPM gauge
    $('#chauffage').highcharts(Highcharts.merge(gaugeOptions, {
        yAxis: {
            min: 0,
            max: 1,
            
        },
        credits: {
            enabled: false
        },
        series: [{
            name: 'RPM',
            data: [<?php echo $etat_chauffage; ?>],
            dataLabels: {
                format: '<span style="font-size:20px">Chauffage</span></div>'
            },
            tooltip: {
                valueSuffix: ' revolutions/min'
            }
        }]

    }));

    


});




</script>





     
<script src="http://code.highcharts.com/stock/highstock.js"></script>
<script src="http://code.highcharts.com/highcharts.js"></script>
<script src="http://code.highcharts.com/highcharts-more.js"></script>
<script src="https://code.highcharts.com/modules/solid-gauge.js"></script>
<script src="https://code.highcharts.com/modules/data.js"></script>
<!-- <script src="http://code.highcharts.com/modules/exporting.js"></script> -->
    </head>
    <body>
       
       <div id="container2" style="width: 55%; height: 100%; float: left; "></div>
       <div id="temp_mini_serre" style="width: 15%; height: 30%; float: left ; "></div>
       <div id="temp_serre_etage_1" style="width: 15%; height: 30%; float: left ; "></div>
       <div id="temp_serre_etage_2" style="width: 15%; height: 30%; float: left ; "></div>
       <div id="temp_serre_etage_3" style="width: 15%; height: 30%; float: left ; "></div>
       <div id="temp_verranda" style="width: 15%; height: 30%; float: left ; "></div>
       <div id="hum_serre" style="width: 15%; height: 30%; float: left ; "></div>
       
       <div style="width: 1%; height: 4%; float: left ;"></div> 
      <div style="width: 10%; height: 4%; float: left; font-size:26px;  top: 50%; margin-top: 50px; right: -50%; "> Aération</div>
      <div style="width: 8%; height: 4%; float: left ;" class="switch demo">
    <input type="checkbox" disabled="disabled"
    <?php 
    if($etat_ouverture == 1) {
        ?>
        checked
        <?php
    }
    ?>
    ><label><i></i></label>
    </div>

      
      <div style="width: 5%; height: 4%; float: left ;"></div>
      <div style="width: 10%; height: 4%; float: left; font-size:26px;  top: 50%; margin-top: 50px; right: -50%; "> Chauffage</div>
      <div style="width: 8%; height: 4%; float: left ;" class="switch demo">
    <input type="checkbox" disabled="disabled"
    <?php 
    if($etat_chauffage == 1) {
        ?>
        checked
        <?php
    }
    ?>
    ><label><i></i></label>
    </div>
      

<div style="width: 44%; height: 20%; float: left ;" class="CSSTableGenerator" >
                <table >
                    <tr>
                        <td width="8%">
                        </td>
                        <td colspan="2" width="15%">
                           Mini Serre
                        </td>
                        <td colspan="2" width="15%">
                           Serre 1
                        </td>
                        <td colspan="2" width="15%">
                           Serre 2
                        </td>
                        <td colspan="2" width="15%">
                           Serre 3
                        </td>
                        <td colspan="2" width="15%">
                           Humidité
                        </td>
                        <td colspan="2" width="15%">
                           Verranda
                        </td>

                    </tr>
                    <tr style="color:#0000FF">
                        <td>
                        Mini
                        </td>
                        <td colspan="2">
                           <?php echo number_format($temperature_minimale_mini,1);?>°C
                        </td>
                        <td colspan="2">
                           <?php echo number_format($temperature_minimale_serre_1,1);?>°C
                        </td>
                        <td colspan="2">
                           <?php echo number_format($temperature_minimale_serre_2,1);?>°C
                        </td>
                        <td colspan="2">
                           <?php echo number_format($temperature_minimale_serre_3,1);?>°C
                        </td>
                        <td colspan="2">
                           <?php echo $humidite_minimale;?>%
                        </td>
                        <td colspan="2">
                           <?php echo $temperature_verranda_minimale;?>°C
                        </td>

                    </tr>
                    
                    <tr style="color:#FF0000">
                        <td>
                        Maxi
                        </td>
                        <td colspan="2">
                           <?php echo number_format($temperature_maximale_mini,1);?>°C
                        </td>
                        <td colspan="2">
                           <?php echo number_format($temperature_maximale_serre_1,1);?>°C
                        </td>
                        <td colspan="2">
                           <?php echo number_format($temperature_maximale_serre_2,1);?>°C
                        </td>
                        <td colspan="2">
                           <?php echo number_format($temperature_maximale_serre_3,1);?>°C
                        </td>
                        <td colspan="2">
                           <?php echo $humidite_maximale;?>%
                        </td>
                        <td colspan="2">
                           <?php echo $temperature_verranda_maximale;?>°C
                        </td>

                    </tr>
                    
                    <tr >
                        <td>
                        Ecart
                        </td>
                        <td 
                        <?php if ($delta_mini_serre<0) {
                            ?>
                            style="color:#FF0000"
                            <?php
                        }
                        ?>
                        colspan="2">
                           <?php echo number_format($delta_mini_serre,2);?>°C
                        </td>
                        <td <?php if ($delta_serre_1<0) {
                            ?>
                            style="color:#FF0000"
                            <?php
                        }
                        ?>
                        colspan="2">
                           <?php echo number_format($delta_serre_1,2);?>°C
                        </td>
                        <td <?php if ($delta_serre_2<0) {
                            ?>
                            style="color:#FF0000"
                            <?php
                        }
                        ?>
                        colspan="2">
                           <?php echo number_format($delta_serre_2,2);?>°C
                        </td>
                        <td <?php if ($delta_serre_3<0) {
                            ?>
                            style="color:#FF0000"
                            <?php
                        }
                        ?>
                        colspan="2">
                           <?php echo number_format($delta_serre_3,2);?>°C
                        </td>
                        <td <?php if ($delta_humidite<0) {
                            ?>
                            style="color:#FF0000"
                            <?php
                        }
                        ?>
                        colspan="2">
                           <?php echo number_format($delta_humidite,2);?>%
                        </td>
                        <td <?php if ($delta_verranda<0) {
                            ?>
                            style="color:#FF0000"
                            <?php
                        }
                        ?>
                        colspan="2">
                           <?php echo number_format($delta_verranda,2);?>°C
                        </td>

                    </tr>
                    
                </table>
                
            </div>
       

    </body>
</html>

Le résultat est visible sur ce lien.

Quelques images en vrac :

IMG_0558 IMG_0536 IMG_0528 IMG_0560 IMG_0561 IMG_0568 IMG_0565IMG_0566

 

3 réflexions au sujet de « Serre connectée ! »

  1. Super tuto
    Néophite dans la programmation de L’arduino dans l’IDE ( j’utilise des interfaces comme mblock etc … forcément moins riches que les bibliothèques)
    Je suis intéressé par votre projet de mini-serre pour mes élèves de 6è ( vous l’avez compris, je suis prof de techno)
    Je vais utiliser une ‘arduino Uno
    Un ruban led de culture r+b
    Un module capteur de température DS18B20
    Un module de luminosité
    Des relais 5/12 v
    Un ventilateur 12v
    Un service moteur pour ouvrir et fermer le toit
    Pensez-vous que je puisse reprendre votre programme ( sans liaison ethernet)?
    Merci et encore bravo
    Cordialement

    1. Bien sur vous pouvez le reprendre sans soucis et le modifier comme vous voulez c’est fait pour ça !

  2. […] (assez geek !) fabriquent eux-mêmes, à leur échelle, leur serre connectée. Il en est certains qui expliquent même dans le détail comment ils ont procédé, codage informatique compris… et […]

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *