Structure et Gestion de l'interface client serveur

Bonjour à toutes et à tous,

J'essaie de développer ce qu'on appelle un routeur photovoltaïque. C'est un système qui redirige le surplus de production de panneaux photovoltaïques vers un consommateur potentiel : un chauffe-eau par exemple.

Ce système se compose :

  • d'une partie électronique pour la gestion du surplus : c'est fait.
  • d'une interface de communication des infos électriques au travers d'un système client serveur WEB. Le serveur est un ESP32 ; le client est un PC ou un smartphone : c'est mon problème.

A ce jour, j'ai réussi à transférer des fichiers (qu'ils soient en mémoire vive, dans la flash ou dans une carte SD) vers mon PC pour soit :

  • les visualiser,
  • les enregistrer,
  • tracer des courbes.

Le problème : je ne maitrise pas du tout le mode de transfert de ces données.

Par exemple, dans mon interface, j'ai un bouton qui me permet d'afficher le contenu d'un fichier. Le problème est que ce fichier s'affiche dans une nouvelle page. Il faut que je revienne sur la page précédente pour retrouver mon bouton. Cela correspond au code suivant :

le bouton dans la page HTML :

        <a href="view-data"><button class="button button-data">Historique Puissance</button></a>

Le code de gestion :

  server.on("/view-data", HTTP_GET, [](AsyncWebServerRequest *request){ // Handle the View Data button
    request->send(LittleFS, "/data.txt", String(), false);
  });

Ce que je voudrais, est que ce fichier s'affiche sur la même page que celle où il y a mon bouton ; dans un espace réservé à des affichages de données, de courbes.

A mon sens, c'est ce qui se trouve dans la partie server.on("/view-data", ..., qu'il faut modifier. Peut-être autre chose. Là, je ne vois pas du tout ce qu'il faut faire.

D'une manière plus globale, ce que je souhaite avoir est page WEB unique dans laquelle j'ai des boutons permettant de choisir ce que je veux visualiser et un espace - plus bas dans cette page - dans lequel vont s'afficher les résultats (données ou courbes).

A suivre pour des problèmes équivalents.

Cordialement.

Pierre.

Peut tu redonner l'intégralité de ton code?

Il faut donc que tu fusionnes tes pages, pour avoir le bouton et ton canvas sur la même page.
lorsque tu appuis sur le bouton, tu appels la fonction "updateChart" qui va rafraichir les données de ton graphe avec le contenu renvoyer par l'ESP32 sur l'URL "/view-data"

je ne sais pas si je suis bien clair ?

Dans l'esprit, oui, mais dans la pratique, non.

C'est ça que je ne sais pas faire.

Cordialement.

Pierre.

Oui, je me doute, malheureusement, je n'ai pas le temps de te faire un exemple avant ce soir.

Je t'en remercie d'avance.

Une image de ce que j'envisage de faire ... Reste plus qu'à relier les boutons aux résultats à afficher.

Cordialement.

Pierre.

Je te remercie "terwal" de la réponse que tu m'as apportée.

En fouillant sur la toile, j'avais aussi fini par trouver comment faire pour afficher des courbes à partir d'un bouton.

Maintenant, mon problème se complique car je voudrais afficher plusieurs types de courbe sur le même espace. Chacun des types étant commandé par un bouton.

Je n'ai pas le temps de développer ce sujet ce soir, j'y reviendrai demain.

Cordialement.

Pierre.

Je viens de m'apercevoir que je me suis planté de fil de discutions :frowning:

