#include #include #include #include #include #include #include #include bool isDryingCycleActive = false; float targetTemperature = 0.0; Adafruit_BME280 bme; // I2C unsigned long dryingStartTime; String currentCycle = ""; const int heaterPin = 19; const int frequency = 5000; // 5 kHz const int channel = 0; const int resolution = 8; // 8-bit resolution, so duty cycle values range from 0 to 255 const char* ssid = "DUMDLOUHA"; const char* password = "71772185"; const int ledPin = 2; String ledState; int dryingDuration = 0; unsigned long elapsedTime = 0; // PID control variables double inputTemperature, outputPower, setPointTemperature; double Kp = 2, Ki = 5, Kd = 1; // PID tuning parameters: proportional, integral, and derivative constants PID myPID(&inputTemperature, &outputPower, &setPointTemperature, Kp, Ki, Kd, DIRECT); AsyncWebServer server(80); String readBME280Temperature() { // Read temperature as Celsius (the default) float t = bme.readTemperature(); // Convert temperature to Fahrenheit //t = 1.8 * t + 32; if (isnan(t)) { Serial.println("Failed to read from BME280 sensor!"); return ""; } else { Serial.println(t); return String(t); } } String getActiveDryingCycle() { return currentCycle; } String getElapsedTime() { unsigned long hours = elapsedTime / 3600; unsigned long minutes = (elapsedTime % 3600) / 60; unsigned long seconds = elapsedTime % 60; return String(hours) + ":" + String(minutes) + ":" + String(seconds); } String readBME280Humidity() { float h = bme.readHumidity(); if (isnan(h)) { Serial.println("Failed to read from BME280 sensor!"); return ""; } else { Serial.println(h); return String(h); } } void controlHeater() { if (isDryingCycleActive) { inputTemperature = bme.readTemperature(); setPointTemperature = targetTemperature; myPID.Compute(); int dutyCycle = outputPower; ledcWrite(channel, dutyCycle); } else { ledcWrite(channel, 0); // Turn off the heater when no drying cycle is active } } void setTargetTemperature(float newTargetTemperature) { if (newTargetTemperature >= 0 && newTargetTemperature <= 80) { targetTemperature = newTargetTemperature; Serial.print("New target temperature: "); Serial.println(targetTemperature); } else { Serial.println("Invalid target temperature received"); targetTemperature=0; } } void setDryingCycle(const String &cycle) { currentCycle = cycle; dryingStartTime = millis(); if (cycle == "PLA") { targetTemperature = 45; dryingDuration = 4 * 3600 * 1000; // 4 hours } else if (cycle == "PETG") { targetTemperature = 60; dryingDuration = 4 * 3600 * 1000; // 4 hours } else if (cycle == "NYLON") { targetTemperature = 80; dryingDuration = 8 * 3600 * 1000; // 8 hours } isDryingCycleActive = true; File file = SPIFFS.open("/drying_cycle.txt", "w"); if (file) { file.print("1"); file.close(); } } void stopDryingCycle() { currentCycle = ""; targetTemperature = 0; isDryingCycleActive = false; SPIFFS.remove("/drying_cycle.txt"); } void handleCurrentTemperature(AsyncWebServerRequest *request) { request->send_P(200, "text/plain", readBME280Temperature().c_str()); } void handleCurrentHumidity(AsyncWebServerRequest *request) { request->send_P(200, "text/plain", readBME280Humidity().c_str()); } void setup(){ // Serial port for debugging purposes Serial.begin(115200); if (SPIFFS.exists("/drying_cycle.txt")) { isDryingCycleActive = true; } else { isDryingCycleActive = false; } ledcSetup(channel, frequency, resolution); ledcAttachPin(heaterPin, channel); // Initialize PID controller myPID.SetMode(AUTOMATIC); myPID.SetOutputLimits(0, 255); // Limit the output power (duty cycle) between 0 and 255 myPID.SetSampleTime(1000); // Set the sample time to 1 second (1000 ms) bool status; // default settings status = bme.begin(0x76); if (!status) { Serial.println("Could not find a valid BME280 sensor, check wiring!"); while (1); } // Initialize SPIFFS if(!SPIFFS.begin()){ Serial.println("An Error has occurred while mounting SPIFFS"); return; } // Connect to Wi-Fi WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.println("Connecting to WiFi.."); } // Print ESP32 Local IP Address Serial.println(WiFi.localIP()); // Route for root / web page server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ request->send(SPIFFS, "/index.html"); }); server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){ request->send_P(200, "text/plain", readBME280Temperature().c_str()); }); server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request){ request->send_P(200, "text/plain", readBME280Humidity().c_str()); }); server.on("/set-drying-cycle", HTTP_GET, [](AsyncWebServerRequest *request) { String cycle = request->getParam("cycle")->value(); setDryingCycle(cycle); request->send(200, "text/plain", "Drying cycle set"); }); server.on("/stop-drying-cycle", HTTP_GET, [](AsyncWebServerRequest *request) { stopDryingCycle(); request->send(200, "text/plain", "Drying cycle stopped"); }); server.on("/elapsed-time", HTTP_GET, [](AsyncWebServerRequest *request) { request->send_P(200, "text/plain", getElapsedTime().c_str()); }); server.on("/active-drying-cycle", HTTP_GET, [](AsyncWebServerRequest *request) { request->send_P(200, "text/plain", getActiveDryingCycle().c_str()); }); server.on("/start-drying-cycle", HTTP_GET, [](AsyncWebServerRequest *request) { String cycle = request->getParam("cycle")->value(); setDryingCycle(cycle); request->send(200, "text/plain", "Drying cycle started"); }); server.on("/stop-drying-cycle", HTTP_GET, [](AsyncWebServerRequest *request) { stopDryingCycle(); request->send(200, "text/plain", "Drying cycle stopped"); }); server.on("/start-drying-cycle", HTTP_GET, [](AsyncWebServerRequest *request) { String cycle = request->getParam("cycle")->value(); setDryingCycle(cycle); request->send(200, "text/plain", "Drying cycle started"); }); server.on("/stop-drying-cycle", HTTP_GET, [](AsyncWebServerRequest *request) { stopDryingCycle(); request->send(200, "text/plain", "Drying cycle stopped"); }); server.on("/current-temperature", HTTP_GET, handleCurrentTemperature); server.on("/current-humidity", HTTP_GET, handleCurrentHumidity); // Start server server.begin(); } void loop(){ if (currentCycle != "" && (millis() - dryingStartTime >= dryingDuration)) { currentCycle = ""; targetTemperature = 0; } controlHeater(); if (currentCycle != "") { elapsedTime = (millis() - dryingStartTime) / 1000; } }