Serveur WEB envoyer cycliquement une valeur àun client

Bonjour à toutes et à tous,

Je débute dans le WEB : je suis nul.

Sur mon ESP32, j'ai chargé un exemple de serveur WEB qui, lorsque le client s'y connecte, il peut envoyer des ordres au serveur pour allumer éteindre une LED par exemple.

Ce que je souhaite faire est différent : dès lors qu'un client se connecte à mon serveur, le serveur va envoyer cycliquement des valeurs au client. Le client va afficher ces valeurs les unes à la suite des autres ou bien seulement remplacer l'ancienne valeur par la nouvelle.

Est-ce faisable (j'espère) et si oui, comment procède-t-on ?

Je ne demande pas du code tout mâché (encore que :upside_down_face:), mais les grandes lignes, le principe.

Cordialement.

Pierre.

Bonsoir
en fait il faut que le client appelle de manières automatique les valeurs par intermédiaires d'un "timer" dans le client.
pour regarde "Ajax"
Ajax est une technique qui te permet de récupérer en javascript des données sur un serveur

Merci pour cette réponse.

Ajax/javascript servent donc à ne recharger qu'une partie qu'on veut rafraichir.

J'ai téléchargé cet exemple.

La question que je me pose est : lorsque je clique sur l'un des boutons dans la page affichée par le client, cela envoie un message au serveur. Est-ce qu'en retour, c'est toute la page qui est renvoyée ou bien est-ce seulement la partie qui affiche "Etat LED Éteinte/Allumée" ?

Cordialement.

Pierre.

Ca peut au choix renvoyer tout mais dans ce cas peu d interet ou juste une valeur ou plusieurs dans un format au choix
Le client envoie une requete au serveur et c est au serveur de formater la réponse a cette requete.

Dans l'exemple que je cite ( le deuxième du lien), je suppose que c'est la fonction "server.handleClient();" qui reçoit la requête du client et qui la distribue vers l'une ou l'autre des deux fonctions "void handleOn()" ou "void handleOff()".

Mais chacune de ces deux fonctions appelle " server.sendHeader("Location","/");". Que fait cette fonction ? Elle renvoie toute la page ou bien alors, comment fait-elle le tri de ce qu'il faut renvoyer ?

Cordialement.

Pierre.

Oui c'est ça, la fonction attend une requête HTTP et en fonction de l'URL enregistrée (/, /on, /off) appel tes fonctions ou renvois la page 404.
Tu as trois URL enregistré :

server.on("/", handleRoot);  // Chargement de la page accueil
  server.on("/on", handleOn);  // Chargement du handleOn - Allumée la led
  server.on("/off", handleOff);  // Chargement du handleOff - Eteindre la led

plus l'erreur 404 : server.onNotFound(handleNotFound);

Cette fonction permet de positionner la propriété de l'header renvoyé au client.

Non elle ne renvoi rien, elle indique à l'objet "server" de modifier la propriété "Location" avec la valeur indiqué.
L'objet renvois quelque chose après l'appel à la fonction "Send".
Dans cet exemple en fait la location est modifié, car le code HTTP renvoyé est 303, qui indique justement que le client doit suivre la relocalisation, qui est indiqué par la proporiété "Location" dans la partie "Header".

Dans le cas par exemple de HandleOn et HandleOff, il n'y aura pas de donnée utile renvoyé, uniquement la partie "Header", qui indique qu'il faut appelé l'URL "/".
Par contre la fonction "handleRoot"

Pour répondre plus génériquement, l'AJAX, permet au javascript de pouvoir faire une requête HTTP, sans que cela implique un rafraichissement de la page HTML.
Charge au javascript de modifier ou pas la page HTML(via le DOM) affiché dans le navigateur.

Donc comme l'indique @jfs59, tu peut te servir de "setInterval", pour interroger ton serveur périodiquement, en générale avec un URL différente de celle qui renvois la page WEB.
Ce qui est renvoyé par le serveur, la partie data, est à ta convenance, mais en générale on utilise du JSON, mais tu peux renvoyer aussi une chaine non structuré, en CSV ou autre.

Mais ca c'est la vielle façon de faire, ou c'est les clients qui "harcèlent" le serveur.
Maintenant on préfère utiliser des "websockets", ou une socket est maintenu ouverte entre le client et le serveur et qui est utilisé par le serveur, pour donner les données au client lorsque celle-ci est disponible.

Bonjour
retourner un json c'est plus facile a traiter, c'est facilement adaptable comme structure

en générale avec un URL différente de celle qui renvois la page WEB.

Dans la fonction associée on "fabrique" le json et on le retourne.

pour le websocket perso jamais fais je passe la main.

Il y a une question qu'il faut te poser avant de choisir une architecture : qui donne la la cadence des valeurs et affichages ?

Si c'est l'appli web (le client) qui doit afficher la valeur toutes les secondes (ou tous les jours à 16h28 et 23h54 ou les mardi de pleine lune etc.) tu peux faire un javascript côté client qui fait une requète au serveur (ESP32). Avantage : c'est assez simple.

Si c'est le serveur (l'ESP32) qui donne le tempo c'est différent. Par exemple il faut envoyer à l'application web la valeur quand elle est disponible, ou lors d'un évènement particulier (l'utilisateur appuie sur un poussoir ou interrupteur pour envoyer la valeur d'une mesure) dans ce cas, tu peux utiliser un websocket ou un SSE (Server-Sent Events)

  • Websocket est bidirectionnel
  • SSE est unidirectionnel

