dimanche 13 septembre 2015

DomoPotame - ESP8266

Alors je me suis essayé à l'ESP8266 il n'y a pas longtemps, ce petit chip Wifi très lowcost mais qui offre quand même pas mal de possibilité.

Le seul inconvénient de ce petit chip, c'est que ces sorties GPIO ne fournissent pas beaucoup d'intensité en sortie, mais on peux rajouter des petits transistors pour couvrir ce manque.

Mon premier petit projet avec, fut de domotiser la veilleuse de ma fille, son hippo (qui était à sa mère avant elle).

Voici la bête modifié :


Il y a un esp8266 dedans, avec un strip LED 12V piloté par un MOSFET pour pouvoir faire varier l'intensité lumineuse.
J'ai rajouté deux LED vertes au niveau des oreilles, ces LED servent de réveil pour lui indiquer qu'elle peux se lever.
Il y a également un switch pour allumer le strip led sans téléphone (un appui passe le strip à 10%, un autre 30%, puis 50% puis 100%).
Et en petit plus une sonde de température/humidité DHT22.
Le tout alimenté par un bloc alim 12V.

Voici le schéma physique du potame :

L'esp8266 est programmé en IDE Arduino.
Pour faire de l'arduino avec l'ESP, il faut passer par ce github qui fourni tout :
https://github.com/esp8266/Arduino

Et voici le sketch de l'ESP potame :

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

    const char* ssid     = "SSIDNAME";
    const char* password = "SSIDPWD";

// 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 buttonState = 0;
int buttonrelease = 0;

void setup() {

  //Prépare la serial
  Serial.begin(115200);
  delay(10);
  //Initialise le DHT
  dht.begin();
  // Défini les GPIO 14 et 4 en sortie
  pinMode(5, OUTPUT);
  pinMode(14, OUTPUT);
  pinMode(13, INPUT);
  // Met à 0 les GPIO
  digitalWrite(5, 0);
  digitalWrite(14, 0);
  // 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;
  buttonState = digitalRead(13);
  if (buttonState == HIGH && buttonrelease == 0) {
    //Bouton Potame HIGH
    if (valu == 0 && buttonrelease == 0) {
      valu = 40;
      analogWrite(5, valu);
      buttonrelease = 1;
      }
      else if (valu < 41 && buttonrelease == 0) {
      valu = 150;
      analogWrite(5, valu);
      buttonrelease = 1;
      }
      else if (valu < 151 && buttonrelease == 0) {
      valu = 550;
      analogWrite(5, valu);
      buttonrelease = 1;
      }
      else if (valu < 551 && buttonrelease == 0) {
      valu = 1024;
      analogWrite(5, valu);
      buttonrelease = 1;
      }
      else if (valu > 851 && buttonrelease == 0) {
      valu = 0;
      analogWrite(5, valu);
      buttonrelease = 1;
      }
  }else if (buttonState == LOW && buttonrelease == 1) {
    buttonrelease = 0;
    delay(500);
    }
  // 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()){
    delay(1);
  }
 
  // 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 /gpio2/0
  if (req.indexOf("/gpio2/0") != -1) {
    val = 0;
    // Met GPIO à 0 comme demandé
    digitalWrite(14, val);
    // Continue la réponse JSON
    resultat += "\"GPIO2\":\"";
    resultat += (val);
   
  // si l'URI est /gpio2/1
  } else if (req.indexOf("/gpio2/1") != -1) {
    val = 1;
    // Met GPIO à 1 comme demandé
    digitalWrite(14, val);
    // Continue la réponse JSON
    resultat += "\"GPIO2\":\"";
    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;
  // si l'URI est /gpio/demodim
  }else if (req.indexOf("/gpio/demodim") != -1) {
    val = 1;
      // Fait un PWM de 0 au MAX
      for (int i=0; i<1024; i++) {
        analogWrite(5, i);  // PWM the LED from 0 to 1024 (max)
        delay(1);
      }
      // Fait un PWM de MAX à 0
      for (int i=1023; i>=0; i--) {
        analogWrite(5, i);  // PWM the LED from 1024 (max) to 0
        delay(1);
      }
    // Continue la réponse JSON
    resultat += "\"GPIO\":\"DEMODIM\"";
    resultat += (val);
  // si l'URI est /gpio/dim 
  }else if (req.indexOf("/gpio/dim") != -1) {
      // Récupère le % désiré (entre 0 et 1023)
      String svalu = req.substring(14,18);
      valu = svalu.toInt();
      //
      analogWrite(5, valu);  // PWM the LED from 255 (max) to 0
    // Continue la réponse JSON
    resultat += "\"GPIO\":\"";
    resultat += (valu);
  // Requete invalide
  } 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
}
Il y a plusieurs commandes possibles qui renvoi du JSON :

http://IP-DE-POTAME/gpio/temp
renvoi la mesure de température de la sonde DHT22
{ "success": "1","TEMP":"23.20","HUM":"75.50" }
http://IP-DE-POTAME/gpio2/0 ou http://IP-DE-POTAME/gpio2/1
Allume ou éteint les petites leds vertes et renvoi
{ "success": "1","GPIO2":"0" }

http://IP-DE-POTAME/gpio/dim=0000 ou http://IP-DE-POTAME/gpio/dim=1023
Allume le strip LED à l'intensité demandé (de 0 à 1023) et renvoi
{ "success": "1","GPIO":"0" }
 Une petite vidéo de l'ensemble relié à l'Eedomus :



Pour info, ce montage tourne depuis 3 mois sans un plantage ni un raté, c'est assez hallucinant d'avoir une si grande fiabilité sur un composant de ce prix.