Faire causer deux ESP32 entre eux, mais de la bonne manière

Bonjour !
Ceci est mon premier message ici en dehors de ma présentation, alors merci d'être indulgent !

Après avoir déjà programmé des Arduino Nano et Uno, je me suis mis à l'ESP32 il y a quelques semaines et j'ai bien sûr voulu exploiter les possibilités offertes par le WiFi intégré.
Alors avec deux ESP32, j'ai fait la chose suivante :
Le premier qu'on appellera "FIXE" est dans la maison et est alimenté en permanence par un chargeur de téléphone et a un écran qui indique l'heure (cherchée sur un serveur NTP) et aussi une température et une hygrométrie qu'il va chercher sur le deuxième ESP32 qu'on appellera "MOBILE", qui est à l'extérieur et est alimenté par un accu Lipo.
FIXE est connecté à mon routeur avec toujours la même adresse IP (générée par le routeur grâce à l'adresse MAC de l'ESP), pareil pour MOBILE (avec bien sûr une adresse IP différente !)
Pour l'instant je procède ainsi :
Sur MOBILE, j'ai créé un serveur avec la librairie WebServer.h et une pages html simple pour afficher les données dans un navigateur quelconque (juste pour le fun, mais pas besoin de cette possibilité), ainsi qu'une autre page "lecture.html" ultra-basique en mode "text-plain" qui contient juste les variables (température, humidité et tension de la batterie)

Sur FIXE, pour pouvoir afficher ces données sur l'écran, j'ai installé la bibliothèque HTTPClient.h avec laquelle je fais toutes les xxx secondes un getString() sur la page "lecture.html" se trouvant sur MOBILE.
J'extrais ensuite mes valeurs du String réceptionné, et je les affiche sur l'écran.

Tout cela fonctionne très bien mais le problème c'est que cela oblige l'ESP MOBILE à tourner 100% du temps, et avec une conso d'environ 50 mA la batterie ne tient pas très longtemps.

Alors l'idée que j'ai, ce serait que ce soit MOBILE qui envoie à intervalles réguliers les données à FIXE, et qu'entretemps il se mette en deep sleep avec timer.
Le deep sleep avec timer j'arrive à le gérer, par contre dire à MOBILE d'envoyer des données à FIXE (qui lui est allumé tout le temps), je ne sais pas trop comment faire...
Ajoutons que je sais faire des pages html pas trop compliquées, mais que je n'ai aucune connaissance ni en javascript ni en CCS...

C'est là que j'aurais besoin d'idées et c'est la raison de ce (long) message.

Bravo à tous ceux qui auront lu jusqu'à la fin, et merci pour tout conseil !

Roland

C'est un simple client WEB (HTTPClient).
L'exemple le plus simple que j'ai pu trouver :

Merci !

C'est exactement ce que je fais avec l'ESP FIXE quand je vais chercher les infos sur le serveur dans MOBILE.
D'ailleurs je me suis appuyé sur ce même exemple ! :slight_smile:
Par contre ce que je voudrais, c'est que ce soit MOBILE qui envoie les infos à FIXE, (et se mette en sommeil entre les envois)

Roland

inversez les rôles: mettez le serveur web sur FIXE et c'est mobile qui fait une requête GET en passant en paramètre les données à afficher. comme ça ensuite MOBILE peut s'endormir