Beaucoup d'exemples biens documentés sur https://randomnerdtutorials.com

Oui et non, si tu as une seul valeur, pas besoin de parser ton JSON et d'avoir des risques de cast.
De même faire un split sur un CSV, reste quelque chose de simple sur quelques données.
Par contre le JSON avec le javascript prends tout son sens sur on a une structure complexe.
Puisque la désérialisation, va donner un objet javascript.

Pour le cas présent, je ne suis pas sûre que cela apporte vraiment quelque chose, c'était plus pour indiquer que cela existe et que c'est quelque pars approprié au coté asynchrone du javascript, que de faire une boucle synchrone.
bien sûre comme l'indique @ProfesseurMephisto la réactivité à aussi tout son importance dans le choix, mais @ChPr ne l'a pas encore décrite.
Si cela doit être de l'ordre de quelque secondes, il serait dommage de "pourrir" son serveur HTTP avec plusieurs clients qui ferait une requête toutes les 10s.

Je n'ai pas compris ton exemple, quel serait l'intérêt d'une websocket dans ce cas ?
Ce n'ai pas le contraire que tu voulais dire ?

Merci "terwal" pour cette longue explication.

Pour autant, quelques points ne sont toujours pas clairs dans ma tête.

J'ai l'impression que dans ton explication le terme "header" prend deux significations :

  • pour moi, le "header" est la première partie du code HTML ; la deuxième étant le "body" ;
  • dans ce que tu dis ci-dessus, le "header" semble être la partie haute de l'affichage où est inscrit "ETAT LED : ALLUME / ETEINT. La propriété étant ALLUME / ETEINT. Cette propriété étant modifiée par les fonctions "HandleOn" et "HandleOff".

C'est quoi les données ?

C'est quoi ici le "header" ? l'URL "/" ?

Je pense que tu utilises une terminologie connue de tout ceux qui font du WEB et qui prête fortement à confusion chez moi.

Phrase non terminée ...

Cordialement.

Pierre.

je me suis mal exprimé : je ne pensais pas à un bouton sur l'interface web (<input type="button" value="Cliquez-moi !" />) mais à un bouton physique, un interupteur, un poussoir ou je ne sais quel contact électrique...

je corrige mon post en conséquence.

Il s'agit du header http et pas du code html...

Le header http n'est pas affiché, il indique au navigateur quoi faire de la suite des données. C'est ce qui permet d'indiquer la nature des données qui vont suivre (image, html, etc.), de forcer un téléchargement, de faire une redirection à une url donnée.

il faut prendre le terme Header comme l'a indiqué @ProfesseurMephisto .
Ca te parle ?

C'est la partie data d'une réponse HTTP.
c'est partie data peut contenir des données de plusieurs type.
dans le cas d'une page HTML, c'est la page HTML.
dans le cas de l'AJAX, ca peut être n'importe quoi, HTML, JSON, CSV, texte non formaté, ...

Oui, c'est là que l'on voit que la vulgarisation est une vrai compétence, que je n'ai pas forcément :slight_smile:

Le header est comme l'a indiqué @ProfesseurMephisto, une partie de la requête/réponse du protocole HTTP, qui ne contient des informations qui ne seront pas affichés par un navigateur WEB, mais il l'utilisera pour l'interpréter, par exemple, dans les entêtes, tu peux indiques l'encodage des caractères utilisé, le type des données(HTML, vidéeo, son, texte brut, ...) ou le code retour.

peut être que c'est mieux expliqué sur cette page Wikipédia
Mais n'hésite pas à demander des reformulations si m'explication ne sont pas assez claire.

Effectivement, je n'y étais pas du tout.

Bon, j'essaie de comprendre.

La partie "header" est une partie que je n'ai pas écrite dans mon application, mais qui est envoyée par le" server". Oui, Non ?

Appeler l'URL "/" c'est bien demander d'afficher le code HTML, tout le code HTML, avec sa variante ALLUME / ETEINT généré par les fonctions HandleOn et HandleOff. Oui, Non ?

En ce qui concerne la demande cyclique, dans mon cas, c'est le serveur qui commanderait ce cycle à chaque fois qu'il dispose d'une nouvelle valeur. Mais oublions ça pour l'instant. Le reste me dépasse déjà.

Cordialement.

Pierre.

