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.

jeudi 22 janvier 2015

Php pour tout contrôler !

Chose promise, chose due.
Loin d'être fini, mais déjà une base que j'utilise depuis plusieurs mois.

J'ai mis ça sur un Github :
https://github.com/nono1024/Rasp-mcp23017

A faire sur le PI :

cd ~
On récupère le projet.
git clone https://github.com/nono1024/Rasp-mcp23017.git
cd  Rasp-mcp23017
On le copie dans le répertoire d'apache
cp -R * /var/www/
On mets les bons droits dessus
sudo chown -R www-data:www-data /var/www/
sudo chmod -R 775 /var/www/
Et normalement, avec un navigateur et en tapant directement l'URL de l'IP de votre PI vous devriez obtenir ceci :

C'est déjà pas mal !
Pour faire succint, Dans l'écran accueil vous avez un accès au 16 relais des banks du MCP23017.
Ici uniquement en ON OFF pour l'instant.

Dans l'onglet relais, vous avez un menu un peu plus complet sur l'action que l'on peux faire sur les relais (fugitif, on, off) mais aussi plus d'infos sur la config de chaque PIN.

Dans l'onglet Conf relais, on peux personnaliser chaque relais, en changeant son nom, le type (uniquement on off ou uniquement fugitif), et si il est nécessaire pour son activation qu'un autre relais soit activé.
Je m'explique, si sur un relais est branché des LED 12V, mais que l'alimentation 12V est sur un autre relais (pour éviter de la laissé branché), il faut linker le relais des LED à l'alimentation.
Ainsi, si vous allumez les LED, l'alim sera automatiquement allumé, et si vous éteignez et que aucun autre relais n'utilise l'alim 12V, l'alim sera éteinte aussi.

Pour rappel, un relais fugitif est un relais qui se comportent comme un poussoir avec un temps par défaut de 1s en état ON.


Il y a aussi un onglet sonde qui détecte automatiquement les sondes DS18B20 1wire et permet de les faire apparaitre sur l'écran principal (en les sauvegardant, cela permettra donc de les mettre sur l'écran d'accueil, mais aussi d'y faire appel par l'API).

Et enfin un onglet API qui permet de détailler les différents appels HTTP possible.


Voici ce que ça donne une fois configuré :

 

On voit que j'ai configuré les PIN B4 à B6 en fugitif, du coup, ça n'affiche sur l'accueil que le bouton ACTIONNER (comme un poussoir).

On voit les 3 sondes DS18B20, Et sur la page Relais :

On voit que j'ai linké aux PIN A0 à A3 le relais B7 qui correspond à mon alim 12V.
Ainsi, si j'actionne le relais A0 ou A1 ou A2 ou A3, il verifiera si l'alim est allumé et l'allumera au besoin.
Pareil pour l'extinction, il vérifiera que les PIN A0, A1, A2, A3 sont bien éteint avant d'éteindre l'alim 12V.

C'est tout pour le moment......

2% du code (la base du début début est d'origine Idleman : http://blog.idleman.fr/ ) Merci à lui pour l'orientation et puis pour son blog !!!! (mais pas pour ces vidéos :):) )