#include <WiFi.h>
#include <WiFiClientSecure.h>
// ReadyMail Configuration
#define ENABLE_SMTP
#include <ReadyMail.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Fonts/FreeSansBold18pt7b.h>
#include <DHT.h>
// --- Pin Definitions ---
#define I2C_SDA 21
#define I2C_SCL 22
#define FLAME_SENSOR_PIN 15
#define GAS_SENSOR_PIN 2
#define DHT_PIN 12
#define DHT_TYPE DHT22
// --- OLED Configuration ---
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define OLED_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
DHT dht(DHT_PIN, DHT_TYPE);
// --- Network & Mail Configuration ---
#define WIFI_SSID "Wokwi-GUEST"
#define WIFI_PASSWORD ""
#define SMTP_HOST "smtp.gmail.com"
#define SMTP_PORT 465
#define AUTHOR_EMAIL "[email protected]"
#define AUTHOR_PASSWORD "viom mfli mpkm fwol"
#define RECIPIENT_EMAIL "[email protected]"
// --- ReadyMail Objects ---
WiFiClientSecure ssl_client;
SMTPClient smtp(ssl_client);
// --- Timing Variables ---
unsigned long lastDisplayUpdate = 0;
const unsigned long displayInterval = 2000;
unsigned long lastEmailSent = 0;
const unsigned long emailCooldown = 60000; // 60s cooldown between emails
bool displayToggle = false;
// Function Prototypes
void send_mail(float temp, float hum, int flame, int gas);
void updateDisplay(float temp, float hum, int flame, int gas);
void showSendingEmailScreen();
void showAlarmScreen(float temp, float hum, int flame, int gas);
void setup() {
Serial.begin(115200);
Wire.begin(I2C_SDA, I2C_SCL);
if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;);
}
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(1);
display.setCursor(0, 10);
display.println(F("System Initializing..."));
display.display();
dht.begin();
pinMode(FLAME_SENSOR_PIN, INPUT_PULLUP);
pinMode(GAS_SENSOR_PIN, INPUT_PULLUP);
// Configure Secure SSL Client
ssl_client.setInsecure(); // Bypass server certificate verification for testing
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
Serial.print("Connecting to Wi-Fi");
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(300);
}
Serial.println("\nConnected with IP: " + WiFi.localIP().toString());
display.clearDisplay();
display.setCursor(0, 10);
display.println(F("WiFi Connected!"));
display.display();
delay(1000);
}
void loop() {
int flameValue = digitalRead(FLAME_SENSOR_PIN);
int gasValue = digitalRead(GAS_SENSOR_PIN);
float humidity = dht.readHumidity();
float temperature = dht.readTemperature();
if (isnan(humidity) || isnan(temperature)) {
Serial.println(F("Failed to read from DHT sensor!"));
return;
}
// Active Low for Flame/Gas Digital Outputs
bool isAlarm = (temperature > 40.0) || (flameValue == LOW) || (gasValue == LOW);
if (isAlarm) {
showAlarmScreen(temperature, humidity, flameValue, gasValue);
if (millis() - lastEmailSent > emailCooldown) {
Serial.println("Alarm condition detected! Sending email via ReadyMail...");
showSendingEmailScreen();
send_mail(temperature, humidity, flameValue, gasValue);
lastEmailSent = millis();
}
} else {
if (millis() - lastDisplayUpdate >= displayInterval) {
lastDisplayUpdate = millis();
displayToggle = !displayToggle;
updateDisplay(temperature, humidity, flameValue, gasValue);
}
}
}
void showSendingEmailScreen() {
display.clearDisplay();
display.setFont();
display.setTextColor(SSD1306_WHITE);
display.fillRect(0, 0, 128, 16, SSD1306_WHITE);
display.setTextColor(SSD1306_BLACK);
display.setTextSize(1);
display.setCursor(12, 4);
display.print(F("CRITICAL ALARM!"));
display.setTextColor(SSD1306_WHITE);
display.setCursor(10, 30);
display.print(F("Sending Alert Email"));
display.setCursor(20, 48);
display.print(F("Please Wait..."));
display.display();
}
void showAlarmScreen(float temp, float hum, int flame, int gas) {
display.clearDisplay();
display.setFont();
display.fillRect(0, 0, 128, 16, SSD1306_WHITE);
display.setTextColor(SSD1306_BLACK);
display.setTextSize(1);
display.setCursor(20, 4);
display.print(F("** ALARM ACTIVE **"));
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 22);
display.printf("Temp : %.1f C %s\n", temp, (temp > 40.0) ? "[OVER]" : "");
display.setCursor(0, 36);
display.printf("Flame: %s\n", (flame == LOW) ? "TRIPPED!" : "OK");
display.setCursor(0, 50);
display.printf("Gas : %s\n", (gas == LOW) ? "TRIPPED!" : "OK");
display.display();
}
void updateDisplay(float temp, float hum, int flame, int gas) {
display.clearDisplay();
if (displayToggle) {
display.setFont();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.print(F("TEMPERATURE"));
display.setFont(&FreeSansBold18pt7b);
display.setCursor(5, 42);
display.printf("%.1f", temp);
display.setFont();
display.setTextSize(1);
display.setCursor(95, 20);
display.print((char)247);
display.print("C");
display.setCursor(0, 54);
display.printf("Humidity: %.1f%%", hum);
} else {
display.setFont();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println(F("--- SENSOR STATUS ---"));
display.setCursor(0, 18);
display.printf("Flame Sensor : %s\n", (flame == LOW) ? "ALARM!" : "OK");
display.setCursor(0, 32);
display.printf("Gas Sensor : %s\n", (gas == LOW) ? "ALARM!" : "OK");
display.setCursor(0, 48);
display.printf("System Temp : %.1f C", temp);
}
display.display();
}
void send_mail(float temp, float hum, int flame, int gas) {
auto statusCallback = [](SMTPStatus status) {
Serial.printf("[ReadyMail] %s\n", status.text.c_str());
};
smtp.connect(SMTP_HOST, SMTP_PORT, statusCallback);
if (!smtp.isConnected()) {
Serial.println("ReadyMail SMTP Connection Failed.");
return;
}
smtp.authenticate(AUTHOR_EMAIL, AUTHOR_PASSWORD, readymail_auth_password);
if (!smtp.isAuthenticated()) {
Serial.println("ReadyMail Authentication Failed.");
return;
}
SMTPMessage msg;
msg.headers.add(rfc822_subject, "CRITICAL ALARM: Hazard Detected!");
msg.headers.add(rfc822_from, "ESP32 Safety System <" + String(AUTHOR_EMAIL) + ">");
msg.headers.add(rfc822_to, "Recipient <" + String(RECIPIENT_EMAIL) + ">");
String bodyText = "CRITICAL ALARM DETECTED!\n\n";
bodyText += "Temperature: " + String(temp, 1) + " C\n";
bodyText += "Humidity: " + String(hum, 1) + " %\n";
bodyText += "Flame Status: " + String((flame == LOW) ? "FIRE DETECTED" : "Normal") + "\n";
bodyText += "Gas Status: " + String((gas == LOW) ? "GAS LEAK DETECTED" : "Normal") + "\n";
msg.text.body(bodyText);
if (smtp.send(msg)) {
Serial.println("Email sent successfully via ReadyMail!");
} else {
Serial.println("Failed to send email via ReadyMail.");
}
}