Merci J-M-L !
Ce qui voudrais donc dire qu'avec la requête GET je peux ENVOYER des données et pas seulement en recevoir, si j'ai bien compris ?
(désolé pour la question bête mais je ne suis pas encore très familier avec tout ce côté WiFi de l'ESP32)

Roland

Les deux mon capitaine, la requête avec la méthode GET ou toutes autres permet dans l'URI de donner des paramètres, c'est ce qui suit le ? dans lURI.
Avec une méthode PUT ou POST tu peux aussi envoyer des données dans le corps de la requête.
Tu obtiendra en réponse un buffer, qui peut contenir aussi bien du code HTML, que javascript, du texte formaté (ex JSON) ou non, que du binaire.

Oui merci terwal et encore une fois J-M-L.

Je suis en train de potasser là-dessus et j'ai déjà appris des choses entretemps !
Merci pour l'impulsion, je pense que pour mon besoin je vais faire un post de "text-plain", avec mes valeurs dedans.
Allez hop, de quoi m'occuper le cerveau quelques heures !

Roland

Bon, pour envoyer mes 3 valeurs Temp, Hum et Vbat je pense faire un GET url sous cette forme dans l'ESP MOBILE :

String mon_url = "http://192.168.1.152/envoi.html?temp=" +String(Temp) + "&hum=" + String(Hum) + "&vbat=" + String(Vbat);
 WiFiClient client;
 HTTPClient http;
 http.begin(mon_url);
 int httpResponseCode = http.GET();
 http.end();

Ce qui enverra (selon les valeurs) le string "http://192.168.1.152/envoi.html/?temp=15.00&hum=15&vbat=3.95"
Est-ce que c'est une bonne approche ?

Par contre sur l'autre ESP, avec le WebServer, je ne vois pas trop comment récupérer ces valeurs.

Il me faudra sûrement ajouter une ligne du genre dans le setup :

server.on("/envoi", handle_envoi);

Là où je ne sais pas, c'est quoi mettre ensuite dans la fonction correspondante pour récupérer les données :

void handle_envoi()
?
?

Pfff, les débuts sont durs...

Roland

Tu as des fonctions args pour récupérer un argument ou savoir si il existe(hasArg).
Dans les exemples de la librairie il y a des démonstrations de l'emploi de la fonction

Utilisez la bibliothèque GitHub - me-no-dev/ESPAsyncWebServer: Async Web Server for ESP8266 and ESP32 et vous avez tout ce qu’il faut pour écrire le serveur en un rien de temps

hasArg() plutôt, ou hasParam() avec AsyncWebServer.

Le premier mais le correcteur orthographique de monde téléphone, a décidé autrement :face_with_hand_over_mouth:

Mais, pourquoi s'embêter avec le protocole HTTP, qui ne sert pas vraiment ici ?
La simplicité me dicte d'utiliser un simple serveur TCP/IP (ou même UDP).
On se connecte, on échange des données.
Il me semble que le HTTP n'apporte rien de plus.

Tu n'a pas tord, bien que je dirais tout le contraire, pourquoi s'embêter avec un serveur TCP, qui n'apporte rien plus que le HTTP :rofl::rofl:.

L'avantage du HTTP, réside plus dans les librairies qui t'offrent un serveur, un parseur de paramètres, des codes d'erreur normé, des clients nombreux(possibilité de tester directement dans n'importe quel navigateur).
En gros quelques lignes de codes te permet de le mettre en œuvre.

Bonjour et merci messieurs pour toutes vos remarques et discussions qui sont pour moi des "discussions d'initiés" et ne font que m'embrouiller plus, vu que je suis débutant en tout ce qui concerne le WiFi sur ESP32 !

