ESP8266 (Client Web – Partie 1) : communication TCP/IP (exemples ESP8266WiFi et ESP866HTTPClient)

Avec l’adaptation pour les modules ESP8266 des librairies Arduino WiFiClient (ESP8266WiFi) , HTTPClient (ESP8266HTTPClient) , il est très facile d’échanger des données avec un serveur domotique ou un service en ligne, de piloter le GPIO de l’ESP8266… Dans la série d’article précédente, nous avons vu comment mettre en place un serveur Web stockée dans le système de fichier FPIFFS de l’ESP82266. Ce tutoriel est le premier d’une nouvelle série d’articles consacrés à la communication avec un client ESP8266.

Dans ce premier tutoriel, nous allons découvrir les librairies ESP8266WiFi,  ESP8266HTTPClient et en bonus ESP8266WiFiMulti.

ESP8266WiFi / ESP8266wifi, la confusion !

Si vous débutez dans la programmation des ESP8266, vous avez sans doute rencontré ces deux librairies qui portent un nom très similaire sur internet. La première est la librairie “officielle” (ESP8266WiFi) installée en même temps que les cartes ESP8266. Il est livrée avec de nombreux exemples, notamment ceux proposés par Wemos pour accompagner ces cartes Wemos D1 mini et Wemos R2. Le dépôt GitHub se trouve ici. Comme beaucoup de librairie ESP8266 adaptées du code Arduino, il n’y a pas de documentation, à nous découvrir les fonctions à l’aide des exemples ou aller chercher dans les librairies d’origine https://www.google.com/#safe=on&q=wifi+site:http:%2F%2Fwww.arduino.cc .

Son homonyme, ESP8266wifi est une librairie équivalente développée par Jonas Ekstrand. Elle n’est pas disponible depuis le gestionnaire de bibliothèque, il faudra l’installer manuellement en décompressant le dépôt dans le répertoire libraries de l’IDE Arduino, puis en redémarrant celui-ci. La librairie de Jonas Ekstrand est beaucoup plus complète que la librairie originale. Disons qu’elle combine plusieurs fonctions en une seule librairie. Elle permet de gérer l’ESP8266 comme un point d’accès, de surveiller l’arriver de messages, de gérer la re-connexion automatique…

A vous de choisir celle qui correspond le mieux à vos besoins. Dans ce tutoriel, nous allons utiliser l’adaptation de la librairie Arduino ESP8266WiFi.

La librairie ESP8266WiFi

La librairie ESP8266WiFi s’installe en même temps que le support des cartes ESP8266. Si ce n’est pas le cas, vous pouvez l’installer directement depuis le gestionnaire de bibliothèques.

Exemple : un watchdog

Pour découvrir le fonctionnement de la librairie, le mieux est encore de passer par un petit exemple. On va se connecter au serveur de test (Node.js ou SocketTest) et lui envoyer le temps écoulé depuis le démarrage de l’ESP8266 (obtenu avec la fonction millis()) ainsi que l’adresse IP du module. On restera à l’écoute jusqu’à ce qu’on ait reçu une réponse du serveur (You are alive!).

Un watchdog peut être utile pour surveiller que le module est toujours en fonctionnent et envoyer une alerte. Pour cet exemple, j’ai adapté le code de l’exemple WiFiClient installé en même temps que la carte Wemos D1 R2 & mini.

On doit donc commencer par établir une connexion avec le réseau WiFi. C’est la classe WiFi.begin qui s’en charge.

WiFi.begin(ssid, password);

On continue le déroulement du programme que lorsqu’une connexion a été établie. Attention, c’est un code parfaitement inadapté à une fonctionnement sur batterie. Dans ce cas, il est préférable de mettre un compteur et mettre en sommeil l’ESP pour recommencer plus tard après plusieurs tentatives infructueuses.

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

Maintenant qu’on dispose d’une connexion WiFi, on va envoyer à intervalle régulier un message au serveur. Pour cela, on doit créer un objet client qui se connectera au serveur.

WiFiClient client;

