458 lines
17 KiB
C
458 lines
17 KiB
C
|
|
// Linear Regression Equation: y = 80.9356x + -2086.7172
|
|
// R^2 for Linear Regression: 0.8820
|
|
// Polynomial Regression (Degree 2) Equation: y = 65.2734x^2 + -3353.2872x + 43075.5362
|
|
// R^2 for Polynomial Regression (Degree 2): 0.9724
|
|
// Polynomial Regression (Degree 3) Equation: y = -71.35479595x^3 + 5699.68320483x^2 + -151636.19028283x + 1343695.66923927
|
|
// R^2 for Polynomial Regression (Degree 3): 0.9821
|
|
|
|
|
|
String to_include = R"=(
|
|
<SCRIPT>
|
|
|
|
var xmlHttp01=createXmlHttpObject();
|
|
var chart;
|
|
|
|
// Fonction pour envoyer la valeur du slider au serveur
|
|
function sendSliderValue(sliderId, value) {
|
|
fetch('/update', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({ slider: sliderId, value: value })
|
|
})
|
|
//.then(response => response.json())
|
|
.then(data => {showNotification('Consigne mise à jour'); console.log('Succès:', data)})
|
|
.catch(error => console.error('Erreur:', error));
|
|
}
|
|
|
|
function createXmlHttpObject(){
|
|
if(window.XMLHttpRequest){
|
|
xmlHttp=new XMLHttpRequest();
|
|
}else{
|
|
xmlHttp=new ActiveXObject('Microsoft.XMLHTTP');
|
|
}
|
|
return xmlHttp;
|
|
}
|
|
function getCurrentTimeString() {
|
|
var now = new Date();
|
|
var hours = now.getHours().toString().padStart(2, '0');
|
|
var minutes = now.getMinutes().toString().padStart(2, '0');
|
|
var seconds = now.getSeconds().toString().padStart(2, '0');
|
|
|
|
var currentTime = hours + ':' + minutes + ':' + seconds;
|
|
return currentTime;
|
|
}
|
|
|
|
|
|
function process(){
|
|
if(xmlHttp01.readyState==0 || xmlHttp01.readyState==4){
|
|
xmlHttp01.open('GET','getVictron',true);
|
|
xmlHttp01.onreadystatechange=handleServerResponse;
|
|
xmlHttp01.send(null);
|
|
}
|
|
setTimeout('process()', 5000);
|
|
}
|
|
function handleServerResponse(){
|
|
var field = document.getElementById('response_items');
|
|
if(field && xmlHttp01.readyState == 4 && xmlHttp01.status == 200){
|
|
const json_obj = JSON.parse(xmlHttp01.response);
|
|
console.log(xmlHttp01.response);
|
|
|
|
// Vérifiez si la table existe déjà, sinon créez-en une
|
|
var table = document.getElementById('response_table');
|
|
if (!table) {
|
|
table = document.createElement('table');
|
|
table.id = 'response_table';
|
|
// Insérez une seule ligne pour les données
|
|
var dataRow = table.insertRow();
|
|
dataRow.id = 'data_row';
|
|
document.getElementById('response_items').appendChild(table);
|
|
// Ajoutez les id
|
|
dataRow.insertCell().innerHTML = "Date";
|
|
for (var i = 3; i < json_obj.length - 1; i++){
|
|
var obj = json_obj[i];
|
|
dataRow.insertCell().innerHTML = obj.key_label ? obj.key_label : obj.id;
|
|
}
|
|
}
|
|
var dataRow = table.insertRow(1);
|
|
dataRow.id = 'data_row';
|
|
document.getElementById('response_items').appendChild(table);
|
|
|
|
// Initialiser le graphique
|
|
var field_chart = document.getElementById('chartCanvas');
|
|
// Ajoutez les nouvelles données dans la même ligne
|
|
dataRow.insertCell().innerHTML = getCurrentTimeString();
|
|
var time_field = document.getElementById('hour');
|
|
time_field.textContent= getCurrentTimeString();
|
|
|
|
var tensions = "";
|
|
for (var i = 3; i < json_obj.length - 1; i++){
|
|
var obj = json_obj[i];
|
|
|
|
if (obj.id == "tensions") {
|
|
if (field_chart && chart) {
|
|
var tensions = obj.value.split(',');
|
|
var numerictensions = tensions.map(Number);
|
|
var labels = obj.labels.split(',');
|
|
|
|
chart.data.labels = labels;
|
|
chart.data.datasets[0].data = numerictensions;
|
|
|
|
// var ctx = chart.ctx;
|
|
// var yAxis = chart.scales.y;
|
|
// var yValues = [25.7, 26.12, 26.42, 26.44, 26.46, 26.56, 26.66, 26.7, 26.74, 26.92 ];
|
|
// var yPercentages = ["10%", "20%", "30%", "40%", "50%", "60%", "70%", "80%", "90%", "100%"];
|
|
//
|
|
// ctx.save();
|
|
// ctx.strokeStyle = 'rgba(255, 255, 255, 0.5)';
|
|
// ctx.lineWidth = 1;
|
|
// yValues.forEach(function(value, index) {
|
|
// var y = yAxis.getPixelForValue(value);
|
|
// ctx.beginPath();
|
|
// ctx.moveTo(chart.chartArea.left, y);
|
|
// ctx.lineTo(chart.chartArea.right, y);
|
|
// ctx.stroke();
|
|
// ctx.fillStyle = 'white';
|
|
// ctx.fillText(yPercentages[index], chart.chartArea.right + 5, y + 3);
|
|
// });
|
|
// ctx.restore();
|
|
chart.update();
|
|
}
|
|
}
|
|
else {
|
|
//dataRow.insertCell().innerHTML = obj.id;
|
|
dataRow.insertCell().innerHTML = obj.label ? obj.label : obj.value;
|
|
|
|
var field = document.getElementById(obj.id);
|
|
if (field) {
|
|
field.textContent = obj.value ;
|
|
}
|
|
field = document.getElementById("IND_" + obj.id);
|
|
if (field) {
|
|
field.textContent = obj.value ;
|
|
}
|
|
}
|
|
}
|
|
// Conservez uniquement les 10 dernières entrées
|
|
while (table.rows.length > 31) { // 1 pour l'en-tête + 10 pour les données
|
|
table.deleteRow(-1); // Supprime la dernière ligne
|
|
}
|
|
|
|
if (field_chart && !chart) {
|
|
var ctx = field_chart.getContext('2d');
|
|
chart = new Chart(ctx, {
|
|
type: 'line',
|
|
data: {
|
|
labels: ['25 mai', '24 mai', '23 mai', '22 mai', '21 mai', '20 mai', '19 mai', '18 mai', '17 mai', '16 mai'],
|
|
datasets: [{
|
|
label: 'Tensions (mV)',
|
|
data: [20, 10, 5, 0, 0, 0, 0, 0, 0, 0],
|
|
backgroundColor: 'rgba(255, 255, 255, 0.6)',
|
|
borderColor: 'rgba(255, 255, 255, 1)',
|
|
borderWidth: 1
|
|
}]
|
|
},
|
|
options: {
|
|
plugins: {
|
|
legend: {
|
|
labels: {
|
|
color: 'white',
|
|
font: {
|
|
size: 30
|
|
}
|
|
}
|
|
},
|
|
beforeDraw: function(chart) {
|
|
var ctx = chart.ctx;
|
|
var yAxis = chart.scales.y;
|
|
var yValues = [25.7, 25.87, 26.04, 26.21, 26.38, 26.55, 26.72, 26.89];
|
|
var yPercentages = ["10%", "20%", "30%", "40%", "50%", "60%", "70%", "80%", "90%", "100%"];
|
|
|
|
ctx.save();
|
|
ctx.strokeStyle = 'rgba(255, 255, 255, 0.5)';
|
|
ctx.lineWidth = 1;
|
|
yValues.forEach(function(value, index) {
|
|
var y = yAxis.getPixelForValue(value);
|
|
ctx.beginPath();
|
|
ctx.moveTo(chart.chartArea.left, y);
|
|
ctx.lineTo(chart.chartArea.right, y);
|
|
ctx.stroke();
|
|
ctx.fillStyle = 'white';
|
|
ctx.fillText(yPercentages[index], chart.chartArea.right + 5, y + 3);
|
|
});
|
|
ctx.restore();
|
|
}
|
|
},
|
|
scales: {
|
|
y: {
|
|
ticks: {
|
|
color: 'white',
|
|
beginAtZero: false
|
|
},
|
|
afterBuildTicks: function(scale) {
|
|
return [25.7, 25.87, 26.04, 26.21, 26.38, 26.55, 26.72, 26.89];
|
|
}
|
|
},
|
|
x: {
|
|
ticks: {
|
|
color: 'white'
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
|
|
// function updateChart(newLabels, newData) {
|
|
// if (chart) {
|
|
// chart.data.labels = newLabels;
|
|
// chart.data.datasets[0].data = newData;
|
|
// chart.update();
|
|
// }
|
|
// }
|
|
//
|
|
// // Example of updating the chart with new values
|
|
// setTimeout(function() {
|
|
// var newLabels = ['26 mai', '25 mai', '24 mai', '23 mai', '22 mai', '21 mai', '20 mai', '19 mai', '18 mai', '17 mai'];
|
|
// var newData = [15, 20, 10, 5, 0, 0, 0, 0, 0, 0];
|
|
// updateChart(newLabels, newData);
|
|
// }, 5000);
|
|
//
|
|
|
|
});
|
|
|
|
|
|
// document.getElementById('slider2').addEventListener('change', function() {
|
|
// sendSliderValue('slider2', this.value);
|
|
// });
|
|
|
|
</SCRIPT>
|
|
)=";
|
|
|
|
|
|
String webpage = R"=(
|
|
<div class="container">
|
|
<header>
|
|
<h1>Controle des batteries : MPPT 100/20 48V</h1>
|
|
<div class="header_info">
|
|
<h2>@@IP@@</h2>
|
|
<h2 id="hour">@@TIME@@</h2>
|
|
<div>
|
|
<span class="connection-indicator">@@CONNECTION_INDICATOR@@</span>
|
|
<button onclick="location.href='/settings'">Paramétrage</button>
|
|
</div>
|
|
</div>
|
|
|
|
</header>
|
|
|
|
<div class="tab-buttons">
|
|
<div class="tab-button" onclick="showTab('main-section')">Main</div>
|
|
<div class="tab-button" onclick="showTab('graph-section')">Graph</div>
|
|
<div class="tab-button" onclick="showTab('data-section')">Data</div>
|
|
</div>
|
|
|
|
<main>
|
|
<div id="main-section" class="tab">
|
|
<div class="buttons_section">
|
|
@@BUTTONS@@
|
|
</div>
|
|
<div class="slider-container">
|
|
<div class="slider-wrapper">
|
|
<span class="slider-label">Courant charge:</span>
|
|
<input type="range" class="slider" id="sliderCurrent" min="0" max="20" value="@@CC@@">
|
|
</div>
|
|
|
|
</div>
|
|
<div class="slider-container">
|
|
<div class="slider-wrapper">
|
|
<span class="slider-label">Courant injection:</span>
|
|
<input type="range" class="slider" id="sliderCurrent2" min="0" max="20" value="@@CC2@@">
|
|
</div>
|
|
</div>
|
|
<ul class="power-displays">
|
|
@@INDICATORS@@
|
|
</ul>
|
|
<aside>
|
|
<div class="status">
|
|
<h2>Statut</h2>
|
|
<div class="status-section">
|
|
<h3>Solaire</h3>
|
|
e<p><span>Tension:</span> <span id="VPV">@@VPV@@</span><span> mV</span></p>
|
|
<p><span>Courant:</span> <span id="PPV">@@PPV@@</span><span> mA</span></p>
|
|
</div>
|
|
<div class="status-section">
|
|
<h3>Batterie</h3>
|
|
<p><span>Tension:</span> <span id="V">@@V@@</span><span> mV</span></p>
|
|
<p><span>Courant:</span> <span id="I">@@I@@</span><span> mA</span></p>
|
|
<p><span>État:</span> <span id="CS">Absorption</span></p>
|
|
</div>
|
|
<div class="status-section">
|
|
<h3>Sortie de charge</h3>
|
|
<p><span>État:</span> <span id="LOAD">@@LOAD@@</span></p>
|
|
<p><span>Courant:</span> <span id="IL">@@IL@@</span><span> mA</span></p>
|
|
<p><span>Puissance:</span> <span id="output-power">3</span><span> W</span></p>
|
|
</div>
|
|
</div>
|
|
</aside>
|
|
</div>
|
|
<div id="graph-section" class="tab">
|
|
<div class="chart">
|
|
<h2>5 dernières heures</h2>
|
|
<canvas id="chartCanvas"></canvas>
|
|
</div>
|
|
</div>
|
|
<div id="data-section" class="tab">
|
|
<div class='victron_data'>
|
|
<span><A id='response_items'></A>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
</main>
|
|
</div>
|
|
)=";
|
|
|
|
String indicator = R"=(
|
|
<li class="power-display">
|
|
<div class="power-indicator">
|
|
<div id="@@KEY@@" class="power-value">@@VALUE@@</div>
|
|
<div id="power-source" class="power-source">@@LABEL@@</div>
|
|
</div>
|
|
</li>
|
|
)=";
|
|
|
|
|
|
String end_script_to_add = R"=(
|
|
|
|
<script>
|
|
function showTab(tabId) {
|
|
var tabs = document.getElementsByClassName('tab');
|
|
for (var i = 0; i < tabs.length; i++) {
|
|
tabs[i].style.display = 'none';
|
|
}
|
|
var tab = document.getElementById(tabId)
|
|
|
|
if (tab) {
|
|
tab.style.display = 'block';
|
|
|
|
|
|
var tabButtons = document.getElementsByClassName('tab-button');
|
|
for (var i = 0; i < tabButtons.length; i++) {
|
|
tabButtons[i].classList.remove('active');
|
|
}
|
|
tab.classList.add('active');
|
|
}
|
|
}
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
showTab('main-section'); // Affiche le premier onglet par défaut
|
|
});
|
|
|
|
// // Ajouter un écouteur d'événement pour chaque slider
|
|
// document.getElementById('sliderCurrent').addEventListener('change', function() {
|
|
// sendSliderValue('sliderCurrent', this.value);
|
|
// });
|
|
// // Ajouter un écouteur d'événement pour chaque slider
|
|
// document.getElementById('sliderCurrent2').addEventListener('change', function() {
|
|
// sendSliderValue('sliderCurrent2', this.value);
|
|
// });
|
|
</script>
|
|
)=";
|
|
|
|
|
|
void handleSettings() {
|
|
String html = "<html>\
|
|
<head>\
|
|
<style>\
|
|
body {\
|
|
font-family: Arial, sans-serif;\
|
|
background-color: #f4f4f4;\
|
|
display: flex;\
|
|
justify-content: center;\
|
|
align-items: center;\
|
|
height: 100vh;\
|
|
margin: 0;\
|
|
}\
|
|
.form-container {\
|
|
background-color: #fff;\
|
|
padding: 20px;\
|
|
border-radius: 8px;\
|
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);\
|
|
width: 600px;\
|
|
}\
|
|
h2 {\
|
|
color: #333;\
|
|
text-align: center;\
|
|
}\
|
|
.form-content {\
|
|
display: flex;\
|
|
justify-content: space-between;\
|
|
}\
|
|
.column {\
|
|
display: flex;\
|
|
flex-direction: column;\
|
|
width: 48%;\
|
|
}\
|
|
label {\
|
|
margin-bottom: 5px;\
|
|
font-weight: bold;\
|
|
color: #555;\
|
|
}\
|
|
input[type='text'] {\
|
|
padding: 10px;\
|
|
margin-bottom: 15px;\
|
|
border: 1px solid #ccc;\
|
|
border-radius: 4px;\
|
|
font-size: 16px;\
|
|
}\
|
|
input[type='submit'] {\
|
|
background-color: #28a745;\
|
|
color: white;\
|
|
border: none;\
|
|
padding: 10px;\
|
|
border-radius: 4px;\
|
|
cursor: pointer;\
|
|
font-size: 16px;\
|
|
margin-top: 10px;\
|
|
width: 100%;\
|
|
}\
|
|
input[type='submit']:hover {\
|
|
background-color: #218838;\
|
|
}\
|
|
</style>\
|
|
</head>\
|
|
<body>\
|
|
<div class=\"form-container\">\
|
|
<h2>Configuration</h2>\
|
|
<form action=\"/save\" method=\"POST\">\
|
|
<div class=\"form-content\">\
|
|
<div class=\"column\">\
|
|
<label for=\"max_current_charge\">MAX CHARGE :</label>\
|
|
<input type=\"number\" id=\"max_current_charge\" name=\"max_current_charge\" min=\"0\" max=\"20\" value=\"" + String(config.max_current_charge) + "\">\
|
|
<label for=\"voltage_charge\">VOLTAGE CHARGE :</label>\
|
|
<input type=\"number\" id=\"voltage_charge\" name=\"voltage_charge\" min=\"0\" max=\"48\" step=\"0.1\" value=\"" + String(config.voltage_charge) + "\">\
|
|
<label for=\"max_current_injection\">MAX INJECTION :</label>\
|
|
<input type=\"number\" id=\"max_current_injection\" name=\"max_current_injection\" min=\"0\" max=\"20\" value=\"" + String(config.max_current_injection) + "\">\
|
|
<label for=\"voltage_injection\">VOLTAGE INJECTION :</label>\
|
|
<input type=\"number\" id=\"voltage_injection\" name=\"voltage_injection\" min=\"0\" max=\"48\" step=\"0.1\" value=\"" + String(config.voltage_injection) + "\">\
|
|
<label for=\"configured\">Configuré :</label>\
|
|
<input type=\"checkbox\" id=\"configured\" name=\"configured\" readonly=\"readonly\" @@checked@@>\
|
|
</div>\
|
|
</div>\
|
|
<input type=\"submit\" value=\"Save\">\
|
|
</form>\
|
|
</div>\
|
|
</body>\
|
|
</html>";
|
|
|
|
html.replace("@@checked@@", (config.configured ? "checked" : ""));
|
|
|
|
server.send(200, "text/html", html);
|
|
}
|