Lectures du capteur de tracé ESP32 dans les graphiques (séries multiples)

Lectures du capteur de tracé ESP32 dans les graphiques (séries multiples)

Ce projet montre comment créer un serveur Web avec l’ESP32 pour tracer les lectures des capteurs dans des graphiques avec plusieurs séries. À titre d’exemple, nous allons tracer les lectures de capteur de quatre capteurs de température DS18B20 différents sur le même graphique. Vous pouvez modifier le projet pour tracer d’autres données. Pour construire les graphiques, nous utiliserons la bibliothèque JavaScript Highcharts.

Lectures du capteur de tracé ESP32 dans les graphiques Série multiple Arduino

Nous avons un tutoriel similaire pour la carte ESP8266 NodeMCU :

Aperçu du projet

Ce projet créera un serveur Web avec l’ESP32 qui affiche les relevés de température de quatre capteurs de température DS18B20 sur le même graphique – graphique avec plusieurs séries. Le graphique affiche un maximum de 40 points de données pour chaque série, et de nouvelles lectures sont ajoutées toutes les 30 secondes. Vous pouvez modifier ces valeurs dans votre code.

Graphique du serveur Web ESP32 avec plusieurs séries ESP32

Capteur de température DS18B20

Le Capteur de température DS18B20 est un capteur de température numérique à un fil. Cela signifie qu’il ne nécessite qu’une seule ligne de données pour communiquer avec votre microcontrôleur.

Module de capteur numérique à un fil pour capteur de température DS18B20

Chaque capteur possède un numéro de série 64 bits unique, ce qui signifie que vous pouvez connecter plusieurs capteurs au même GPIO, comme nous le ferons dans ce didacticiel. En savoir plus sur le capteur de température DS18B20 :

Événements envoyés par le serveur

Les lectures sont mises à jour automatiquement sur la page Web à l’aide des événements envoyés par le serveur (SSE).

Lectures de capteur Événements envoyés par le serveur de plusieurs séries DS18B20

Pour en savoir plus sur SSE, vous pouvez lire :

Fichiers enregistrés sur le système de fichiers

Pour que notre projet reste mieux organisé et plus facile à comprendre, nous enregistrerons les fichiers HTML, CSS et JavaScript pour créer la page Web sur le système de fichiers du forum (SPIFFS).

En savoir plus sur la création d’un serveur Web avec des fichiers enregistrés sur le système de fichiers :

Conditions préalables

Assurez-vous de vérifier toutes les conditions préalables dans cette section avant de poursuivre le projet.

1. Installez la carte ESP32 dans l’IDE Arduino

Nous allons programmer l’ESP32 à l’aide de l’IDE Arduino. Donc, vous devez avoir installé le module complémentaire ESP32. Suivez le tutoriel suivant si vous ne l’avez pas déjà fait :

Si vous souhaitez utiliser VS Code avec l’extension PlatformIO, suivez plutôt le tutoriel suivant pour apprendre à programmer l’ESP32 :

2. Plugin de téléchargement de système de fichiers

Pour télécharger les fichiers HTML, CSS et JavaScript dans la mémoire flash ESP32 (SPIFFS), nous utiliserons un plugin pour Arduino IDE : SPIFFS Filesystem Uploader. Suivez le tutoriel suivant pour installer le plugin filesystem uploader :

Si vous utilisez VS Code avec l’extension PlatformIO, lisez le didacticiel suivant pour savoir comment télécharger des fichiers sur le système de fichiers :

3. Installation des bibliothèques

Pour compiler ce projet, vous devez installer les bibliothèques suivantes :

Vous pouvez installer les deux premières bibliothèques à l’aide du gestionnaire de bibliothèque Arduino. Accédez à Esquisse > Inclure la bibliothèque > Gérer les bibliothèques et recherchez le nom de la bibliothèque.

Les bibliothèques ESPAsyncWebServer et AsynTCP ne peuvent pas être installées via le gestionnaire de bibliothèque Arduino, vous devez donc copier les fichiers de bibliothèque dans le dossier Bibliothèques d’installation Arduino. Alternativement, dans votre IDE Arduino, vous pouvez aller à Sketch> Inclure la bibliothèque> Ajouter une bibliothèque .zip et sélectionner les bibliothèques que vous venez de télécharger.

Installation de bibliothèques (VS Code + PlatformIO)

Si vous programmez l’ESP32 à l’aide de PlatformIO, vous devez ajouter les lignes suivantes dans le fichier platformio.ini pour inclure les bibliothèques (modifiez également la vitesse du moniteur série à 115200) :

monitor_speed = 115200
lib_deps = ESP Async WebServer
	arduino-libraries/Arduino_JSON @ 0.1.0
	milesburton/[email protected]^3.9.1
	paulstoffregen/[email protected]^2.3.5

Pièces requises

Pour suivre ce tutoriel vous avez besoin des pièces suivantes :