if (!client.connect(host, port)) {
  Serial.println("connection failed");
  return;
}

On construit ensuite une chaine dans laquelle on va encoder les données envoyées au serveur. Ici le temps passé depuis le démarrage de l’ESP8266 ainsi que l’adresse IP de ce dernier.

String url = "/watchdog?command=watchdog&uptime=";
    url += String(millis());
    url += "&ip=";
    url += WiFi.localIP().toString();

Il ne reste plus qu’à envoyer le message au serveur

client.print(String("GET ") + url + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" + 
               "Connection: close\r\n\r\n");

Si comme moi, vous trouvez que l’écriture de cette commande est difficile, nous allons voir comment améliorer ça juste après.

Voici le code complet du sketch.

/*
 * TCP/IP communication ESP8266WiFi
 * Copyright (C) 2017 https://www.projetsdiy.fr - http://www.diyprojects.io
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include <ESP8266WiFi.h>
const char* ssid     = "xxxx";      // SSID
const char* password = "xxxx";      // Password
const char* host = "xxx.xxx.xxx.xxx";  // IP serveur - Server IP
const int   port = 8080;            // Port serveur - Server Port
const int   watchdog = 5000;        // Fréquence du watchdog - Watchdog frequency
unsigned long previousMillis = millis(); 

void setup() {
  Serial.begin(115200);
  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());
}

void loop() {
  unsigned long currentMillis = millis();

  if ( currentMillis - previousMillis > watchdog ) {
    previousMillis = currentMillis;
    WiFiClient client;
  
    if (!client.connect(host, port)) {
      Serial.println("connection failed");
      return;
    }

    String url = "/watchdog?command=watchdog&uptime=";
    url += String(millis());
    url += "&ip=";
    url += WiFi.localIP().toString();
    
    // Envoi la requete au serveur - 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");
    unsigned long timeout = millis();
    while (client.available() == 0) {
      if (millis() - timeout > 5000) {
        Serial.println(">>> Client Timeout !");
        client.stop();
        return;
      }
    }
  
    // 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);
    }
  }
}

Connexion sécurisée HTTPS : WiFiClientSecure

La sécurisation de la connexion HTTP n’est pas prise en charge nativement par la librairie ESP8266WiFi. Pour cela, il faut intégrer la librairie WiFiClientSecure.h. Si vous en avez besoin, voici un exemple disponible sur GitHub ainsi que la discussion qui traite du sujet.

La librairie ESP8266WiFiMulti

Avant de présenter la librairie ESP8266HTTPClent, nous allons parler de la librairie ESP8266WiFiMulti. L’objectif de cette librairie est de laisser l’ESP8266 choisir le réseau WiFi sur lequel se connecter en fonction de sa disponibilité et de la force du signal. Cette librairie est incluse avec la librairie ESP8266WiFi.

Elle est très simple à utiliser. On comme par créer un objet wifiMulti.

ESP8266WiFiMulti wifiMulti;

On ajoute les différents points d’accès dans une liste à l’aide de la classe wifiMulti.addAP()

wifiMulti.addAP("ssid1","psk1");
wifiMulti.addAP("ssid2","psk2");

On ouvre une connexion avec la classe run().

wifiMulti.run()

On dispose de plusieurs clés permettant de tester le bon fonctionnement de la connexion :

  • WL_CONNECTED : la connexion est établie
  • WL_NO_SSID_AVAIL : aucun point d’accès indiqué dans la liste n’est disponible
  • WL_CONNECT_FAILED : échec de connexion. Probablement que le mot de passe est mauvais ou un filtrage par adresse MAC a été mis en place sur le routeur.

Pour voir ce qui se passe, vous pouvez ajouter cette option dans le setup().

Serial.setDebugOutput(true);

La librairie ESP8266HTTPClient

Comme vous avez pu voir dans l’exemple précédent, on envoi un message au serveur à l’aide de la fonction client.print() dans laquelle on passe une chaine de caractère qui contient la commande HTTP. C’est efficace mais pas forcément super sympa à utiliser surtout si on est pas un pro du Web. Pour faire quelque chose de “plus propre” et plus poussé, il existe la librairie ESP8266HTTPClient. C’est aussi une adaptation d’une librairie Arduino (ArduinoHTTPClient) pour l’ESP8266. Elle est disponible depuis le gestionnaire de bibliothèque de l’IDE Arduino.

On va donc créer un objet http au début du sketch

HTTPClient http;

On construit l’url exactement de la même façon que précédemment.

String url = "/watchdog?command=watchdog&uptime=";
    url += String(millis());
    url += "&ip=";
    url += WiFi.localIP().toString();

Avant d’envoyer la requête on passe les paramètres à l’objet http comme ceci

http.begin(host,port,url);

On dispose maintenant de trois classes distincts correspond aux requêtes HTTP les plus classiques : GET (demande de données), POST (envoi de données) et PUT (envoi de fichier). Ici on va faire un requête GET pour simuler la réception d’une réponse du serveur

int httpCode = http.GET();

Chaque classe renvoi un code permettant de savoir si la requête à pu aboutir. Le code respecte la norme RFC7231 (source).

typedef enum {
    HTTP_CODE_CONTINUE = 100,
    HTTP_CODE_SWITCHING_PROTOCOLS = 101,
    HTTP_CODE_PROCESSING = 102,
    HTTP_CODE_OK = 200,
    HTTP_CODE_CREATED = 201,
    HTTP_CODE_ACCEPTED = 202,
    HTTP_CODE_NON_AUTHORITATIVE_INFORMATION = 203,
    HTTP_CODE_NO_CONTENT = 204,
    HTTP_CODE_RESET_CONTENT = 205,
    HTTP_CODE_PARTIAL_CONTENT = 206,
    HTTP_CODE_MULTI_STATUS = 207,
    HTTP_CODE_ALREADY_REPORTED = 208,
    HTTP_CODE_IM_USED = 226,
    HTTP_CODE_MULTIPLE_CHOICES = 300,
    HTTP_CODE_MOVED_PERMANENTLY = 301,
    HTTP_CODE_FOUND = 302,
    HTTP_CODE_SEE_OTHER = 303,
    HTTP_CODE_NOT_MODIFIED = 304,
    HTTP_CODE_USE_PROXY = 305,
    HTTP_CODE_TEMPORARY_REDIRECT = 307,
    HTTP_CODE_PERMANENT_REDIRECT = 308,
    HTTP_CODE_BAD_REQUEST = 400,
    HTTP_CODE_UNAUTHORIZED = 401,
    HTTP_CODE_PAYMENT_REQUIRED = 402,
    HTTP_CODE_FORBIDDEN = 403,
    HTTP_CODE_NOT_FOUND = 404,
    HTTP_CODE_METHOD_NOT_ALLOWED = 405,
    HTTP_CODE_NOT_ACCEPTABLE = 406,
    HTTP_CODE_PROXY_AUTHENTICATION_REQUIRED = 407,
    HTTP_CODE_REQUEST_TIMEOUT = 408,
    HTTP_CODE_CONFLICT = 409,
    HTTP_CODE_GONE = 410,
    HTTP_CODE_LENGTH_REQUIRED = 411,
    HTTP_CODE_PRECONDITION_FAILED = 412,
    HTTP_CODE_PAYLOAD_TOO_LARGE = 413,
    HTTP_CODE_URI_TOO_LONG = 414,
    HTTP_CODE_UNSUPPORTED_MEDIA_TYPE = 415,
    HTTP_CODE_RANGE_NOT_SATISFIABLE = 416,
    HTTP_CODE_EXPECTATION_FAILED = 417,
    HTTP_CODE_MISDIRECTED_REQUEST = 421,
    HTTP_CODE_UNPROCESSABLE_ENTITY = 422,
    HTTP_CODE_LOCKED = 423,
    HTTP_CODE_FAILED_DEPENDENCY = 424,
    HTTP_CODE_UPGRADE_REQUIRED = 426,
    HTTP_CODE_PRECONDITION_REQUIRED = 428,
    HTTP_CODE_TOO_MANY_REQUESTS = 429,
    HTTP_CODE_REQUEST_HEADER_FIELDS_TOO_LARGE = 431,
    HTTP_CODE_INTERNAL_SERVER_ERROR = 500,
    HTTP_CODE_NOT_IMPLEMENTED = 501,
    HTTP_CODE_BAD_GATEWAY = 502,
    HTTP_CODE_SERVICE_UNAVAILABLE = 503,
    HTTP_CODE_GATEWAY_TIMEOUT = 504,
    HTTP_CODE_HTTP_VERSION_NOT_SUPPORTED = 505,
    HTTP_CODE_VARIANT_ALSO_NEGOTIATES = 506,
    HTTP_CODE_INSUFFICIENT_STORAGE = 507,
    HTTP_CODE_LOOP_DETECTED = 508,
    HTTP_CODE_NOT_EXTENDED = 510,
    HTTP_CODE_NETWORK_AUTHENTICATION_REQUIRED = 511
}

Il est donc très facile de savoir si le message a bien été reçu par le serveur. On récupère le contenu du message (payload) à l’aide de la classe http.getString().

if (httpCode) {
  if (httpCode == 200) {
    String payload = http.getString();
    Serial.println(payload);
  }
}

Voici le code modifié basée. L’ESP8266 cherchera le meilleur réseau WiFi sur lequel se connecter. Durant la phase d’inactivité, le WiFi est coupé à l’aide de la classe WiFi.disconnect().

/*
 * TCP/IP communication ESP8266HTTPClient
 * Copyright (C) 2017 https://www.projetsdiy.fr - http://www.diyprojects.io
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266WiFiMulti.h>

const char* host = "192.168.1.33";
const int  port = 8080;
const int   watchdog = 5000;
unsigned long previousMillis = millis(); 

ESP8266WiFiMulti wifiMulti;
HTTPClient http;

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

  // We start by connecting to a WiFi network
  wifiMulti.addAP("ssid1", "psk1");
  wifiMulti.addAP("ssid2", "psk2");

  Serial.println("Connecting Wifi...");
  if(wifiMulti.run() == WL_CONNECTED) {
    Serial.println("");
    Serial.println("WiFi connected");
    Serial.println("IP address: ");
    Serial.print(WiFi.localIP());
  }
  Serial.setDebugOutput(true);
  
}

int value = 0;

void loop() {
  unsigned long currentMillis = millis();

  if ( currentMillis - previousMillis > watchdog ) {
    previousMillis = currentMillis;

    if(wifiMulti.run() != WL_CONNECTED) {
      Serial.println("!!");
    } else {  
      Serial.println("WiFi connected");
      Serial.println("IP address: ");
      Serial.println(WiFi.localIP());
    
      String url = "/watchdog?command=watchdog&uptime=";
      url += String(millis());
      url += "&ip=";
      url += WiFi.localIP().toString();
      
      Serial.print("connecting to ");
      Serial.println(host);
      Serial.print("Requesting URL: ");
      Serial.println(url);
     
      http.begin(host,port,url);
      int httpCode = http.GET();
      if (httpCode) {
        if (httpCode == 200) {
          String payload = http.getString();
          Serial.println(payload);
        }
      }
      Serial.println("closing connection");
      http.end();
      WiFi.disconnect();
    }
  }
}

On peut attendre une éventuelle réponse du serveur. Si vos transmettez à un serveur domotique, il y a de grande change qu’il vous renvoi un status:OK, au minimum, vous devriez recevoir une réponse de code 200 signifiant que le message a correctement été réceptionné par le serveur. Vous pouvez imaginer d’autre traitements en fonction de la réponse : mettre dans un pile et recommencer ultérieurement, supprimer la mesure ou au contraire la stocker dans un journal, ajouter dans un journal l’événement et le message d’erreur (pour faciliter la mise au point), piloter le GPIO (faire clignoter une LED)…

Serveur de test Node.js pour communiquer avec l’ESP8266

Pour tester les différentes librairies, je vous propose de développer rapidement un petit serveur Node.js. Dans les prochains tutoriels, nous irons plus loin en mettant en place une communication complète avec quelques serveurs domotiques (Jeedom, Domoticz, Home Assistant). Si vous débutez avec Node.js, suivez ce tutoriel pour installer et découvrir Node.js

Pour ce serveur, vous aurez besoin d’installer les packages moment, express.

sudo npm moment express

Ouvrez un éditeur de texte et créez un nouveau fichier appelé server.js en y collant ce code

/*
*   Serveur de test pour librairies ESP8266WiFi et ESP8266HTTPClient
*   Test server for ESP8266WiFi and ESP8266HTTPClient libraries
*   https://www.projetsdiy.fr - 2017
*/
var express = require('express');
var moment = require('moment');
var app = express();

