From 65ac75cb9f9a3973c60a65689df2b10653fb53c2 Mon Sep 17 00:00:00 2001 From: Vincent van der Wal Date: Sat, 6 Sep 2025 20:49:46 +0200 Subject: [PATCH] add under and over shoot corrections --- README.md | 3 ++- index.html | 4 +-- src/main.cpp | 73 ++++++++++++++++++++++++++++++++++++++++---------- src/main.ts | 39 ++++++++++++++++++--------- src/styles.css | 2 +- 5 files changed, 90 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index e8c4063..44e90e8 100644 --- a/README.md +++ b/README.md @@ -141,4 +141,5 @@ ESP32Async/ESPAsyncWebServer | https://github.com/ESP32Async/ESPAsyncWebServer | ### Display -In the long run a capacative LCD screen might be used in addition to the WebSocket connection \ No newline at end of file +- Add capacative LCD screen to be used in addition to the WebSocket connection for direct control on the oven +- Maybe add sensor to indicate if the lid has been opened \ No newline at end of file diff --git a/index.html b/index.html index b80780e..2806ce1 100644 --- a/index.html +++ b/index.html @@ -15,7 +15,7 @@

- Temperature

+ Sensor Temperature

°C

@@ -34,7 +34,7 @@
- +
diff --git a/src/main.cpp b/src/main.cpp index 9696c14..0804002 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -31,10 +31,12 @@ int thermoCLK = 5; MAX6675 thermocouple(thermoCLK, thermoCS, thermoDO); int targetTemp = 300; -int overShoot = 10; -int underShoot = 5; +float setOverShoot = 15; +float setUnderShoot = 10; +float derivedOverShoot = targetTemp; +float derivedUnderShoot = targetTemp; unsigned long lastSwitch = 0; -unsigned long switchDelay = 60000; +unsigned long switchDelay = 30000; // 30s bool autoSwitch = true; // Get Sensor Readings and return JSON object @@ -49,6 +51,9 @@ String getSensorReadings() { readings["relais"] = 0; } + readings["target_temp"] = targetTemp; + readings["derived_overshoot"] = derivedOverShoot; + readings["derived_undershoot"] = derivedUnderShoot; serializeJson(readings, jsonString); return jsonString; } @@ -108,11 +113,12 @@ void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) digitalWrite(relay, HIGH); lastSwitch = millis(); } + resetDerivedValues(); } if (message.startsWith("setTargetTemp")) { String target = message.substring(15, 18); - targetTemp = target.toInt(); + targetTemp = target.toFloat(); Serial.printf("\nTarget temp set to "); Serial.print(targetTemp); Serial.printf("°C"); @@ -145,6 +151,54 @@ void initWebSocket() server.addHandler(&ws); } +void regulateRelais() +{ + if (autoSwitch) + { + if ((millis() - lastSwitch) > switchDelay) + { + float temperature = thermocouple.readCelsius(); + float sinceLastSwitch = millis() - lastSwitch; + float fiveMinutesInMillis = 5 * 60 * 1000; + float shootFactor = sinceLastSwitch / fiveMinutesInMillis; + + float overshoot = setOverShoot * shootFactor; // derive over 5 mins -> 1 min eq. 3°C, 5mins eq. 15°C + float dirivedOvershoot = min(overshoot, setOverShoot); + + float undershoot = setUnderShoot * shootFactor; // derive over 5 min -> 1 min eq. 3°C, 5mins eq. 15°C + float dirivedUndershoot = min(undershoot, setUnderShoot); + + float overShootCorrectedTarget = derivedOverShoot = targetTemp - dirivedOvershoot; + float underShootCorrectedTarget = derivedUnderShoot = targetTemp + dirivedUndershoot; + + if (temperature > overShootCorrectedTarget) // > 285°C + { + if (digitalRead(relay) == HIGH) + { + digitalWrite(relay, LOW); + lastSwitch = millis(); + resetDerivedValues(); + } + } + else if (temperature < underShootCorrectedTarget) // < 310°C + { + if (digitalRead(relay) == LOW) + { + digitalWrite(relay, HIGH); + lastSwitch = millis(); + resetDerivedValues(); + } + } + } + } +} + +void resetDerivedValues() +{ + derivedOverShoot = targetTemp; + derivedUnderShoot = targetTemp; +} + void setup() { Serial.begin(9600); @@ -172,16 +226,7 @@ void loop() { String sensorReadings = getSensorReadings(); notifyClients(sensorReadings); - if (((millis() - lastSwitch) > switchDelay) && thermocouple.readCelsius() >= (targetTemp - overShoot)) // >= 285°C - { - digitalWrite(relay, LOW); - lastSwitch = millis(); - } - if (((millis() - lastSwitch) > switchDelay) && thermocouple.readCelsius() < (targetTemp - underShoot)) // < 270°C - { - digitalWrite(relay, HIGH); - lastSwitch = millis(); - } + regulateRelais(); lastTime = millis(); } diff --git a/src/main.ts b/src/main.ts index bd2ee0f..0dd479e 100644 --- a/src/main.ts +++ b/src/main.ts @@ -19,17 +19,17 @@ let ws: WebSocket; const now = new Date() let container: HTMLElement | null = document.querySelector('#plot') -let temperatureData = [ - [now.getTime(), 25] -] + let relais = 0 let relaisData = [ [now.getTime(), 0] ] -let temp = 25; -let targetTemp = 350 +let temp = 300; +let targetTemp = 300 +let targetTempOverShoot = 300 +let targetTempUnderShoot = 300 const oven = document.querySelector('#oven') const temperature = document.querySelector('#temperature') @@ -42,6 +42,10 @@ let maxValues = 4 * 60 * 60 // 60 minutes (4 values/sec) let hs: Highcharts.StockChart; let hsOptions: Highcharts.Options +let temperatureData = [ + [now.getTime(), temp] +] + const getRelaisBands = () => { let relaisBands = [] let active = false; @@ -65,15 +69,18 @@ const getRelaisBands = () => { } const dashStyle: DashStyleValue = 'Dash' -const getTargetLine = () => { +const getTargetLines = () => { return [ - { value: targetTemp, width: 3, dashStyle: dashStyle } + { value: targetTemp, width: 3, dashStyle: dashStyle }, + { value: targetTempOverShoot, width: 1, dashStyle: dashStyle, color: "red" }, + { value: targetTempUnderShoot, width: 1, dashStyle: dashStyle, color: "red" } ] } const createChart = () => { hsOptions = { chart: { + height: '650px', animation: { duration: 250, easing: 'linear' @@ -121,7 +128,7 @@ const createChart = () => { to: 600, color: 'rgba(255, 0, 0, 0.4)' }], - plotLines: getTargetLine() + plotLines: getTargetLines() }, xAxis: { @@ -233,7 +240,7 @@ const onLoad = () => { hs.xAxis[0].update({ plotBands: getRelaisBands() }) - hs.yAxis[0].update({ plotLines: getTargetLine() }) + hs.yAxis[0].update({ plotLines: getTargetLines() }) hs.series[0].setData(temperatureData, true) }, 250) } @@ -302,10 +309,16 @@ const onMessage = (event: MessageEvent) => { if (relaisSwitchInput) relaisSwitchInput.checked = false } + } else if (key === 'target_temp') { + targetTemp = myObj[key] + } else if (key === 'derived_overshoot') { + targetTempOverShoot = myObj[key] + } else if (key === 'derived_undershoot') { + targetTempUnderShoot = myObj[key] } hs.xAxis[0].update({ plotBands: getRelaisBands() }) - hs.yAxis[0].update({ plotLines: getTargetLine() }) + hs.yAxis[0].update({ plotLines: getTargetLines() }) hs.series[0].setData(temperatureData, true) } } @@ -336,10 +349,10 @@ const switchRelais = () => { const changeTargetTemp = (e: Event) => { const target = e.target as HTMLTextAreaElement; let value = Number(target?.value) - targetTemp = value - console.log('Changed target temp to ' + targetTemp) + // targetTemp = value + console.log('Changed target temp to ' + value) if (!import.meta.env.DEV) { - ws.send("setTargetTemp: " + pad(targetTemp, 3)); + ws.send("setTargetTemp: " + pad(value, 3)); } } diff --git a/src/styles.css b/src/styles.css index c0997ca..51ae976 100644 --- a/src/styles.css +++ b/src/styles.css @@ -36,7 +36,7 @@ p { } .graph { - height: 310px; + height: 570px; overflow: hidden; display: flex; justify-content: center;