J'ai jeté un oeil à AsyncWebServer que je trouve beaucoup trop complexe pour mes connaissances actuelles et pour ce que je veux faire, c'est à dire juste envoyer 3 valeurs par une requête GET ou POST faite avec HTTPClient.h (que ce soit sous forme de String ou d'url) sur un serveur basé sur WebServer.h

Pour le côté GET ou POST par HHTPClient je pense m'en sortir, c'est du côté de la réception par le serveur que je bloque (en supposant qu'un serveur basé sur WebServer.h soit capable de réceptionner ces données ?)
J'ai jeté un oeil à plusieurs exemples, ça ne m'a pas avancé...

Roland

Dans le Modèle OSI, TCP est la couche 4 (transport), alors que HTTP est la couche 7 (application), bâtie (entre autres) sur TCP.

Par définition donc, TCP apporte moins de choses que HTTP, cependant TCP est suffisant pour transporter quelques données d'un ESP à l'autre.
Alors bien sûr on ne pourra pas utiliser un navigateur pour voir ce qui se passe, mais la mise en oeuvre avec TCP est beaucoup plus simple : côté client, c'est juste connect() puis read() ou write().
Pas de GET, pas de chaînes de caractères à convertir, pas de test pour savoir si un paramètre existe...

KISS (Keep it Simple, S...)

C’est la ou on vous dit que ESPAsyncWebServer peut vous aider

Regardez l’exemple https://github.com/me-no-dev/ESPAsyncWebServer/blob/master/examples/simple_server/simple_server.ino

Ils traitent une requête GET avec comme paramètre message=xxx (tapez l’URL votreIP/get?message=coucou par exemple

C’est ce bout de code qui gère cela

    server.on("/get", HTTP_GET, [] (AsyncWebServerRequest *request) {
        String message;
        if (request->hasParam(PARAM_MESSAGE)) {
            message = request->getParam(PARAM_MESSAGE)->value();
        } else {
            message = "No message sent";
        }
        request->send(200, "text/plain", "Hello, GET: " + message);
    });

Ça dit avec server.on("/get", HTTP_GET si tu reçois une requête HTTP GET qui commence par /get alors exécute la fonction suivante

{
        String message;
        if (request->hasParam(PARAM_MESSAGE)) {
            message = request->getParam(PARAM_MESSAGE)->value();
        } else {
            message = "No message sent";
        }
        request->send(200, "text/plain", "Hello, GET: " + message);
}

Qui demande à la requête en cours s’il y a un paramètre qui s’appelle message ( la valeur du #define PARAM_MESSAGE) et si oui on va afficher sa valeur (ce qui se trouve après le =, dans mon exemple plus haut, c’est coucou)

Ensuite on retourne à l’appelant un petit message pour montrer qu’on a bien traiter la demande et le code 200 pour dire succès

Je suis forcément d'accord sur la partie technique, mais pour un débutant, il n'est pas forcément plus simple de faire un connect ou un listen et la lecture ou écriture du buffer qui y correspond.
Puis de parser le buffer résultant, d'ailleurs dans ce cas je préfère passer une structure et non une chaîne, si tout est fixe.
Alors oui, tu peux avoir à convertir avec du urlencode ou du base64, mais ce n'est pas toujours nécessaire.
Je dirais même que n'étant plus débutant je trouve plus simple de passer par du HTTP, que de passer par une socket et les options associés.
Après comme je l'ai dit, tu n'a pas tord non plus et ça économiserait la bande passante, cher à certains :rofl::rofl::rofl:

@rollmops67 Ça peut te paraître plus compliqué ou inaccessible, mais je te promets que tu y gagnera à suivre ce que @J-M-L te propose :smiley:

Ah ben ça y est ÇA MARCHE avec ESPAsyncWebServer et avec le sketch "simple_server.ino" :star_struck:

Je n'en reviens pas moi-même...
Comme quoi il ne faut jamais désespérer !

Bon, le temps que je comprenne que ma chaîne à envoyer devait commencer par "message" :thinking:
(le if (request->hasParam(PARAM_MESSAGE))) , en faisant une simple requête GET avec HTTPClient depuis l'ESP MOBILE vers l'ESP FIXE sur lequel se trouve ESPAsyncWebServer j'arrive maintenant à passer des données, yyyeeesssss !
Il ne me reste plus qu'à "emballer" ça proprement dans le code qui va bien...

Par contre j'ai une question par rapport au sketch "simple_server.ino" (j'ai fait un copier-coller depuis la page github), dans le comportement duquel quelque chose m'échappe. (ça ne me dérange pas pour ce que je veux faire, mais j'aimerais comprendre)

Quand je tapes sur un navigateur 192.168.1.152 (l'adresse IP de mon serveur) ça m'affiche "Hello World", preuve que je suis bien "aiguillé".

Quand je tapes "192.168.1.152/get" ça me dit bien "Hello, GET: No message sent", preuve que j'ai encore une fois été bien été aiguillé..."

Par contre quand je tapes "192.168.1.152/post" je me retrouve avec le message "Not found" envoyé par la fonction "void notFound(AsyncWebServerRequest *request)", je suis donc mal aiguillé, et j'ai beau chercher dans le code de la page, je ne vois pas d'où ça peut venir.

En tout cas merci pour votre aide précieuse, ça donne envie de continuer à avancer !

Roland

Dans un navigateur, la requête que tu fais utilise la méthode GET.
Dans l'exemple que tu as utilisé, l'URI /post est utilisé avec la méthode post.
Personnellement je trouve pas du tout opportun d'utiliser une URI qui contient le nom d'une méthode HTTP.
Il y a des extensions pour les navigateurs qui permet de jouer avec les requêtes HTTP et de choisir les arguments, méthodes, header/paramètres.