Je ne sais pas si c'est cela que tu veux, j'ai modifié le HTML, pour avoir deux boutons qui rafraichi chacun un jeu de donné dédié.
Du coup, il évidement que tu modifie ton code Arduino, pour avoir un route(server.on) pour chaque jeu de donnée
Il est aussi possible d'avoir qu'une seul route et de choisir via le bouton, un jeu de donnée à rafraichir, mais je trouve ça moins logique.

    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>ESP32 Routeur photovoltaïque</title>
      <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    </head>
    <body>
      <h1 style="text-align: center;">ESP32 Routeur photovoltaïque</h1>
      <button onclick="updateChart(0);" class="button button-data">Rafraichissement des données 1</button>
      <button onclick="updateChart(1);" class="button button-data">Rafraichissement des données 2</button>
      <canvas id="myChart" width="800" height="300"></canvas>
      
      <script>
        const ctx = document.getElementById('myChart').getContext('2d');
        const chart = new Chart(ctx, {
          type: 'line',
          data: {
            labels: [],
            datasets: [{
              label: "Forme d\'onde 1",
              data: [],
              borderColor: 'rgb(75, 192, 192)',
              tension: 0.5 // Filtrage du signal ; doit être compris entre 0 (pas de filtrage) et 1 (filtrage max)
            },{
              label: "Forme d\'onde 2",
              data: [],
              borderColor: 'rgb(192, 192, 75)',
              tension: 0.1
            }]
          }
        });

        function updateChart(set) {
          fetch('/data'+set)
            .then(response => response.json())
            .then(data => {
              const labels = data.labels;
              const values = data.values;
              
              chart.data.labels = labels;
              chart.data.datasets[set].data = values;
              chart.update();
            });
        }
      </script>
    </body>
    </html>

Merci encore "terwal" pour ce mode opératoire. Pour autant, ce n'est pas cela qui m'intéresse pour le moment.

Je veux afficher deux jeux de courbes qui n'ont rien à voir les uns avec les autres. Par exemple :

  • Premier jeu : forme du courant et forme de la tension sur 48 points.

  • Deuxième jeu : Historique de puissance, tension et courant fonction de dates en abscisse.

Ce que j'ai envisagé, et qui ne fonctionne pas est ce qui suit :

function AfficheUI() {

        const ctxUI = document.getElementById('myChart').getContext('2d');

        const chart_UI = new Chart(ctxUI, {
          ...
          toutes le définitions de titre et d'axes qui vont bien
           ...
          } );

          fetch('/dataUI')
            .then(response => response.text())
            .then(data => {
              récupération des bonnes valeurs
              });             
              .... enregistrement dans Chart_UI des bonnes valeurs
              chart_UI.update();
            });
};

function AfficheHisto() {

        const ctxHisto = document.getElementById('myChart').getContext('2d');

        const chart_Histo = new Chart(ctxHisto, {
          ...
          toutes le définitions de titre et d'axes qui vont bien
           ...
          } );

          fetch('/dataHisto')
            .then(response => response.text())
            .then(data => {
              récupération des bonnes valeurs
              });             
              .... enregistrement dans Chart_Histo des bonnes valeurs
              chart_Histo.update();
            });
};

On y voit deux procédures identiques dans la forme : function AfficheUI et function AfficheHisto, mais différentes dans leur contenu.

Deux boutons. Chacun d'eux active une fonction.

Quand j'entre l'adresse du serveur dans mon navigateur et que je clique sur l'un des deux boutons, les graphiques relatifs au bouton choisi s'affichent correctement.

Par contre, si je souhaite passer d'un graphique à l'autre en cliquant sur le bouton correspondant, ça ne bascule pas sur le bon graphique, ça reste sur celui que j'ai choisi au moment de la connexion au serveur.

Je ne sais comment gérer cela. Est-ce qu'il faut libérer un contexte pour passer à l'autre ? Que faut-il faire ?

Cordialement.

Pierre.

