292 lines
7.5 KiB
C++
292 lines
7.5 KiB
C++
#include <ESP8266WiFi.h>
|
|
#include <FS.h>
|
|
#include <Wire.h>
|
|
#include <LiquidCrystal_I2C.h>
|
|
#include <DHT.h>
|
|
#include <ESP8266WebServer.h>
|
|
|
|
#define DHT_PIN 11
|
|
#define MOSFET_HEATING_PIN 13
|
|
#define MOSFET_COOLING_PIN 14
|
|
|
|
#define DHT_TYPE DHT11
|
|
|
|
DHT dht(DHT_PIN, DHT_TYPE);
|
|
LiquidCrystal_I2C lcd(0x27, 20, 4);
|
|
|
|
ESP8266WebServer server(80);
|
|
|
|
const char* ssid = "OpenCure";
|
|
const char* password = "12345678";
|
|
|
|
enum Mode { OFF, TIME_MODE, HOLD_MODE, CURVE_MODE };
|
|
Mode currentMode = OFF;
|
|
|
|
float targetTemperature = 25.0;
|
|
unsigned long startTime = 0;
|
|
unsigned long duration = 0;
|
|
|
|
float fridgeTemp = 0.0;
|
|
|
|
bool heatingActive = false;
|
|
bool coolingActive = false;
|
|
|
|
void setup() {
|
|
Serial.begin(115200);
|
|
|
|
pinMode(MOSFET_HEATING_PIN, OUTPUT);
|
|
pinMode(MOSFET_COOLING_PIN, OUTPUT);
|
|
analogWriteRange(255); // Set PWM range to 0-255
|
|
analogWriteFreq(20000); // Set PWM frequency to 20 kHz
|
|
|
|
dht.begin();
|
|
lcd.begin(20,4);
|
|
lcd.backlight();
|
|
|
|
if (!SPIFFS.begin()) {
|
|
Serial.println("Failed to mount file system");
|
|
return;
|
|
}
|
|
|
|
WiFi.softAP(ssid, password);
|
|
server.on("/", handleRoot);
|
|
server.on("/bootstrap.min.css", []() {
|
|
serveFile("/bootstrap.min.css", "text/css");
|
|
});
|
|
server.on("/bootstrap.min.js", []() {
|
|
serveFile("/bootstrap.min.js", "application/javascript");
|
|
});
|
|
server.on("/jquery.min.js", []() {
|
|
serveFile("/jquery.min.js", "application/javascript");
|
|
});
|
|
server.on("/setTemperature", handleSetTemperature);
|
|
server.on("/setMode", handleSetMode);
|
|
server.begin();
|
|
Serial.println("HTTP server started");
|
|
|
|
lcd.setCursor(0, 0);
|
|
lcd.print("ESP8266 Peltier Fridge");
|
|
delay(2000);
|
|
}
|
|
|
|
void loop() {
|
|
server.handleClient();
|
|
updateSensors();
|
|
controlPeltier();
|
|
updateLCD();
|
|
|
|
switch (currentMode) {
|
|
case TIME_MODE:
|
|
timeMode();
|
|
break;
|
|
case HOLD_MODE:
|
|
holdMode();
|
|
break;
|
|
case CURVE_MODE:
|
|
curveMode();
|
|
break;
|
|
case OFF:
|
|
disablePeltier();
|
|
break;
|
|
}
|
|
}
|
|
|
|
void updateSensors() {
|
|
fridgeTemp = dht.readTemperature();
|
|
Serial.printf("Fridge Temp: %.1f C\n", fridgeTemp);
|
|
}
|
|
|
|
void controlHeating(int dutyCycle) {
|
|
analogWrite(MOSFET_COOLING_PIN, 0); // Ensure cooling is off
|
|
analogWrite(MOSFET_HEATING_PIN, dutyCycle);
|
|
heatingActive = true;
|
|
coolingActive = false;
|
|
}
|
|
|
|
void controlCooling(int dutyCycle) {
|
|
analogWrite(MOSFET_HEATING_PIN, 0); // Ensure heating is off
|
|
analogWrite(MOSFET_COOLING_PIN, dutyCycle);
|
|
coolingActive = true;
|
|
heatingActive = false;
|
|
}
|
|
|
|
void disablePeltier() {
|
|
analogWrite(MOSFET_HEATING_PIN, 0);
|
|
analogWrite(MOSFET_COOLING_PIN, 0);
|
|
heatingActive = false;
|
|
coolingActive = false;
|
|
}
|
|
|
|
void controlPeltier() {
|
|
if (currentMode == OFF) {
|
|
disablePeltier();
|
|
return;
|
|
}
|
|
|
|
if (targetTemperature < 25) {
|
|
if (fridgeTemp > targetTemperature) {
|
|
int dutyCycle = map(fridgeTemp - targetTemperature, 0, 10, 0, 255);
|
|
controlCooling(dutyCycle);
|
|
} else {
|
|
disablePeltier();
|
|
}
|
|
} else if (targetTemperature > 25) {
|
|
if (fridgeTemp < targetTemperature) {
|
|
int dutyCycle = map(targetTemperature - fridgeTemp, 0, 10, 0, 255);
|
|
controlHeating(dutyCycle);
|
|
} else {
|
|
disablePeltier();
|
|
}
|
|
} else {
|
|
disablePeltier();
|
|
}
|
|
}
|
|
|
|
void updateLCD() {
|
|
lcd.clear();
|
|
lcd.setCursor(0, 0);
|
|
lcd.print("Target Temp: ");
|
|
lcd.print(targetTemperature, 1);
|
|
lcd.print(" C");
|
|
|
|
lcd.setCursor(0, 1);
|
|
lcd.print("Fridge Temp: ");
|
|
lcd.print(fridgeTemp, 1);
|
|
lcd.print(" C");
|
|
|
|
lcd.setCursor(0, 2);
|
|
lcd.print("Mode: ");
|
|
switch (currentMode) {
|
|
case TIME_MODE:
|
|
lcd.print("Time Mode");
|
|
break;
|
|
case HOLD_MODE:
|
|
lcd.print("Hold Mode");
|
|
break;
|
|
case CURVE_MODE:
|
|
lcd.print("Curve Mode");
|
|
break;
|
|
case OFF:
|
|
lcd.print("Off");
|
|
break;
|
|
}
|
|
}
|
|
|
|
void handleRoot() {
|
|
String html = R"rawliteral(
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>OpenCure</title>
|
|
<link rel="stylesheet" href="/bootstrap.min.css">
|
|
<script src="/jquery.min.js"></script>
|
|
<script src="/bootstrap.min.js"></script>
|
|
<script>
|
|
function setTemperature() {
|
|
var temp = document.getElementById('temperature').value;
|
|
$.get("/setTemperature?temp=" + temp, function(data) {
|
|
alert(data);
|
|
});
|
|
}
|
|
|
|
function setMode(mode) {
|
|
var duration = 0;
|
|
if (mode === 'time' || mode === 'curve') {
|
|
var hours = parseInt(document.getElementById('hours').value);
|
|
var minutes = parseInt(document.getElementById('minutes').value);
|
|
duration = (hours * 60 + minutes) * 60;
|
|
}
|
|
$.get("/setMode?mode=" + mode + "&duration=" + duration, function(data) {
|
|
alert(data);
|
|
});
|
|
}
|
|
</script>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<h1>OpenCure</h1>
|
|
<div class="form-group">
|
|
<label for="temperature">Set Temperature (°C):</label>
|
|
<input type="number" class="form-control" id="temperature" placeholder="Enter temperature">
|
|
<button class="btn btn-primary mt-2" onclick="setTemperature()">Set Temperature</button>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="mode">Select Mode:</label>
|
|
<select class="form-control" id="mode">
|
|
<option value="off">Off</option>
|
|
<option value="time">Time Mode</option>
|
|
<option value="hold">Hold Mode</option>
|
|
<option value="curve">Curve Mode</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group" id="time-settings" style="display: none;">
|
|
<label for="hours">Hours:</label>
|
|
<input type="number" class="form-control" id="hours" placeholder="Enter hours">
|
|
<label for="minutes">Minutes:</label>
|
|
<input type="number" class="form-control" id="minutes" placeholder="Enter minutes">
|
|
</div>
|
|
<button class="btn btn-primary mt-2" onclick="setMode(document.getElementById('mode').value)">Set Mode</button>
|
|
<script>
|
|
document.getElementById('mode').addEventListener('change', function () {
|
|
var mode = this.value;
|
|
if (mode === 'time' || mode === 'curve') {
|
|
document.getElementById('time-settings').style.display = 'block';
|
|
} else {
|
|
document.getElementById('time-settings').style.display = 'none';
|
|
}
|
|
});
|
|
</script>
|
|
</div>
|
|
</body>
|
|
</html>
|
|
)rawliteral";
|
|
|
|
server.send(200, "text/html", html);
|
|
}
|
|
|
|
void handleSetTemperature() {
|
|
if (server.hasArg("temp")) {
|
|
targetTemperature = server.arg("temp").toFloat();
|
|
server.send(200, "text/plain", "Temperature Set");
|
|
} else {
|
|
server.send(400, "text/plain", "Bad Request");
|
|
}
|
|
}
|
|
|
|
void handleSetMode() {
|
|
if (server.hasArg("mode")) {
|
|
String mode = server.arg("mode");
|
|
if (mode == "time") {
|
|
currentMode = TIME_MODE;
|
|
startTime = millis();
|
|
if (server.hasArg("duration")) {
|
|
duration = server.arg("duration").toInt();
|
|
}
|
|
} else if (mode == "hold") {
|
|
currentMode = HOLD_MODE;
|
|
} else if (mode == "curve") {
|
|
currentMode = CURVE_MODE;
|
|
startTime = millis();
|
|
if (server.hasArg("duration")) {
|
|
duration = server.arg("duration").toInt();
|
|
}
|
|
} else {
|
|
currentMode = OFF;
|
|
}
|
|
server.send(200, "text/plain", "Mode Set");
|
|
} else {
|
|
server.send(400, "text/plain", "Bad Request");
|
|
}
|
|
}
|
|
|
|
void serveFile(const char* path, const char* mimeType) {
|
|
File file = SPIFFS.open(path, "r");
|
|
if (file) {
|
|
server.streamFile(file, mimeType);
|
|
file.close();
|
|
} else {
|
|
server.send(404, "text/plain", "File Not Found");
|
|
}
|
|
}
|
|
|