app.get('/', function(req, res) {
  res.send('HTTP ESP8266 Test Server')
});

app.use('/watchdog', function (req, res, next) {
  var t = moment.duration(parseInt(req.param('uptime')), 'milliseconds')
  var _message = req.param('ip') + " uptime " + t.hours() + "h " + t.minutes() + "m " + t.seconds() +"s";
  console.log("watchdog from " + _message);
  res.send("You are alive!");
});

app.listen(8080);

Ouvrez le Terminal (ou PowerShell sous Windows). Placez vous dans le répertoire dans lequel vous avez enregistré le fichier server.js et démarrez le serveur avec la commande node server.js  ou nodemon server.js  (nodemon s’occupe de redémarrer le serveur à chaque modification des fichiers).

A chaque message reçu, le serveur récupère les données passées en paramètres et construit un message d’information qui est ensuite envoyé sur le Terminal.

serveur test communication tcp ip http esp8266wifi

SocketTest : un serveur de test

Si vous n’avez pas le courage de vous lancer avec Node.js, vous pouvez opter pour SocketTest qui est un petit programme qui démarre un serveur de test sur votre machine. Vous pouvez le récupérer sur Sourceforge ici. SocketTest fonctionne sur macOS (lancez SocketTest.jar), Windows (SocketTest.exe) et Linux (SocketTest.sh).

 sockettest sourceforge test esp8266wifi