Si vous n’avez pas quatre capteurs DS18B20, vous pouvez en utiliser trois ou deux. Alternativement, vous pouvez également utiliser d’autres capteurs (vous devez modifier le code) ou des données provenant de toute autre source (par exemple, des lectures de capteurs reçues via MQTT, ESP-NOW ou des valeurs aléatoires – pour expérimenter ce projet…)

Vous pouvez utiliser les liens précédents ou accéder directement à MakerAdvisor.com/tools pour trouver toutes les pièces pour vos projets au meilleur prix !

1680087138 925 Lectures du capteur de trace ESP32 dans les graphiques series

Diagramme schématique

Câblez quatre capteurs DS18B20 à votre carte.

Schéma de câblage de plusieurs capteurs ESP32 DS18B20

Lecture recommandée : Référence de brochage ESP32 : Quelles broches GPIO devez-vous utiliser ?

Obtenir les adresses des capteurs DS18B20

Chaque capteur de température DS18B20 a un numéro de série attribué. Tout d’abord, vous devez trouver ce numéro pour étiqueter chaque capteur en conséquence. Vous devez le faire pour savoir plus tard à partir de quel capteur vous lisez la température.

Téléchargez le code suivant sur l’ESP32. Assurez-vous d’avoir sélectionné la bonne carte et le bon port COM.

/*
 * Rui Santos 
 * Complete Project Details https://www.raspberryme.com
 */

#include <OneWire.h>

// Based on the OneWire library example

OneWire ds(4);  //data wire connected to GPIO 4

void setup(void) {
  Serial.begin(115200);
}

void loop(void) {
  byte i;
  byte addr[8];
  
  if (!ds.search(addr)) {
    Serial.println(" No more addresses.");
    Serial.println();
    ds.reset_search();
    delay(250);
    return;
  }
  Serial.print(" ROM =");
  for (i = 0; i < 8; i++) {
    Serial.write(' ');
    Serial.print(addr[i], HEX);
  }
}

Afficher le code brut

Câblez un seul capteur à la fois pour trouver son adresse (ou ajoutez successivement un nouveau capteur) afin de pouvoir identifier chacun par son adresse. Ensuite, vous pouvez ajouter une étiquette physique à chaque capteur.

Ouvrez le moniteur série à un débit en bauds de 115200, appuyez sur le bouton RST/EN intégré et vous devriez obtenir quelque chose comme suit (mais avec des adresses différentes) :

Obtenir l'adresse onewire DS18B20 Serial Monitor

Décochez l’option « Défilement automatique » pour pouvoir copier les adresses. Dans notre cas, nous avons les adresses suivantes :

  • Capteur 1 : 28 FF A0 11 33 17 3 96
  • Capteur 2 : 28 FF B4 6 33 17 3 4B
  • Capteur 3 : 28 FF 11 28 33 18 1 6B
  • Capteur 4 : 28 FF 43 F5 32 18 2 A8

Organisation de vos fichiers

Pour garder le projet organisé et le rendre plus facile à comprendre, nous allons créer quatre fichiers pour construire le serveur Web :

  • Esquisse Arduino qui gère le serveur Web ;
  • index.html : pour définir le contenu de la page Web ;
  • sytle.css : pour styliser la page Web ;
  • script.js : pour programmer le comportement de la page Web : gérer les réponses du serveur Web, les événements, créer le graphique, etc.
Organisation de vos fichiers Arduino sketch index html css javascript

Vous devez enregistrer les fichiers HTML, CSS et JavaScript dans un dossier appelé data dans le dossier d’esquisse Arduino, comme indiqué dans le diagramme précédent. Nous allons télécharger ces fichiers sur le système de fichiers ESP32 (SPIFFS).

Vous pouvez télécharger tous les fichiers du projet :

Fichier HTML

Copiez ce qui suit dans le fichier index.html.

<!-- Complete project details: https://www.raspberryme.com/esp32-plot-readings-charts-multiple/ -->

<!DOCTYPE html>
<html>
  <head>
    <title>ESP IOT DASHBOARD</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="icon" type="image/png" href="https://www.raspberryme.com/esp32-plot-readings-charts-multiple/favicon.png">
    <link rel="stylesheet" type="text/css" href="style.css">
    <script src="https://code.highcharts.com/highcharts.js"></script>
  </head>
  <body>
    <div class="topnav">
      <h1>ESP WEB SERVER CHARTS</h1>
    </div>
    <div class="content">
      <div class="card-grid">
        <div class="card">
          <p class="card-title">Temperature Chart</p>
          <div id="chart-temperature" class="chart-container"></div>
        </div>
      </div>
    </div>
    <script src="script.js"></script>
  </body>
</html>

Afficher le code brut

Le fichier HTML pour ce projet est très simple. Il comprend le Bibliothèque JavaScript Highcharts dans l’en-tête du fichier HTML :

<script src="https://code.highcharts.com/highcharts.js"></script>

Il y a une section

avec l’id chart-temperature où nous rendrons notre graphique plus tard.

