mardi 21 février 2017

DomoRadiateur - ESP8266

Ça faisait longtemps que je n'avais pas posté, j'en ai fait des choses mais pas documenté.
Mon dernier truc en date est la réparation de mon radiateur soufflant de salle de bains de marque Delonghi.







http://www.castorama.fr/images/products/h/h_643036.jpg
Il ne s'allumait plus du tout juste après avoir fait un sapin de noël.
La carte de contrôle était noire, bref la merde.....
Cout d'une nouvelle carte : 65€

J'ai donc démonté et j'ai vu que le deux composants (radiant et soufflant) était piloté via 2 relais sur la carte de contrôle. La sécurité du soufflant est géré par les composants interne au soufflant et pas sur la carte de contrôle, et le radiant est piloté par une sonde de température à l'arrière.
Il y a 2 boutons en façade pour lancer soit le soufflant soit le radiant.
Quand on appui dessus ça le lance, et quand on ré-appui dessus ça l'éteint.

Le soufflant à un timer de 15mn et le radiant un timer de 1h.
Une fois le constat fait, il m'est venue l'idée de faire la carte de contrôle moi même avec un ESP8266.

J'ai donc opté pour une liste de courses assez facile :

Un ESP8266-07 -> 4€12

Une carte 2 relais opto-isolé -> 0€93
 
Une sonde DHT22 -> 2€44

Une alimentation 220V -> 5V -> 3€26

Un regulateur 5v -> 3.3V -> 2€33 les 5


Du fil, quelques resistances.

TOTAL :  13€08

La carte qui contient les 2 switchs est vissé et indépendante de la carte de contrôle, je la garde donc et j'isole les 2 inters sur lesquels je soude 2 fils.

Voici le schéma final :



La sonde DHT22 me permet de contrôler la température et l'humidité dans la salle de bains.
Les deux inters isolés sont branchés sur du 3.3V et sur 2 entrées de l'ESP (avec des resistances pulldown).

Il y a une alim 220V -> 5V et un régulateur 5V -> 3.3V.
La carte relais est alimentés directement par le 5V et les sorties de l'ESP ne débite que pour l'opto de la carte relais (donc pas besoin de résistance ou autre, les sorties directement sur les entrées de la carte relais).

Et donc la carte relais pilote les 2 éléments du chauffage indépendamment.

Les ESP sont programmés via l'IDE Arduino comme pour le DomoPotame.

