/* Medicine Temperature Control - ESP32 + DHT + LCD + SD + RTC
Updated 2025-11-07
Features:
- Fully offline (no Wi-Fi/Blynk)
- DHT, LCD, SD logging, control every 2 seconds
- Relays active HIGH
- Continuous buzzer while fan/heater ON
- Professional SD log format using "|"
*/
#define DHTPIN 4
#define DHTTYPE DHT22 // or DHT11
#define RELAY_FAN 16
#define RELAY_HEATER 17
#define GREEN_LED 26
#define RED_LED 27
#define BUZZER 23
#define SD_CS 5
// Relays are active HIGH
#define RELAY_ACTIVE_HIGH true
#define LCD_I2C_ADDR 0x27
#define UPDATE_INTERVAL_MS 2000UL // 2 seconds
#include <DHT.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <SD.h>
#include <RTClib.h>
DHT dht(DHTPIN, DHTTYPE);
LiquidCrystal_I2C lcd(LCD_I2C_ADDR, 16, 2);
RTC_DS3231 rtc;
float lastTempC = NAN;
float lastHum = NAN;
bool fanOn = false;
bool heaterOn = false;
unsigned long lastUpdate = 0;
void setup() {
Serial.begin(115200);
delay(200);
pinMode(RELAY_FAN, OUTPUT);
pinMode(RELAY_HEATER, OUTPUT);
pinMode(GREEN_LED, OUTPUT);
pinMode(RED_LED, OUTPUT);
pinMode(BUZZER, OUTPUT);
// Initial states
digitalWrite(RELAY_FAN, LOW);
digitalWrite(RELAY_HEATER, LOW);
digitalWrite(GREEN_LED, LOW);
digitalWrite(RED_LED, LOW);
digitalWrite(BUZZER, LOW);
Wire.begin();
lcd.init();
lcd.backlight();
dht.begin();
// --- RTC Setup ---
if (!rtc.begin()) {
Serial.println("RTC not found!");
lcd.setCursor(0, 0);
lcd.print("RTC not found!");
} else if (rtc.lostPower()) {
Serial.println("RTC lost power, setting time...");
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}
// --- SD Setup ---
if (!SD.begin(SD_CS)) {
Serial.println("SD init failed!");
lcd.setCursor(0, 1);
lcd.print("SD init failed!");
} else {
Serial.println("SD initialized.");
}
lcd.clear();
lcd.print("System Ready");
delay(1000);
lcd.clear();
}
void loop() {
unsigned long now = millis();
if (now - lastUpdate >= UPDATE_INTERVAL_MS) {
lastUpdate = now;
updateSystem();
}
}
void updateSystem() {
// --- Read DHT Sensor ---
float t = dht.readTemperature();
if (!isnan(t)) lastTempC = t;
// --- Control Logic ---
if (!isnan(lastTempC)) {
if (lastTempC >= 26.0) { // too warm
fanOn = true;
heaterOn = false;
} else if (lastTempC <= 25.0) {
fanOn = false;
}
if (lastTempC <= 19.0) { // too cold
heaterOn = true;
fanOn = false;
} else if (lastTempC >= 20.0) {
heaterOn = false;
}
if (fanOn && heaterOn) heaterOn = false; // safety
}
// --- Relay Outputs ---
digitalWrite(RELAY_FAN, fanOn ? HIGH : LOW);
digitalWrite(RELAY_HEATER, heaterOn ? HIGH : LOW);
// --- LEDs & Buzzer ---
if (!isnan(lastTempC) && lastTempC >= 20 && lastTempC <= 25) {
digitalWrite(GREEN_LED, HIGH);
} else {
digitalWrite(GREEN_LED, LOW);
}
if (fanOn || heaterOn) {
digitalWrite(RED_LED, HIGH);
digitalWrite(BUZZER, HIGH); // continuous tone
} else {
digitalWrite(RED_LED, LOW);
digitalWrite(BUZZER, LOW);
}
// --- LCD Display ---
lcd.clear();
lcd.setCursor(0, 0);
if (!isnan(lastTempC))
lcd.printf("Temp: %.2f C", lastTempC);
else
lcd.print("Temp: --.- C");
lcd.setCursor(0, 1);
lcd.printf("Fan:%s Heat:%s", fanOn ? "ON " : "OFF", heaterOn ? "ON" : "OFF");
// --- Logging (SD + Serial) ---
DateTime nowTime;
String timestamp;
if (rtc.begin()) {
nowTime = rtc.now();
timestamp = String(nowTime.year()) + "-" + twoDigits(nowTime.month()) + "-" +
twoDigits(nowTime.day()) + " " + twoDigits(nowTime.hour()) + ":" +
twoDigits(nowTime.minute()) + ":" + twoDigits(nowTime.second());
} else {
timestamp = String(millis() / 1000) + "s";
}
String tempStr = isnan(lastTempC) ? "NaN" : String(lastTempC, 2);
String fanStr = fanOn ? "FAN ON" : "FAN OFF";
String heatStr = heaterOn ? "HEATER ON" : "HEATER OFF";
String logLine = timestamp + " | " + tempStr + "°C | " + fanStr + " | " + heatStr + "\n";
// Print to Serial
Serial.print(logLine);
// --- SD Logging ---
if (SD.begin(SD_CS)) {
File logFile = SD.open("/templog.txt", FILE_APPEND);
if (logFile) {
logFile.print(logLine);
logFile.close();
} else {
Serial.println("SD write failed!");
}
} else {
Serial.println("SD not ready.");
}
}
String twoDigits(int v) {
if (v < 10) return "0" + String(v);
return String(v);
}