<div id="chart-temperature" class="chart-container"></div>

Fichier CSS

Copiez les styles suivants dans votre fichier style.css.

/*  Complete project details: https://www.raspberryme.com/esp32-plot-readings-charts-multiple/  */

html {
  font-family: Arial, Helvetica, sans-serif;
  display: inline-block;
  text-align: center;
}
h1 {
  font-size: 1.8rem;
  color: white;
}
p {
  font-size: 1.4rem;
}
.topnav {
  overflow: hidden;
  background-color: #0A1128;
}
body {
  margin: 0;
}
.content {
  padding: 5%;
}
.card-grid {
  max-width: 1200px;
  margin: 0 auto;
  display: grid;
  grid-gap: 2rem;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
.card {
  background-color: white;
  box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);
}
.card-title {
  font-size: 1.2rem;
  font-weight: bold;
  color: #034078
}
.chart-container {
  padding-right: 5%;
  padding-left: 5%;
}

Afficher le code brut

Fichier JavaScript (création des graphiques)

Copiez ce qui suit dans le fichier script.js. Voici une liste de ce que fait ce code :

  • initialiser le protocole de source d’événement ;
  • ajouter un écouteur d’événement pour l’événement new_readings ;
  • créer le graphique ;
  • obtenir les dernières lectures de capteur à partir de l’événement new_readings et les tracer dans le graphique ;
  • faire une requête HTTP GET pour les lectures actuelles du capteur lorsque vous accédez à la page Web pour la première fois.
// Complete project details: https://www.raspberryme.com/esp32-plot-readings-charts-multiple/

// Get current sensor readings when the page loads
window.addEventListener('load', getReadings);

// Create Temperature Chart
var chartT = new Highcharts.Chart({
  chart:{
    renderTo:'chart-temperature'
  },
  series: [
    {
      name: 'Temperature #1',
      type: 'line',
      color: '#101D42',
      marker: {
        symbol: 'circle',
        radius: 3,
        fillColor: '#101D42',
      }
    },
    {
      name: 'Temperature #2',
      type: 'line',
      color: '#00A6A6',
      marker: {
        symbol: 'square',
        radius: 3,
        fillColor: '#00A6A6',
      }
    },
    {
      name: 'Temperature #3',
      type: 'line',
      color: '#8B2635',
      marker: {
        symbol: 'triangle',
        radius: 3,
        fillColor: '#8B2635',
      }
    },
    {
      name: 'Temperature #4',
      type: 'line',
      color: '#71B48D',
      marker: {
        symbol: 'triangle-down',
        radius: 3,
        fillColor: '#71B48D',
      }
    },
  ],
  title: {
    text: undefined
  },
  xAxis: {
    type: 'datetime',
    dateTimeLabelFormats: { second: '%H:%M:%S' }
  },
  yAxis: {
    title: {
      text: 'Temperature Celsius Degrees'
    }
  },
  credits: {
    enabled: false
  }
});


//Plot temperature in the temperature chart
function plotTemperature(jsonValue) {

  var keys = Object.keys(jsonValue);
  console.log(keys);
  console.log(keys.length);

  for (var i = 0; i < keys.length; i++){
    var x = (new Date()).getTime();
    console.log(x);
    const key = keys[i];
    var y = Number(jsonValue[key]);
    console.log(y);

    if(chartT.series[i].data.length > 40) {
      chartT.series[i].addPoint([x, y], true, true, true);
    } else {
      chartT.series[i].addPoint([x, y], true, false, true);
    }

  }
}

// Function to get current readings on the webpage when it loads for the first time
function getReadings(){
  var xhr = new XMLHttpRequest();
  xhr.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      var myObj = JSON.parse(this.responseText);
      console.log(myObj);
      plotTemperature(myObj);
    }
  };
  xhr.open("GET", "/readings", true);
  xhr.send();
}

if (!!window.EventSource) {
  var source = new EventSource('/events');

  source.addEventListener('open', function(e) {
    console.log("Events Connected");
  }, false);

  source.addEventListener('error', function(e) {
    if (e.target.readyState != EventSource.OPEN) {
      console.log("Events Disconnected");
    }
  }, false);

  source.addEventListener('message', function(e) {
    console.log("message", e.data);
  }, false);

  source.addEventListener('new_readings', function(e) {
    console.log("new_readings", e.data);
    var myObj = JSON.parse(e.data);
    console.log(myObj);
    plotTemperature(myObj);
  }, false);
}

Afficher le code brut

Obtenir des lectures

Lorsque vous accédez à la page Web pour la première fois, nous demandons au serveur d’obtenir les lectures actuelles des capteurs. Sinon, nous devrons attendre l’arrivée de nouvelles lectures de capteurs (via les événements envoyés par le serveur), ce qui peut prendre un certain temps en fonction de l’intervalle que vous avez défini sur le serveur.

Ajoutez un écouteur d’événement qui appelle la fonction getReadings lors du chargement de la page Web.