quelque chose comme ça ?

    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>ESP32 Routeur photovoltaïque</title>
      <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    </head>
    <body>
      <h1 style="text-align: center;">ESP32 Routeur photovoltaïque</h1>
      <button onclick="updateChart(0);" class="button button-data">Rafraichissement des données 1</button>
      <button onclick="updateChart(1);" class="button button-data">Rafraichissement des données 2</button>
      <canvas id="myChart" width="800" height="300"></canvas>
      
      <script>
        const ctx = document.getElementById('myChart').getContext('2d');
        const chart = new Chart(ctx, {
          type: 'line',
          data: {
            labels: [],
            datasets: [{
              label: "Forme d\'onde 1",
              data: [],
              borderColor: 'rgb(75, 192, 192)',
              tension: 0.5 // Filtrage du signal ; doit être compris entre 0 (pas de filtrage) et 1 (filtrage max)
            },{
              label: "Forme d\'onde 2",
              data: [],
              borderColor: 'rgb(192, 192, 75)',
              tension: 0.1
            }]
          }
        });

        function updateChart(set) {
          fetch('/data'+set)
            .then(response => response.json())
            .then(data => {
              const labels = data.labels;
              const values = data.values;
              

              chart.data.labels = labels;
              chart.data.datasets[set].data = values;
              
              chart.data.datasets[0].hidden = (set != 0);
              chart.data.datasets[1].hidden = (set != 1);
              
              chart.update();
            });
        }
      </script>
    </body>
    </html>

Merci "terwal", mais non, ce n'est pas ce que je souhaite faire.

Ce que je souhaite est défini dans le post#8.

Pour autant, il semble qu'il y ait un autre problème.

En reprenant un simple affichage d'un jeu de courbes déclenché par un bouton, je m'aperçois que si je clique plusieurs fois sur le même bouton, l'affichage n'est pas rafraichi avec les nouvelles données. Il faut que je relance la connexion au serveur puis clique sur le bouton pour que les données à jour s'affichent.

Donc, à la base, je pense que j'ai tout simplement un problème de rafraichissement : comment fait-on pour rafraichir un affichage en re-cliquant sur le bouton ?

Cordialement.

Pierre.

Ouai, mais moi de ce que je comprends cela correspond à ce que je t'ai fait :frowning:
peut être que si tu me décris ce qui ne va pas dans ce que je t'ai fait, je pourrais comprendre ?

C'est ce que fait le dernier code que je t'ai envoyer.
Pour tester, je produis des données différentes à chaque appel de la route /data0 ou /data1
et a chaque appuis sur le bouton, j'ai bien les donnés qui change

Dans ce que tu me proposes, tu ne fais que changer le fichier source des données.

Dans ce que je décris au post#8, le premier graph comporte deux courbes avec des titres "forme courant" et "forme tension". Le second graph comporte, lui, trois courbes avec des intitulés différents : "Histo puissance", "Histo tension" et "Histo courant". Donc, c'est tout le contenu des parties datasets[ ... ] et fetch ... qu'il faut modifier. C'est à dire que lorsqu'on change de bouton, on change complètement d'affichage. Cela veut dire qu'on efface le premier pour le remplacer par le second et vice et versa ; d'où le type de rafraichissement auquel je pense.

Cordialement.

Pierre.

Non pas vraiment, je cache le jeu de données qui ne t'intéresse pas.
On peut tout à fait appliqué ce procédé à ce que tu demandes.
C'est à dire qu'entre le graphe de Tension et histo Tension, la courbe manipule le même type de valeur.
Donc entre tes deux graphes la seul chose qui change est la puissance, qui peut être caché.
Le nom des courbes pouvant normalement aussi être changé à la volé.
Mais ce n'est pas très élégant et un peu brouillon.

