Publié le

Une box domotique sur RaspberryPi avec Domoticz !

Depuis un (grand) moment j’avais envie de me faire une box domotique pour un peu tout surveiller.

Début des vacances donc je me suis lancé !

1. La base : la box

Pour installer la box rien de plus simple : Un Raspberry Pi 2 (mon 3 me sert de serveur d’impression pour l’imprimante 3D) et on récupère une image de Domoticz ici.

Une fois récupérée, on utilise Win32DiskImager pour créer la carte Sd du Rasp.

J’y ai ajouté un Z-stick pour pouvoir contrôler des périphériques Z-Wave.

2. Configuration du Z-stick

Pour l’installer un petit tour sur Réglages – Matériel et on ajoute OpenZWave USB, on sélectionne le bon port et c’est parti pour installer les périphériques Z-Wave (je passe rapidement, c’est pas le plus passionnant et on trouve beaucoup de doc sur ça sur internet).

3. Ajout de la station météo Netatmo

L’an dernier j’ai fait des scrips php dans tous les sens pour récupérer les infos de la station météo, j’ai fait des graphes … Mais le soucis est la centralisation des données.

Ici c’est un jeu d’enfant, on ajoute dans matériel Netatmo, on renseigne l’identifiant et le mot de passe et ça récupère tout !

4. Une sonde de température sur le Rasp ?

Tiens j’ai vu qu’on pouvait mettre une sonde de température sur le Rasp pour avoir la température soit à proximité du Rasp, soit dans la pièce !

Cool j’ai une sonde DS18B20 en filaire qui traine !

Voici le schéma de branchement :

raspds18b20

Dans matériel on ajoute 1-Wire (System) et ça roule ! On a la température de la sonde !

 

Question : Il sert à quoi ton blog c’est tout simple ?

Réponse : On va attaquer le plus « dur »

5. Interfaçage avec Kodi (média player)

Pour le fun, j’ai installé Kodi sur mon pc, j’avais envie de créer une petite règle : quand je met mon film en pause ça allume la lumière et quand je reprend la lecture ça éteint la lumière.

J’ai donc installé Kodi (ex XBMC) et je suis allé réglé dans Système – Paramètres – Service – Serveur web :

Kodi

On coche « Autoriser le contrôle à distance via HTTP »

on relève le numéro de port et on va ajouter un nouveau matériel dans Domoticz : Kodi Media Server.

Une fois ajouté on clique sur Réglages :

kodi2

Kodi est donc configuré sur Domoticz, je vais aller créer un Evènement pour allumer/éteindre ma lampe !

Direction Réglages – Plus d’options – Evènement

Ca ressemble beaucoup à Scratch c’est à dire de la programmation par glisser/déposer.

Voilà à quoi ressemble mon événement :

Kodi3

Du coup quand je met en pause sur Kodi la lumière s’allume, quand je remet en lecture ça coupe !

6. Interfaçage avec Octoprint :

Alors je fais du graduel en difficulté, je n’ai pas tout fait dans cet ordre (et Octoprint je l’ai fait en deux fois).

Ce que je voulais avec Octoprint est de pouvoir récupérer les températures de la tête et du lit ainsi que la vidéo.

6.1 Récupérer la vidéo :

Il y a deux solutions : soit ajouter une webcam (mais alors le résultat est très très très moche donc je passe), soit utiliser l’onglet Perso (qui permet d’afficher un peu tout ce qu’on veut).

J’ai choisit la seconde option qui est plus propre :

Il faut aller dans le dossier /domoticz/www/templates, j’ai créé un fichier cam3d.html avec le contenu suivant :

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="fr" xml:lang="fr">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
  <title>Webcams</title>
<style type="text/CSS">
  h2     {
color:#4E632C;
}

#main {
max-width:960px;
margin:auto;
position:relative;
}
#cam1 {
width:900px;
position:absolute;
}

</style>
</head>
<body>
<div id="cam1">
 <h2>Webcam Imprimante 3D</h2>

<img src="http://192.168.1.56/webcam/?action=stream"></img>
</div>

</div>
</div>
</body>
</html>

Et j’obtient la page suivante dans l’onglet perso :

cam3d

Youpi ! Je vois l’impression en direct depuis Domoticz (avec la solution de simplicité).

Pour info voici ce que ça fait en ajoutant une webcam :

cam3d2

On a vu moins moche quand même !

6.2 Récupérer les infos de l’imprimante 3D

Ah ah ah alors là c’est le plus fun (pas le plus dur, mais le plus fun je me suis bien amusé).

6.2.1 Créer un matériel virtuel dans Domoticz :

On ajoute dans matériel un « Dummy » qui va en fait être un groupe de capteurs virtuels.

Je l’ai appelé « Imprimante 3D »

On clique ensuite sur Créer des capteurs virtuels. J’en ai créé 3 : deux de type température (pour la tête et pour le lit) et un de type interrupteur (pour savoir si l’imprimante est en impression ou à l’arrêt) et je relève leurs idx.

Ici j’ai les idx 23, 24, 25

octo

6.2.2 Récupérer les infos d’Octoprint :

Alors petit tour sur le guide de l’API d’Octoprint, la requête est assez simple :

http://192.168.1.56/api/printer?apikey=1EF6D3B280D44A589F29BBE1BEBA73C4

(pour l’API key il faut prendre la votre hein)

Un coup dans chrome pour voir ce que ça donne :

{
  "sd": {
    "ready": false
  }, 
  "state": {
    "flags": {
      "closedOrError": false, 
      "error": false, 
      "operational": true, 
      "paused": false, 
      "printing": true, 
      "ready": true, 
      "sdReady": false
    }, 
    "text": "Printing"
  }, 
  "temperature": {
    "bed": {
      "actual": 45.3, 
      "offset": 0, 
      "target": 45.0
    }, 
    "tool0": {
      "actual": 209.8, 
      "offset": 0, 
      "target": 210.0
    }
  }
}

Ah plutôt cool avec cette requête j’obtient directement les infos que j’ai besoin ! Youpi !

Bon maintenant, il faut voir comment récupérer les valeurs et les envoyer à Domoticz !

6.2.3 Un petit coup de Python !

J’aurai pu faire du C, du Pearl… Mais j’avais envie de faire un petit programme en Python (que je n’ai pas touché depuis environ 10 ans).

déjà première étape on va installer un petit paquet pour faire les requêtes :

sudo apt-get install python-requests

Il est lancé ? Alors amusons nous un peu avant d’attaquer le programme !

On lance python dans le bash !