// Get current sensor readings when the page loads
window.addEventListener('load', getReadings);

L’objet window représente une fenêtre ouverte dans un navigateur. La méthode addEventListener() définit une fonction à appeler lorsqu’un certain événement se produit. Dans ce cas, nous appellerons la fonction getReadings lors du chargement de la page (« load ») pour obtenir les lectures actuelles du capteur.

Examinons maintenant la fonction getReadings. Créez un nouvel objet XMLHttpRequest. Ensuite, envoyez une requête GET au serveur sur l’URL /readings à l’aide des méthodes open() et send().

function getReadings() {
  var xhr = new XMLHttpRequest();
  xhr.open("GET", "/readings", true);
  xhr.send();
}

Lorsque nous envoyons cette demande, l’ESP enverra une réponse avec les informations requises. Nous devons donc gérer ce qui se passe lorsque nous recevons la réponse. Nous utiliserons la propriété onreadystatechange qui définit une fonction à exécuter lorsque la propriété readyState change. La propriété readyState contient le statut de XMLHttpRequest. La réponse de la demande est prête lorsque readyState est 4 et le statut est 200.

  • readyState = 4 signifie que la demande est terminée et que la réponse est prête ;
  • statut = 200 signifie « OK »

Ainsi, la requête devrait ressembler à ceci :

function getStates(){
  var xhr = new XMLHttpRequest();
  xhr.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      … DO WHATEVER YOU WANT WITH THE RESPONSE …
    }
  };
  xhr.open("GET", "/states", true);
  xhr.send();
}

La réponse envoyée par l’ESP est le texte suivant au format JSON.

{
  "sensor1" : "25",
  "sensor2" : "21",
  "sensor3" : "22",
  "sensor4" : "23"
}

Nous devons convertir la chaîne JSON en un objet JSON à l’aide de la méthode parse(). Le résultat est enregistré dans la variable myObj.

var myObj = JSON.parse(this.responseText);

La variable myObj est un objet JSON qui contient toutes les lectures de température. Nous voulons tracer ces lectures sur le même graphique. Pour cela, nous avons créé une fonction appelée plotTemperature() qui trace les températures stockées dans un objet JSON sur un graphique.

plotTemperature(myObj);

Voici la fonction complète getReadings().

function getReadings(){
  var xhr = new XMLHttpRequest();
  xhr.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      var myObj = JSON.parse(this.responseText);
      console.log(myObj);
      plotTemperature(myObj);
    }
  }; 
  xhr.open("GET", "/readings", true);
  xhr.send();
}

Création du graphique

Les lignes suivantes créent les graphiques avec plusieurs séries.

// Create Temperature Chart
var chartT = new Highcharts.Chart({
  chart:{ 
    renderTo:'chart-temperature' 
  },
  series: [
    {
      name: 'Temperature #1',
      type: 'line',
      color: '#101D42',
      marker: {
        symbol: 'circle',
        radius: 3,
        fillColor: '#101D42',
      }
    },
    {
      name: 'Temperature #2',
      type: 'line',
      color: '#00A6A6',
      marker: {
        symbol: 'square',
        radius: 3,
        fillColor: '#00A6A6',
      }
    },
    {
      name: 'Temperature #3',
      type: 'line',
      color: '#8B2635',
      marker: {
        symbol: 'triangle',
        radius: 3,
        fillColor: '#8B2635',
      }
    },
    {
      name: 'Temperature #4',
      type: 'line',
      color: '#71B48D',
      marker: {
        symbol: 'triangle-down',
        radius: 3,
        fillColor: '#71B48D',
      }
    },
  ],
  title: { 
    text: undefined
  },
  xAxis: {
    type: 'datetime',
    dateTimeLabelFormats: { second: '%H:%M:%S' }
  },
  yAxis: {
    title: { 
      text: 'Temperature Celsius Degrees' 
    }
  },
  credits: { 
    enabled: false 
  }
});

Pour créer un nouveau graphique, utilisez la nouvelle méthode Highcharts.Chart() et passez en argument les propriétés du graphique.

