#include <DHT.h>
#include <PID_v1.h>
// --- PIN DEFINITIONS ---
#define DHT22_1PIN 4 // PID Control Sensor 1
#define DHT22_2PIN 2 // Safety Protection Sensor 2
#define HEATER_CONTROL_PIN 16 // PID control to Heater MOSFET (PWM)
#define HEATER_SAFETY_PIN 17 // Safety protection (on/off depending on temp/humid hihi)
#define DHTTYPE DHT22
// --- EC11 Rotary Encoder Pins ---
// #define ENCODER_A 13 // CLK pin (usually labeled A or CLK)
// #define ENCODER_B 14 // DT pin (usually labeled B or DT)
// #define ENCODER_SW 15 // SW pin (push button)
// --- ROTARY ENCODER SETTINGS ---
// #define SETPOINT_MIN 20.0 // Minimum setpoint (°C)
// #define SETPOINT_MAX 50.0 // Maximum setpoint (°C)
// #define SETPOINT_STEP 0.5 // Step size (°C)
// ### SENSOR SETTINGS ###
// --- SENSOR 1: PID CONTROL SETTIGNS ---
#define DHT22_1SETPOINT 20.0 // FIXED Temperature setpoint
#define DHT22_1HIGH_ALARM 25.0 // Temp: High alarm (alarm only to cloud and phone)
#define DHT22_1LOW_ALARM 15.0 // Temp: Low alarm (alarm only to cloud and phone)
// --- SENSOR 2: SAFETY PROTECTION SETTINGS---
#define DHT22_2TEMP_HIHI 35.0 // Temperature HiHi - CUT OFF heater
#define DHT22_2HUMID_HIHI 70.0 // Humidity HiHi - TURN ON heater
// --- PID Variables ---
double pidSetpoint, pidInput, pidOutput;
// PID Tuning (Aggressive P for heater, Slow I for steady state, Reduce D oscillation time)
double Kp = 20.0, Ki = 5.0, Kd = 1.0;
// --- DIRECT mode: Heater speeds UP when Temp goes UP ---
PID heaterPID(&pidInput, &pidOutput, &pidSetpoint, Kp, Ki, Kd, DIRECT);
// --- Sensor objects with clear names ---
DHT DHT22_1PID(DHT22_1PIN, DHTTYPE); // For PID control
DHT DHT22_2Safety(DHT22_2PIN, DHTTYPE); // For process safety protection
// --- VARIABLES ---
float temp1, humid1; // Sensor 1 readings
float temp2, humid2; // Sensor 2 readings
bool Heater_On = true; // Controls PID heater
bool DHT22_2tempHiHi = false; // Temp > 35°C
bool DHT22_2humidHiHi = false; // Humid > 70%
bool DHT22_1highAlarm = false; // Temp > 25°C
bool DHT22_1lowAlarm = false; // Temp < 15°C
// --- PWM CONFIGURATION FOR GPIO16 ---
const int PIDHEATER_CHANNEL = 0; // Use channel 0 for heater
// --- Timing Variables ---
unsigned long lastPIDTime = 0;
const long pidInterval = 2000; // 2 seconds (matches DHT22 speed)
// --- SETUP FUNCTION ---
void setup() {
Serial.begin(115200);
Serial.println("\n========================================");
Serial.println(" HEATING CONTROL SYSTEM");
Serial.println("========================================");
Serial.println("\nCONFIGURATION:");
Serial.println("----------------------------------------");
Serial.println("DHT22_1 (Sensor 1 PID Control):");
Serial.print(" Setpoint: "); Serial.print(pidSetpoint); Serial.println("°C");
Serial.print(" High Alarm: "); Serial.print(HIGH_ALARM); Serial.println("°C");
Serial.print(" Low Alarm: "); Serial.print(LOW_ALARM); Serial.println("°C");
Serial.println(" Controls: GPIO16 (PWM)");
Serial.println("\nDHT22_2 (Sensor 2 Safety Protection):");
Serial.print(" Temp HiHi: "); Serial.print(TEMP_HIHI); Serial.print("°C → GPIO17 OFF");
Serial.print(" Humid HiHi: "); Serial.print(HUMID_HIHI); Serial.println("% → GPIO17 ON");
Serial.println(" Controls: GPIO17 (ON/OFF)");
Serial.println("----------------------------------------\n");
// --- Initialize sensors ---
DHT22_1.begin();
DHT22_2.begin();
delay(2000);
// --- ESP32 PWM SETUP FOR GPIO16 PID CONTROL HEATER---
// --- SETUP PID CONTROL SIGNAL FOR HEATER (GPI016 - PWM) ---
ledcSetup(PIDHEATER_CHANNEL, 5000, 8); // Channel 0, 5kHz, 8-bit
ledcAttachPin(HEATER_CONTROL_PIN, PIDHEATER_CHANNEL); // Attach GPIO16 to channel 0
ledcWrite(PIDHEATER_CHANNEL, 0); // Start with heater OFF
// --- SETUP SAFETY PROTECTION SIGNAL FOR HEATER (GPIO17 - ON/OFF) ---
pinMode(HEATER_SAFETY_PIN, OUTPUT); // GPIO17 as digital output
digitalWrite(HEATER_SAFETY_PIN, LOW); // Start OFF
// --- SETUP PID controller PARAMETERS ---
heaterPID.SetMode(AUTOMATIC);
heaterPID.SetOutputLimits(0, 255); // Match PWM range
heaterPID.SetSampleTime(1000); // Update every second
Serial.println("System Initialized");
Serial.println("========================================\n");
}
// --- Rotary Encoder Variables ---
//int encoderPos = 0;
//int lastEncoderPos = 0;
//int encoderAState;
//int encoderALastState = LOW;
//unsigned long lastEncoderRead = 0;
//const long ENCODER_DEBOUNCE = 5; // 5ms debounce
//bool encoderButtonPressed = false;
//unsigned long lastButtonPress = 0;
//const long BUTTON_DEBOUNCE = 50;
// --- MAIN LOOP ---
void loop() {
unsigned long currentMillis = millis();
if (currentMillis - lastUpdate >= UPDATE_INTERVAL) {
lastUpdate = currentMillis;
// 1. READ SENSORS
readSensors();
// 2. CHECK SENSOR 2 SAFETY CONDITIONS
checkSafetyConditions();
// 3. CHECK SENSOR 1 ALARMS
checkPIDAlarms();
// 4. CONTROL HEATER
controlHeaters();
// 5. DISPLAY STATUS
displayStatus();
}
}
// --- 1. READ SENSORS ---
void readSensors() {
// Read Sensor 1 (PID control)
temp1 = DHT22_1.readTemperature();
1humid = DHT22_1.readHumidity();
// Read Sensor 2 (Safety protection)
temp2 = DHT22_2.readTemperature();
humid2 = DHT22_2.readHumidity();
// Check for sensor errors
if (isnan(temp1) || isnan(humid1)) {
// check whether a value is invalid
Serial.println("ERROR: Sensor 1 (PID) failed!");
}
if (isnan(temp2) || isnan(humid2)) {
// check whether a value is invalid
Serial.println("ERROR: Sensor 2 (Safety) failed!");
}
}
// --- 2. CHECK SAFETY CONDITIONS (SENSOR 2) ---
void checkSafetyConditions() {
// Reset flags
tempHiHiActive = false;
humidHiHiActive = false;
// Check Temperature HiHi
if (temp2 >= TEMP_HIHI) {
tempHiHiActive = true;
Heater_ON = false; // CUT OFF PID heater
digitalWrite(HEATER_SAFETY_PIN, LOW); // TURN OFF heater for safety purpose
}
// Check Humidity HiHi
if (humid2 >= HUMID_HIHI) {
humidHiHiActive = true;
Heater_ON = true; // TURN ON PID heater
digitalWrite(HEATER_SAFETY_PIN, HIGH); // TURN ON safety heater
}
}
// --- 3. CHECK PID ALARMS (SENSOR 1) ---
void checkPIDAlarms() {
// Reset flags
DHT22_1highAlarm = false;
DHT22_1lowAlarm = false;
if (sDHT22_1temp >= DHT22_1HIGH_ALARM) {
DHT22_1highAlarm = true;
}
if (DHT22_1temp <= DHT22_1LOW_ALARM) {
DHT22_1lowAlarm = true;
}
}
void loop() {
static unsigned long lastUpdate = 0;
if (millis() - lastUpdate >= 1000) {
lastUpdate = millis();
// Read both sensors
float temp1 = sensor1.readTemperature(); // PID sensor
float temp2 = sensor2.readTemperature(); // Safety sensor
float humid2 = sensor2.readHumidity(); // Safety humidity
// --- PROCESS SAFETY LOGIC ---
void processSafetyLogic() {
DHT22_2tempHiHi = false;
DHT22_2humidHiHi = false;
if (DHT22_2temp >= DHT22_2TEMP_HIHI) {
sensor2_tempHiHi = true;
Heater_On = false;
}
if (DHT22_2humid >= DHT22_2HUMID_HIHI) {
DHT22_2humidHiHi = true;
Heater_On = true;
}
}
// --- RUN PID CONTROL ---
void runPIDControl() {
pidInput = DHT22_1temp;
heaterPID.Compute();
int pwmValue = (int)pidOutput;
ledcWrite(heaterChannel, pwmValue);
}