generated from jmgiacalone/esp32-template
Functional.
This commit is contained in:
13
data/css/materialize.min.css
vendored
Normal file
13
data/css/materialize.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
114
data/index.htm
114
data/index.htm
@@ -1,7 +1,7 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>eMAKER Printer Climate Control</title>
|
<title>eMAKER Reflow Controller</title>
|
||||||
<!--Import Google Icon Font-->
|
<!--Import Google Icon Font-->
|
||||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
|
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
|
||||||
<!--Let browser know website is optimized for mobile-->
|
<!--Let browser know website is optimized for mobile-->
|
||||||
@@ -9,27 +9,111 @@
|
|||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<link type="text/css" rel="stylesheet" href="css/materialize.min.css" media="screen,projection" />
|
<link type="text/css" rel="stylesheet" href="css/materialize.min.css" media="screen,projection" />
|
||||||
<link rel="stylesheet" type="text/css" href="css/style.css" />
|
<link rel="stylesheet" type="text/css" href="css/style.css" />
|
||||||
<link rel="icon" type="image/x-icon" href="favicon.ico" />
|
<link rel="icon" type="image/x-icon" href="emaker.ico" />
|
||||||
|
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.min.js"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-dragdata@0.1.0/dist/chartjs-plugin-dragData.min.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<!-- Header row-->
|
<!-- Header row -->
|
||||||
<div id="header" class="row">
|
<div class="row">
|
||||||
<div class="col 6 logo">
|
<div class="col 6 logo">
|
||||||
<img src="eMAKER.png" alt="eMAKER logo" />
|
<img src="eMAKER.png" alt="eMAKER" />
|
||||||
</div>
|
</div>
|
||||||
<div class="col 6">
|
<div class="col 6">
|
||||||
<h5>Printer Climate Control</h5>
|
<h5>Oven control</h5>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Data tabs row -->
|
||||||
|
<div class="row">
|
||||||
|
<div class="card blue-grey darken-1 z-depth-3">
|
||||||
|
<div class="card-tabs">
|
||||||
|
<ul class="tabs tabs-transparent">
|
||||||
|
<li class="tab col s3"><a href="#tabTemp">Temperature control</a>
|
||||||
|
</li>
|
||||||
|
<li class="tab col s3"><a href="#tabPID">Edit PID</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="card-content blue-grey darken-1">
|
||||||
|
<div id="tabTemp" class="active">
|
||||||
|
<div class="row">
|
||||||
|
<div class="input-field col s3">
|
||||||
|
<input disabled id="tempinfo" type="number" value="-1" />
|
||||||
|
<label for="tempinfo">Temperature</label>
|
||||||
|
</div>
|
||||||
|
<div class="input-field col s3">
|
||||||
|
<input disabled id="targetinfo" type="number" value="-1" />
|
||||||
|
<label for="targetinfo">Target</label>
|
||||||
|
</div>
|
||||||
|
<div class="input-field col s3">
|
||||||
|
<input disabled id="powerinfo" type="number" value="-1" />
|
||||||
|
<label for="powerinfo">Power</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="input-field col s3">
|
||||||
|
<input type="number" name="Target" id="target" />
|
||||||
|
<label for="target">Target:</label>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="valign-wrapper">
|
||||||
|
<h5><a class="waves-effect waves-light btn" id="btnTarget" onclick="setTarget()">Set</a></h5>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="tabPID">
|
||||||
|
<div class="row">
|
||||||
|
<div class="input-field col s3">
|
||||||
|
<input type="number" name="Kp" id="kp" />
|
||||||
|
<label for="kp">Kp:</label>
|
||||||
|
</div>
|
||||||
|
<div class="input-field col s3">
|
||||||
|
<input type="number" name="Ki" id="ki" />
|
||||||
|
<label for="ki">Ki:</label>
|
||||||
|
</div>
|
||||||
|
<div class="input-field col s3">
|
||||||
|
<label for="kd">Kd:</label>
|
||||||
|
<input type="number" name="Kd" id="kd" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="valign-wrapper">
|
||||||
|
<h5><a class="waves-effect waves-light btn" id="btnPID" onclick="setPID()">Submit</a></h5>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Data row-->
|
<!-- Graph row -->
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="card">
|
<div class="card blue-grey darken-1 z-depth-3">
|
||||||
<div class="card-content">
|
<div class="card-content white-text chart-container">
|
||||||
<a href="/wifimanager.html">WiFi</a>
|
<canvas id="myChart"></canvas>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="card-action">
|
||||||
|
<div class="row">
|
||||||
|
<div class="input-field col s3">
|
||||||
|
<input type="number" name="Xmax" id="xmax" />
|
||||||
|
<label for="Xmax">Set overall time</label>
|
||||||
|
</div>
|
||||||
|
<div class="valign-wrapper col s3">
|
||||||
|
<h5><a class="waves-effect waves-light btn tooltipped" data-position="bottom" data-tooltip="Set time period." id="btnXmax" onclick="setXmax()">Set</a></h5>
|
||||||
|
</div>
|
||||||
|
<div class="col s6">
|
||||||
|
<div class="center-align">
|
||||||
|
<h5><a class="teal waves-effect waves-light btn tooltipped" data-position="bottom" data-tooltip="Run temperature profile." id="btnRunProfile" onclick="runProfile()">Run</a></h5>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Footer row -->
|
||||||
|
<div class="row">
|
||||||
|
ESP32
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script type="text/javascript" src="js/materialize.min.js"></script>
|
<script type="text/javascript" src="js/materialize.min.js"></script>
|
||||||
|
|||||||
985
data/js/dragData.min.js
vendored
Normal file
985
data/js/dragData.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
6
data/js/materialize.min.js
vendored
Normal file
6
data/js/materialize.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -1,37 +1,106 @@
|
|||||||
|
var oven_status = "";
|
||||||
|
var _run = 0;
|
||||||
var _elapsedTime = 0;
|
var _elapsedTime = 0;
|
||||||
|
|
||||||
function getParams() {
|
|
||||||
const url = '/paraams';
|
|
||||||
fetch(url)
|
|
||||||
.then((respone)=>{
|
|
||||||
return respone.json();
|
|
||||||
})
|
|
||||||
.then((data)=>{
|
|
||||||
document.getElementById('Iim').value = data.Iim || -1;
|
|
||||||
document.getElementById('Imp').value = data.Imp || -1;
|
|
||||||
document.getElementById('Tu').value = data.Tu || -1;
|
|
||||||
document.getElementById('Tl').value = data.Tl || -1;
|
|
||||||
M.updateTextFields();
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function setParams() {
|
setInterval(function () {
|
||||||
|
const url = '/status';
|
||||||
const data = new URLSearchParams();
|
fetch(url)
|
||||||
|
.then((respone)=>{
|
||||||
data.append('Iim',document.getElementById('Iim').value);
|
return respone.json();
|
||||||
data.append('Imp',document.getElementById('Imp').value);
|
})
|
||||||
data.append('Tu',document.getElementById('Tu').value);
|
.then((data)=>{
|
||||||
data.append('Tl',document.getElementById('Tl').value);
|
document.getElementById("tempinfo").value = data.temp || -1;
|
||||||
|
document.getElementById("targetinfo").value = data.target || -1;
|
||||||
fetch('/params', {
|
document.getElementById("powerinfo").value = data.power || -1;
|
||||||
method: 'POST',
|
_run = data.runProfile || 0;
|
||||||
headers: {
|
_elapsedTime = data.elapsedTime || 0;
|
||||||
'Content-Type': 'application/x-www-form-urlencoded'
|
M.updateTextFields();
|
||||||
},
|
|
||||||
body: data
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if(_run == 1){
|
||||||
|
myChart.data.datasets[1].data.push({
|
||||||
|
x:_elapsedTime / 1000,
|
||||||
|
y:document.getElementById("tempinfo").value
|
||||||
|
});
|
||||||
|
myChart.update();
|
||||||
}
|
}
|
||||||
|
}, 4000);
|
||||||
|
|
||||||
|
function setXmax() {
|
||||||
|
myChart.data.datasets[0].data[9].x = document.getElementById('xmax').value;
|
||||||
|
myChart.update();
|
||||||
|
}
|
||||||
|
function setTarget() {
|
||||||
|
const data = new URLSearchParams();
|
||||||
|
data.append('value',document.getElementById('target').value);
|
||||||
|
fetch('/target', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded'
|
||||||
|
},
|
||||||
|
body: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPID() {
|
||||||
|
const url = '/pid';
|
||||||
|
fetch(url)
|
||||||
|
.then((respone)=>{
|
||||||
|
return respone.json();
|
||||||
|
})
|
||||||
|
.then((data)=>{
|
||||||
|
document.getElementById('kp').value = data.kp || -1;
|
||||||
|
document.getElementById('ki').value = data.ki || -1;
|
||||||
|
document.getElementById('kd').value = data.kd || -1;
|
||||||
|
M.updateTextFields();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function setPID() {
|
||||||
|
const data = new URLSearchParams();
|
||||||
|
data.append('kp', document.getElementById('kp').value);
|
||||||
|
data.append('ki', document.getElementById('ki').value);
|
||||||
|
data.append('kd', document.getElementById('kd').value);
|
||||||
|
fetch('/pid', {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded'
|
||||||
|
},
|
||||||
|
body: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function runProfile() {
|
||||||
|
var btn = document.getElementById("btnRunProfile");
|
||||||
|
const data = new URLSearchParams();
|
||||||
|
if(_run == 1){
|
||||||
|
//stop profile
|
||||||
|
_run = 0;
|
||||||
|
btn.classList.remove("red");
|
||||||
|
btn.classList.add("teal");
|
||||||
|
btn.innerHTML = "Run";
|
||||||
|
data.append('run', _run);
|
||||||
|
}else{
|
||||||
|
//run profile
|
||||||
|
_run = 1;
|
||||||
|
data.append('run', _run);
|
||||||
|
data.append('profile', JSON.stringify(myChart.data.datasets[0].data));
|
||||||
|
btn.classList.remove("teal");
|
||||||
|
btn.classList.add("red");
|
||||||
|
btn.innerHTML = "Stop";
|
||||||
|
_elapsedTime = 0;
|
||||||
|
myChart.data.datasets[1].data.length = 0;
|
||||||
|
myChart.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch('/profile', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded'
|
||||||
|
},
|
||||||
|
body: data
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function joinNetwork() {
|
function joinNetwork() {
|
||||||
|
|
||||||
@@ -61,24 +130,80 @@ async function scanNetworks() {
|
|||||||
document.getElementById("networks").innerHTML = listHTML;
|
document.getElementById("networks").innerHTML = listHTML;
|
||||||
}
|
}
|
||||||
|
|
||||||
setInterval(function () {
|
var ctx = document.getElementById("myChart");
|
||||||
aja()
|
Chart.defaults.global.defaultFontColor = 'red';
|
||||||
.url('/sensors')
|
var myChart = new Chart(ctx, {
|
||||||
.on('success', function (data) {
|
type: 'scatter',
|
||||||
document.getElementById("tempinfo").value = data.temperature || -1;
|
data: {
|
||||||
document.getElementById("humidityinfo").value = data.humidity || -1;
|
datasets: [{
|
||||||
document.getElementById("pressureinfo").value = data.pressure || -1;
|
label: 'Temperature profile',
|
||||||
//document.getElementById("targetinfo").value = data.target.toFixed(2) || -1;
|
data: [{
|
||||||
_run = data.runProfile || 0;
|
x: 0, y: 25
|
||||||
_elapsedTime = data.elapsedTime || 0;
|
}, {
|
||||||
M.updateTextFields();
|
x: 90, y: 150
|
||||||
})
|
}, {
|
||||||
.go();
|
x: 270, y: 200
|
||||||
}, 4000);
|
}, {
|
||||||
|
x: 300, y: 235
|
||||||
|
}, {
|
||||||
|
x: 330, y: 250
|
||||||
|
}, {
|
||||||
|
x: 360, y: 217
|
||||||
|
}, {
|
||||||
|
x: 420, y: 25
|
||||||
|
}, {
|
||||||
|
x: 480, y: 25
|
||||||
|
}, {
|
||||||
|
x: 540, y: 25
|
||||||
|
}, {
|
||||||
|
x: 600, y: 25
|
||||||
|
}],
|
||||||
|
lineTension: 0,
|
||||||
|
showLine: true
|
||||||
|
},{
|
||||||
|
label: 'History',
|
||||||
|
data: [{
|
||||||
|
x:0, y:0
|
||||||
|
}],
|
||||||
|
lineTension: 0,
|
||||||
|
showLine: true,
|
||||||
|
pointBackgroundColor: 'red'
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
layout: {
|
||||||
|
padding: {
|
||||||
|
bottom: 20
|
||||||
|
}
|
||||||
|
},
|
||||||
|
responsive: true,
|
||||||
|
scales: {
|
||||||
|
yAxes: [{
|
||||||
|
ticks: {
|
||||||
|
beginAtZero:true,
|
||||||
|
min: 0,
|
||||||
|
max: 280
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
dragData: true,
|
||||||
|
dragX: true,
|
||||||
|
onDragStart: function (event, element) {},
|
||||||
|
onDrag: function (event, datasetIndex, index, value) {},
|
||||||
|
onDragEnd: function (event, datasetIndex, index, value) {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var ttOptions = {
|
||||||
|
enterDelay: 500,
|
||||||
|
inDuration: 300
|
||||||
|
};
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
var elems = document.querySelectorAll('.tooltipped');
|
||||||
|
var instances = M.Tooltip.init(elems, ttOptions);
|
||||||
|
getPID();
|
||||||
M.AutoInit();
|
M.AutoInit();
|
||||||
getParams();
|
|
||||||
// var elems = document.querySelectorAll('.tooltipped');
|
|
||||||
// var instances = M.Tooltip.init(elems, ttOptions);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -26,6 +26,9 @@ lib_deps =
|
|||||||
adafruit/Adafruit GFX Library@^1.11.9
|
adafruit/Adafruit GFX Library@^1.11.9
|
||||||
adafruit/Adafruit SSD1306@^2.5.9
|
adafruit/Adafruit SSD1306@^2.5.9
|
||||||
adafruit/MAX6675 library@^1.1.2
|
adafruit/MAX6675 library@^1.1.2
|
||||||
|
br3ttb/PID@^1.2.1
|
||||||
|
bblanchon/ArduinoJson@^7.0.3
|
||||||
|
dlloydev/QuickPID@^3.1.9
|
||||||
|
|
||||||
[env:lolin32]
|
[env:lolin32]
|
||||||
board = lolin32
|
board = lolin32
|
||||||
@@ -33,10 +36,13 @@ lib_deps =
|
|||||||
adafruit/Adafruit GFX Library@^1.11.9
|
adafruit/Adafruit GFX Library@^1.11.9
|
||||||
adafruit/Adafruit SSD1306@^2.5.9
|
adafruit/Adafruit SSD1306@^2.5.9
|
||||||
https://github.com/me-no-dev/ESPAsyncWebServer.git
|
https://github.com/me-no-dev/ESPAsyncWebServer.git
|
||||||
me-no-dev/AsyncTCP@^1.1.1
|
me-no-dev/AsyncTCP
|
||||||
ayushsharma82/AsyncElegantOTA@^2.2.7
|
ayushsharma82/AsyncElegantOTA@^2.2.7
|
||||||
arduino-libraries/Arduino_JSON@^0.1.0
|
arduino-libraries/Arduino_JSON
|
||||||
adafruit/MAX6675 library@^1.1.2
|
adafruit/MAX6675 library@^1.1.2
|
||||||
|
bblanchon/ArduinoJson@^7.0.3
|
||||||
|
; dlloydev/QuickPID@^3.1.9
|
||||||
|
br3ttb/PID@^1.2.1
|
||||||
build_flags =
|
build_flags =
|
||||||
'-D ELEGANTOTA_USE_ASYNC_WEBSERVER=1'
|
'-D ELEGANTOTA_USE_ASYNC_WEBSERVER=1'
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
@@ -51,3 +57,6 @@ lib_deps =
|
|||||||
adafruit/Adafruit GFX Library@^1.11.9
|
adafruit/Adafruit GFX Library@^1.11.9
|
||||||
adafruit/Adafruit SSD1306@^2.5.9
|
adafruit/Adafruit SSD1306@^2.5.9
|
||||||
adafruit/MAX6675 library@^1.1.2
|
adafruit/MAX6675 library@^1.1.2
|
||||||
|
br3ttb/PID@^1.2.1
|
||||||
|
bblanchon/ArduinoJson@^7.0.3
|
||||||
|
dlloydev/QuickPID@^3.1.9
|
||||||
|
|||||||
252
src/main.cpp
252
src/main.cpp
@@ -1,4 +1,5 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
#define DEBUG
|
||||||
|
|
||||||
//Peripherals includes
|
//Peripherals includes
|
||||||
#include <Wire.h>
|
#include <Wire.h>
|
||||||
@@ -6,6 +7,8 @@
|
|||||||
#include <Adafruit_GFX.h>
|
#include <Adafruit_GFX.h>
|
||||||
#include <Adafruit_SSD1306.h>
|
#include <Adafruit_SSD1306.h>
|
||||||
#include <max6675.h>
|
#include <max6675.h>
|
||||||
|
// #include <QuickPID.h>
|
||||||
|
#include <PID_v1.h>
|
||||||
|
|
||||||
//Web server includes
|
//Web server includes
|
||||||
#include <AsyncElegantOTA.h>
|
#include <AsyncElegantOTA.h>
|
||||||
@@ -16,14 +19,49 @@
|
|||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <ESPAsyncWebServer.h>
|
#include <ESPAsyncWebServer.h>
|
||||||
#include <SPIFFSEditor.h>
|
#include <SPIFFSEditor.h>
|
||||||
#include <Arduino_JSON.h>
|
// #include <Arduino_JSON.h>
|
||||||
|
#include "AsyncJson.h"
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
|
||||||
#include <Preferences.h>
|
#include <Preferences.h>
|
||||||
Preferences settings;
|
Preferences settings;
|
||||||
|
|
||||||
|
#define MAX6675_SCLK 12
|
||||||
|
#define MAX6675_CS 13
|
||||||
|
#define MAX6675_MISO 15
|
||||||
#define I2C_SDA 5//13
|
#define I2C_SDA 5//13
|
||||||
#define I2C_SCL 4//15
|
#define I2C_SCL 4//15
|
||||||
#define LED_PIN 5
|
#define LED_PIN 16
|
||||||
|
#define HEATER_PIN 14
|
||||||
|
|
||||||
|
//PID
|
||||||
|
#define T_SAMPLE_PERIOD 1000 // in milliseconds.
|
||||||
|
uint32_t temperature_sample_timer = 0;
|
||||||
|
double target = 0;
|
||||||
|
double temperature = 0;
|
||||||
|
double power = 0;
|
||||||
|
int runProfile = 0;
|
||||||
|
long int profileStartTime = 0;
|
||||||
|
long int elapsedTime = 0;
|
||||||
|
|
||||||
|
struct dataPoint{
|
||||||
|
double time;
|
||||||
|
double temp;
|
||||||
|
};
|
||||||
|
struct dataPoint sProfile[10];
|
||||||
|
|
||||||
|
double kp = 950;
|
||||||
|
double ki = 0.05;
|
||||||
|
double kd = 100;
|
||||||
|
PID outputPID(&temperature, &power, &target, kp, ki, kd, DIRECT);
|
||||||
|
int cycle = 10000; //WindowSize
|
||||||
|
unsigned long duty = 0; //WindowStartTime
|
||||||
|
|
||||||
|
// boolean on_off = false;
|
||||||
|
|
||||||
|
//DATA
|
||||||
|
// StaticJsonBuffer<JSON_OBJECT_SIZE(5)> jbStatus;
|
||||||
|
// JsonObject& objStatus = jbStatus.createObject();
|
||||||
|
|
||||||
//*****
|
//*****
|
||||||
// Display defines
|
// Display defines
|
||||||
@@ -39,7 +77,6 @@ unsigned long lastScreenRefresh = 0;
|
|||||||
//MAX6675(int8_t SCLK, int8_t CS, int8_t MISO);
|
//MAX6675(int8_t SCLK, int8_t CS, int8_t MISO);
|
||||||
MAX6675 tc(12, 13, 15);
|
MAX6675 tc(12, 13, 15);
|
||||||
unsigned long lastTempTime = 0;
|
unsigned long lastTempTime = 0;
|
||||||
float temperature;
|
|
||||||
|
|
||||||
//*********************************************************
|
//*********************************************************
|
||||||
// Web server variable declarations
|
// Web server variable declarations
|
||||||
@@ -51,7 +88,7 @@ AsyncWebServer server(80);
|
|||||||
// AsyncEventSource events("/events");
|
// AsyncEventSource events("/events");
|
||||||
|
|
||||||
//Variables to save values from HTML form
|
//Variables to save values from HTML form
|
||||||
JSONVar scannedSSIDs;
|
// JSONVar scannedSSIDs;
|
||||||
String ssid;
|
String ssid;
|
||||||
String pass;
|
String pass;
|
||||||
String ip;
|
String ip;
|
||||||
@@ -86,14 +123,43 @@ bool initWiFi();
|
|||||||
String getLEDState();
|
String getLEDState();
|
||||||
// ----------------------------------------------
|
// ----------------------------------------------
|
||||||
|
|
||||||
|
String getStatus(void)
|
||||||
|
{
|
||||||
|
// String json;
|
||||||
|
JsonDocument jsonStatus;
|
||||||
|
jsonStatus["temp"] = String(temperature);
|
||||||
|
jsonStatus["target"] = String(target);
|
||||||
|
jsonStatus["power"] = String(power);
|
||||||
|
jsonStatus["runProfile"] = String(runProfile);
|
||||||
|
jsonStatus["elapsedTime"] = String(elapsedTime);
|
||||||
|
String out;
|
||||||
|
serializeJson(jsonStatus,out);
|
||||||
|
return out;
|
||||||
|
// return JSON.stringify(jsonStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
String getPID(AsyncWebServerRequest * request)
|
||||||
|
{
|
||||||
|
JsonDocument jsonPID;
|
||||||
|
jsonPID["kp"] = String(kp);
|
||||||
|
jsonPID["ki"] = String(ki);
|
||||||
|
jsonPID["kd"] = String(kd);
|
||||||
|
String out;
|
||||||
|
serializeJson(jsonPID,out);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
String getJSONTemp(){
|
String getJSONTemp(){
|
||||||
JSONVar jsonTemp;
|
JsonDocument jsonTemp;
|
||||||
jsonTemp["t"]=String(temperature);
|
jsonTemp["t"]=String(temperature);
|
||||||
return JSON.stringify(jsonTemp);
|
String out;
|
||||||
|
serializeJson(jsonTemp,out);
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
pinMode(LED_PIN, OUTPUT);
|
pinMode(LED_PIN, OUTPUT);
|
||||||
|
pinMode(HEATER_PIN, OUTPUT);
|
||||||
|
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
|
||||||
@@ -146,7 +212,7 @@ server.addHandler(new SPIFFSEditor(SPIFFS,http_username,http_password));
|
|||||||
server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
|
server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
String json = getJSONTemp();
|
String json = getJSONTemp();
|
||||||
request->send(200, "application/json", json);
|
request->send(200, "application/json", json);
|
||||||
json = String();
|
// json = String();
|
||||||
});
|
});
|
||||||
|
|
||||||
server.on("/scanNetworks", HTTP_GET, [](AsyncWebServerRequest *request){
|
server.on("/scanNetworks", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
@@ -288,32 +354,182 @@ server.addHandler(new SPIFFSEditor(SPIFFS,http_username,http_password));
|
|||||||
ESP.restart();
|
ESP.restart();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
server.on("/heap", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
|
request->send(200, "text/plain", String(ESP.getFreeHeap()));
|
||||||
|
});
|
||||||
|
server.on("/status", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
|
request->send(200, "text/plain", getStatus());
|
||||||
|
});
|
||||||
|
server.on("/pid", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
|
request->send(200, "text/plain", getPID(request));
|
||||||
|
});
|
||||||
|
server.on("/pid",HTTP_POST, [](AsyncWebServerRequest *request){
|
||||||
|
if (request->hasParam("kp",true))
|
||||||
|
{
|
||||||
|
kp = request->getParam("kp",true)->value().toFloat();
|
||||||
|
#ifdef DEBUG
|
||||||
|
Serial.print("kp=");
|
||||||
|
Serial.print(kp,2);
|
||||||
|
Serial.print("; ");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
if (request->hasParam("ki",true))
|
||||||
|
{
|
||||||
|
ki = request->getParam("ki",true)->value().toFloat();
|
||||||
|
#ifdef DEBUG
|
||||||
|
Serial.print("ki=");
|
||||||
|
Serial.print(ki,2);
|
||||||
|
Serial.print("; ");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
if (request->hasParam("kd",true))
|
||||||
|
{
|
||||||
|
kd = request->getParam("kd",true)->value().toFloat();
|
||||||
|
#ifdef DEBUG
|
||||||
|
Serial.print("kd=");
|
||||||
|
Serial.print(kd,2);
|
||||||
|
Serial.print("; ");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#ifdef DEBUG
|
||||||
|
Serial.print("\n");
|
||||||
|
#endif
|
||||||
|
outputPID.SetTunings(kp, ki, kd);
|
||||||
|
|
||||||
server.begin();
|
request->send(200, "text/plain", getPID(request));
|
||||||
|
});
|
||||||
|
server.on("/target", HTTP_POST, [](AsyncWebServerRequest *request){
|
||||||
|
int params = request->params();
|
||||||
|
if(params > 0){
|
||||||
|
// AsyncWebParameter* p = request->getParam("value",true)->value().toFloat();
|
||||||
|
target = request->getParam("value",true)->value().toDouble();
|
||||||
|
Serial.printf("Target: %3.2f\n",target);
|
||||||
|
}else{
|
||||||
|
target = -273;
|
||||||
|
}
|
||||||
|
// if(request->hasParam("value")){
|
||||||
|
// target = request->getParam("value")->value().toFloat();
|
||||||
|
// Serial.printf("Target: %d",target);
|
||||||
|
// }
|
||||||
|
request->send(200, "text/plain", (String)target);
|
||||||
|
});
|
||||||
|
server.on("/profile", HTTP_POST,[](AsyncWebServerRequest *request){
|
||||||
|
// AsyncCallbackJsonWebHandler *handler = new AsyncCallbackJsonWebHandler("/profile", [](AsyncWebServerRequest *request, JsonVariant &json) {
|
||||||
|
|
||||||
|
int params = request->params();
|
||||||
|
if(request->hasParam("profile",true)){
|
||||||
|
JsonDocument jsonObj;
|
||||||
|
Serial.println(request->getParam("profile",true)->value());
|
||||||
|
|
||||||
|
DeserializationError error = deserializeJson(jsonObj, request->getParam("profile",true)->value());
|
||||||
|
if (error) {
|
||||||
|
// Handle the error
|
||||||
|
Serial.println(error.c_str()); request->send(400, "text/plain", "Invalid JSON payload"); return;
|
||||||
|
}else{
|
||||||
|
for(int i = 0;i<10;i++) {
|
||||||
|
//double point[2];
|
||||||
|
//int pointCount = jsonObj["profile"][i].as<JsonArray>().copyTo(point);
|
||||||
|
sProfile[i].time = jsonObj[i]["x"];
|
||||||
|
sProfile[i].temp = jsonObj[i]["y"];
|
||||||
|
#ifdef DEBUG
|
||||||
|
Serial.print("Point:");
|
||||||
|
Serial.print(i);
|
||||||
|
Serial.print(", Time:");
|
||||||
|
Serial.print(sProfile[i].time);
|
||||||
|
Serial.print(", Temp:");
|
||||||
|
Serial.println(sProfile[i].temp);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(request->hasParam("run",true)){
|
||||||
|
runProfile = request->getParam("run",true)->value().toInt();
|
||||||
|
Serial.println(runProfile);
|
||||||
|
if(runProfile == 1){
|
||||||
|
profileStartTime = millis();
|
||||||
|
elapsedTime = 0;
|
||||||
|
}else{
|
||||||
|
target = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
request->send(200, "text/plain", "{test: \"ok\"}");
|
||||||
|
});
|
||||||
|
|
||||||
|
server.begin();
|
||||||
|
duty = millis();
|
||||||
|
outputPID.SetOutputLimits(0, cycle);
|
||||||
|
outputPID.SetSampleTime(T_SAMPLE_PERIOD);
|
||||||
|
outputPID.SetTunings(kp, ki, kd);
|
||||||
|
outputPID.SetMode(AUTOMATIC);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
digitalWrite(LED_PIN,HIGH);
|
long now = millis();
|
||||||
temperature = tc.readCelsius();
|
if(now - temperature_sample_timer >= T_SAMPLE_PERIOD)
|
||||||
delay(500);
|
{
|
||||||
digitalWrite(LED_PIN,LOW);
|
temperature = tc.readCelsius();
|
||||||
delay(500);
|
temperature_sample_timer = now;
|
||||||
if ((millis() - lastScreenRefresh) > SCREEN_REFRESH) {
|
//deal with profile
|
||||||
|
if(runProfile == 1){
|
||||||
|
elapsedTime = millis() - profileStartTime;
|
||||||
|
if(sProfile[9].time * 1000 > elapsedTime){
|
||||||
|
//find segment
|
||||||
|
int segment = 0;
|
||||||
|
for(segment;segment<10;segment++){
|
||||||
|
if(sProfile[segment].time * 1000 < elapsedTime && sProfile[segment+1].time * 1000 >= elapsedTime){
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Serial.print("Segment:");
|
||||||
|
Serial.print(segment);
|
||||||
|
double t_t1 = elapsedTime - (sProfile[segment].time * 1000);
|
||||||
|
double t2_t1 = (sProfile[segment+1].time - sProfile[segment].time) * 1000;
|
||||||
|
double T2_T1 = sProfile[segment+1].temp - sProfile[segment].temp;
|
||||||
|
|
||||||
|
target = sProfile[segment].temp + (t_t1 / t2_t1) * T2_T1;
|
||||||
|
Serial.print(", Target:");
|
||||||
|
Serial.println(target);
|
||||||
|
}else{
|
||||||
|
runProfile = 0;
|
||||||
|
target = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//set heater output
|
||||||
|
outputPID.Compute();
|
||||||
|
|
||||||
|
unsigned long rightNow = millis();
|
||||||
|
if (rightNow - duty > cycle)
|
||||||
|
{ //time to shift the Relay Window
|
||||||
|
duty += cycle;
|
||||||
|
}
|
||||||
|
if (power > rightNow - duty){
|
||||||
|
digitalWrite(HEATER_PIN, HIGH);
|
||||||
|
}else{
|
||||||
|
digitalWrite(HEATER_PIN, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((now - lastScreenRefresh) > SCREEN_REFRESH) {
|
||||||
Serial.printf("T:%.2f\n", temperature);
|
Serial.printf("T:%.2f\n", temperature);
|
||||||
|
|
||||||
display.clearDisplay();
|
display.clearDisplay();
|
||||||
display.setTextSize(3);
|
|
||||||
display.setCursor(0, 5);
|
|
||||||
display.printf("T:%.1f\n", temperature);
|
|
||||||
display.setTextSize(1);
|
display.setTextSize(1);
|
||||||
|
display.setCursor(0, 3);
|
||||||
|
display.printf("T:%.1f/%.1f\n", temperature, target);
|
||||||
|
display.setCursor(0,24);
|
||||||
|
display.printf("P:%.1f\n", power);
|
||||||
display.setCursor(0,48);
|
display.setCursor(0,48);
|
||||||
display.printf("%s\n",ssid);
|
display.printf("%s\n",ssid);
|
||||||
display.printf("%s",ip);
|
display.printf("%s",ip);
|
||||||
display.display();
|
display.display();
|
||||||
|
|
||||||
lastScreenRefresh = millis();
|
lastScreenRefresh = now;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user