var chartT = new Highcharts.Chart({

Dans la ligne suivante, définissez où vous voulez placer le graphique. Dans notre exemple, nous voulons le placer dans l’élément HTML avec l’id chart-temperature—voir le Section de fichier HTML.

chart:{ 
  renderTo:'chart-temperature' 
},

Ensuite, définissez les options de la série. Les lignes suivantes créent la première série :

série: [
  {
    name: 'Temperature #1',
    type: 'line',
    color: '#101D42',
    marker: {
      symbol: 'circle',
      radius: 3,
      fillColor: '#101D42',
  }

The name property defines the series name. The type property defines the type of chart—in this case, we want to build a line chart. The color refers to the color of the line—you can change it to whatever color you desire.

Next, define the marker properties. You can choose from several default symbols—square, circle, diamond, triangle, triangle-down. You can also create your own symbols. The radius refers to the size of the marker, and the fillColor refers to the color of the marker. There are other properties you can use to customize the marker—learn more.

marker: {
  symbol: 'circle',
  radius: 3,
  fillColor: '#101D42',
}

Creating the other series is similar, but we’ve chosen different names, markers and colors.

There are many other options you can use to customize your series—check the documentation about plotOptions.

You can also define the chart title—in this case, as we’ve already defined a title for the chart in a heading of the HTML file, we will not set the title here. The title is displayed by default, so we must set it to undefined.

title: { 
  text: undefined
},

Define the properties for the X axis—this is the axis where we’ll display data and time. Check more options to customize the X axis.

xAxis: {
  type: 'datetime',
  dateTimeLabelFormats: { second: '%H:%M:%S' }
},

We set the title for the y axis. See all available properties for the y axis.

yAxis: {
  title: { 
    text: 'Temperature Celsius Degrees' 
  }
}

Time Zone

If, for some reason, after building the project, the charts are not showing the right time zone, add the following lines to the JavaScript file after the second line:

Highcharts.setOptions({
  time: {
    timezoneOffset: -60 //Add your time zone offset here in minutes
  }
});

The charts will show the time in UTC. If you want it to display in your timezone, you must set the useUTC parameter (which is a time parameter) as false:

time:{
  useUTC: false
},

So, add that when creating the chart as follows:

var chart = new Highcharts.Chart({
  time:{
    useUTC: false
  },
(…)

To learn more about this property, check this link on the documentation: https://api.highcharts.com/highcharts/time.useUTC

Finally, set the credits option to false to hide the credits of the Highcharts library.

credits: { 
  enabled: false 
}

Plot Temperatures

We’ve created the plotTemperature() function that accepts as an argument a JSON object with the temperature readings we want to plot.

//Plot temperature in the temperature chart
function plotTemperature(jsonValue) {

  var keys = Object.keys(jsonValue);
  console.log(keys);
  console.log(keys.length);

  for (var i = 0; i < keys.length; i++){
    var x = (new Date()).getTime();
    console.log(x);
    const key = keys[i];  var y = Number(jsonValue[key]);  console.log(y);  si(graphiqueT.série[i].data.length > 40) { chartT.series[i].addPoint([x, y], vrai, vrai, vrai);  } else { chartT.series[i].addPoint([x, y], vrai, faux, vrai);  } } }

Tout d’abord, nous récupérons les clés de notre objet JSON et les enregistrons dans la variable keys. Cela nous permet de parcourir toutes les clés de l’objet.

var keys = Object.keys(jsonValue);

La variable keys sera un tableau avec toutes les clés de l’objet JSON. Dans notre cas:

["sensor1", "sensor2", "sensor3", "sensor4"]

Cela fonctionne si vous avez un objet JSON avec un nombre différent de clés ou avec des clés différentes. Ensuite, nous passerons en revue toutes les clés (keys.length()) pour tracer chacune de ses valeurs dans le graphique.

La valeur x du graphique est l’horodatage.

var x = (new Date()).getTime()

La variable clé contient la clé actuelle dans la boucle. La première fois que nous parcourons la boucle, la variable clé est « capteur1 ».

const key = keys[i];

Ensuite, nous obtenons la valeur de la clé (jsonValue[key]) et enregistrez-le sous forme de nombre dans la variable y.

Notre graphique comporte plusieurs séries (l’indice commence à 0). On peut accéder à la première série dans le
diagramme de température utilisant: chartT.series[0]qui correspond à chartT.series[i] la première fois que nous parcourons la boucle.

Tout d’abord, nous vérifions la longueur des données de la série :

  • Si la série compte plus de 40 points : ajouter et décaler un nouveau point ;
  • Ou si la série compte moins de 40 points : ajouter un nouveau point.

Pour ajouter un nouveau point, utilisez la méthode addPoint() qui accepte les arguments suivants :

  • La valeur à tracer. S’il s’agit d’un nombre unique, un point avec cette valeur y est
    annexé à la série. S’il s’agit d’un tableau, il sera interprété comme des valeurs x et y. Dans notre cas, nous passons un tableau avec les valeurs x et y ;
  • Option de redessiner (booléen) : définir sur vrai pour redessiner le graphique après l’ajout du point.
  • Option de décalage (booléen) : Si vrai, un point est décalé du début de la série tandis qu’un autre est ajouté à la fin. Lorsque la longueur du graphique est supérieure à 40, nous définissons l’option de décalage sur true.
  • withEvent option (boolean) : utilisée en interne pour déclencher l’événement addPoint de la série. En savoir plus ici.

Ainsi, pour ajouter un point au graphique, nous utilisons les lignes suivantes :

if(chartT.series[i].data.length > 40) {
  chartT.series[i].addPoint([x, y], true, true, true);
} else {
  chartT.series[i].addPoint([x, y], true, false, true);
}

Gérer les événements

Tracez les lectures sur les graphiques lorsque le client reçoit les lectures sur l’événement new_readings.

Créez un nouvel objet EventSource et spécifiez l’URL de la page qui envoie les mises à jour. Dans notre cas, il s’agit de /events.

if (!!window.EventSource) {
  var source = new EventSource('/events');

Une fois que vous avez instancié une source d’événement, vous pouvez commencer à écouter les messages du serveur avec addEventListener().

Ce sont les écouteurs d’événements par défaut, comme indiqué ici dans AsyncWebServer Documentation.

source.addEventListener('open', function(e) {
  console.log("Events Connected");
}, false);

source.addEventListener('error', function(e) {
  if (e.target.readyState != EventSource.OPEN) {
    console.log("Events Disconnected");
  }
}, false);

source.addEventListener('message', function(e) {
  console.log("message", e.data);
}, false);

Ensuite, ajoutez l’écouteur d’événement pour new_readings.

source.addEventListener('new_readings', function(e) {

Lorsque de nouvelles lectures sont disponibles, l’ESP32 envoie un événement (new_readings) au client. Les lignes suivantes gèrent ce qui se passe lorsque le navigateur reçoit cet événement.

source.addEventListener('new_readings', function(e) {
  console.log("new_readings", e.data);
  var myObj = JSON.parse(e.data);
  console.log(myObj);
  plotTemperature(myObj);
}, false);

Fondamentalement, imprimez les nouvelles lectures sur la console du navigateur, convertissez les données en un objet JSON et tracez les lectures sur le graphique en appelant la fonction plotTemperature().

Esquisse Arduino

Copiez le code suivant dans votre IDE Arduino ou dans le fichier main.cpp si vous utilisez PlatformIO.

/*********
  Rui Santos
  Complete instructions at https://Raspberryme.com/esp32-plot-readings-charts-multiple/

  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*********/

#include <Arduino.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include "SPIFFS.h"
#include <Arduino_JSON.h>
#include <OneWire.h>
#include <DallasTemperature.h>

// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

// Create AsyncWebServer object on port 80
AsyncWebServer server(80);

// Create an Event Source on /events
AsyncEventSource events("/events");

// Json Variable to Hold Sensor Readings
JSONVar readings;

// Timer variables
unsigned long lastTime = 0;
unsigned long timerDelay = 30000;

// GPIO where the DS18B20 sensors are connected to
const int oneWireBus = 4;

// Setup a oneWire instance to communicate with OneWire devices (DS18B20)
OneWire oneWire(oneWireBus);

// Pass our oneWire reference to Dallas Temperature sensor
DallasTemperature sensors(&oneWire);

// Address of each sensor
DeviceAddress sensor3 = { 0x28, 0xFF, 0xA0, 0x11, 0x33, 0x17, 0x3, 0x96 };
DeviceAddress sensor1 = { 0x28, 0xFF, 0xB4, 0x6, 0x33, 0x17, 0x3, 0x4B };
DeviceAddress sensor2 = { 0x28, 0xFF, 0x43, 0xF5, 0x32, 0x18, 0x2, 0xA8 };
DeviceAddress sensor4 = { 0x28, 0xFF, 0x11, 0x28, 0x33, 0x18, 0x1, 0x6B };

// Get Sensor Readings and return JSON object
String getSensorReadings(){
  sensors.requestTemperatures();
  readings["sensor1"] = String(sensors.getTempC(sensor1));
  readings["sensor2"] = String(sensors.getTempC(sensor2));
  readings["sensor3"] = String(sensors.getTempC(sensor3));
  readings["sensor4"] = String(sensors.getTempC(sensor4));

  String jsonString = JSON.stringify(readings);
  return jsonString;
}

// Initialize SPIFFS
void initSPIFFS() {
  if (!SPIFFS.begin()) {
    Serial.println("An error has occurred while mounting SPIFFS");
  }
  else{
    Serial.println("SPIFFS mounted successfully");
  }
}

// Initialize WiFi
void initWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi ..");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(1000);
  }
  Serial.println(WiFi.localIP());
}

void setup() {
  // Serial port for debugging purposes
  Serial.begin(115200);
  initWiFi();
  initSPIFFS();

  // Web Server Root URL
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(SPIFFS, "/index.html", "text/html");
  });

  server.serveStatic("/", SPIFFS, "/");

  // Request for the latest sensor readings
  server.on("/readings", HTTP_GET, [](AsyncWebServerRequest *request){
    String json = getSensorReadings();
    request->send(200, "application/json", json);
    json = String();
  });

  events.onConnect([](AsyncEventSourceClient *client){
    if(client->lastId()){
      Serial.printf("Client reconnected! Last message ID that it got is: %u\n", client->lastId());
    }
    // send event with message "hello!", id current millis
    // and set reconnect delay to 1 second
    client->send("hello!", NULL, millis(), 10000);
  });
  server.addHandler(&events);

  // Start server
  server.begin();
}

void loop() {
  if ((millis() - lastTime) > timerDelay) {
    // Send Events to the client with the Sensor Readings Every 10 seconds
    events.send("ping",NULL,millis());
    events.send(getSensorReadings().c_str(),"new_readings" ,millis());
    lastTime = millis();
  }
}

Afficher le code brut

Comment fonctionne le code

Examinons le code et voyons comment il fonctionne pour envoyer des lectures au client à l’aide d’événements envoyés par le serveur.

Y compris les bibliothèques

Les bibliothèques OneWire et DallasTemperature sont nécessaires pour s’interfacer avec les capteurs de température DS18B20.

#include <OneWire.h>
#include <DallasTemperature.h>

Les librairies WiFi, ESPAsyncWebServer et AsyncTCP sont utilisées pour créer le serveur web.

#include <Arduino.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>

Les fichiers HTML, CSS et JavaScript pour créer la page Web sont enregistrés sur le système de fichiers ESP32 (SPIFFS). Nous devons donc également inclure la bibliothèque SPIFFS.

#include "SPIFFS.h"

Vous devez également inclure la bibliothèque Arduino_JSON pour faciliter la gestion des chaînes JSON.

#include <Arduino_JSON.h>

Informations d’identification réseau

Insérez vos informations d’identification réseau dans les variables suivantes, afin que l’ESP32 puisse se connecter à votre réseau local en utilisant le Wi-Fi.

const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

AsyncWebServer et AsyncEventSource

Créez un objet AsyncWebServer sur le port 80.

AsyncWebServer server(80);

La ligne suivante crée une nouvelle source d’événement sur /events.

AsyncEventSource events("/events");

Déclaration de variables

La variable lectures est une variable JSON pour conserver les lectures du capteur au format JSON.

JSONVar readings;

Les variables lastTime et timerDelay seront utilisées pour mettre à jour les lectures du capteur toutes les X secondes. Par exemple, nous obtiendrons de nouvelles lectures de capteur toutes les 30 secondes (30 000 millisecondes). Vous pouvez modifier ce délai dans la variable timerDelay.

// Timer variables
unsigned long lastTime = 0;
unsigned long timerDelay = 30000;

Capteurs DS18B20

Les capteurs de température DS18B20 sont connectés au GPIO 4.

// GPIO where the DS18B20 sensors are connected to
const int oneWireBus = 4;

Configurez une instance oneWire pour communiquer avec les appareils OneWire (DS18B20) :

OneWire oneWire(oneWireBus);

Passez notre référence oneWire au capteur de température Dallas

DallasTemperature sensors(&oneWire);

Insérez les adresses de vos capteurs DS18B20 dans les lignes suivantes (consultez cette rubrique si vous n’avez pas les adresses de vos capteurs) :

// Address of each sensor
DeviceAddress sensor3 = { 0x28, 0xFF, 0xA0, 0x11, 0x33, 0x17, 0x3, 0x96 };
DeviceAddress sensor1 = { 0x28, 0xFF, 0xB4, 0x6, 0x33, 0x17, 0x3, 0x4B };
DeviceAddress sensor2 = { 0x28, 0xFF, 0x43, 0xF5, 0x32, 0x18, 0x2, 0xA8 };
DeviceAddress sensor4 = { 0x28, 0xFF, 0x11, 0x28, 0x33, 0x18, 0x1, 0x6B };

Obtenez des lectures DS18B20

Pour obtenir des lectures des capteurs de température DS18B20, vous devez d’abord appeler la méthode requesTemperatures() sur l’objet capteurs. Ensuite, utilisez la fonction getTempC() et passez en argument l’adresse du capteur dont vous souhaitez obtenir la température – cela obtient la température en degrés Celsius.

Remarque : si vous souhaitez obtenir la température en degrés Fahrenheit, utilisez plutôt la fonction getTemF().

Enfin, enregistrez les lectures dans une chaîne JSON (variable jsonString) et renvoyez cette variable.

// Get Sensor Readings and return JSON object
String getSensorReadings(){
  sensors.requestTemperatures();
  readings["sensor1"] = String(sensors.getTempC(sensor1));
  readings["sensor2"] = String(sensors.getTempC(sensor2));
  readings["sensor3"] = String(sensors.getTempC(sensor3));
  readings["sensor4"] = String(sensors.getTempC(sensor4));

  String jsonString = JSON.stringify(readings);
  return jsonString;
}

Initialiser les SPIFF

La fonction initSPIFFS() initialise le système de fichiers SPIFFS :

// Initialize SPIFFS
void initSPIFFS() {
  if (!SPIFFS.begin()) {
    Serial.println("An error has occurred while mounting SPIFFS");
  }
  else{
    Serial.println("SPIFFS mounted successfully");
  }
}

Initialiser le Wi-Fi

La fonction initWiFi() initialise le Wi-Fi et imprime l’adresse IP sur le moniteur série.

// Initialize WiFi
void initWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi ..");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(1000);
  }
  Serial.println(WiFi.localIP());
}

installation()

Dans le setup (), initialisez le moniteur série, le Wi-Fi et le système de fichiers.

Serial.begin(115200);
initWiFi();
initSPIFFS();

Traiter les demandes

Lorsque vous accédez à l’adresse IP ESP32 sur la root/l’URL, envoyez le texte stocké dans le fichier index.html pour créer la page Web.

server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
  request->send(SPIFFS, "/index.html", "text/html");
});

Servir les autres fichiers statiques demandés par le client (style.css et script.js).

server.serveStatic("/", SPIFFS, "/");

Envoyez la chaîne JSON avec les relevés actuels du capteur lorsque vous recevez une demande sur l’URL /readings.

// Request for the latest sensor readings
server.on("/readings", HTTP_GET, [](AsyncWebServerRequest *request){
  String json = getSensorReadings();
  request->send(200, "application/json", json);
  json = String();
});

La variable json contient le retour de la fonction getSensorReadings(). Pour envoyer une chaîne JSON en réponse, la méthode send() accepte comme premier argument le code de réponse (200), le second est le type de contenu (« application/json ») et enfin le contenu (variable json).

Source d’événement du serveur

Configurez la source d’événement sur le serveur.

events.onConnect([](AsyncEventSourceClient *client){
  if(client->lastId()){
    Serial.printf("Client reconnected! Last message ID that it got is: %u\n", client->lastId());
  }
  // send event with message "hello!", id current millis
  // and set reconnect delay to 1 second
  client->send("hello!", NULL, millis(), 10000);
});
server.addHandler(&events);

Enfin, démarrez le serveur.

server.begin();

boucle()

Dans la boucle (), envoyez des événements au navigateur avec les dernières lectures de capteur pour mettre à jour la page Web toutes les 30 secondes.

if ((millis() - lastTime) > timerDelay) {
  // Send Events to the client with the Sensor Readings Every 10 seconds
  events.send("ping",NULL,millis());
  events.send(getSensorReadings().c_str(),"new_readings" ,millis());
  lastTime = millis();
}

Utilisez la méthode send() sur l’objet events et transmettez en argument le contenu que vous souhaitez envoyer et le nom de l’événement. Dans ce cas, nous souhaitons envoyer la chaîne JSON renvoyée par la fonction getSensorReadings(). Le nom des événements est new_readings.

Téléchargement de code et de fichiers

Après avoir inséré vos informations d’identification réseau, enregistrez le code. Accédez à Sketch > Show Sketch Folder et créez un dossier appelé data.

Arduino IDE Open Sketch Folder pour créer un dossier de données

Dans ce dossier, vous devez enregistrer les fichiers HTML, CSS et JavaScript.

Ensuite, téléchargez le code sur votre carte ESP32. Assurez-vous d’avoir sélectionné la bonne carte et le bon port COM. Assurez-vous également d’avoir ajouté vos informations d’identification réseau et les adresses des capteurs au code.

Télécharger le code Arduino

Après avoir téléchargé le code, vous devez télécharger les fichiers. Accédez à Outils> ESP32 Data Sketch Upload et attendez que les fichiers soient téléchargés.

Téléchargement de données d'esquisse ESP32 SPIFFS Arduino IDE

Lorsque tout est téléchargé avec succès, ouvrez le moniteur série à un débit en bauds de 115200. Appuyez sur le bouton ESP32 EN/RST, et il devrait imprimer l’adresse IP ESP32.

Manifestation

Ouvrez votre navigateur et tapez l’adresse IP ESP32. Vous devriez avoir accès à la page Web qui affiche les lectures du capteur. Attendez un peu jusqu’à ce qu’il rassemble des points de données.

Température de démonstration des graphiques du serveur Web ESP

Vous pouvez sélectionner un point pour voir sa valeur et son horodatage.

ESP Web Server Charts démonstration température plusieurs séries

Conclusion

Dans ce didacticiel, vous avez appris à créer des graphiques avec plusieurs séries pour afficher la température de plusieurs capteurs DS18B20. Vous pouvez modifier ce projet pour créer autant de graphiques et de séries que vous le souhaitez et tracer les données de tout autre capteur ou source.

Vous aimerez peut-être aussi lire : ESP32/ESP8266 Plot Sensor Readings in Real Time Charts – Web Server

En savoir plus sur l’ESP32 avec nos ressources :

Merci pour la lecture.

Cette vidéo vous emmène dans l’histoire de Raspberry Pi :

YouTube video

  • Ulegqin ESP32 Kit de démarrage de Base de la Carte de développement, kit de démarrage ESP32 avec OLED, capteurs, modules d'affichage sur Carte de Montage Compatible avec Arduino IDE
  • Lot de 4 Carte Développement ESP32-C3, Module ESP32-C3 Mini, WiFi 2,4GHz et Bluetooth 5.0 Le, Processeur RISC-V 32 Bits 160MHz, pour Arduino MicroPython, IoT Maison Intelligente Réseau de Capteurs