Voilà tout le code. Il y a la partie HTML
et la partie routage
.
HTML :
String pageHTML = R"rawliteral(
<!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="init();">
<h1 style="text-align: center;">ESP32 Routeur photovoltaïque</h1>
<div style="text-align: center;">
<button id="maj-DT">MaJ Date & Heure</button>
<button onclick="updateChart(1);" class="button button-data">Forme Courant & Tension</button>
<button onclick="updateChart(2);" class="button button-data">Historique Puissance</button>
<a href="download-data"><button class="button button-data">Télécharger les données</button></a>
</div>
<div id = "txt1">
<p>Date et Heure : <span id="DetH">0.00</span></p>
<p>Puissance active (W) : <span id="PA">0.00</span></p>
</div>
<div id = "txt2">
<p>Puissance max : <input type="number" id="pMaxMod" value="1000" min="0"> <button onclick="ajusterPmax()">Ajuster</button></p>
</div>
<canvas id="myChart1" width="800" height="300" style="display: none"></canvas>
<canvas id="myChart2" width="800" height="300" style="display: none"></canvas>
<script>
let txt1 = document.getElementById("txt1");
let txt2 = document.getElementById("txt2");
const interval = 2000;
let intervalId = -1;
let pAjustee = 1000; // Limite par défaut du nombre de points affichés
function init() {
txt1.style.display = "none";
txt2.style.display = "none";
}
function ajusterPmax() {
const newPmax = document.getElementById('pMaxMod').value;
const parsedPmax = parseInt(newPmax, 10); // On force la base 10 pour la conversion
if (!isNaN(parsedPmax) && parsedPmax > 0) {
pAjustee = parsedPmax;
chart2.options.scales.y0.max = pAjustee;
chart2.update();
fetch('/modifVal?val='+pAjustee);
}
}
document.getElementById('maj-DT').addEventListener('click', function() {
fetch('/maj-DT')
.then(response => response.text())
.then(data => {
document.getElementById('DetH').textContent = data;
});
});
const ctx1 = document.getElementById('myChart1').getContext('2d');
const chart1 = new Chart(ctx1, {
type: 'line',
data: {
labels: [],
datasets: [{
label: "Tension",
yAxisID: 'y0',
data: [],
borderColor: 'rgb(75, 192, 192)',
tension: 0.3 // Filtrage du signal ; doit être compris entre 0 (pas de filtrage) et 1 (filtrage max)
},
{
label: "Courant",
yAxisID: 'y1',
data: [],
borderColor: 'rgb(192, 192, 75)',
tension: 0.3
}]
},
options: {
scales: {
x: {
display: true,
title : {
display: true,
text: 'Echantillons',
}
},
y0: {
display: true,
position: 'left',
title : {
display: true,
text: 'Tension (V)',
}
},
y1: {
display: true,
position: 'left',
title : {
display: true,
text: 'Courant (A)',
}
}
}
}
});
const ctx2 = document.getElementById('myChart2').getContext('2d');
const chart2 = new Chart(ctx2, {
type: 'line',
data: {
labels: [],
datasets: [{
pointRadius: 0,
label: "Historique Puissance",
yAxisID: 'y0',
data: [],
borderColor: 'blue',
tension: 0.3 // Filtrage du signal ; doit être compris entre 0 (pas de filtrage) et 1 (filtrage max)
},
{
pointRadius: 0,
label: "Historique Tension",
yAxisID: 'y1',
data: [],
borderColor: 'green',
tension: 0.3
},
{
pointRadius: 0,
label: "Historique Courant",
yAxisID: 'y2',
data: [],
borderColor: 'red',
tension: 0.3
}]
},
options: {
scales: {
x: {
display: true,
title : {
display: true,
text: 'Date et heure',
}
},
y0: {
min : 0,
max : pAjustee,
display: true,
position: 'right',
title : {
display: true,
text: 'Puissance (W)',
}
},
y1: {
min : 0,
max : 300,
display: true,
position: 'left',
title : {
display: true,
text: 'Tension (V)',
}
},
y2: {
min : 0,
max : 20,
display: true,
position: 'left',
title : {
display: true,
text: 'Courant (A)',
}
}
}
}
});
function updateChart(type) {
if (type == 1) {
fetch('/maj-DT')
.then(response => response.text())
.then(data => {
document.getElementById('DetH').textContent = data;
});
fetch('/pActive')
.then(response => response.text())
.then(data => {
document.getElementById('PA').textContent = data;
});
if (intervalId == -1) {
intervalId = setInterval(updateChart, interval, 1);
}
fetch('/formeUI')
.then(response => response.text())
.then(data => {
const rows = data.split('\n');
const labels = [];
const values0 = [];
const values1 = [];
let indx = 0;
rows.forEach(row => {
const [value0, value1] = row.split(',');
labels.push(indx++);
values0.push(parseFloat(value0));
values1.push(parseFloat(value1));
});
chart1.data.labels = labels;
chart1.data.datasets[0].data = values0;
chart1.data.datasets[1].data = values1;
chart1.update();
});
txt1.style.display = 'block';
txt2.style.display = 'none';
document.getElementById('myChart1').style.display = 'block';
document.getElementById('myChart2').style.display = 'none';
} else {
if (intervalId != -1) {
clearInterval(intervalId);
}
intervalId = -1;
fetch('/histoUIP')
.then(response => response.text())
.then(data => {
const rows = data.split('\n');
const labels = [];
const values0 = [];
const values1 = [];
const values2 = [];
rows.forEach(row => {
const [label, value0, value1, value2] = row.split(',');
labels.push(label);
values0.push(parseFloat(value0));
values1.push(parseFloat(value1));
values2.push(parseFloat(value2));
});
chart2.data.labels = labels;
chart2.data.datasets[0].data = values0;
chart2.data.datasets[1].data = values1;
chart2.data.datasets[2].data = values2;
chart2.update();
});
txt1.style.display = 'none';
txt2.style.display = 'block';
document.getElementById('myChart1').style.display = 'none';
document.getElementById('myChart2').style.display = 'block';
}
}
</script>
</body>
</html>
)rawliteral";
le routage :
#ifndef ROUTES_H
#define ROUTES_H
#include <ESPAsyncWebServer.h>
String infUI; // Chaîne de caractère représentant la forme de la tension et du courant
float pAonde; // Valeur de la puissance active sur une période de 50 Hz
void setupRoutes(AsyncWebServer &server) {
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ // Affichage de la page HTML
request->send(200, "text/html", pageHTML);
});
server.on("/formeUI", HTTP_GET, [](AsyncWebServerRequest *request){ // Envoi du fichier de forme de la tension et du courant
request->send(200, "text/plain", infUI);
});
server.on("/pActive", HTTP_GET, [](AsyncWebServerRequest *request){ // Envoi de la puissance active
request->send(200, "text/plain", String(pAonde));
});
server.on("/histoUIP", HTTP_GET, [](AsyncWebServerRequest *request){ // Envoi du fichier d'historique pour affichage
request->send(LittleFS, "/data.txt", String(), false);
});
server.on("/modifVal", HTTP_GET, [](AsyncWebServerRequest *request){
Serial.println("Requête vue");
String inputValue;
if (request->hasParam("val")) {
inputValue = request->getParam("val")->value();
Serial.print("Valeur reçue : ");
Serial.println(inputValue);
}
request->send(200, "text/plain", "OK"); // Cette ligne n'existe pas lorsqu'il y a répétition
});
server.on("/download-data", HTTP_GET, [](AsyncWebServerRequest *request){ // Envoi du fichier d'hisorique pour téléchargement
request->send(LittleFS, "/data.txt", String(), true);
});
}
#endif
Cordialement.
Pierre.