Dans ce cas il serait peut être intéressant d'envoyer cette/ ces valeurs a un serveur sql qui stockerait le tout et d'interroger ce serveur par la page internet ...
mais c'est surtout pour le cas ou il faudrait garder des valeurs successives et ensuite tracer des stats ou un graphe.

evidemment faut avoir acces a un site sql et un site en php (savoir programmer) etc ...

Tu ne nous as pas dis grand chose de ton projet mais je pense que c'est pourtant par ce point là que tu dois commencer...

Ensuite si tu peux nous en dire un peu plus, il y a sûrement un projet existant duquel tu peux partir pour ensuite le faire évoluer. J'ai l'impression que tu as une idée assez précise en tête et que tu la simplifies au maximum pour cette discussion. C'est à priori une très bonne idée sauf que là je pense que tu as trop simplifié.

Dans ton message initial tu dis

Ceci est-il encore utile pour la suite ?

Tu peux même commencer avec des valeurs issues de random() pour commencer par mettre au point la communication client-serveur

Ensuite s'il s'agit de valeurs issues de capteur, il y a surement un exemple chez randomnerdtuto

Mon idée est de réaliser un routeur photovoltaïque. C'est un système qui envoie vers un chauffe-eau par exemple le surplus de production photovoltaïque, lorsqu'il y en a.

Ma demande de fonction cyclique venait seulement du fait que, développant la partie mesure du courant et de la tension, je me disais que ce serait bien de pouvoir lire ce résultat sur une page WEB ; sans plus.

Dans une version finale, je pense enregistrer les données et venir les lire par bloc une fois de temps en temps.

Cordialement.

Pierre.

Le traitement doit donc être fait par l'ESP 32 indépendamment du client web.

Vu le contexte, tu peux faire une structure assez simple sans SSE ou websocket : des requètes HTTP tout à fait classiques

  1. l'ESP32 enregistre les valeurs à intervalle régulier (combien ?) et les stocke en mémoire
  2. l'ESP les sauvegarde à intervalle régulier (combien ?) sur un support de stockage pérène (à choisir)
  3. le client interroge l'ESP qui renvoie la dernière mesure (ou fait une mesure immédiate si c'est préférable)
  4. le client demande la totalité des mesures si l'utilisateur le souhaite et l'ESP renvoie les données sous la forme que tu as choisi (tableau HTML, fichier CSV, graphique etc.)

Je pense que tu as intérêt à commencer par les points 1 et 2 (stockage des données) avant de passer à la partie "affichage des données"

oui, l'objet "server" va envoyer une réponse au client, lors de l'appel à la fonction "send".
Cette réponse normalement contient une partie header.
L'objet pourra aussi envoyer ou pas une partie donnée.
la page HTML avec l'instruction "server.send(200, "text/html", page);"
Aucune donnée avec l'instruction "server.send(303);" ou " server.send(404);"

Non pas du tout.
"/", "/on" et "/off" sont 3 URL différentes, que tu définis via la fonction "on".
Lorsque le client fait une requête avec l'un des trois URL, la fonction HandleRoot, HandleOn ou HandleOff est appelée.
Donc si tu utilises l'URL "/", la fonction HandleRoot est appelée, celle-ci définit la page HTML dans la variable page.
Donne la longueur des données à setContentLength et demande avec la fonction send de répondre au client avec en donnée le contenu de la page HTML et le code 200.

par contre si tu demandes l'URL "/on", c'est la fonction handleOn qui est appelée est définit la propriété "Location" du header et le code retour 303.
Aucune donné est renvoyée dans ce cas là.

Ceci n'est pas possible dans le contexte de l'exemple que tu as pris, il ne peut s'agir que de requête/réponse.
Le client fait une requête et le serveur doit lui répondre dans un temps limite.
Dans ce cas là, il faudra faire ce que t'a indiqué @jfs59, c'est à dire faire en sorte via le javascript d'interroger le serveur régulièrement pour savoir si il y a de nouvelle donnée.

J'ai dû mal visualiser ce que tu veux vraiment faire.
imaginons que tu lis le couple tension/courant toutes les 10s, tu voudrais visualiser sur une page WEB en temps réel la valeur lu par ton ESP32 sur une page WEB en plus d'autre information comme la quantité d'Energie produites?

Qu'entends tu par enregistrer, sur un l'ESP32 ou d'une façon plus pérenne en base de donnée ou une carte SD ?
Cela sera lu par qui de temps en temps ?

Alors, si rien n'est envoyé, comment se fait-il que l'entête "ETAT LED passe de ETEINT à ALLUME ?

Oublions cette demande cyclique, c'était juste pour voir mes données dans la validation de mes fonctions de mesure. Ça n’existera plus.

L'enregistrement se fera sur une carte SD.

C'est moi qui lirai ces données sur mon PC via le WIFI. Ça peut être toutes les dix minutes par exemple si je veux suivre une phase particulière. Sinon, une fois pas jour.

Cordialement.

Pierre.