Allez à l’onglet Server puis indiquez l’adresse ip de votre machine. Il faut absolument indiquer l’adresse ip de la machine sur lequel fonctionne SocketTest pour que ça fonctionne.

Ensuite démarrez le serveur en cliquant sur Start Listening. Vous allez recevoir vos premiers messages (en fonction de la fréquence d’envoi définie par la variable watchdog).

sockettest watchdog esp8266wifi

Vous pouvez envoyer une réponse à l’ESP8266 en le saisissant dans le champ message puis en cliquant sur Send. Par exemple ici, j’ai répondu OK qui apparait dans la console sous S: OK. Si vous avez ouvert le moniteur série sur l’IDE Arduino, vous pourrez voir le message reçu. Si vous ne répondez pas dans le temps prévu dans le programme (ici 5 secondes), vous aurez un message d’erreur (>>> Client Timeout !) avant que le client ne se déconnecte.

Remarque. Les réponses envoyées par SocketTest ne sont pas réceptionnées avec la librairie ESP8266HTTPClient. A creuser…

sockettst watchdog send response esp8266wifi client

Vous connaissez maintenant les 3 principales librairies permettant de faire communiquer un programme Arduino/ESP8266 en TCP/IP à l’aide de requêtes HTTP. Il nous reste maintenant à mettre en pratique tout ça sur des cas concrets. Nous verrons dans les prochains tutoriels comment envoyer simplement des mesures de température (ou n’importe quoi d’autre d’ailleurs) à Domoticz, Jeedom et Home Assistant.

Print Friendly, PDF & Email

Inscrivez-vous à la newsletter hebdomadaire

Aucun spam et aucun autre usage ne sera fait de votre email. Vous pouvez vous désinscrire à tout moment.

Comparateur de prix

Bons plans

Les offres suivantes se terminent bientôt. Utilisez le coupon indiqué pour profiter du prix promo

Domotique et objets connectés à faire soi-même