Je te propose donc une ébauche d'un autre code, qui contient deux graphes différents et donc les boutons provoque le rafraichissement du graphe concerné et le masquage de l'autre graphe.
Je pense que cela correspond plus à ce que tu veux faire ?

    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>ESP32 Routeur photovoltaïque</title>
      <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    </head>
    <body onload="updateChart(1);">
      <h1 style="text-align: center;">ESP32 Routeur photovoltaïque</h1>
      <button onclick="updateChart(1);" class="button button-data">Rafraichissement Instantané</button>
      <button onclick="updateChart(2);" class="button button-data">Rafraichissement Histo</button>
      <canvas id="myChart1" width="800" height="300"></canvas>
      <canvas id="myChart2" width="800" height="300" style="visibility: none;"></canvas>
      
      <script>
        const ctx1 = document.getElementById('myChart1').getContext('2d');
        const chart1 = new Chart(ctx1, {
          type: 'line',
          data: {
            labels: [],
            datasets: [{
              label: "Tension",
              data: [],
              borderColor: 'rgb(75, 192, 192)',
              tension: 0.5 // Filtrage du signal ; doit être compris entre 0 (pas de filtrage) et 1 (filtrage max)
            },{
              label: "Courant",
              data: [],
              borderColor: 'rgb(192, 192, 75)',
              tension: 0.1
            }]
          }
        });

        const ctx2 = document.getElementById('myChart2').getContext('2d');
        const chart2 = new Chart(ctx2, {
          type: 'line',
          data: {
            labels: [],
            datasets: [{
              label: "Historique Puissance",
              data: [],
              borderColor: 'rgb(75, 192, 192)',
              tension: 0.5 // Filtrage du signal ; doit être compris entre 0 (pas de filtrage) et 1 (filtrage max)
            },{
              label: "Historique Tension",
              data: [],
              borderColor: 'rgb(192, 192, 75)',
              tension: 0.1
            },
            {
              label: "Tension Courant",
              data: [],
              borderColor: 'rgb(192, 192, 75)',
              tension: 0.1
            }]
          }
        });

        function updateChart(type) {
          if (type == 1) {
            fetch('/instant')
            .then(response => response.json())
            .then(data => {
              const labels = data.labels;
              const values0 = data.values0;
              const values1 = data.values1;
              
              console.log("Labels:", labels);
              console.log("Data:" + values0);
              console.log("Data:" + values1);
              
              chart1.data.labels = labels;
              chart1.data.datasets[0].data = values0;
              chart1.data.datasets[1].data = values1;
              chart1.update();
            });
            document.getElementById('myChart1').style.display = 'block';
            document.getElementById('myChart2').style.display = 'none';
          } else {
            fetch('/histo')
            .then(response => response.json())
            .then(data => {
              const labels = data.labels;
              const values0 = data.values0;
              const values1 = data.values1;
              const values2 = data.values2;

              console.log("Labels:", labels);
              console.log("Data:" + values0);
              console.log("Data:" + values1);
              console.log("Data:" + values2);
              
              chart2.data.labels = labels;
              chart2.data.datasets[0].data = values0;
              chart2.data.datasets[1].data = values1;
              chart2.data.datasets[2].data = values2;
              chart2.update();
            });
            document.getElementById('myChart1').style.display = 'none';
            document.getElementById('myChart2').style.display = 'block';
          }
        }
      </script>
    </body>
    </html>
    

Après j'ai un doute sur la grandeur des valeurs manipulés entre les tensions, courant et puissance.
Tes trois grandeurs sont bien lisible sur tes graphes ?

Un grand merci à toi "terwal" car ta dernière proposition correspond exactement à ce que souhaite faire. J'aurai quelques petites précision à demander. Je reviendrai pour cela.

Qu'est-ce qui te fait douter sur ces valeurs ?

Encore merci.

Pierre.

Dans un précédant post, j'avais demandé comment faire pour que l'affichage se mette régulièrement à jour. Tu m'avais indiqué la fonction setInterval() et cela fonctionnait très bien.

Dans la dernière configuration que tu m'as donnée, et qui fonctionne aussi très bien, je voudrais introduire cette fonction, mais pour un des deux graphiques seulement. chart1 par exemple.

J'ai fait quelques essais ... infructueux.

Cordialement.

Pierre.

Je ne sais pas si les grandeurs de tes valeurs sont compatible.
par exemple quel est l'écarte de valeur entre le maximun de la courbe qui monte le plus haut et le minimun de la courbe qui descend le plus bas.

Mais je ne sais pas les valeurs que ton systéme de donne.
Par exemple si tu as 50v par quelque A(ex 5A), tu va avoir au maximum de puissance à 250Watt avec une courbe de courant variant de 1A à 5A, ta courbe est-elle alors lisible ?
Mais c'est plus une quesiton existentielle :slight_smile:

Peu importe qu’elles soient compatibles ou pas, elles ont chacune des échelles de présentation en rapport à leur étendue propre.

Par exemple :

  • puissance : de 0 à 3000 W
  • tension : de 0 à 250 V
  • courant : de 0 à 15 A