>>> import requests >>> r = requests.get(« http://192.168.1.56/api/printer?apikey=1EF6D3B280D44A589F29BBE1BEBA73C4 ») >>> r.content ‘{\n « sd »: {\n « ready »: false\n }, \n « state »: {\n « flags »: {\n « closedOrError »: false, \n « error »: false, \n « operational »: true, \n « paused »: false, \n « printing »: true, \n « ready »: true, \n « sdReady »: false\n }, \n « text »: « Printing »\n }, \n « temperature »: {\n « bed »: {\n « actual »: 44.7, \n « offset »: 0, \n « target »: 45.0\n }, \n « tool0 »: {\n « actual »: 210.4, \n « offset »: 0, \n « target »: 210.0\n }\n }\n}’ 

Wahooo j’ai mes données ! Amusons nous à les formater un peu !

Découpons un peu tout ça :

>>> reponse = r.content.split() >>> reponse [‘{‘, ‘ »sd »:’, ‘{‘, ‘ »ready »:’, ‘false’, ‘},’, ‘ »state »:’, ‘{‘, ‘ »flags »:’, ‘{‘, ‘ »closedOrError »:’, ‘false,’, ‘ »error »:’, ‘false,’, ‘ »operational »:’, ‘true,’, ‘ »paused »:’, ‘false,’, ‘ »printing »:’, ‘true,’, ‘ »ready »:’, ‘true,’, ‘ »sdReady »:’, ‘false’, ‘},’, ‘ »text »:’, ‘ »Printing »‘, ‘},’, ‘ »temperature »:’, ‘{‘, ‘ »bed »:’, ‘{‘, ‘ »actual »:’, ‘44.7,’, ‘ »offset »:’, ‘0,’, ‘ »target »:’, ‘45.0’, ‘},’, ‘ »tool0″:’, ‘{‘, ‘ »actual »:’, ‘210.4,’, ‘ »offset »:’, ‘0,’, ‘ »target »:’, ‘210.0’, ‘}’, ‘}’, ‘}’] 

Cherchons ce qui nous intéresse :

>>> reponse[19]
'true,'

J’ai un soucis ! il me rajoute une virgule à la fin :

>>> reponse[19]
'true,'
>>> reponse[19].strip(',')
'true'

Ah c’est mieux ! Mais mon interrupteur ne sais voir que « On » et « Off » dans domoticz, formatons tout ça :

>>> etatbouton = reponse[19].strip(',')
>>> etatbouton
'true'
>>> if etatbouton == "true": etatbouton = "On"
...
>>> etatbouton
'On'

Bon je crois qu’on est bon ! Petit tour sur la doc json de Domoticz

  • Interrupteur :
    http://192.168.1.37:8080/json.htm?type=command&param=switchlight&idx=25&switchcmd=
  • Température :
    http://192.168.1.37:8080/json.htm?type=command&param=udevice&idx=23&nvalue=0&svalue=12.3

Plus qu’à faire un petit script python domoticz.py :

import sys
import requests

r = requests.get("http://192.168.1.56/api/printer?apikey=1EF6D3B280D44A589F29BBE1BEBA73C4")
reponse = r.content.split()
bed =  reponse[33].strip(',')
tete = reponse[42].strip(',')
etat = reponse[19].strip(',')

base1 = "http://192.168.1.37:8080/json.htm?type=command&param=udevice&idx=24&nvalue=0&svalue="
base2 = "http://192.168.1.37:8080/json.htm?type=command&param=udevice&idx=23&nvalue=0&svalue="
base3 = "http://192.168.1.37:8080/json.htm?type=command&param=switchlight&idx=25&switchcmd="

if etat == "true": etat = 'On'
else : etat = 'Off'

sendbed = base1 + bed
sendtete = base2 + tete
sendetat = base3 + etat

requests.get(sendbed)
requests.get(sendtete)
requests.get(sendetat)

Un petit test pour voir si ça modifie bien les valeurs dans Domoticz :

python domoticz.py

si ça fonctionne on va aller l’ajouter dans le cron pour exécuter le script toutes les minutes :

sudo crontab -e

Et on crée la règle :

# Edit this file to introduce tasks to be run by cron.
#
# Each task to run has to be defined through a single line
# indicating with different fields when the task will be run
# and what command to run for the task
#
# To define the time you can provide concrete values for
# minute (m), hour (h), day of month (dom), month (mon),
# and day of week (dow) or use '*' in these fields (for 'any').#
# Notice that tasks will be started based on the cron's system
# daemon's notion of time and timezones.
#
# Output of the crontab jobs (including errors) is sent through
# email to the user the crontab file belongs to (unless redirected).
#
# For example, you can run a backup of all your user accounts
# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
#
# For more information see the manual pages of crontab(5) and cron(8)
#
# m h  dom mon dow   command

*/1 * * * * /usr/bin/python /home/pi/domoticz.py

7. HomeBridge

Avec la béta d’iOS 10, une nouvelle application « Domicile » est arrivée, elle permet de controler les équipements domotiques certifiés HomeKit avec iOS et TvOS.

Il y a un moyen de l’utiliser avec Domoticz : HomeBrigde

7.1 Installation :

Allez plein de commandes à taper dans le shell ! Youpi !

sudo npm install -g homebridge --unsafe-perm

C’est tout ? Ben oui c’est tout !

7.2 Configuration :

On installe en premier le pluggin pour Domoticz :

sudo npm install -g homebridge-edomoticz

on va dans le dossier /home/pi/.homebridge et on crée un fichier config.json :

{
    "bridge": {
        "name": "Homebridge",
        "username": "CC:22:3D:E3:CE:30",
        "port": 51826,
        "pin": "031-45-154"
    },

    "description": "This is an example configuration file with one fake accessory and one fake platform. You can use this as a template for creating your own configuration file containing devices you actually own.",

"platforms": [
        {
            "platform": "eDomoticz",
            "name": "eDomoticz",
            "server": "127.0.0.1",
            "port": "8080",
            "ssl": 0,
            "roomid": 0
        }
    ],
    "accessories": []
}

On teste HomeBridge en lançant la commande « homebridge » si tout va bien :

homebridge

Et on a plus qu’à ajouter le périphérique Domoticz avec l’application Domicile d’Apple !

8. MySensors !

J’ai commencé à jouer avec les Arduinos l’an dernier quand j’ai voulu faire un monitoring de ma piscine.

Je m’étais fait un mini-site qui récupérait les infos de la piscine pour pouvoir la surveiller à distance.

J’ai repris mon projet cette année pour l’intégrer à Domoticz.

8.1 MySensors c’est quoi ?

MySensors c’est un un arduino connecté sur le Rasp qui fait office de serveur NRF et d’autres arduinos en mode client.

Je vous conseille un petit tout sur MySensors pour plus de détails.

8.2 Coté serveur :

8.2.1 Matériel :

  • Arduino Uno
  • 1 Module NRF24L01
  • Des cables

8.2.2 Installation du serveur

Alors là je ne rentre pas dans le détail, je ne vais pas reprendre le guide vous le trouverez ici pour les branchements et ici pour la mise en place du serveur.

8.2.3 Ajout dans Domoticz

On va encore ajouter un matériel : MySensors Gateway USB

arduino 1

8.3 Coté client :

Un an que je repousse, mais quand il faut il faut ! Voilà comment je surveille ma piscine :

  • Température de l’eau
  • pH
  • Température et humidité du bloc de filtration
  • Pression du filtre à sable

Je compte ajouter un détecteur de fuite, je l’ai, mais pas monté.

8.3.1 Le montage :

Piscine_bb

8.3.2 Le programme :

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

// Configuration MySensors
MySensor gw;
#define CHILD_ID_TEMP 0
#define CHILD_ID_PH 1
#define CHILD_ID_PRESSION 2

MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
MyMessage msgPh(CHILD_ID_PH, V_VOLTAGE);
MyMessage msgPres(CHILD_ID_PRESSION, V_PRESSURE);

boolean metric = true;

//Déclarations de l'écran
LiquidCrystal_I2C lcd(0x27, 16, 2);
#define SensorPin A2
#define etalonnagepH A1

// Déclaration des sondes DS18B20
int DS18S20_Pin = 3;
OneWire ds(DS18S20_Pin);

// Déclaration DHT :
#define DHTTYPE DHT11
#define DHTPIN 4
DHT dht(DHTPIN, DHTTYPE);

// Capteur pression filtre
float valeur ;
int analog = A0;



void setup() {
  Serial.begin(9600);
  lcd.begin();
  lcd.backlight();
  lcd.setCursor(0,0);
 
  dht.begin();
  lcd.print("Connection");
  lcd.clear();

  lcd.print("Temp : ");
  lcd.setCursor(2,1);
  lcd.print("pH : ");

   gw.begin();
   gw.sendSketchInfo("Piscine","1.5");

   gw.present(CHILD_ID_TEMP, S_TEMP);
   gw.present(CHILD_ID_PH, S_MULTIMETER);
   gw.present(CHILD_ID_PRESSION, S_BARO);
  

   metric = gw.getConfig().isMetric;
  
}

void loop() {
  // Requête du DS18B20 :
  float mesure = getTemp();

  // Requete du DHT22 :
  float tdht = dht.readTemperature();
  float hdht = dht.readHumidity();
  float voltage = getpH();
  float Offset = (analogRead(etalonnagepH)-512.0)/500;
  float pH = 7-(2.5-voltage/200)/(0.257179+0.000941468*mesure) +Offset;

  //PRESSION
  valeur = analogRead(analog);
  float pression = 3*valeur*5/1023-3*0.47;
      
  // AFFICHAGE SUR LE LCD :
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Temp");
  lcd.setCursor(7,0);
  lcd.print(mesure);
  lcd.print(" C");
  lcd.setCursor(0,1);
  lcd.print("pH");
  lcd.setCursor(7,1);
  lcd.print(pH);
  lcd.setCursor(12,1);
  delay(5000);
  
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Temp b");
   lcd.setCursor(7,0);
  lcd.print(tdht);
  lcd.print(" C");
  lcd.setCursor(0,1);
  lcd.print("hum b");
  lcd.setCursor(7,1);
  lcd.print(hdht);
  lcd.setCursor(12,1);
  delay(5000);

  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Temp");
   lcd.setCursor(7,0);
  lcd.print(mesure);
  lcd.print(" C");
  lcd.setCursor(0,1);
  lcd.print("pH");
  lcd.setCursor(7,1);
  lcd.print(pH);
  lcd.setCursor(12,1);
  delay(5000);

  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Filtre");
  lcd.setCursor(7,0);
  lcd.print(pression);

  lcd.setCursor(0,1);
  if (pression < 0.5) {
  lcd.print("Pression faible");
  }
  if (pression >= 0.5 && pression <= 1.1) {
  lcd.print("Pression ok");
  }
  if (pression > 1.1 && pression <= 1.5) {
  lcd.print("Pression haute");
  }
  if (pression >1.5)
  {
    lcd.print("URGENT");
  }

  delay(5000);

  
  gw.send(msgTemp.set(mesure, 2));
  gw.send(msgPh.set(pH, 2));
  gw.send(msgPres.set(pression, 2));
  
}

float getpH(){
 
  float temp = getTemp();
// float temp = 25.00;
static float pHValue,voltage;

voltage = analogRead(SensorPin) ;

//voltage = analogRead(SensorPin);

return voltage;
//return pHValue ;
}

float getTemp(){
 //returns the temperature from one DS18S20 in DEG Celsius

 byte data[12];
 byte addr[8];

 if ( !ds.search(addr)) {
   //no more sensors on chain, reset search
   ds.reset_search();
   return -1000;
 }

 if ( OneWire::crc8( addr, 7) != addr[7]) {
   Serial.println("CRC is not valid!");
   return -1000;
 }

 if ( addr[0] != 0x10 && addr[0] != 0x28) {
   Serial.print("Device is not recognized");
   return -1000;
 }

 ds.reset();
 ds.select(addr);
 ds.write(0x44,1); // start conversion, with parasite power on at the end

 byte present = ds.reset();
 ds.select(addr);  
 ds.write(0xBE); // Read Scratchpad

 
 for (int i = 0; i < 9; i++) { // we need 9 bytes
  data[i] = ds.read();
 }
 
 ds.reset_search();
 
 byte MSB = data[1];
 byte LSB = data[0];

 float tempRead = ((MSB << 8) | LSB); //using two's compliment
 float TemperatureSum = tempRead / 16;
 
 return TemperatureSum;
 
}

9. Et la boite dans tout ça ?

C’est bien joli d’avoir un imprimante 3D, encore faut il s’en servir ! Je me suis donc fait une petite boite pour ranger tout ça !

vRUi0a77

Et histoire de tester mon nouveau pluggin :

STL Files
  • Domoticz-box
Color:
Render:
Capture:
Download STL

Attention c’est pas le bon modèle !

Voici les pièces de la version corrigée :

Base uno :

STL Files
  • base uno
Color:
Render:
Capture:
Download STL

Contour :

STL Files
  • contour
Color:
Render:
Capture:
Download STL

Couvercle

STL Files
  • couvercle
Color:
Render:
Capture:
Download STL

Base Raspi

STL Files
  • base pi
Color:
Render:
Capture:
Download STL

 

Publié le

Collier wifi pour chien (ESP8266)

Mathieu m’a demandé si je pouvais lui faire un système pour être prévenu lorsque Stuart (son chien) n’est plus à portée du wifi. Du coup je me suis lancé dans la confection d’un prototype ainsi que d’une interface de contrôle.

1. Le prototype :

Je suis habitué à travailler avec l’ESP8266 donc naturellement je vais l’utiliser ici.

Le prototype est assez simple (mais relativement efficace !) :

IMG_0923

Je passe sur les branchements, voici le fichier :

#include <ESP8266WiFi.h>
#define led 2

const char* ssid     = "Livebox-4246-ext";
const char* password = "";

const char* host = "192.168.1.50";

void setup() {
  Serial.begin(115200);
  delay(10);
  pinMode(led,OUTPUT);
  digitalWrite(led,LOW);
  
  // We start by connecting to a WiFi network

  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  
  WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");  
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

int value = 0;

void loop() {
  if (WiFi.status() == WL_CONNECTED){
    digitalWrite(led,HIGH);
  }
  else {
    digitalWrite(led,LOW);
  }
  

  Serial.print("connecting to ");
  Serial.println(host);
  
  // Use WiFiClient class to create TCP connections
  WiFiClient client;
  const int httpPort = 80;
  if (!client.connect(host, httpPort)) {
    Serial.println("connection failed");
    return;
  }
  
  // We now create a URI for the request
  String url = "/stuart/stuart.php";
  
  Serial.print("Requesting URL: ");
  Serial.println(url);
  
  // This will send the request to the server
  client.print(String("GET ") + url + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" + 
               "Connection: close\r\n\r\n");
  delay(10);
  
  // Read all the lines of the reply from server and print them to Serial
  while(client.available()){
    String line = client.readStringUntil('\r');
    Serial.print(line);
  }
  
  Serial.println();
  Serial.println("closing connection");

  delay(60000);
}

 

 

IMG_0929

Voici la version sans les leds.

La vidéo suivante vous montre le passage de l’état non connecté (led rouge) à connecté (led verte) :

 

2. La partie récupération des données et traitement :

Pour le moment j’ai tout hébergé sur mon NAS synology.

J’ai donc créé dans un premier temps deux tables :

  • Une « detection » qui va enregistrer le timestamp de la dérnière connexion de l’ESP8266
  • Une « suivit » pour activer/désactiver le tracking.

2.1 L’alimentation de la table détection :

J’ai créé un script php qui ajoute juste à ma table le temps php :

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

   $date = time();
   mysql_query("INSERT INTO detection (datedetection) VALUES ('$date')");
 echo $date;
?>

2.2 Le contrôle de la surveillance :

Bon Mathieu ne vas pas surveiller Stuart H24, donc il fallait trouver un système pour ne pas créer d’alerte quand on éteint le boitier.

J’ai donc ajouté la table suivit pour savoir si oui ou non on surveille le chien :

<?php 
$page = $_SERVER['PHP_SELF'];
$sec = "5";
include("connexionDB.php");
$req2 = mysql_query("SELECT * FROM suivit ORDER BY rowid DESC LIMIT 1");
   $data2 = mysql_fetch_array($req2);
   
   $etat_suivit = $data2['etat_suivit'];
?>

<style>
    html, body {
   margin: 0;
   padding: 20;
        width:100%;
   height: 100%;
}
    
    div#contenu 
    {
     
   border:none;
        width:100%;
   min-height:100%;
   
    }
    
</style>


<html>
    <head>
   <!-- <meta http-equiv="refresh" content="<?php echo $sec?>;URL='<?php echo $page?>'"> -->
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, user-scalable=no">
          <link rel="stylesheet" type="text/css" href="css/style.css" />
        <title>Gestion tracker</title>
    </head>
    <body>
        <!-- Menu d'entête : -->
        
        <?php if($etat_suivit == 1) {
         $date = time();
   $req = mysql_query("SELECT * FROM detection ORDER BY rowid DESC LIMIT 1");
   $data = mysql_fetch_array($req);
   $last = $data['datedetection'];
   $ecart = $date-$last;
         ?>
         Temps depuis la dernière détection : <?php echo $ecart; ?> sec <Br>
         <?php
        }
        ?>
        <!-- Menu Gauche : -->
        Etat du tracker : 
        
         <div style="width: 50%; height: 10%; float: left ;" class="switch demo">
         <form method='POST' action="post.php">

   
   <input type="checkbox" name="myCheckbox" value="on"
   <?php
   $req2 = mysql_query("SELECT * FROM suivit ORDER BY rowid DESC LIMIT 1");
   $data2 = mysql_fetch_array($req2);
   
   $etat_suivit = $data2['etat_suivit'];
   if ($etat_suivit == 1) {
      ?>
      CHECKED
      <?php
   }
   ?>
   > 
   
   <label><i></i></label>
   
   </div>
   <div style="width: 50%; height: 10%; float: left ;">
   <input type="submit" name="Envoyer" value="Envoyer" />
   </div>
   </form>
   
        
    </body>
</html>

Et le fichier post.php :

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


if(isset($_POST['myCheckbox']) && $_POST['myCheckbox']=="on")
{
    $myCheckbox='1';
}
else
{      
    $myCheckbox='0';
}

mysql_query("INSERT INTO suivit(etat_suivit) VALUES ('$myCheckbox')");
         
?>

<SCRIPT LANGUAGE="JavaScript"> 
document.location.href="gestion.php" 
</SCRIPT> 

 

C’est pas du grand art, mais c’est juste dans un premier temps faire des tests, voilà ce que ça donne :

IMG_0932 [162328]IMG_0933 [162329]

 

2.3 Le système d’alerte :

Alors petit fichier php toujours, que mon NAS va exécuter toutes les minutes :

<?php
   

   include("connexionDB.php");
   $date = time();
   $req = mysql_query("SELECT * FROM detection ORDER BY rowid DESC LIMIT 1");
   $data = mysql_fetch_array($req);
   $last = $data['datedetection'];
   $ecart = $date-$last;
   echo $ecart;

   $req2 = mysql_query("SELECT * FROM suivit ORDER BY rowid DESC LIMIT 1");
   $data2 = mysql_fetch_array($req2);
   
   $etat_suivit = $data2['etat_suivit'];
   echo $etat_suivit ;
?>

<?php
if ($ecart > 65 && $etat_suivit > 0) {
$to = "j.pgarcia@me.com";
$subject = "Alerte Stuart";
$body = "Stuart est hors de porté wifi depuis ".$ecart." secondes !";
$headers = 'From: ESP8266 Stuart';

mail($to, $subject, $body, $headers);


}


?>

Et voilà pour le moment !

 

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

 

Publié le

Netatmo et ESP partie 2

Une seconde partie n’était pas prévue, mais Mathieu (ouais c’est un blog de cuisine) c’est lancé dans l’aventure et du coup m’a fait pas mal retravailler mon code !

Du coup, j’ai repris mon code php pour l’importation des données Netatmo et ajouter la pluviométrie (Que je vais devoir aller ajouter dans Station météo maison couplée à une station Netatmo Part. 1 ça sera donc la partie 2).

Donc pour commencer, il faut récupérer les infos sur la pluviométrie. J’avais déjà identifié mon module, donc petit tour sur dev.netatmo.com ;

For Weather Station :

  • max -> Temperature, CO2, Humidity, Pressure, Noise, Rain (if module_id is a rain sensor), WindStrength, WindAngle, GustStrength, GustAngle, date_max_gust (if module_id is a Wind Gauge)
  • 30min, 1hour, 3hours -> Temperature, CO2, Humidity, Pressure, Noise, min_temp, max_temp, min_hum, max_hum, min_pressure, max_pressure, min_noise, max_noise, sum_rain (if module_id is a rain sensor), WindStrength, WindAngle, GustStrength, GustAngle, date_max_gust (if module_id is a Wind Gauge)
  • 1day, 1week, 1month -> Temperature, Co2, Humidity, Pressure, Noise, min_temp, date_min_temp, max_temp, date_max_temp, min_hum, date_min_hum, max_hum, date_max_hum, min_pressure, date_min_pressure, max_pressure, date_max_pressure, min_noise, date_min_noise, max_noise, date_max_noise, date_min_co2, date_max_co2, sum_rain (if module_id is a rain sensor), WindStrength, WindAngle, GustStrength, GustAngle, date_max_gust (if module_id is a Wind Gauge)

Donc, on peut en mettant des timers  récupérer le « sum_rain » !

Allez hop on intègre du code : (je ne rebalance pas tout hein)

$pluvio=$json_devices["body"]["modules"][1]["_id"];

$h_moins_1 = time() - 3600;
$hier = time() - 24* 3600;

$url_pluvio_h = "https://api.netatmo.net/api/getmeasure?access_token=" .  $params['access_token'] . "&device_id=" . $module_interne . "&module_id=" . $pluvio . "&scale=5min&type=sum_rain&date_begin=". $h_moins_1;
$pluvio_h = file_get_contents($url_pluvio_h);   

$url_pluvio_j = "https://api.netatmo.net/api/getmeasure?access_token=" .  $params['access_token'] . "&device_id=" . $module_interne . "&module_id=" . $pluvio . "&scale=30min&type=sum_rain&date_begin=". $hier;
$pluvio_j = file_get_contents($url_pluvio_j);

Donc là, je définit mon module pluvio (le mien est 1, celui de Mathieu est 3 ou 4).

Je définit $h_moins-1 et $hier en timestamp pour ma requête (Je veux le cumul sur la dernière heure et sur les dernières 24h).

Comme pour les autres mesures, il faut attaquer le découpage (et c’est la fête !) la sortie donne un truc du style :

{"body":[{"beg_time":1446581259,"step_time":300,"value":[[0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[0]]}],"status":"ok","time_exec":0.012279987335205,"time_server":1446584710}

Ce qui nous intéresse c’est le cumul de

[[0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[0],[0]]

Allez hop on découpe et on somme les valeurs !

$pluvio_h_decoupe = substr($pluvio_h,57,1000);
$recup1_pluvio_h = explode("}", $pluvio_h_decoupe);
$recup2_pluvio_h = explode("[",$recup1_pluvio_h[0]);
$sum_pluvio_h = 0;
for ($i=0; $i<count($recup2_pluvio_h); $i++) {
$mesure = explode("]",$recup2_pluvio_h["$i"]);
$sum_pluvio_h += $mesure[0];
}

Et on fait pareil pour la pluvio des dernières 24h.

On ajoute ensuite les sommes dans la chaîne à afficher pour obtenir en sortie notre fichier out.txt qui ressemble à ça :

[21.1n635n74n1017.4n45n14.8n91n0n0[

Comme je suis joueur, avant de donner mon code Arduino, je vais vous montrer le résultat qu’on souhaitait :

Donc en gros, toutes les 10 secondes on alterne l’affichage intérieur/extérieur dans un boucle de 3 rotations avant mise à jour des données.

J’ai du formater un peu l’affichage pour la pression et la pluviométrie :

#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <ESP8266WiFi.h>

LiquidCrystal_I2C lcd(0x3F, 20, 4);

const char* ssid     = "Votre SSID";
const char* password = "MDP Wifi";

const char* host = "192.168.1.50";

void setup() {
  Serial.begin(115200);
  delay(10);
  Wire.begin(0,2);
  lcd.begin();
  lcd.backlight();
  // We start by connecting to a WiFi network

  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");  
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

int value = 0;

void loop() {
 
  ++value;

  Serial.print("connecting to ");
  Serial.println(host);
  
  // Use WiFiClient class to create TCP connections
  WiFiClient client;
  const int httpPort = 80;
  if (!client.connect(host, httpPort)) {
    Serial.println("connection failed");
    return;
  }
  
  // We now create a URI for the request
  String url = "/Netatmo/out.txt";
  
  
  Serial.print("Requesting URL: ");
  Serial.println(url);
  
  // This will send the request to the server
  client.print(String("GET ") + url + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" + 
               "Connection: close\r\n\r\n");
  delay(10);
  String line = "";
  // Read all the lines of the reply from server and print them to Serial
  while(client.available()){
    line = client.readStringUntil('\r');
   }

char messageChar[500]; 
  line.toCharArray(messageChar,500);
  
  char dlm[] = "[";
            int cnt = 0;
            char* tab[255] = { 0 };
            char *pch = strtok(messageChar, dlm);
            while ( pch != NULL ) {
              if (cnt < 60) {
              tab[cnt++] = pch;
              } else {
              break;
              }
            pch = strtok (NULL, dlm);
            }
 
  
  char *chaine = tab[1];

  char dlm2[] = "n";
            int cnt2 = 0;
            char* tab2[255] = { 0 };
            char *pch2 = strtok(chaine, dlm2);
            while ( pch2 != NULL ) {
              if (cnt2 < 60) {
              tab2[cnt2++] = pch2;
              } else {
              break;
              }
            pch2 = strtok (NULL, dlm2);
            }
String pressionStr = tab2[3];
int pressionStrLength = pressionStr.length()+1;
char pressionStrChar[pressionStrLength];
pressionStr.toCharArray(pressionStrChar,pressionStrLength);
int pression = atoi(pressionStrChar);

String preci_hString = tab2[7];
float preci_h = preci_hString.toFloat(); 

String preci_jString = tab2[8];
float preci_j = preci_jString.toFloat(); 

if (tab2[1] > 0) {
for (int i = 0; i<3; i++)
{
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Interieur");
  lcd.setCursor(0,1);
  lcd.print("T: ");
  lcd.print(tab2[0]);
  lcd.print(char(223));
  lcd.print("C");
  lcd.setCursor(0,2);
  lcd.print("CO2: ");
  lcd.print(tab2[1]);
  lcd.print("ppm");
  lcd.setCursor(0,3);
  lcd.print("Hum: ");
  lcd.print(tab2[2]);
  lcd.print("% P: ");
  lcd.print(pression);
  lcd.print(" hPa");
  delay(10000);
  
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("Exterieur");
  lcd.setCursor(0,1);
  lcd.print("T: ");
  lcd.print(tab2[5]);
  lcd.print(char(223));
  lcd.print("C  Hum: ");
  lcd.print(tab2[6]);
  lcd.print("%");
  lcd.setCursor(0,2);
  lcd.print("Pluie : ");
  lcd.print(preci_h);
  lcd.print(" mm/h");
  lcd.setCursor(8,3);
  lcd.print(preci_j);
  lcd.print(" mm/j");
  delay(10000);
}
}

  Serial.println();
  Serial.println("closing connection");
}

 

 

 

Publié le

Afficher les données de Netatmo avec… Un ESP8266 ESP1

Et pourquoi ne pas réduire un peu ce que j’ai fait sur l’autre tuto ?

Alors oui on pourrait remplacer l’Arduino Méga par un nano, mais pour le Wifi on fait comment ?

Dans mon précédant tuto, je parle de l’ESP8266, mais comment ça fonctionne ?

1. L’ESP8266

Voici l’ESP8266 ESP01.

WiFi Serial Transceiver Module

On pourrait reprendre la formule « Petit mais costaud », c’est petit, assez sympa, mais aussi très galère au début quand on y connait rien !

1.1 Les pins :

images

8 pins seulement, on a pas besoin de plus (on pourrait même faire avec 6…).

1.2 On le programme avec Arduino IDE !

Et oui, on ne s’embête pas pour le programmer on peut le faire à l’aide de l’IDE Arduino, mais avant il faut la préparer un peu :

1.2.1 Configuration de l’interface Arduino :

Alors dans un premier temps on installe Arduino 1.6.5.

On ouvre les préférences et dans « Additional Bords Manager URLs » on ajoute l’URL

http://arduino.esp8266.com/stable/package_esp8266com_index.json

prefs

Et on clique sur Ok.

Ensuite on va dans Outils > type de carte > Boards Manager , dans le champ de recherche on tape esp8266 et On voit apparaitre un cadre avec esp8266… On clique dessus puis sur install.

Une fois installé dans Outils > type de carte en bas on va retrouver l’esp8266 :

Esp

 

On utilisera le type de carte « Generic ESP8266 module ». L’interface est donc prête, on ferme l’interface Arduino pour installer les librairies.

1.2.2 Installation des librairies :

Première étape, on va sur le Github de Sandeepmistery et on télécharge la dernière release.

Ensuite on va dans le dossier Arduino, le dossier dans mes documents qui contient les sketches Arduino et on crée un dossier hardware.

Une fois le fichier télécharger (archive Zip) on copie-colle le dossier esp8266 dans le dossier hardware que nous venons de créer.

Attention : mon nom de compte sur mon pc est JiPé et Arduino n’aime pas ça, j’ai donc un second compte utilisateur nomé JiP, (oui oui avec une virgule à la place du é) et c’est dans ce compte utilisateur que j’ai du faire ces manipulations.

 

2. Premiers pas : récupération du fichier out.txt.

On revient en fait à l’étape 3.1 du tuto  Afficher les données Netatmo avec un Arduino.

Voici le code utilisé (d’après un exemple contenu dans la libairie esp8266wifi) :

#include <ESP8266WiFi.h>

const char* ssid     = "SSID Wifi";
const char* password = "MDP Wifi";

const char* host = "192.168.1.50";

void setup() {
  Serial.begin(115200);
  delay(10);

  // We start by connecting to a WiFi network

  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

int value = 0;

void loop() {
  ++value;

  Serial.print("connecting to ");
  Serial.println(host);

  // Use WiFiClient class to create TCP connections
  WiFiClient client;
  const int httpPort = 80;
  if (!client.connect(host, httpPort)) {
    Serial.println("connection failed");
    return;
  }

  // We now create a URI for the request
  String url = "/Netatmo/out.txt";


  Serial.print("Requesting URL: ");
  Serial.println(url);

  // This will send the request to the server
  client.print(String("GET ") + url + " HTTP/1.1\r\n" +
 "Host: " + host + "\r\n" + 
 "Connection: close\r\n\r\n");
  delay(10);

  // Read all the lines of the reply from server and print them to Serial
  while(client.available()){
    String line = client.readStringUntil('r');
    Serial.print(line);
  }

  Serial.println();
  Serial.println("closing connection");
  delay(60000);
}

Et en sortie j’obtient :

Capture

 

3. Affichage LCD des données reçues :

Alors la partie qui m’a pris le plus de temps (en oubliant une ligne dans le code c’est sur que ça ne peut pas fonctionner).

L’ESP8266 ESP1 a deux GPIO qui peuvent servir pour l’I2C :

  • GPIO0 => SDA
  • GPIO2 => SCL

Du coup il est facile d’afficher sur un écran LCD avec une interface I2C.

Voici le code utilisé :

#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <ESP8266WiFi.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);

const char* ssid     = "SSID Wifi";
const char* password = "MDP Wifi";

const char* host = "192.168.1.50";

void setup() {
  Serial.begin(115200);
  delay(10);
  Wire.begin(0,2);                                  //LIGNE LA PLUS IMPORTANTE POUR DEMARRER L'I2C SUR L'ESP8266
  lcd.begin();
  lcd.backlight();

  // We start by connecting to a WiFi network

  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

int value = 0;

void loop() {

  ++value;

  Serial.print("connecting to ");
  Serial.println(host);

  // Use WiFiClient class to create TCP connections
  WiFiClient client;
  const int httpPort = 80;
  if (!client.connect(host, httpPort)) {
    Serial.println("connection failed");
    return;
  }

  // We now create a URI for the request
  String url = "/Netatmo/out.txt";


  Serial.print("Requesting URL: ");
  Serial.println(url);

  // This will send the request to the server
  client.print(String("GET ") + url + " HTTP/1.1\r\n" +
 "Host: " + host + "\r\n" + 
 "Connection: close\r\n\r\n");
  delay(10);
  String line = "";
  // Read all the lines of the reply from server and print them to Serial
  while(client.available()){
    line = client.readStringUntil('r');
   // Serial.print(line);
  }

//Serial.println(line);



char messageChar[500];
  line.toCharArray(messageChar,500);

  char dlm[] = "[";
            int cnt = 0;
            char* tab[255] = { 0 };
            char *pch = strtok(messageChar, dlm);
            while ( pch != NULL ) {
              if (cnt < 60) {
              tab[cnt++] = pch;
              } else {
              break;
              }
            pch = strtok (NULL, dlm);
            }


  char *chaine = tab[1];
  //Serial.println(chaine);
  char dlm2[] = "n";
            int cnt2 = 0;
            char* tab2[255] = { 0 };
            char *pch2 = strtok(chaine, dlm2);
            while ( pch2 != NULL ) {
              if (cnt2 < 60) {
              tab2[cnt2++] = pch2;
              } else {
              break;
              }
            pch2 = strtok (NULL, dlm2);
            }

lcd.clear();
lcd.print("T:");
lcd.print(tab2[0]);
lcd.print(" CO2:");
lcd.print(tab2[1]);
lcd.setCursor(0,1);
lcd.print("H:");
lcd.print(tab2[2]);
lcd.print(" P:");
lcd.print(tab2[3]);

  Serial.println();
  Serial.println("closing connection");
  delay(60000);
}

Et du coup :

 

IMG_0012

Publié le

Afficher les données Netatmo avec un Arduino

L’inconvénient des stations météo Netatmo c’est qu’il faut avoir un smartphone/pc/tablette à disposition pour pouvoir consulter les données de la station (ou avoir un Karotz comme Mathieu).

Du coup je me suis mis à la recherche de pistes pour faire un afficheur LCD avec un Arduino pour avoir les données en temps réel !

Du coup il faut pas mal de choses :

  • Un NAS Synology (ou un pc sous Unix ou un Raspberry Pi),
  • un Arduino avec un lcd,
  • de la patience quand on est pas doué comme moi.

Et il faut aussi quelques connaissances :

  • Savoir programmer sur Arduino,
  • maitriser le PHP,
  • savoir bidouiller dans son NAS (merci encore une fois à Mathieu).

 

1. Créer une application Netatmo :

La première étape est d’aller créer un application sur dev.netatmo.com.

On clique en haut sur « CREATE AN APP » et on se connecte avec nos identifiants Netatmo.

On remplit les champs avec astérisque, dans mon cas :

 

Netatmo1

On descend en bas de la page, on pose la case et on valide.

On arrive ensuite sur la page OAUTH SETTINGS d’ou nous allons récupérer les identifiants de l’application :

Sans titre

On récupère le « Client id » et le « Client secret » qui vont nous servir dans la partie PHP.

2. Partie PHP / Synology

2.1 Partie PHP :

On a donc les « Client id » et « Client secret » de notre application Netatmo, on va maintenant mettre tout ça dans un fichier PHP pour récupérer les informations de la station météo Netatmo.

Voici le code de mon fichier netatmo.php (qui à l’origine vient de Domotique Info mais que j’ai modifié).

<?php
$password="Mot de passe du compte Netatmo";
$username="Identifiant du compte Netatmo";
$app_id = "Client id de l'app";
$app_secret ="client secret de l'app";

$token_url = "https://api.netatmo.net/oauth2/token";
$postdata = http_build_query(
        array(
            'grant_type' => "password",
            'client_id' => $app_id,
            'client_secret' => $app_secret,
            'username' => $username,
            'password' => $password
    )
);

$opts = array('http' =>
    array(
        'method'  => 'POST',
        'header'  => 'Content-type: application/x-www-form-urlencoded',
        'content' => $postdata
    )
);

$context  = stream_context_create($opts);
$response = file_get_contents($token_url, false, $context);

$params = null;
$params = json_decode($response, true);
$api_url = "https://api.netatmo.net/api/getuser?access_token=" . $params['access_token'];
$requete = file_get_contents($api_url);

$url_devices = "https://api.netatmo.net/api/devicelist?access_token=" .  $params['access_token'];
$resulat_device = file_get_contents($url_devices);
$json_devices = json_decode($resulat_device,true);
$module_interne = $json_devices["body"]["devices"][0]["_id"];
$module_externe = $json_devices["body"]["modules"][0]["_id"];

$url_mesures_internes = "https://api.netatmo.net/api/getmeasure?access_token=" .  $params['access_token'] . "&device_id=" . $module_interne . "&scale=max&type=Temperature,CO2,Humidity,Pressure,Noise&date_end=last";
$mesures_internes = file_get_contents($url_mesures_internes);

$url_mesures_externes = "https://api.netatmo.net/api/getmeasure?access_token=" .  $params['access_token'] . "&device_id=" . $module_interne . "&module_id=" . $module_externe . "&scale=max&type=Temperature,Humidity&date_end=last";
$mesures_externes = file_get_contents($url_mesures_externes);

$int = substr($mesures_internes,42,25);
$ext = substr($mesures_externes,42,25);

$interieur=explode(",", $int);
$exterieur=explode(",",$ext);
$h_ext=explode("]",$exterieur["1"]);
$decibel=explode("]", $interieur["4"]);
$message = "[".$interieur["0"]."n".$interieur["1"]."n".$interieur["2"]."n".$interieur["3"]."n".$decibel["0"]."n".$exterieur["0"]."n".$h_ext["0"]."[";
echo $message;


?>

Petites précision sur la fin du script php :

Quand le script exécute

$url_mesures_internes = "https://api.netatmo.net/api/getmeasure?access_token=" .  $params['access_token'] . "&device_id=" . $module_interne . "&scale=max&type=Temperature,CO2,Humidity,Pressure,Noise&date_end=last";
$mesures_internes = file_get_contents($url_mesures_internes);

il nous renvoie un résultat du type :

{"body":[{"beg_time":1444133653,"value":[[24.1,433,60,1007.7,50]]}],"status":"ok","time_exec":0.020297050476074,"time_server":1444134057}

sachant que les valeurs dont nous avons besoin sont : 24.1,433,60,1007.7,50 (Température, CO2, Humidité, Pression, Décibels).

Du coup pour ne récupérer que ça (et pas toute la chaine $mesures_internes) je vais me placer sur le premier chiffre pour la température, j’extrait 25 caractères et ensuite je découpe entre avec mon séparateur « , » puis pour la dernière mesure je découpe avec le séparateur « ] ». (Je ne suis pas en pro, on doit bien pouvoir faire plus propre, mais je fais avec mes connaissances !).

Une fois fait, je compose un message à afficher après avoir exécuté le script PHP sous forme d’un écho qu’on récupèrera avec l’arduino (message avec les séparateurs « [ » et « n » on verra ça dans la partie Arduino).

2.2 Mise en place sur le Synology :

J’ai déjà un serveur Web installé sur mon NAS, donc je suis allé dans le dossier « www », j’ai créé un dossier « Netatmo » et j’ai copié mon fichier « netatmo.php » dedans. Pour automatiser l’exécution de mon script, direction le panneau de configuration et « planificateur de tâche ».

On clique sur créer et on rentre le code suivant :

/usr/bin/php -f /volume1/web/Netatmo/netatmo.php > /volume1/web/Netatmo/out.txt

Voilà ce qu’on obtient :

syno1

 

On va dans l’onglet Programmer :

syno2

On valide et on exécute le script (pour voir si tout se passe bien, le fichier out.txt devrait apparaitre dans le dossier Netatmo.

Le contenu du fichier doit ressembler à ça :

[24.3n450n60n1007.8n51n26.9n45[

Génial c’est la chaine qu’on va récupérer sur l’Arduino !

Note : ne pas faire de bêtises et ne pas effacer le fichier /usr/bin/php (ne me demandez pas comment je l’ai fait, merci à Mathieu de m’avoir envoyé le sien).

 

3. Récupération et affichage sur un LCD : Partie ARDUINO.

3.1 Tests préliminaires (Et il y en a eu…) :

Habituellement, je travaille avec des ESP8266, mais il y a un mois, je me suis commandé un shield CC3000 sur ebay qui ressemble à ça :

$_57

Avantage : il fonctionne avec les librairies ADAFRUIT que l’on trouve ici.

Pour le codage, j’ai fait le flemmard. J’avais déjà testé le code exemple WebClient.ino fournit avec la librairie ADAFRUIT, donc je l’ai bêtement repris.

Il faut juste modifier un peu les premières ligne (je ne montre que les premières lignes) :

#define WLAN_SSID       "LE SSID DE LA BOX"           // cannot be longer than 32 characters!
#define WLAN_PASS       "MOT DE PASSE WIFI"
// Security can be WLAN_SEC_UNSEC, WLAN_SEC_WEP, WLAN_SEC_WPA or WLAN_SEC_WPA2
#define WLAN_SECURITY   WLAN_SEC_WPA2

#define IDLE_TIMEOUT_MS  3000      // Amount of time to wait (in milliseconds) with no data
                                   // received before closing the connection.  If you know the server
                                   // you're accessing is quick to respond, you can reduce this value.

// What page to grab!
#define WEBSITE      "IP DU NAS"
#define WEBPAGE      "/Netatmo/out.php"  // lien vers out.txt

Sur la voie série quand j’exécute mon programme, j’ai la visualisation suivante :

Hello, CC3000!

Free RAM: 5687

Initializing...

Attempting to connect to Livebox-4246
Connected!
Request DHCP

IP Addr: 192.168.1.65
Netmask: 255.255.255.0
Gateway: 192.168.1.1
DHCPsrv: 192.168.1.1
DNSserv: 192.168.1.1
192.168.1.50 -> 192.168.1.50-------------------------------------
HTTP/1.1 200 OK
Date: Tue, 06 Oct 2015 13:02:00 GMT
Server: Apache
Last-Modified: Tue, 06 Oct 2015 13:01:11 GMT
ETag: "1d-5216f395e9d25"
Accept-Ranges: bytes
Content-Length: 29
Vary: Accept-Encoding
Content-Type: text/plain

[24.5n455n60n1007.9n51n27n44[-------------------------------------


Disconnecting

En fait le programme WebClient.ino me renvoie la réponse donnée par le site web, mais la réponse COMPLETE, c’est à dire :

HTTP/1.1 200 OK
Date: Tue, 06 Oct 2015 13:02:00 GMT
Server: Apache
Last-Modified: Tue, 06 Oct 2015 13:01:11 GMT
ETag: "1d-5216f395e9d25"
Accept-Ranges: bytes
Content-Length: 29
Vary: Accept-Encoding
Content-Type: text/plain

[24.5n455n60n1007.9n51n27n44[

Et devinez ce dont on a besoin ? Et oui juste la fin de la réponse…

3.2 Après les tests, le programme fonctionnel :

Donc j’ai passé un peu de temps à voir comment récupérer juste le contenu de mon fichier « out.txt », j’ai retravaillé le fichier « WebClient.ino » car d’une part, tout était dans le void setup, et d’autre part, il me fallait récupérer l’essentiel (c’est lors de cette étape que j’ai rajouté les délimiter « [ » dans le fichier netatmo.php).

Voici mon code :

#include <Adafruit_CC3000.h>
#include <LiquidCrystal.h>
#include <ccspi.h>
#include <SPI.h>
#include <string.h>
#include "utility/debug.h"


#define ADAFRUIT_CC3000_IRQ   3  // MUST be an interrupt pin!
#define ADAFRUIT_CC3000_VBAT  5
#define ADAFRUIT_CC3000_CS    10
Adafruit_CC3000 cc3000 = Adafruit_CC3000(ADAFRUIT_CC3000_CS, ADAFRUIT_CC3000_IRQ, ADAFRUIT_CC3000_VBAT,
                                         SPI_CLOCK_DIVIDER); // you can change this clock speed

#define WLAN_SSID       "SSID Wifi"           // cannot be longer than 32 characters!
#define WLAN_PASS       "Mot de passe Wifi"
// Security can be WLAN_SEC_UNSEC, WLAN_SEC_WEP, WLAN_SEC_WPA or WLAN_SEC_WPA2
#define WLAN_SECURITY   WLAN_SEC_WPA2

#define IDLE_TIMEOUT_MS  3000      // Amount of time to wait (in milliseconds) with no data
                                   // received before closing the connection.  If you know the server
                                   // you're accessing is quick to respond, you can reduce this value.

// What page to grab!
#define WEBSITE      "192.168.1.50"             //ip NAS
#define WEBPAGE      "/Netatmo/out.txt"         //Chemin du fichier Out


LiquidCrystal lcd(42,41,37,38,39,40);

/**************************************************************************/
/*!
    @brief  Sets up the HW and the CC3000 module (called automatically
            on startup)
*/
/**************************************************************************/

uint32_t ip;

void setup(void)
{
  Serial.begin(115200);
  lcd.begin(16,2);
  lcd.clear();
  lcd.write("test");
}

void loop(void)
{
    Serial.println(F("Hello, CC3000!n"));

  Serial.print("Free RAM: "); Serial.println(getFreeRam(), DEC);

  /* Initialise the module */
  Serial.println(F("nInitializing..."));
  if (!cc3000.begin())
  {
    Serial.println(F("Couldn't begin()! Check your wiring?"));
    while(1);
  }

  // Optional SSID scan
  // listSSIDResults();

  Serial.print(F("nAttempting to connect to ")); Serial.println(WLAN_SSID);
  if (!cc3000.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY)) {
    Serial.println(F("Failed!"));
    while(1);
  }

  Serial.println(F("Connected!"));

  /* Wait for DHCP to complete */
  Serial.println(F("Request DHCP"));
  while (!cc3000.checkDHCP())
  {
    delay(100); // ToDo: Insert a DHCP timeout!
  }

  /* Display the IP address DNS, Gateway, etc. */
  while (! displayConnectionDetails()) {
    delay(1000);
  }

  ip = 0;
  // Try looking up the website's IP address
  Serial.print(WEBSITE); Serial.print(F(" -> "));
  while (ip == 0) {
    if (! cc3000.getHostByName(WEBSITE, &ip)) {
      Serial.println(F("Couldn't resolve!"));
    }
    delay(500);
  }

  cc3000.printIPdotsRev(ip);

  // Optional: Do a ping test on the website
  /*
  Serial.print(F("nrPinging ")); cc3000.printIPdotsRev(ip); Serial.print("...");
  replies = cc3000.ping(ip, 5);
  Serial.print(replies); Serial.println(F(" replies"));
  */

  /* Try connecting to the website.
     Note: HTTP/1.1 protocol is used to keep the server from closing the connection before all data is read.
  */
  Adafruit_CC3000_Client www = cc3000.connectTCP(ip, 80);
  if (www.connected()) {
    www.fastrprint(F("GET "));
    www.fastrprint(WEBPAGE);
    www.fastrprint(F(" HTTP/1.1rn"));
    www.fastrprint(F("Host: ")); www.fastrprint(WEBSITE); www.fastrprint(F("rn"));
    www.fastrprint(F("rn"));
    www.println();
  } else {
    Serial.println(F("Connection failed"));
    return;
  }

  Serial.println(F("-------------------------------------"));
  int i=0;
  String message ="";
  /* Read data until either the connection is closed, or the idle timeout is reached. */
  unsigned long lastRead = millis();
  while (www.connected() && (millis() - lastRead < IDLE_TIMEOUT_MS)) {
    while (www.available()) {
      char c = www.read();
      message += c;
      Serial.print(c);
      lastRead = millis();
    }
  }

 //Serial.println(message);
  www.close();
  Serial.println(F("-------------------------------------"));

  /* You need to make sure to clean up after yourself or the CC3000 can freak out */
  /* the next time your try to connect ... */
  Serial.println(F("nnDisconnecting"));
  cc3000.disconnect();

  char messageChar[500];
  message.toCharArray(messageChar,500);

  char dlm[] = "[";
            int cnt = 0;
            char* tab[255] = { 0 };
            char *pch = strtok(messageChar, dlm);
            while ( pch != NULL ) {
              if (cnt < 60) {
              tab[cnt++] = pch;
              } else {
              break;
              }
            pch = strtok (NULL, dlm);
            }


  char *chaine = tab[1];
  //Serial.println(chaine);
  char dlm2[] = "n";
            int cnt2 = 0;
            char* tab2[255] = { 0 };
            char *pch2 = strtok(chaine, dlm2);
            while ( pch2 != NULL ) {
              if (cnt2 < 60) {
              tab2[cnt2++] = pch2;
              } else {
              break;
              }
            pch2 = strtok (NULL, dlm2);
            }
 char *temp = tab2[0];
 Serial.print(temp);
 lcd.clear();
 lcd.setCursor(0,0);
 lcd.write("t:");
 lcd.write(temp);
 lcd.write("C CO2:");
 lcd.write(tab2[1]);
 lcd.setCursor(0,1);
 lcd.write("h:");
 lcd.write(tab2[2]);
 lcd.write("% p:");
 lcd.write(tab2[3]);

 delay(120000);
}

/**************************************************************************/
/*!
    @brief  Begins an SSID scan and prints out all the visible networks
*/
/**************************************************************************/

void listSSIDResults(void)
{
  uint32_t index;
  uint8_t valid, rssi, sec;
  char ssidname[33];

  if (!cc3000.startSSIDscan(&index)) {
    Serial.println(F("SSID scan failed!"));
    return;
  }

  Serial.print(F("Networks found: ")); Serial.println(index);
  Serial.println(F("================================================"));

  while (index) {
    index--;

    valid = cc3000.getNextSSID(&rssi, &sec, ssidname);

    Serial.print(F("SSID Name    : ")); Serial.print(ssidname);
    Serial.println();
    Serial.print(F("RSSI         : "));
    Serial.println(rssi);
    Serial.print(F("Security Mode: "));
    Serial.println(sec);
    Serial.println();
  }
  Serial.println(F("================================================"));

  cc3000.stopSSIDscan();
}

/**************************************************************************/
/*!
    @brief  Tries to read the IP address and other connection details
*/
/**************************************************************************/
bool displayConnectionDetails(void)
{
  uint32_t ipAddress, netmask, gateway, dhcpserv, dnsserv;

  if(!cc3000.getIPAddress(&ipAddress, &netmask, &gateway, &dhcpserv, &dnsserv))
  {
    Serial.println(F("Unable to retrieve the IP Address!rn"));
    return false;
  }
  else
  {
    Serial.print(F("nIP Addr: ")); cc3000.printIPdotsRev(ipAddress);
    Serial.print(F("nNetmask: ")); cc3000.printIPdotsRev(netmask);
    Serial.print(F("nGateway: ")); cc3000.printIPdotsRev(gateway);
    Serial.print(F("nDHCPsrv: ")); cc3000.printIPdotsRev(dhcpserv);
    Serial.print(F("nDNSserv: ")); cc3000.printIPdotsRev(dnsserv);
    Serial.println();
    return true;
  }
}

Et voici le résultat :

IMG_2739

3.3 Ce qu’il reste à faire :

  • J’ai commandé un écran LCD 20×4 I2C car sur le 16×2 (qui n’est pas en I2C) je ne peux pas tout afficher.
  • Voir pour récupérer les infos du pluviomètre.
Publié le

Capteur RFID

Semaine très chargée et week-end à venir encore plus… Je vais quand même prendre un peu de temps pour vous présenter le capteur RFID RC522 que j’ai reçu aujourd’hui.

Déballage :

Voici le petit bijou que j’ai reçu :

 

IMG_2665

Il se compose donc :

  • Un module  RV522
  • Une carte RFID
  • Un porte clef RFID

Le montage :

  • Un arduino MEGA
  • Deux LEDS
  • Deux résistances de 330Ω
  • Des fils…

Pour la connection du capteur RFID sur une arduino MEGA :

MOSI: Pin 51 / ICSP-4
MISO: Pin 50 / ICSP-1
SCK : Pin 52 / ISCP-3
SDA : Pin 53 (Configurable)
RST : Pin 5 (Configurable)

Si ce n’est pas un MEGA :

MOSI: Pin 11 / ICSP-4
MISO: Pin 12 / ICSP-1
SCK : Pin 13 / ISCP-3
SDA : Pin 10 (Configurable)
RST : Pin 9 (Configurable)

Je vous propose le montage COMPLET (c’est à dire avec les LEDS mais qui ne vont pas servir dans la première partie de l’article :

ATTENTION LE MODULE RFID FONCTIONNE EN 3,3V 

RFID-mega_bb1 RFID-Nano_bb

Lecture de l’identifiant de la carte et du porte clef :

Les cartes RFID possèdent un identifiant qu’il va falloir retrouver pour pouvoir ensuite savoir si notre carte est autorisée ou refusée.

#include <SPI.h>                            // Librairies nécessaires
#include <RFID.h>

RFID monModuleRFID(53,5);                  // On déclare les PINS SDA et RST Pour le NANO : monModuleRFID(10,9)

int UID[5];                                // On crée notre variable qui vit stocker l'UID de notre carte

void setup()
{
  Serial.begin(9600);
  SPI.begin();
  monModuleRFID.init();                    // On initialise le module RFID

}

void loop()
{
    if (monModuleRFID.isCard()) {
          if (monModuleRFID.readCardSerial()) {
            Serial.print("L'UID est: ");
            for(int i=0;i<=4;i++)
            {
              UID[i]=monModuleRFID.serNum[i];
              Serial.print(UID[i],DEC);
              Serial.print(".");
            }
            Serial.println("");
          }
          monModuleRFID.halt();
    }
    delay(5000);
}

En sortie j’obtient ceci (J’ai passé le porte clef et premier puis la carte) :

Sans-titre2

  • Porte clef : 105.115.122.158.254
  • Carte : 138.55.50.59.180

Commande d’une LED :

Mettons en pratique l’authentification. Je vais programmer pour que le porte clef soit reconnu comme valide (LED verte) et que la carte soit invalide (LED ROUGE) :

#include <SPI.h>
#include <RFID.h>

const char DOUT_LED_ROUGE = 2;
const char DOUT_LED_VERTE = 3;

RFID monModuleRFID(53,5);

int UID[5]={};
int MASTERKEY[5]={105,115,122,158,254};

void setup()
{
  Serial.begin(9600);
  SPI.begin();
  monModuleRFID.init();
  pinMode(DOUT_LED_ROUGE, OUTPUT);
  pinMode(DOUT_LED_VERTE, OUTPUT);
  digitalWrite(DOUT_LED_ROUGE, LOW);
  digitalWrite(DOUT_LED_VERTE, LOW);

}

void loop()
{
    if (monModuleRFID.isCard()) {
          if (monModuleRFID.readCardSerial()) {
            Serial.print("L'UID est: ");
            for(int i=0;i<=4;i++)
            {
              UID[i]=monModuleRFID.serNum[i];
              Serial.print(UID[i],DEC);
              Serial.print(".");
            }
            Serial.println("");
          }

          if (UID[0] == MASTERKEY[0]
           && UID[1] == MASTERKEY[1]
           && UID[2] == MASTERKEY[2]
           && UID[3] == MASTERKEY[3]
           && UID[4] == MASTERKEY[4])
          {
              digitalWrite(DOUT_LED_VERTE, HIGH);
              delay(500);
              digitalWrite(DOUT_LED_VERTE, LOW);
          }
          else
          {
              digitalWrite(DOUT_LED_ROUGE, HIGH);
              delay(500);
              digitalWrite(DOUT_LED_ROUGE, LOW);
          }
          monModuleRFID.halt();
    }
    delay(1);
}

Le résultat en vidéo :

Téléchargement des librairies ICI

Publié le

Sonde humidité pour le sol

Ce soir, je vous propose de nous occuper de nos plantes vertes. on va prendre le cas d’une plante qui a besoin d’un taux d’humidité du sol supérieur à 75%, si le taux d’humidité est entre 50% et 75% il faut arroser et si on passe en dessous de 50% c’est critique.

Matériel requis :

  • Un Arduino NANO ;
  • 3 Résistances 330Ω;
  • Un capteur humidité pour le sol.

Le capteur :

Mon kit est en deux parties, une carte et la fourche à mettre dans le sol. Il y a deux possibilités pour le relier à l’Arduino :

  • D0 : sortie digitale qui va nous renvoyer soit 1, soit 0
  • A0 : sortie analogique qui nous renvoie une valeur entre 0 et 1023

Ici je ne vais m’intéresser qu’à la sortie analogique vu que je souhaite obtenir un taux d’humidité pour le sol.

Le montage :

humité sol_bb

Programmation :

Intoduction – Déclarations :

int pinA =A0;          // Pin Analogique du capteur
int Sensor = 3;        // Pin d'alimentation du capteur
int ledR = 4;          // Pin LED Rouge
int ledJ = 5;          // Pin LED Jaune
int ledV = 6;          // Pin LED Verte

Dans le Void Setup

void setup() {
 Serial.begin(9600);
 pinMode(pinA,INPUT);
 pinMode(ledR,OUTPUT);
 pinMode(ledJ,OUTPUT);
 pinMode(ledV,OUTPUT);
 pinMode(Sensor,OUTPUT);
}

Dans le Void loop :

void loop() {
digitalWrite(Sensor,HIGH);
delay(1000);
float h=analogRead(pinA);
float taux = (1023.0-h)/7.0;
 Serial.print(h);
 Serial.print(" ");
 Serial.println(taux);
 led(taux);
 digitalWrite(Sensor,LOW);
 delay(20000);

}

Dans le void led() :

void led(float taux)
{

  digitalWrite(ledV,LOW);
  digitalWrite(ledJ,LOW);
  digitalWrite(ledR,LOW);

  if (taux > 70)
      digitalWrite(ledV,HIGH);
      else {
        if (taux > 50)
            digitalWrite(ledJ,HIGH);
            else digitalWrite(ledR,HIGH);
          }
}

Résultat :

Si je laisse la sonde à l’air libre, pas de conduction entre les deux fourches de la sonde, valeur renvoyée sur le pin A0 : 1023, la led rouge est allumée.

IMG_2574

Si je met la sonde dans un verre d’eau, conduction entre les deux fourches de la sonde, valeur mesurée sur le pin A0 : 300, la led verte est allumée.

IMG_2575

Je passe l’explication mathématique pour définir l’équation d’une fonction affine, ce qui m’a permit de définir que

taux = (1023.0-h)/7.0;

Si je tiens la fourche de la sonde avec les doigts légèrement humides, j’obtiens une valeur intermédiaire qui allume la led jaune.

IMG_2576

 

Publié le

Capteur humidité / température DHT22

Et pourquoi ne pas se faire une petite station météo avec l’Arduino ?

Pour cela je vais vous parler aujourd’hui des sondes humidité – température DHT.

Il existe 2 types de DHT :

  • DHT11 : Précision humidité 5%, température 2°C
  • DHT22 : Précision humidité 2%, température 0,5°C

 

Matériel requis :

Le montage :

DHT

 

Programmation :

Intoduction – Déclarations :

#include <DHT.h>

#define DHTPIN 2                  // Declaration du pin du DHT

//#define DHTTYPE DHT11 // DHT 11
#define DHTTYPE DHT22 // DHT 22

DHT dht(DHTPIN, DHTTYPE); // Initialisation du capteur

Dans le Void Setup

void setup() {
 Serial.begin(9600);
 Serial.print("Test du DHT");
 Serial.println(DHTTYPE);
 dht.begin();
}

Dans le Void loop

void loop(){
// Pause en début pour laisser le temps au capteur de démarrer
 delay(5000);

 float h = dht.readHumidity();
 float t = dht.readTemperature();

 Serial.print("Humidity: ");
 Serial.print(h);
 Serial.print(" %t");
 Serial.print("Temperature: ");
 Serial.print(t);
 Serial.println(" *C ");
}

Capture

Publié le

Controle d'un module Relais par une module RTC

Je vous ai déjà présenté les modules Relais et RTC, mais qu’en est il d’un module RTC qui pourrait commander un relais ?

 

Matériel requis :

  • Un Arduino MEGA;
  • 1 Résistances 330Ω;
  • Une led;
  • Un module RTC ici
  • Un module Relais ici

 

Le montage :

Pour le montage, on fait une fusion des deux concernant Relais et RTC :

RTC_relai

 

Programmation :

Intoduction – Déclarations :

#include <Wire.h>
#include <RTClib.h>

RTC_DS1307 RTC;                  // Declaration du module RTC

const int RELAIS = 3;           // Declaration broche 3 output
float temp;
boolean etatRelais = 0;

Dans le Void Setup

void setup() {
 pinMode(RELAIS, OUTPUT);      // Configure la broche RELAIS en sortie
 digitalWrite(RELAIS,0);       // On place le relais dans l'etat off
 Wire.begin();
 RTC.begin();
}

Dans le Void loop

void loop(){
heure();                      // On fait tourner la fonction heure
}

La fonction « heure »

void heure()
{
 DateTime now = RTC.now();                     // On récupère le temps actuel
 if (now.hour() <=17 && now.minute() <= 45)    // Boucle de condition avec des variables
 {
 etatRelais=1;                                 // Si la condition est respectée on allume la led
 digitalWrite(RELAIS,etatRelais);
 }
 else
 {
 etatRelais=0;                                 // Si la condition n'est pas respectée on éteint la led
 digitalWrite(RELAIS,etatRelais);
 }
}