/*
===============================================================================
ESP32 SMART HOME MONITORING โ FIX v2 (No-LEDC, F() safe)
===============================================================================
What changed in v2:
- ๐ ๏ธ Removed LEDC APIs (ledcAttachPin) to avoid core 3.1.1 symbol errors. Implemented
a lightweight software tone() replacement using digitalWrite + delayMicroseconds.
- ๐งน Fixed ambiguous String + F() concatenation by splitting into Serial.print/println.
- ๐ Still using WiFiClientSecure + setInsecure() for HTTPS Discord webhooks.
Drop-in replacement for the previous sketch.
===============================================================================
*/
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <HTTPClient.h>
#include <Wire.h>
#include <DHT.h>
#include <LiquidCrystal_I2C.h>
// ========================================
// ๐ง CONFIGURATION - UPDATE THESE VALUES!
// ========================================
// WiFi Settings (Wokwi)
const char* ssid = "Wokwi-GUEST";
const char* password = ""; // No password needed for Wokwi-GUEST
// ThingSpeak Settings (Optional - for data logging)
const String thingspeak_server = "http://api.thingspeak.com";
const String writeAPIKey = "0N0YBU4OW5PEZG4Z"; // Optional
const String channelID = "3049438"; // Optional
// ๐ข DISCORD WEBHOOK SETTINGS - MUST UPDATE THIS!
// Get from: Discord Channel Settings โ Integrations โ Webhooks
const String discord_webhook = "https://discord.com/api/webhooks/1410184528596832346/050LqUXG2dU-XJ7p7F2JQki1WmEv4F6FUK9oC0Ak4cdjpkA8JDtRK_n0LPq-gdGQZwzq"; // ๐ฅ REPLACE THIS!
// Example: "https://discord.com/api/webhooks/1234567890123456789/abcdefghijklmnopqrstuvwxyz"
// ๐ก๏ธ TEMPERATURE ALERT THRESHOLDS
const float TEMP_ALERT_THRESHOLD = 40.0; // Send Discord alert when temp >= 40ยฐC
const float TEMP_RECOVERY_THRESHOLD = 35.0; // Send recovery alert when temp < 35ยฐC
// ๐ฑ ALERT SETTINGS
const unsigned long DISCORD_COOLDOWN = 300000; // 5 minutes between alerts (anti-spam)
// ========================================
// ๐ HARDWARE PIN DEFINITIONS
// ========================================
#define DHT_PIN 4 // DHT22 data pin
#define DHT_TYPE DHT22 // DHT sensor type
#define PIR_PIN 2 // PIR motion sensor
#define LDR_PIN 34 // LDR light sensor (ADC)
#define LED_RED 18 // Red LED (Emergency)
#define LED_GREEN 19 // Green LED (Normal)
#define LED_YELLOW 5 // Yellow LED (Warning/Activity)
#define BUZZER_PIN 23 // Buzzer for alerts
// ========================================
// ๐ SOFTWARE TONE HELPERS (no LEDC/tone())
// ========================================
void toneESP32(int pin, double freq, int duration_ms = 0) {
if (freq <= 0) return;
pinMode(pin, OUTPUT);
unsigned long half_us = (unsigned long)(500000.0 / freq); // half period in usec
if (half_us == 0) return;
unsigned long cycles = (unsigned long)((duration_ms * 1000.0) / (2.0 * half_us));
for (unsigned long i = 0; i < cycles; i++) {
digitalWrite(pin, HIGH);
delayMicroseconds(half_us);
digitalWrite(pin, LOW);
delayMicroseconds(half_us);
}
}
void noToneESP32(int pin) {
pinMode(pin, OUTPUT);
digitalWrite(pin, LOW);
}
// ========================================
// ๐ GLOBAL OBJECTS & VARIABLES
// ========================================
// Hardware objects
DHT dht(DHT_PIN, DHT_TYPE);
LiquidCrystal_I2C lcd(0x27, 16, 2); // Try 0x3F if 0x27 doesn't work
// Sensor data
float temperature = 0.0;
float humidity = 0.0;
int lightLevel = 0;
bool motionDetected = false;
// System status
bool wifiConnected = false;
bool tempAlertActive = false; // Track if high temp alert is active
int discordAlertsTotal = 0; // Count of Discord alerts sent
int thingspeakDataPoints = 0; // Count of ThingSpeak uploads
// Timing control
unsigned long lastSensorRead = 0;
unsigned long lastDiscordAlert = 0;
unsigned long lastThingSpeakUpdate = 0;
unsigned long lastDisplayUpdate = 0;
unsigned long systemStartTime = 0;
// Update intervals
const unsigned long SENSOR_INTERVAL = 2000; // Read sensors every 2 seconds
const unsigned long DISPLAY_INTERVAL = 1000; // Update LCD every 1 second
const unsigned long THINGSPEAK_INTERVAL = 30000; // Upload to ThingSpeak every 30 seconds
// ========================================
// ๐ MAIN SETUP FUNCTION
// ========================================
void setup() {
Serial.begin(115200);
delay(1000);
systemStartTime = millis();
// Display startup banner
Serial.println("\n===============================================================================" );
Serial.println("๐ ESP32 SMART HOME - DISCORD TEMPERATURE ALERTS");
Serial.println("===============================================================================" );
Serial.println("๐ฏ Alert Trigger: Temperature >= 40ยฐC");
Serial.println("๐ข Notification: Discord Rich Embeds (FREE)");
Serial.println("๐ป Platform: Wokwi + ESP32");
Serial.println("โฑ๏ธ Lab Duration: 2.5 hours");
Serial.println("===============================================================================" );
// Initialize all hardware
initializeHardware();
// Connect to WiFi
connectToWiFi();
// Test Discord webhook if WiFi connected
if (wifiConnected) {
testDiscordWebhook();
}
// Display system ready status
Serial.println("๐ SYSTEM INITIALIZATION COMPLETED!");
Serial.println("๐ Monitoring temperature for alerts >= 40ยฐC");
Serial.print("๐ฑ Discord notifications: ");
Serial.println(wifiConnected ? "ACTIVE" : "OFFLINE");
Serial.println("===============================================================================\n");
// Show ready message on LCD
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("System Ready!");
lcd.setCursor(0, 1);
lcd.print(wifiConnected ? "Discord Active" : "WiFi Failed");
delay(3000);
}
// ========================================
// ๐ MAIN LOOP FUNCTION
// ========================================
void loop() {
unsigned long currentTime = millis();
// Monitor WiFi connection
checkWiFiConnection();
// Read sensors at regular intervals
if (currentTime - lastSensorRead >= SENSOR_INTERVAL) {
readAllSensors();
checkTemperatureAlert();
updateStatusIndicators();
lastSensorRead = currentTime;
}
// Update LCD display
if (currentTime - lastDisplayUpdate >= DISPLAY_INTERVAL) {
updateLCDDisplay();
lastDisplayUpdate = currentTime;
}
// Upload to ThingSpeak (optional)
if (currentTime - lastThingSpeakUpdate >= THINGSPEAK_INTERVAL && wifiConnected) {
uploadToThingSpeak();
lastThingSpeakUpdate = currentTime;
}
// Print status summary every 30 seconds
static unsigned long lastStatusPrint = 0;
if (currentTime - lastStatusPrint >= 30000) {
printSystemStatus();
lastStatusPrint = currentTime;
}
}
// ========================================
// ๐ง HARDWARE INITIALIZATION
// ========================================
void initializeHardware() {
Serial.println("๐ง Initializing hardware components...");
// Initialize DHT22 sensor
dht.begin();
Serial.println(" โ
DHT22 temperature sensor initialized");
// Initialize LCD with I2C
lcd.init();
lcd.backlight();
Serial.println(" โ
I2C LCD display initialized");
// Configure GPIO pins
pinMode(PIR_PIN, INPUT);
pinMode(LED_RED, OUTPUT);
pinMode(LED_GREEN, OUTPUT);
pinMode(LED_YELLOW, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
Serial.println(" โ
GPIO pins configured");
// Display startup message on LCD
lcd.setCursor(0, 0);
lcd.print("ESP32 Smart Home");
lcd.setCursor(0, 1);
lcd.print("Starting up...");
// Test all hardware components
testHardwareComponents();
Serial.println("โ
Hardware initialization completed!");
}
void testHardwareComponents() {
Serial.println("๐งช Testing hardware components...");
// Test LEDs in sequence
digitalWrite(LED_RED, HIGH);
delay(300);
digitalWrite(LED_RED, LOW);
digitalWrite(LED_YELLOW, HIGH);
delay(300);
digitalWrite(LED_YELLOW, LOW);
digitalWrite(LED_GREEN, HIGH);
delay(300);
digitalWrite(LED_GREEN, LOW);
// Test buzzer with ascending tones
toneESP32(BUZZER_PIN, 800, 200);
delay(250);
toneESP32(BUZZER_PIN, 1200, 200);
delay(250);
toneESP32(BUZZER_PIN, 1600, 200);
delay(250);
// Test LCD display
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Hardware Test");
lcd.setCursor(0, 1);
lcd.print("All OK!");
delay(1500);
Serial.println(" โ
All hardware components tested successfully");
}
// ========================================
// ๐ WIFI CONNECTION MANAGEMENT
// ========================================
void connectToWiFi() {
Serial.println("๐ Connecting to WiFi network...");
Serial.print("๐ก SSID: ");
Serial.println(ssid);
// Show connection status on LCD
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("WiFi Connecting");
lcd.setCursor(0, 1);
lcd.print(ssid);
WiFi.begin(ssid, password);
// Wait for connection with timeout
int connectionAttempts = 0;
while (WiFi.status() != WL_CONNECTED && connectionAttempts < 20) {
delay(1000);
Serial.print(".");
// Show progress dots on LCD
if (connectionAttempts < 16) {
lcd.setCursor(connectionAttempts, 1);
lcd.print(".");
}
connectionAttempts++;
}
if (WiFi.status() == WL_CONNECTED) {
wifiConnected = true;
Serial.println();
Serial.println("โ
WiFi connected successfully!");
Serial.print("๐ IP Address: ");
Serial.println(WiFi.localIP());
Serial.print("๐ถ Signal Strength: ");
Serial.print(WiFi.RSSI());
Serial.println(" dBm");
// Display success on LCD
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("WiFi Connected!");
lcd.setCursor(0, 1);
lcd.print(WiFi.localIP());
delay(2000);
// Success feedback
digitalWrite(LED_GREEN, HIGH);
toneESP32(BUZZER_PIN, 1500, 300);
delay(300);
digitalWrite(LED_GREEN, LOW);
} else {
wifiConnected = false;
Serial.println();
Serial.println("โ WiFi connection failed!");
Serial.println(" Discord alerts will be disabled");
Serial.println(" System will continue in offline mode");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("WiFi Failed!");
lcd.setCursor(0, 1);
lcd.print("Offline Mode");
delay(2000);
// Error feedback
for (int i = 0; i < 3; i++) {
digitalWrite(LED_RED, HIGH);
toneESP32(BUZZER_PIN, 400, 200);
delay(300);
digitalWrite(LED_RED, LOW);
delay(200);
}
}
}
void checkWiFiConnection() {
// Monitor WiFi and attempt reconnection if lost
if (wifiConnected && WiFi.status() != WL_CONNECTED) {
wifiConnected = false;
Serial.println("โ ๏ธ WiFi connection lost! Attempting to reconnect...");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("WiFi Lost!");
lcd.setCursor(0, 1);
lcd.print("Reconnecting...");
connectToWiFi();
}
}
// ========================================
// ๐ SENSOR DATA COLLECTION
// ========================================
void readAllSensors() {
// Read temperature and humidity from DHT22
float newTemperature = dht.readTemperature();
float newHumidity = dht.readHumidity();
// Validate DHT22 readings
if (!isnan(newTemperature) && !isnan(newHumidity)) {
temperature = newTemperature;
humidity = newHumidity;
} else {
Serial.println("โ ๏ธ DHT22 sensor read error - using previous values");
// Keep previous values if sensor fails
}
// Read light level from LDR (convert 12-bit ADC to percentage)
int rawLightValue = analogRead(LDR_PIN);
lightLevel = map(rawLightValue, 0, 4095, 0, 100);
// Read motion detection from PIR sensor
motionDetected = digitalRead(PIR_PIN);
// Log motion events
static bool previousMotionState = false;
if (motionDetected && !previousMotionState) {
Serial.println("๐ฅ Motion detected!");
}
previousMotionState = motionDetected;
}
// ========================================
// ๐ข DISCORD WEBHOOK ALERT SYSTEM
// ========================================
String getCurrentISOTimestamp() {
// Simple timestamp for Discord (you can enhance this with NTP)
unsigned long uptimeSeconds = (millis() - systemStartTime) / 1000;
char buf[40];
unsigned long hours = uptimeSeconds / 3600;
unsigned long minutes = (uptimeSeconds % 3600) / 60;
snprintf(buf, sizeof(buf), "2024-12-15T%02lu:%02lu:00.000Z", hours, minutes);
return String(buf);
}
void handleDiscordError(int errorCode) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Discord Error!");
lcd.setCursor(0, 1);
switch(errorCode) {
case 404:
Serial.println("๐ Error 404: Webhook URL not found");
Serial.println(" โ Check your Discord webhook URL");
lcd.print("URL not found");
break;
case 429:
Serial.println("๐ Error 429: Rate limited");
Serial.println(" โ Too many requests, please wait");
lcd.print("Rate limited");
break;
case 400:
Serial.println("๐ Error 400: Bad request");
Serial.println(" โ Check JSON format");
lcd.print("Bad request");
break;
default:
Serial.print("๐ HTTP Error: ");
Serial.println(errorCode);
lcd.print("Code: ");
lcd.print(errorCode);
break;
}
delay(3000);
}
void sendDiscordEmergencyAlert(float temp, float hum) {
Serial.println("๐ข Sending Discord EMERGENCY alert...");
WiFiClientSecure client;
client.setInsecure(); // โ ๏ธ For lab/demo only
HTTPClient http;
http.setTimeout(15000);
if (!http.begin(client, discord_webhook)) {
Serial.println("โ http.begin failed (EMERGENCY)");
return;
}
http.addHeader("Content-Type", "application/json");
// Create rich Discord embed - Red color for emergency
String payload = "{\"embeds\": [{"
"\"title\": \"๐จ CRITICAL TEMPERATURE ALERT ๐จ\","
"\"description\": \"Dangerous temperature levels detected in your smart home system!\","
"\"color\": 15158332," // Red color (#E74C3C)
"\"fields\": ["
"{\"name\": \"๐ก๏ธ Temperature\", \"value\": \"" + String(temp, 1) + "ยฐC\", \"inline\": true},"
"{\"name\": \"๐ง Humidity\", \"value\": \"" + String(hum, 1) + "%\", \"inline\": true},"
"{\"name\": \"โ ๏ธ Alert Level\", \"value\": \"EMERGENCY\", \"inline\": true},"
"{\"name\": \"๐ Location\", \"value\": \"ESP32 Smart Home Lab\", \"inline\": false},"
"{\"name\": \"โฐ System Uptime\", \"value\": \"" + String((millis() - systemStartTime) / 1000) + " seconds\", \"inline\": true},"
"{\"name\": \"๐ก Light Level\", \"value\": \"" + String(lightLevel) + "%\", \"inline\": true},"
"{\"name\": \"๐ถโโ๏ธ Motion\", \"value\": \"" + String(motionDetected ? "Detected" : "None") + "\", \"inline\": true}"
"],"
"\"footer\": {\"text\": \"ESP32 Smart Home System โข Immediate action required!\"},"
"\"timestamp\": \"" + getCurrentISOTimestamp() + "\""
"}}]}";
int httpResponseCode = http.POST(payload);
if (httpResponseCode == 204) {
discordAlertsTotal++;
Serial.println("โ
Discord EMERGENCY alert sent successfully!");
Serial.print("๐ Total Discord alerts sent: ");
Serial.println(discordAlertsTotal);
// Visual feedback
digitalWrite(LED_YELLOW, HIGH);
toneESP32(BUZZER_PIN, 1800, 300);
delay(300);
digitalWrite(LED_YELLOW, LOW);
// Show confirmation on LCD
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Discord Alert!");
lcd.setCursor(0, 1);
lcd.print("EMERGENCY Sent");
delay(2000);
} else {
Serial.println("โ Discord alert failed!");
Serial.print("๐ HTTP Response: ");
Serial.println(httpResponseCode);
handleDiscordError(httpResponseCode);
}
http.end();
}
void sendDiscordRecoveryAlert(float temp, float hum) {
Serial.println("๐ข Sending Discord RECOVERY alert...");
WiFiClientSecure client;
client.setInsecure(); // โ ๏ธ For lab/demo only
HTTPClient http;
http.setTimeout(15000);
if (!http.begin(client, discord_webhook)) {
Serial.println("โ http.begin failed (RECOVERY)");
return;
}
http.addHeader("Content-Type", "application/json");
// Create rich Discord embed - Green color for recovery
String payload = "{\"embeds\": [{"
"\"title\": \"โ
Temperature Recovery Confirmed\","
"\"description\": \"Smart home temperature has returned to safe operating levels.\","
"\"color\": 3066993," // Green color (#2ECC71)
"\"fields\": ["
"{\"name\": \"๐ก๏ธ Current Temperature\", \"value\": \"" + String(temp, 1) + "ยฐC\", \"inline\": true},"
"{\"name\": \"๐ง Humidity\", \"value\": \"" + String(hum, 1) + "%\", \"inline\": true},"
"{\"name\": \"โ
Status\", \"value\": \"NORMAL\", \"inline\": true},"
"{\"name\": \"๐ Location\", \"value\": \"ESP32 Smart Home Lab\", \"inline\": false},"
"{\"name\": \"โฐ Recovery Time\", \"value\": \"" + String((millis() - systemStartTime) / 1000) + " seconds uptime\", \"inline\": true},"
"{\"name\": \"๐ Alert Count\", \"value\": \"" + String(discordAlertsTotal + 1) + " total alerts\", \"inline\": true}"
"],"
"\"footer\": {\"text\": \"ESP32 Smart Home System โข All systems normal\"},"
"\"timestamp\": \"" + getCurrentISOTimestamp() + "\""
"}}]}";
int httpResponseCode = http.POST(payload);
if (httpResponseCode == 204) {
discordAlertsTotal++;
Serial.println("โ
Discord RECOVERY alert sent successfully!");
// Show confirmation on LCD
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Recovery Alert");
lcd.setCursor(0, 1);
lcd.print("Sent to Discord");
delay(2000);
} else {
Serial.println("โ Discord recovery alert failed!");
Serial.print("๐ HTTP Response: ");
Serial.println(httpResponseCode);
}
http.end();
}
void testDiscordWebhook() {
Serial.println("๐งช Testing Discord webhook connection...");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Testing Discord");
lcd.setCursor(0, 1);
lcd.print("Webhook...");
WiFiClientSecure client;
client.setInsecure(); // โ ๏ธ For lab/demo only
HTTPClient http;
http.setTimeout(15000);
if (!http.begin(client, discord_webhook)) {
Serial.println("โ http.begin failed (TEST)");
return;
}
http.addHeader("Content-Type", "application/json");
String testPayload = "{\"embeds\": [{"
"\"title\": \"๐งช Discord Webhook Test\","
"\"description\": \"ESP32 Smart Home system successfully connected to Discord!\","
"\"color\": 3447003," // Blue color
"\"fields\": ["
"{\"name\": \"๐ System\", \"value\": \"ESP32 Smart Home\", \"inline\": true},"
"{\"name\": \"๐ป Platform\", \"value\": \"Wokwi Simulation\", \"inline\": true},"
"{\"name\": \"๐ก Connection\", \"value\": \"Active\", \"inline\": true}"
"],"
"\"footer\": {\"text\": \"Connection test completed successfully\"}"
"}}]}";
int httpResponseCode = http.POST(testPayload);
if (httpResponseCode == 204) {
Serial.println("โ
Discord webhook test successful!");
Serial.println("๐ฑ Check your Discord channel for the test message");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Discord Ready!");
lcd.setCursor(0, 1);
lcd.print("Check channel");
delay(2000);
} else {
Serial.println("โ Discord webhook test failed!");
Serial.print("๐ HTTP Error Code: ");
Serial.println(httpResponseCode);
handleDiscordError(httpResponseCode);
}
http.end();
}
void checkTemperatureAlert() {
// Skip if WiFi not connected
if (!wifiConnected) return;
unsigned long currentTime = millis();
// ๐ฅ HIGH TEMPERATURE ALERT (>= 40ยฐC)
if (temperature >= TEMP_ALERT_THRESHOLD && !tempAlertActive) {
// Check cooldown period
if (currentTime - lastDiscordAlert >= DISCORD_COOLDOWN) {
Serial.println("๐จ CRITICAL TEMPERATURE DETECTED!");
Serial.print("๐ก๏ธ Temperature: ");
Serial.print(temperature, 1);
Serial.println("ยฐC");
sendDiscordEmergencyAlert(temperature, humidity);
tempAlertActive = true;
lastDiscordAlert = currentTime;
// Trigger emergency indicators
triggerEmergencyAlarm();
} else {
// Still in cooldown
unsigned long timeRemaining = (DISCORD_COOLDOWN - (currentTime - lastDiscordAlert)) / 1000;
Serial.print("โฐ Discord alert cooldown: ");
Serial.print(timeRemaining);
Serial.println(" seconds remaining");
}
}
// โ
TEMPERATURE RECOVERY ALERT (< 35ยฐC)
else if (temperature < TEMP_RECOVERY_THRESHOLD && tempAlertActive) {
// Check cooldown period
if (currentTime - lastDiscordAlert >= DISCORD_COOLDOWN) {
Serial.println("โ
Temperature returned to safe levels");
Serial.print("๐ก๏ธ Current temperature: ");
Serial.print(temperature, 1);
Serial.println("ยฐC");
sendDiscordRecoveryAlert(temperature, humidity);
tempAlertActive = false;
lastDiscordAlert = currentTime;
// Success feedback
digitalWrite(LED_GREEN, HIGH);
toneESP32(BUZZER_PIN, 1200, 500);
delay(500);
digitalWrite(LED_GREEN, LOW);
}
}
}
// ========================================
// ๐จ EMERGENCY ALARM & INDICATORS
// ========================================
void triggerEmergencyAlarm() {
Serial.println("๐จ Triggering emergency alarm sequence...");
// Emergency LED and sound pattern
for (int i = 0; i < 5; i++) {
digitalWrite(LED_RED, HIGH);
toneESP32(BUZZER_PIN, 2000, 300);
delay(300);
digitalWrite(LED_RED, LOW);
delay(200);
digitalWrite(LED_RED, HIGH);
toneESP32(BUZZER_PIN, 1000, 300);
delay(300);
digitalWrite(LED_RED, LOW);
delay(500);
}
// Show emergency message on LCD
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("!! EMERGENCY !!");
lcd.setCursor(0, 1);
lcd.print("High Temperature");
delay(3000);
}
void updateStatusIndicators() {
// Control LEDs based on temperature
digitalWrite(LED_RED, LOW);
digitalWrite(LED_GREEN, LOW);
digitalWrite(LED_YELLOW, LOW);
if (temperature >= TEMP_ALERT_THRESHOLD) {
// Emergency: Red LED
digitalWrite(LED_RED, HIGH);
} else if (temperature >= 35.0) {
// Warning: Yellow LED
digitalWrite(LED_YELLOW, HIGH);
} else {
// Normal: Green LED
digitalWrite(LED_GREEN, HIGH);
}
// Motion detection blinking
if (motionDetected) {
static unsigned long lastBlink = 0;
static bool blinkState = false;
if (millis() - lastBlink >= 300) {
blinkState = !blinkState;
digitalWrite(LED_YELLOW, blinkState);
lastBlink = millis();
}
}
}
// ========================================
// ๐บ LCD DISPLAY MANAGEMENT
// ========================================
void updateLCDDisplay() {
lcd.clear();
// Line 1: Temperature and Humidity
lcd.setCursor(0, 0);
lcd.print("T:");
lcd.print(temperature, 1);
lcd.print("C H:");
lcd.print(humidity, 0);
lcd.print("%");
// Line 2: Status and indicators
lcd.setCursor(0, 1);
// Temperature status
if (temperature >= TEMP_ALERT_THRESHOLD) {
lcd.print("CRITICAL!");
} else if (temperature >= 35.0) {
lcd.print("WARNING");
} else {
lcd.print("NORMAL");
}
// Connection indicators
lcd.setCursor(10, 1);
lcd.print(wifiConnected ? "W" : "w"); // WiFi status
lcd.print(tempAlertActive ? "A" : "a"); // Alert status
lcd.print("D"); // Discord indicator
// Alert counter
if (discordAlertsTotal > 0) {
lcd.setCursor(14, 1);
lcd.print(discordAlertsTotal % 100); // Show last 2 digits
}
// Show motion indicator
if (motionDetected) {
lcd.setCursor(13, 0);
lcd.print("M");
}
}
// ========================================
// โ๏ธ THINGSPEAK DATA LOGGING (OPTIONAL)
// ========================================
void uploadToThingSpeak() {
// Skip if no API key provided or WiFi not connected
if (writeAPIKey == "YOUR_THINGSPEAK_WRITE_API_KEY" || !wifiConnected) {
return;
}
Serial.println("โ๏ธ Uploading data to ThingSpeak...");
HTTPClient http;
String url = thingspeak_server + "/update";
url += "?api_key=" + writeAPIKey;
url += "&field1=" + String(temperature);
url += "&field2=" + String(humidity);
url += "&field3=" + String(lightLevel);
url += "&field4=" + String(motionDetected ? 1 : 0);
url += "&field5=" + String(tempAlertActive ? 1 : 0);
http.begin(url);
http.setTimeout(15000);
int httpResponseCode = http.GET();
if (httpResponseCode > 0) {
String response = http.getString();
if (response.toInt() > 0) {
thingspeakDataPoints++;
Serial.println("โ
ThingSpeak upload successful");
}
} else {
Serial.println("โ ThingSpeak upload failed");
}
http.end();
}
// ========================================
// ๐ SYSTEM STATUS & MONITORING
// ========================================
void printSystemStatus() {
unsigned long uptimeSeconds = (millis() - systemStartTime) / 1000;
Serial.println("\n๐ SYSTEM STATUS REPORT");
Serial.println("========================");
Serial.print("โฐ System Uptime: ");
Serial.print(uptimeSeconds);
Serial.println(" seconds");
Serial.print("๐ก๏ธ Temperature: ");
Serial.print(temperature, 1);
Serial.print("ยฐC");
if (temperature >= TEMP_ALERT_THRESHOLD) {
Serial.print(" ๐จ CRITICAL");
} else if (temperature >= 35.0) {
Serial.print(" โ ๏ธ WARNING");
} else {
Serial.print(" โ
NORMAL");
}
Serial.println();
Serial.print("๐ง Humidity: ");
Serial.print(humidity, 1);
Serial.println("%");
Serial.print("๐ก Light Level: ");
Serial.print(lightLevel);
Serial.println("%");
Serial.print("๐ถโโ๏ธ Motion: ");
Serial.println(motionDetected ? "DETECTED" : "None");
Serial.print("๐ถ WiFi Status: ");
Serial.println(wifiConnected ? "Connected" : "Disconnected");
Serial.print("๐ Alert Status: ");
Serial.println(tempAlertActive ? "ACTIVE (Temp > 40ยฐC)" : "Normal");
Serial.print("๐ข Discord Alerts Sent: ");
Serial.println(discordAlertsTotal);
if (thingspeakDataPoints > 0) {
Serial.print("โ๏ธ ThingSpeak Data Points: ");
Serial.println(thingspeakDataPoints);
}
Serial.println("========================\n");
}
// ========================================
// ๐ฏ SYSTEM DIAGNOSTICS & UTILITIES
// ========================================
void runSystemDiagnostics() {
Serial.println("\n๐ RUNNING SYSTEM DIAGNOSTICS");
Serial.println("==============================");
// WiFi diagnostics
Serial.print("๐ก WiFi Connection: ");
if (WiFi.status() == WL_CONNECTED) {
Serial.println("โ
CONNECTED");
Serial.print(" IP Address: ");
Serial.println(WiFi.localIP());
Serial.print(" Signal: ");
Serial.print(WiFi.RSSI());
Serial.println(" dBm");
} else {
Serial.println("โ DISCONNECTED");
}
// Sensor diagnostics
Serial.print("๐ก๏ธ DHT22 Sensor: ");
if (!isnan(temperature) && !isnan(humidity)) {
Serial.println("โ
OPERATIONAL");
Serial.print(" Current readings: ");
Serial.print(temperature, 1);
Serial.print("ยฐC, ");
Serial.print(humidity, 1);
Serial.println("%");
} else {
Serial.println("โ ERROR");
}
Serial.print("๐ก LDR Sensor: โ
OPERATIONAL (");
Serial.print(lightLevel);
Serial.println("%)");
Serial.print("๐ถโโ๏ธ PIR Sensor: โ
OPERATIONAL (");
Serial.print(motionDetected ? "Motion detected" : "No motion");
Serial.println(")");
// Discord webhook status
Serial.print("๐ข Discord Webhook: ");
if (wifiConnected) {
Serial.println("โ
READY");
if (discord_webhook != "YOUR_DISCORD_WEBHOOK_URL") {
Serial.println(" Webhook URL configured");
} else {
Serial.println(" โ ๏ธ Webhook URL not configured");
}
} else {
Serial.println("โ OFFLINE (No WiFi)");
}
// Memory status
Serial.print("๐พ Free Memory: ");
Serial.print(ESP.getFreeHeap());
Serial.println(" bytes");
Serial.println("==============================\n");
}
// ========================================
// ๐ฎ INTERACTIVE COMMANDS (OPTIONAL)
// ========================================
void checkSerialCommands() {
// Check for serial commands for testing
if (Serial.available()) {
String command = Serial.readStringUntil('\n');
command.trim();
command.toLowerCase();
if (command == "test") {
Serial.println("๐งช Running system test...");
testDiscordWebhook();
}
else if (command == "status") {
printSystemStatus();
}
else if (command == "diag") {
runSystemDiagnostics();
}
else if (command == "alert") {
Serial.println("๐งช Testing emergency alert...");
sendDiscordEmergencyAlert(temperature, humidity);
}
else if (command == "help") {
Serial.println("\n๐ Available Commands:");
Serial.println(" test - Test Discord webhook");
Serial.println(" status - Show system status");
Serial.println(" diag - Run diagnostics");
Serial.println(" alert - Test emergency alert");
Serial.println(" help - Show this menu");
Serial.println();
}
}
}