Cordialement.

Pierre.

Je ne comprends pas justement, si ton échelle tes ordonnées va de 0 à 3000, comment tu apprécis la variation du courant de 0 à 15 A?

Mais ce sont deux courbes indépendantes, chacune avec ses échelles. Voir par exemple le graphique dans mon post #5 et celui-ci (simple simulation avec des sinus et du random) :

As-tu une réponse à me donner pour le post #15 ?

Cordialement.

Pierre.

Effectivement je n'avais pas du tout fait attention :slight_smile:

Décidément, j'ai loupé ta question.
Tu peux essayer ça, je n'ai pas testé, car je ne suis pas sur le même PC et je n'ai pas transféré, le code Python pour simuler ton ESP.

<!DOCTYPE html>
    <html>
      <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>ESP32 Routeur photovoltaïque</title>
        <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
      </head>
      <body onload="updateChart(1);">
        <h1 style="text-align: center;">ESP32 Routeur photovoltaïque</h1>
        <button onclick="updateChart(1);" class="button button-data">Rafraichissement Instantané</button>
        <button onclick="updateChart(2);" class="button button-data">Rafraichissement Histo</button>
        <canvas id="myChart1" width="800" height="300"></canvas>
        <canvas id="myChart2" width="800" height="300" style="visibility: none;"></canvas>
        
        <script>
          const ctx1 = document.getElementById('myChart1').getContext('2d');
          const chart1 = new Chart(ctx1, {
            type: 'line',
            data: {
              labels: [],
              datasets: [{
                label: "Tension",
                data: [],
                borderColor: 'rgb(75, 192, 192)',
                tension: 0.5 // Filtrage du signal ; doit être compris entre 0 (pas de filtrage) et 1 (filtrage max)
              },{
                label: "Courant",
                data: [],
                borderColor: 'rgb(192, 192, 75)',
                tension: 0.1
              }]
            }
          });

          const ctx2 = document.getElementById('myChart2').getContext('2d');
          const chart2 = new Chart(ctx2, {
            type: 'line',
            data: {
              labels: [],
              datasets: [{
                label: "Historique Puissance",
                data: [],
                borderColor: 'rgb(75, 192, 192)',
                tension: 0.5 // Filtrage du signal ; doit être compris entre 0 (pas de filtrage) et 1 (filtrage max)
              },{
                label: "Historique Tension",
                data: [],
                borderColor: 'rgb(192, 192, 75)',
                tension: 0.1
              },
              {
                label: "Tension Courant",
                data: [],
                borderColor: 'rgb(192, 192, 75)',
                tension: 0.1
              }]
            }
          });

          function updateChart(type) {
            if (type == 1) {
              setInterval(updateChart(1), 1000);
              fetch('/instant')
              .then(response => response.json())
              .then(data => {
                const labels = data.labels;
                const values0 = data.values0;
                const values1 = data.values1;
                
                console.log("Labels:", labels);
                console.log("Data:" + values0);
                console.log("Data:" + values1);
                
                chart1.data.labels = labels;
                chart1.data.datasets[0].data = values0;
                chart1.data.datasets[1].data = values1;
                chart1.update();
              });
              document.getElementById('myChart1').style.display = 'block';
              document.getElementById('myChart2').style.display = 'none';
            } else {
              clearInterval();
              fetch('/histo')
              .then(response => response.json())
              .then(data => {
                const labels = data.labels;
                const values0 = data.values0;
                const values1 = data.values1;
                const values2 = data.values2;

                console.log("Labels:", labels);
                console.log("Data:" + values0);
                console.log("Data:" + values1);
                console.log("Data:" + values2);
                
                chart2.data.labels = labels;
                chart2.data.datasets[0].data = values0;
                chart2.data.datasets[1].data = values1;
                chart2.data.datasets[2].data = values2;
                chart2.update();
              });
              document.getElementById('myChart1').style.display = 'none';
              document.getElementById('myChart2').style.display = 'block';
            }
          }
        </script>
      </body>
    </html>