si vous avez un exemple pour lire une variable je suis preneur.
Voici un exemple qui n'utilise pas le serveur HTTP pour faire les demandes mais juste la connexion TCP
Vous avez un ESP32 principal qui veut lire des données (c'est un client) et un autre qui fournit des données (c'est un serveur).
Pour que la communication TCP fonctionne entre 2 ordinateurs sur un réseau IP, il faut que le client connaisse l'adresse du serveur --> Pour simplifier l'exemple, j'ai câblé en dur l'adresse du serveur
L'idée de cet exemple c'est que le client envoie une requête TCP au serveur qui ne contient qu'un seul octet: un caractère qui sera le nom de la variable attendue ('x' par exemple).
Le serveur va recevoir cette demande et va fabriquer une réponse qui sera un texte ASCII
"[color=blue]x[/color] = [color=purple]1234[/color]"
on reprendra donc le x et comme je n'ai pas voulu rendre compliqué le code, la valeur retournée pour la variable sera simplement millis() à l'instant de la requête.
Donc pour résumer: l'utilisateur tape x dans la console série du client, le caractère 'x' est envoyé dans une requête TCP au serveur qui fabrique une réponse "x = 1234" et la retourne au client qui nous l'affiche.
Voici le code du serveur:
// FOURNISSEUR DE DONNEES
#include <WiFi.h>
#include <AsyncTCP.h>
const uint16_t serverPort = 7050;
AsyncServer server(serverPort); // écoute le port tcp 7050
const char* ssid = "*********"; // A REMPLIR
const char* password = "*********"; // A REMPLIR
void reception(void* arg, AsyncClient* client, void *data, size_t len) {
char reponse[30];
Serial.print(F("Demande ")); Serial.println(((char*)data)[0]);
if (client->space() > sizeof(reponse) && client->canSend()) {
snprintf(reponse, 30, "%c = %lu", ((char*)data)[0], millis()); // fabique "x = 1000" par exemple
client->add(reponse, strlen(reponse));
client->send();
}
}
void gestionClient(void* arg, AsyncClient* client) {
Serial.print(F("Nouveau client: ")); Serial.println(client->remoteIP());
client->onData(&reception, NULL); // attacher le callback appeler reception() quand on reçoit des données
}
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.printf("Serveur: Erreur connexion WiFi\n");
while (true) yield();
}
Serial.print("Serveur IP: "); Serial.println(WiFi.localIP());
server.onClient(gestionClient, &server);
server.begin();
}
void loop() {}
Le code devrait se comprendre assez aisément
- on a une variable globale
server de type AsyncServer qui écoute sur le port 7050
- dans le setup on se connecte au Wi-Fi, puis on attache la fonction gestionClient() si on a un événement de type 'nouvelle Connection' sur notre serveur. et on active le serveur.
Quand un client se connecte, la fonction est déclenchée et on attache à ce client un callback qui s'appelle reception(). Dès que ce client envoie une requête, la fonction reception() est appelée avec les bons paramètres (on peut avoir plusieurs clients).
Dans cette fonction reception(), on prépare simplement une petite réponse en ASCII du type "x = 1234" où x est le caractère reçu dans la requête et le nombre la valeur de millis(). C'est fait par
snprintf(reponse, 30, "%c = %lu", ((char*)data)[0], millis());
puis on envoie cela au client.
Vous chargez donc ce code sur votre premier ESP32
Vous ouvrez la console série à 115200 bauds et regardez ce qu'il s'affiche.
Le mien dit [color=purple]Serveur IP: 10.0.0.23[/color]
==> Prenez note de cette adresse IP car on en a besoin pour le code du client (MASTER)
Voici le code du client
// DEMANDE DE DONNEES
#include <WiFi.h>
#include <AsyncTCP.h>
IPAddress serverIP(10, 0, 0, 23); // <<=== ICI RENTRER L'ADRESSE IP DU SERVEUR
const uint16_t serverPort = 7050;
AsyncClient client;
const char* ssid = "*********"; // A REMPLIR
const char* password = "*********"; // A REMPLIR
void demande(char variable) {
if (client.space() > sizeof(variable) && client.canSend()) {
Serial.print(F("envoi req pour ")); Serial.println(variable);
client.add(&variable, sizeof(variable));
client.send();
} else Serial.println(F("MASTER: CAN'T SEND A REQUEST"));
}
void reception(void* arg, AsyncClient* client, void *data, size_t len) {
Serial.write('\t');
Serial.write((uint8_t*)data, len); // la réponse
Serial.write('\n');
}
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.printf("Master: Erreur connexion WiFi\n");
while (true) yield();
}
client.onData(&reception, &client); // appeler reception() quand on reçoit des données
client.connect(serverIP, serverPort);
Serial.println(F("\n-----\nEntrez une variable entre 'a' et 'z'\n"));
}
void loop() {
int r = Serial.read();
if ((r >= 'a') && (r <= 'z')) demande(r); // simulation de demande d'une variable
}
Notez la ligne IPAddress serverIP([color=red]10, 0, 0, 23[/color]); où j'ai codé en dur l'adresse du serveur (attention séparation par des virgules, pas des points).
Le code devrait se comprendre assez aisément
- on a une variable globale
client de type AsyncClient qui va représenter notre connexion au serveur.
- dans le setup on se connecte au Wi-Fi, puis on attache la fonction reception() si on a un événement de type "réception de données" sur ce client puis on se connecte au serveur sur le bon port.
- la loop ne fait qu'écouter le port série et si le caractère reçu est entre 'a' et 'z' alors on appelle la fonction demande()
- cette fonction demande() construit une requête de taille 1 octet (la taille d'un char), puis l'envoie au serveur
- le système est asynchrone donc la fonction est terminée, mais quand le serveur répond, notre fonction reception() est appelée et les data[] contiennent le message préparé par le serveur, que l'on imprime.
Vous chargez ce ce code sur le second ESP32 et dans la console à 115200 bauds vous allez voir
[color=purple]-----
Entrez une variable entre 'a' et 'z'[/color]
tapez x par exemple dans la console, vous devriez voir
[color=purple]envoi req pour x
x = 279076[/color]
tapez maintenant y dans la console, vous devriez voir
[color=purple]envoi req pour y
y = 306119[/color]
Bien sûr la valeur de la variable va changer en fonction de millis() sur le serveur, les vôtres seront différentes.
Vous verrez que ce n'est pas toujours instantané, il y a bien envoi de la demande et un peu plus tard la réponse arrive.
pour adapter ce code à votre besoin, vous aurez un client (le master) qui va juste balancer 1 octet à différents serveurs (faudra connaître leur IP ou utiliser le DNS). Chaque serveur reçoit la demande, va bâtir une réponse qui sera simplement une structure qui contient tous les paramètres y compris son identifiant (puisque vous allez recevoir les réponse de manière asynchrone, il faudra savoir si c'est la chambre ou le salon qui vous répond) et envoyer (c'est en binaire) la structure.
La fonction de reception() du master va donc être appelée plusieurs fois avec des réponses des différents serveurs, vous recevez les data[] dans une structure similaire à celle du serveur et vous pouvez comme cela extraire facilement les données et les stocker ou les afficher.
PS/ ici je fais la connexion au serveur dans le setup(), en dur et qu'une seule fois. Si pour une raison ou pour une autre cette connexion tombe, ça ne fonctionne plus et faut rebooter. Votre code devra donc être plus solide et se connecter à la demande, puis une fois obtenu la réponse clore la connection par exemple.