Mon voyage dans le nuage (19) : serveur Web simple avec l'ESP32
20 octobre 2017
sur
sur
Dans les épisodes précédents, nous avons utilisé le protocole MQTT pour échanger des messages contenant des mesures et des commandes entre différents clients. À l'aide d'une carte ESP32 DevKitC (disponible dans l'e-choppe Elektor), nous avons réalisé un actionneur et branché des capteurs. La carte accueille l'ESP32, un puissant microcontrôleur qui prend le Wi-Fi en charge et se programme facilement à l'aide de l'IDE Arduino grâce à une bibliothèque conçue intelligemment.
Avec les épisodes précédents, nous avons aussi appris comment MQTT, protocole peu gourmand, fonctionne : via une connexion TCP/IP, nous échangeons quelques octets entre client (notre carte ESP32) et serveur (le courtier MQTT à l'extérieur dans le nuage) dans les deux sens. Dans cet épisode, nous allons nous tourner vers un autre protocole s'appuyant également sur TCP/IP, à savoir le HTTP (HyperText Transfer Protocol). En fait, nous inversons la relation : notre matériel ESP32 agit comme serveur TCP/IP et un PC connecté au même réseau Wi-Fi local joue le rôle du clientTCP/IP. Pour le PC, il n'y a pas besoin de logiciel supplémentaire, il suffit d'utiliser un navigateur Web standard. Si vous lisez ces lignes, vous avez justement utilisé le protocole HTTP : sur le champ d'adresse du navigateur, vous avez saisi www.elektormagazine.fr et le serveur d'Elektor vous renvoie la page correspondante en tant que contenu codé sous protocole HTTP. Cette page est codée en HTML : en plus du texte, ont été transmis des boutons, des liens Web, des images et bien d'autres éléments.
L'ESP32 peut également envoyer des pages Web que l'on peut afficher sur un PC avec un navigateur. Ainsi, une page peut par exemple contenir un formulaire sur lequel nous saisissons des valeurs de configuration que nous pouvons renvoyer à l'ESP32 à l'aide d'un bouton. Alors vous avez sans doute une idée de là où notre voyage va nous conduire : jusqu'à maintenant nous avons dû coder tous les réglages « en dur » dans un croquis Arduino. Ce serait plus agréable de pouvoir programmer notre matériel à distance par le Wi-Fi ; l'écran du PC, la souris et le clavier forment une interface utilisateur beaucoup plus confortable pour notre carte. Pour apprendre comment configurer l'ESP32 en serveur Web simple, j'ai tout d'abord pensé à une application simple : sur demande du navigateur, l'ESP32 doit afficher une page avec un petit formulaire (voir la copie d'écran). Dans le premier champ texte, à côté de LED1, nous pouvons indiquer 00 ou FF pour commuter la LED rouge que nous avons raccordée à la carte ESP32 lors de l'épisode 17. Nous réutilisons aussi la LED RVB : elle indique la connexion réussie sur le réseau Wi-Fi domestique.
lance un serveur TCP/IP à l'écoute de requêtes de clients. Il peut s'agir d'un navigateur du PC mais également d'un smartphone ou d'une tablette, qui se transforment alors en télécommandes mobiles.
Ce qui est en fait intéressant, c'est la fonction loop (boucle). Si une requête du client est présente, le microcontrôleur analyse les caractères qui lui parviennent maintenant via TCP/IP. Le protocole de la requête est le HTTP. Comme tous les caractères sont également envoyés sur le moniteur série, on peut observer facilement à quel point le HTTP est bavard en comparaison du MQTT. Un avantage est toutefois que seuls des octets appartenant au code ASCII sont utilisés ; pour les analyser, on peut donc employer les fonctions de manipulation des chaînes de caractères d'Arduino. Le caractère de saut de ligne (Line-Feed) sépare les différentes chaînes de la requête (voir la copie d'écran).
Ce qui nous intéresse, c'est l'évaluation de la première ligne qui commence par GET. Dans le cas le plus simple, l'utilisateur a signifié dans la ligne d'adresse de son navigateur seulement l'adresse locale de l'ESP32 (par exemple 192.168.0.23) et appuyé sur la touche d'entrée pour démarrer la requête. Il est cependant possible d'envoyer bien d'autres caractères ASCII au serveur après le signe /. Lorsque vous surfez sur le Web, cette possibilité est exploitée pour indiquer des sous-pages que vous voulez visiter et vous pouvez également y mettre des commandes à destination d'un serveur Web. Dans l'application que j'utilise par défaut, nous avons utilisé une URL du genre 192.168.0.23/H pour allumer une LED. Dans le flux de données de la requête, apparaît /H et tout de suite après, GET suivi d'un espace. Comme il y a ensuite un autre espace, la commande peut facilement être extraite par le programme Arduino et la commutation de la LED ordonnée.
Pour ma propre application, j'utilise un autre mécanisme dont tous les navigateurs sont pourvus. Un formulaire Web est construit à partir d'éléments de commande HTML, voici l'un d'eux particulièrement utile :
Le navigateur représente l'élément comme bouton, ici avec l'inscription Submit (Envoyer). Lorsque l'utilisateur clique sur le bouton, le navigateur envoie la nouvelle requête au serveur ; toutes les données du formulaire (par exemple le texte contenu dans les champs) sont adjointes à l'adresse. S'il y a, par exemple, un champ texte dénommé Pays contenant, par exemple, France, et un second champ texte dénommé Ville contenant, par exemple, Vannes, le navigateur enverrait la requête suivante au serveur de notre réseau local :
Tout ce qui se trouve après le / se retrouve dans le flux de données TCP/IP de la requête ; Les signes de séparation = et & simplifient le traitement de la chaîne.
La première fonction se contente d'encapsuler la commande server.begin(), qu'il faut appeler dans la fonction setup. La seconde fonction est plus intéressante, il faut la parcourir cycliquement rapidement. Si aucune requête ne se présente, elle renvoie simplement une chaîne de caractères vide. Si un client transmet une requête, alors les chaînes de caractères HTTP sont traitées. Si l'utilisateur a donné une adresse simple comme 192.168.0.23, la fonction renvoie simplement la chaîne -. S'il s'agit d'une requête selon le modèle 192.168.0.23/?Pays=France&Ville=Vannes, l'expression après le point d'interrogation est renvoyée. Après une requête du client, la connexion est maintenue ouverte. Nous pouvons maintenant arriver sur une page HTML à l'aide de la 3e fonction mentionnée ci-dessus.
Pour préparer l'ensemble en vue de l'application de configuration envisagée, j'ai défini un certain nombre de tableaux de huit éléments chacun (un pour chaque possibilité de réglage). ConfigName[x] est le libellé du nom du réglage, ConfigValue[x] la valeur correspondante et ConfigStatus[x] indique si la valeur est indéterminée (0), valable (1) ou erronée (-1). Dans l'application de démonstration, chacune des valeurs 00 et FF est valable.
Dans la boucle principale, les actions ci-dessous sont exécutées cycliquement :
La suite au prochain épisode !
Avec les épisodes précédents, nous avons aussi appris comment MQTT, protocole peu gourmand, fonctionne : via une connexion TCP/IP, nous échangeons quelques octets entre client (notre carte ESP32) et serveur (le courtier MQTT à l'extérieur dans le nuage) dans les deux sens. Dans cet épisode, nous allons nous tourner vers un autre protocole s'appuyant également sur TCP/IP, à savoir le HTTP (HyperText Transfer Protocol). En fait, nous inversons la relation : notre matériel ESP32 agit comme serveur TCP/IP et un PC connecté au même réseau Wi-Fi local joue le rôle du clientTCP/IP. Pour le PC, il n'y a pas besoin de logiciel supplémentaire, il suffit d'utiliser un navigateur Web standard. Si vous lisez ces lignes, vous avez justement utilisé le protocole HTTP : sur le champ d'adresse du navigateur, vous avez saisi www.elektormagazine.fr et le serveur d'Elektor vous renvoie la page correspondante en tant que contenu codé sous protocole HTTP. Cette page est codée en HTML : en plus du texte, ont été transmis des boutons, des liens Web, des images et bien d'autres éléments.
L'ESP32 peut également envoyer des pages Web que l'on peut afficher sur un PC avec un navigateur. Ainsi, une page peut par exemple contenir un formulaire sur lequel nous saisissons des valeurs de configuration que nous pouvons renvoyer à l'ESP32 à l'aide d'un bouton. Alors vous avez sans doute une idée de là où notre voyage va nous conduire : jusqu'à maintenant nous avons dû coder tous les réglages « en dur » dans un croquis Arduino. Ce serait plus agréable de pouvoir programmer notre matériel à distance par le Wi-Fi ; l'écran du PC, la souris et le clavier forment une interface utilisateur beaucoup plus confortable pour notre carte. Pour apprendre comment configurer l'ESP32 en serveur Web simple, j'ai tout d'abord pensé à une application simple : sur demande du navigateur, l'ESP32 doit afficher une page avec un petit formulaire (voir la copie d'écran). Dans le premier champ texte, à côté de LED1, nous pouvons indiquer 00 ou FF pour commuter la LED rouge que nous avons raccordée à la carte ESP32 lors de l'épisode 17. Nous réutilisons aussi la LED RVB : elle indique la connexion réussie sur le réseau Wi-Fi domestique.
Programme du serveur Web de l'ESP32
Lors de la programmation du serveur Web, je n'ai pas cherché à réinventer la roue. Une simple recherche de « esp32 webserver arduino » sur Google permet de trouver cette jolie procédure Arduino. Nous sommes déjà familiers avec la fonction setup : l'ESP32 se connecte au réseau Wi-Fi. Il envoie ensuite l'adresse qu'il occupe sur le réseau local au moniteur série ; nous en avons en effet encore besoin. Mais il y a du nouveau : la ligneserver.begin();
lance un serveur TCP/IP à l'écoute de requêtes de clients. Il peut s'agir d'un navigateur du PC mais également d'un smartphone ou d'une tablette, qui se transforment alors en télécommandes mobiles.
Ce qui est en fait intéressant, c'est la fonction loop (boucle). Si une requête du client est présente, le microcontrôleur analyse les caractères qui lui parviennent maintenant via TCP/IP. Le protocole de la requête est le HTTP. Comme tous les caractères sont également envoyés sur le moniteur série, on peut observer facilement à quel point le HTTP est bavard en comparaison du MQTT. Un avantage est toutefois que seuls des octets appartenant au code ASCII sont utilisés ; pour les analyser, on peut donc employer les fonctions de manipulation des chaînes de caractères d'Arduino. Le caractère de saut de ligne (Line-Feed) sépare les différentes chaînes de la requête (voir la copie d'écran).
Ce qui nous intéresse, c'est l'évaluation de la première ligne qui commence par GET. Dans le cas le plus simple, l'utilisateur a signifié dans la ligne d'adresse de son navigateur seulement l'adresse locale de l'ESP32 (par exemple 192.168.0.23) et appuyé sur la touche d'entrée pour démarrer la requête. Il est cependant possible d'envoyer bien d'autres caractères ASCII au serveur après le signe /. Lorsque vous surfez sur le Web, cette possibilité est exploitée pour indiquer des sous-pages que vous voulez visiter et vous pouvez également y mettre des commandes à destination d'un serveur Web. Dans l'application que j'utilise par défaut, nous avons utilisé une URL du genre 192.168.0.23/H pour allumer une LED. Dans le flux de données de la requête, apparaît /H et tout de suite après, GET suivi d'un espace. Comme il y a ensuite un autre espace, la commande peut facilement être extraite par le programme Arduino et la commutation de la LED ordonnée.
Pour ma propre application, j'utilise un autre mécanisme dont tous les navigateurs sont pourvus. Un formulaire Web est construit à partir d'éléments de commande HTML, voici l'un d'eux particulièrement utile :
<input type="submit" value="Submit" />
Le navigateur représente l'élément comme bouton, ici avec l'inscription Submit (Envoyer). Lorsque l'utilisateur clique sur le bouton, le navigateur envoie la nouvelle requête au serveur ; toutes les données du formulaire (par exemple le texte contenu dans les champs) sont adjointes à l'adresse. S'il y a, par exemple, un champ texte dénommé Pays contenant, par exemple, France, et un second champ texte dénommé Ville contenant, par exemple, Vannes, le navigateur enverrait la requête suivante au serveur de notre réseau local :
192.168.0.23/?Country=France&City=Vannes
Tout ce qui se trouve après le / se retrouve dans le flux de données TCP/IP de la requête ; Les signes de séparation = et & simplifient le traitement de la chaîne.
Petite bibliothèque de serveur Web
J'avais désormais tous les ingrédients pour programmer l'application serveur Web adéquate ; vous pouvez télécharger le résultat ci-dessous. C'est intentionnellement que j'ai renoncé à utiliser des variables et à tout optimiser ; le traitement des erreurs est encore rudimentaire. Ma petite bibliothèque de serveur Web comprend les fonctions ci-dessous :void Webserver_Start()
String Webserver_GetRequestGETParameter()
void Webserver_SendHTMLPage(String HTMLPage)
String Webserver_GetRequestGETParameter()
void Webserver_SendHTMLPage(String HTMLPage)
La première fonction se contente d'encapsuler la commande server.begin(), qu'il faut appeler dans la fonction setup. La seconde fonction est plus intéressante, il faut la parcourir cycliquement rapidement. Si aucune requête ne se présente, elle renvoie simplement une chaîne de caractères vide. Si un client transmet une requête, alors les chaînes de caractères HTTP sont traitées. Si l'utilisateur a donné une adresse simple comme 192.168.0.23, la fonction renvoie simplement la chaîne -. S'il s'agit d'une requête selon le modèle 192.168.0.23/?Pays=France&Ville=Vannes, l'expression après le point d'interrogation est renvoyée. Après une requête du client, la connexion est maintenue ouverte. Nous pouvons maintenant arriver sur une page HTML à l'aide de la 3e fonction mentionnée ci-dessus.
Pour préparer l'ensemble en vue de l'application de configuration envisagée, j'ai défini un certain nombre de tableaux de huit éléments chacun (un pour chaque possibilité de réglage). ConfigName[x] est le libellé du nom du réglage, ConfigValue[x] la valeur correspondante et ConfigStatus[x] indique si la valeur est indéterminée (0), valable (1) ou erronée (-1). Dans l'application de démonstration, chacune des valeurs 00 et FF est valable.
Dans la boucle principale, les actions ci-dessous sont exécutées cycliquement :
- Nous appelons la fonction Webserver_GetRequestGETParameter et regardons si une requête (HTTP-Request) du navigateur Web arrive. Si c'est le cas, la communication avec le navigateur (le client) est maintenue ouverte et les caractères reçus sont traités. La fonction renvoie alors un - ou le paramètre GET après le ?.
- S'il y a plus d'un caractère, nous supposons alors que l'utilisateur a appuyé sur le bouton Submit et que les données du formulaire arrivent (théoriquement il est possible de rajouter manuellement des caractères à la fin de la ligne d'adresse).
- Le paramètre GET est décomposé et les valeurs de ConfigValue[x] sont réinitialisées (la suite des valeurs en paramètres est déterminante).
- La fonction ProcessAndValidateConfigValues(…) vérifie les valeurs ConfigValue[x] obtenues. ConfigStatus[x] prend alors la valeur correspondant au résultat ; ensuite, la LED rouge est commutée en fonction de la valeur du premier champ texte. Cette fonction est très dépendante de l'application, c'est pourquoi, dans le croquis, elle figure juste avant la boucle de programme.
- Pour terminer, la page Web (nouvelle) est reconstruite avec ses éléments HTML. Le formulaire est par conséquent reconstruit avec les valeurs de configuration effectives placées dans les champs texte. Les couleurs d'arrière-plan verte et rouge symbolisent respectivement la validité et l'erreur de la valeur. La page Web et ensuite dotée d'un en-tête HTTP (HTTP-Response) et envoyée. La communication avec le client est alors fermée.
- Et ainsi de suite.
La suite au prochain épisode !
Lire l'article complet
Hide full article
Discussion (0 commentaire(s))