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>
|
||||
<html>
|
||||
<head>
|
||||
<title>eMAKER Printer Climate Control</title>
|
||||
<title>eMAKER Reflow Controller</title>
|
||||
<!--Import Google Icon Font-->
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
|
||||
<!--Let browser know website is optimized for mobile-->
|
||||
@@ -9,27 +9,111 @@
|
||||
<meta charset="utf-8" />
|
||||
<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="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>
|
||||
<body>
|
||||
<div class="container">
|
||||
<!-- Header row-->
|
||||
<div id="header" class="row">
|
||||
<div class="col 6 logo">
|
||||
<img src="eMAKER.png" alt="eMAKER logo" />
|
||||
</div>
|
||||
<div class="col 6">
|
||||
<h5>Printer Climate Control</h5>
|
||||
<!-- Header row -->
|
||||
<div class="row">
|
||||
<div class="col 6 logo">
|
||||
<img src="eMAKER.png" alt="eMAKER" />
|
||||
</div>
|
||||
<div class="col 6">
|
||||
<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>
|
||||
<!-- Data row-->
|
||||
<!-- Graph row -->
|
||||
<div class="row">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="/wifimanager.html">WiFi</a>
|
||||
</div>
|
||||
|
||||
<div class="card blue-grey darken-1 z-depth-3">
|
||||
<div class="card-content white-text chart-container">
|
||||
<canvas id="myChart"></canvas>
|
||||
</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>
|
||||
<!-- Footer row -->
|
||||
<div class="row">
|
||||
ESP32
|
||||
</div>
|
||||
</div>
|
||||
<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;
|
||||
|
||||
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() {
|
||||
|
||||
const data = new URLSearchParams();
|
||||
|
||||
data.append('Iim',document.getElementById('Iim').value);
|
||||
data.append('Imp',document.getElementById('Imp').value);
|
||||
data.append('Tu',document.getElementById('Tu').value);
|
||||
data.append('Tl',document.getElementById('Tl').value);
|
||||
|
||||
fetch('/params', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
},
|
||||
body: data
|
||||
setInterval(function () {
|
||||
const url = '/status';
|
||||
fetch(url)
|
||||
.then((respone)=>{
|
||||
return respone.json();
|
||||
})
|
||||
.then((data)=>{
|
||||
document.getElementById("tempinfo").value = data.temp || -1;
|
||||
document.getElementById("targetinfo").value = data.target || -1;
|
||||
document.getElementById("powerinfo").value = data.power || -1;
|
||||
_run = data.runProfile || 0;
|
||||
_elapsedTime = data.elapsedTime || 0;
|
||||
M.updateTextFields();
|
||||
})
|
||||
|
||||
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() {
|
||||
|
||||
@@ -61,24 +130,80 @@ async function scanNetworks() {
|
||||
document.getElementById("networks").innerHTML = listHTML;
|
||||
}
|
||||
|
||||
setInterval(function () {
|
||||
aja()
|
||||
.url('/sensors')
|
||||
.on('success', function (data) {
|
||||
document.getElementById("tempinfo").value = data.temperature || -1;
|
||||
document.getElementById("humidityinfo").value = data.humidity || -1;
|
||||
document.getElementById("pressureinfo").value = data.pressure || -1;
|
||||
//document.getElementById("targetinfo").value = data.target.toFixed(2) || -1;
|
||||
_run = data.runProfile || 0;
|
||||
_elapsedTime = data.elapsedTime || 0;
|
||||
M.updateTextFields();
|
||||
})
|
||||
.go();
|
||||
}, 4000);
|
||||
var ctx = document.getElementById("myChart");
|
||||
Chart.defaults.global.defaultFontColor = 'red';
|
||||
var myChart = new Chart(ctx, {
|
||||
type: 'scatter',
|
||||
data: {
|
||||
datasets: [{
|
||||
label: 'Temperature profile',
|
||||
data: [{
|
||||
x: 0, y: 25
|
||||
}, {
|
||||
x: 90, y: 150
|
||||
}, {
|
||||
x: 270, y: 200
|
||||
}, {
|
||||
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() {
|
||||
var elems = document.querySelectorAll('.tooltipped');
|
||||
var instances = M.Tooltip.init(elems, ttOptions);
|
||||
getPID();
|
||||
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 SSD1306@^2.5.9
|
||||
adafruit/MAX6675 library@^1.1.2
|
||||
br3ttb/PID@^1.2.1
|
||||
bblanchon/ArduinoJson@^7.0.3
|
||||
dlloydev/QuickPID@^3.1.9
|
||||
|
||||
[env:lolin32]
|
||||
board = lolin32
|
||||
@@ -33,10 +36,13 @@ lib_deps =
|
||||
adafruit/Adafruit GFX Library@^1.11.9
|
||||
adafruit/Adafruit SSD1306@^2.5.9
|
||||
https://github.com/me-no-dev/ESPAsyncWebServer.git
|
||||
me-no-dev/AsyncTCP@^1.1.1
|
||||
me-no-dev/AsyncTCP
|
||||
ayushsharma82/AsyncElegantOTA@^2.2.7
|
||||
arduino-libraries/Arduino_JSON@^0.1.0
|
||||
arduino-libraries/Arduino_JSON
|
||||
adafruit/MAX6675 library@^1.1.2
|
||||
bblanchon/ArduinoJson@^7.0.3
|
||||
; dlloydev/QuickPID@^3.1.9
|
||||
br3ttb/PID@^1.2.1
|
||||
build_flags =
|
||||
'-D ELEGANTOTA_USE_ASYNC_WEBSERVER=1'
|
||||
monitor_speed = 115200
|
||||
@@ -51,3 +57,6 @@ lib_deps =
|
||||
adafruit/Adafruit GFX Library@^1.11.9
|
||||
adafruit/Adafruit SSD1306@^2.5.9
|
||||
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>
|
||||
#define DEBUG
|
||||
|
||||
//Peripherals includes
|
||||
#include <Wire.h>
|
||||
@@ -6,6 +7,8 @@
|
||||
#include <Adafruit_GFX.h>
|
||||
#include <Adafruit_SSD1306.h>
|
||||
#include <max6675.h>
|
||||
// #include <QuickPID.h>
|
||||
#include <PID_v1.h>
|
||||
|
||||
//Web server includes
|
||||
#include <AsyncElegantOTA.h>
|
||||
@@ -16,14 +19,49 @@
|
||||
#include <AsyncTCP.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <SPIFFSEditor.h>
|
||||
#include <Arduino_JSON.h>
|
||||
// #include <Arduino_JSON.h>
|
||||
#include "AsyncJson.h"
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
#include <Preferences.h>
|
||||
Preferences settings;
|
||||
|
||||
#define MAX6675_SCLK 12
|
||||
#define MAX6675_CS 13
|
||||
#define MAX6675_MISO 15
|
||||
#define I2C_SDA 5//13
|
||||
#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
|
||||
@@ -39,7 +77,6 @@ unsigned long lastScreenRefresh = 0;
|
||||
//MAX6675(int8_t SCLK, int8_t CS, int8_t MISO);
|
||||
MAX6675 tc(12, 13, 15);
|
||||
unsigned long lastTempTime = 0;
|
||||
float temperature;
|
||||
|
||||
//*********************************************************
|
||||
// Web server variable declarations
|
||||
@@ -51,7 +88,7 @@ AsyncWebServer server(80);
|
||||
// AsyncEventSource events("/events");
|
||||
|
||||
//Variables to save values from HTML form
|
||||
JSONVar scannedSSIDs;
|
||||
// JSONVar scannedSSIDs;
|
||||
String ssid;
|
||||
String pass;
|
||||
String ip;
|
||||
@@ -86,14 +123,43 @@ bool initWiFi();
|
||||
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(){
|
||||
JSONVar jsonTemp;
|
||||
JsonDocument jsonTemp;
|
||||
jsonTemp["t"]=String(temperature);
|
||||
return JSON.stringify(jsonTemp);
|
||||
String out;
|
||||
serializeJson(jsonTemp,out);
|
||||
return out;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
pinMode(LED_PIN, OUTPUT);
|
||||
pinMode(HEATER_PIN, OUTPUT);
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
@@ -146,7 +212,7 @@ server.addHandler(new SPIFFSEditor(SPIFFS,http_username,http_password));
|
||||
server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
String json = getJSONTemp();
|
||||
request->send(200, "application/json", json);
|
||||
json = String();
|
||||
// json = String();
|
||||
});
|
||||
|
||||
server.on("/scanNetworks", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||
@@ -288,32 +354,182 @@ server.addHandler(new SPIFFSEditor(SPIFFS,http_username,http_password));
|
||||
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() {
|
||||
digitalWrite(LED_PIN,HIGH);
|
||||
temperature = tc.readCelsius();
|
||||
delay(500);
|
||||
digitalWrite(LED_PIN,LOW);
|
||||
delay(500);
|
||||
if ((millis() - lastScreenRefresh) > SCREEN_REFRESH) {
|
||||
long now = millis();
|
||||
if(now - temperature_sample_timer >= T_SAMPLE_PERIOD)
|
||||
{
|
||||
temperature = tc.readCelsius();
|
||||
temperature_sample_timer = now;
|
||||
//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);
|
||||
|
||||
display.clearDisplay();
|
||||
display.setTextSize(3);
|
||||
display.setCursor(0, 5);
|
||||
display.printf("T:%.1f\n", temperature);
|
||||
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.printf("%s\n",ssid);
|
||||
display.printf("%s",ip);
|
||||
display.display();
|
||||
|
||||
lastScreenRefresh = millis();
|
||||
lastScreenRefresh = now;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user