Voici le sketch correspondant :
    #include "DHT.h"
    #include <ESP8266WiFi.h>

        const char* ssid     = "***********";  //SSID WIFI
        const char* password = "***********"; //MDP WIFI

    // Créé une instance WEB
    // Sur le Port 80
    WiFiServer server(80);
    // Défini le Port GPIO du DHT
    #define DHTPIN 12
    // Défini le type de DHT (DHT11-DHT21-DHT22)
    #define DHTTYPE DHT22
    // Crée le DHT
    DHT dht(DHTPIN, DHTTYPE, 15);
    int valu = '0';
    int buttonState1 = 0;
    int buttonState2 = 0;
    int buttonVal1 = 0;
    int buttonVal2 = 0;
    int A = 0;

    void setup() {

      //Prépare la serial
      Serial.begin(115200);
      delay(10);
      //Initialise le DHT
      dht.begin();
      // Défini les GPIO 4 et 5 en sortie
      pinMode(5, OUTPUT);
      pinMode(4, OUTPUT);
      pinMode(13, INPUT);
      pinMode(14, INPUT);
      // Met à 0 les GPIO
      digitalWrite(5, 1);
      digitalWrite(4, 1);
      // Connection au WiFi
      Serial.println();
      Serial.println();
      Serial.print("Connecting to ");
      Serial.println(ssid);
      // Met l'ESP uniquement en station et pas Access Point
      WiFi.mode(WIFI_STA);
      // Connection au WiFi
      WiFi.begin(ssid, password);

      for (int i=0; i<60; i++) {
        if (WiFi.status() == WL_CONNECTED) {
        i = 60;
        }
        delay(500);
        Serial.print(".");
      }
   
      if (WiFi.status() == WL_CONNECTED) {
   
      Serial.println("");
      Serial.println("WiFi connected");
      }
      // Démarre le server WEB
      server.begin();
      Serial.println("Server started");

      // Affiche l'adresse IP obtenue
      Serial.println(WiFi.localIP());
   
    }

    void loop() {
      //Déclare les variables Temp et humidity
      float temp;
      float humidity;
      delay(500);
      buttonState1 = digitalRead(13);

      if (buttonState1 == HIGH && buttonVal1 == 0 ) {
        Serial.println("Pin 13 pushed Val 0");
        digitalWrite(4, 0);
        buttonVal1 = 1;
         do {
         buttonState1 = digitalRead(13);
         Serial.println("Pin 13 released");
         delay(500);
         } while (buttonState1 == HIGH);
      
      } else if (buttonState1 == HIGH && buttonVal1 >= 1 ) {
        Serial.println("Pin 13 pushed Val 1");
        digitalWrite(4, 1);
        buttonVal1 = 0;
          do {
         buttonState1 = digitalRead(13);
         Serial.println("Pin 13 released");
         delay(500);
         } while (buttonState1 == HIGH); 
      }
   
      buttonState2 = digitalRead(14);
      if (buttonState2 == HIGH && buttonVal2 == 0 ) {
        Serial.println("Pin 14 pushed Val 0");
        digitalWrite(5, 0);
        buttonVal2 = 1; 
          do {
         buttonState2 = digitalRead(14);
         Serial.println("Pin 14 released");
         delay(500);
         } while (buttonState2 == HIGH);
      } else if (buttonState2 == HIGH && buttonVal2 >= 1 ) {
        Serial.println("Pin 14 pushed Val 1");
        digitalWrite(5, 1);
        buttonVal2 = 0;
        do {
         buttonState2 = digitalRead(14);
         Serial.println("Pin 14 released");
         delay(500);
         } while (buttonState2 == HIGH);
      }
   
      if (buttonVal1 >= 1 ) {
        Serial.println("ButtonVal1 + 1");
        buttonVal1 = buttonVal1 + 1;
        Serial.println(buttonVal1);
      }
   
      if (buttonVal2 >= 1 ) {
        Serial.println("ButtonVal2 + 1");
        buttonVal2 = buttonVal2 + 1;
        Serial.println(buttonVal2);
      }

        //Si ça fait 2400 tics de 0.5s (soit 20mn)
      if (buttonVal1 >= 2400 ) {
        digitalWrite(4, 1);
        Serial.println("ButtonVal1 OFF");
        buttonVal1 = 0;
      } 

        //Si ça fait 1200 tics de 0.5s (soit 10mn)
      if (buttonVal2 >= 1200 ) {
        digitalWrite(5, 1);
        Serial.println("ButtonVal2 OFF");
        buttonVal2 = 0;
      }
   
      // Vérifie si quelqu'un se connecte sur le Web server
      WiFiClient client = server.available();
      if (!client) {
        return;
      }
   
      // Attendre que le client envoi des infos
      Serial.println("new client");
      while(!client.available() && A < 3000){
        delay(1);
        A++;
      }
      A = 0;
      // Lit la première ligne de la requête
      String req = client.readStringUntil('\r');
      Serial.println(req);
      client.flush();
      //Prépare la sortie JSON en success
      int val;
      String httpHeader = "HTTP/1.1 200 OK\r\nContent-Type:application/json\r\nAccess-Control-Allow-Origin:*\r\nCache-Control:no-cache\r\n";
      httpHeader += "Content-Length: ";
      String resultat = "{ \"success\": \"1\",";
      // Analyse de la requête client
   
      // si l'URI est /gpio4/0
      if (req.indexOf("/gpio4/0") != -1) {
        val = 1;
        // Met GPIO à 0 comme demandé
        digitalWrite(4, val);
        // Continue la réponse JSON
        resultat += "\"GPIO4\":\"";
        resultat += (val);
        buttonVal1 = 0;
      // si l'URI est /gpio4/1
      } else if (req.indexOf("/gpio4/1") != -1) {
        val = 0;
        // Met GPIO à 1 comme demandé
        digitalWrite(4, val);
        buttonVal1 = 1;
        // Continue la réponse JSON
        resultat += "\"GPIO4\":\"";
        resultat += (val);
       // si l'URI est /gpio5/0
       } else if (req.indexOf("/gpio5/0") != -1) {
        val = 1;
        // Met GPIO à 0 comme demandé
        digitalWrite(5, val);
        buttonVal2 = 0;
        // Continue la réponse JSON
        resultat += "\"GPIO5\":\"";
        resultat += (val);
     
      // si l'URI est /gpio5/1
      } else if (req.indexOf("/gpio5/1") != -1) {
        val = 0;
        // Met GPIO à 1 comme demandé
        digitalWrite(5, val);
        buttonVal2 = 1;
        // Continue la réponse JSON
        resultat += "\"GPIO5\":\"";
        resultat += (val);
     
      // si l'URI est /gpio/temp
      } else if (req.indexOf("/gpio/temp") != -1) {
        // Prépare une boucle en cas de non réponse du DHT
         int A=0;
         do {
           A++;
          delay(2000);
           humidity = dht.readHumidity();
           temp = dht.readTemperature();
           Serial.println(temp);
           Serial.println(humidity);
           // Si aucune réponse n'est valide au bout de 10 essai, Echec
           if (A == 10) {
               //Renvoi le JSON en success 0 et erreur
               String resultat = "{ \"success\": \"0\",";
               resultat += "\"TEMP\":\"Error\"";
               resultat += "\" }\n";
               httpHeader += resultat.length();
               httpHeader += "\r\n";
               httpHeader +="Connection: close\r\n\r\n";
               String MESSAGE = httpHeader + resultat;
               client.flush();
               // Send the response to the client
               client.print(MESSAGE);
               client.stop();
               Serial.println("Client disconnected");
             return;
             }
         } while (isnan(temp) || isnan(humidity));
        // Continue la réponse JSON
        resultat += "\"TEMP\":\"";
        resultat += temp;
        resultat += "\",\"HUM\":\"";
        resultat += humidity;
      } else {
        Serial.println("invalid request");
        client.stop();
        return;
      }
      // Fini la réponse JSON
      resultat += "\" }\n";
      httpHeader += resultat.length();
      httpHeader += "\r\n";
      httpHeader +="Connection: close\r\n\r\n";

      String MESSAGE = httpHeader + resultat;

      client.flush();
      // Envoi la réponse JSON complète au client
      client.print(MESSAGE);
      delay(1);
      Serial.println("Client disconnected");

      // Déconnecte le client
   
    }
 Pareil que pour le potame, des appels http qui renvoi du JSON en réponse.
http://IP-DE-RADIATEUR/gpio/temp
renvoi la mesure de température de la sonde DHT22
{ "success": "1","TEMP":"23.20","HUM":"75.50" }
http://IP-DE-RADIATEUR/gpio4/0 ou http://IP-DE-RADIATEUR/gpio4/1
Allume ou éteint le Radiant (qui s'éteint tout seul au bout de 20mn)
{ "success": "1","GPIO4":"0" }
http://IP-DE-RADIATEUR/gpio5/0 ou http://IP-DE-RADIATEUR/gpio5/1
Allume ou éteint le Soufflant (qui s'éteint tout seul au bout de 10mn)
{ "success": "1","GPIO5":"0" }
Enfin une petite vidéo de l'ensemble via Eedomus : 


Et les graphs de température :