// #define
#define BLYNK_TEMPLATE_ID "TMPL6B9reJwCp"
#define BLYNK_TEMPLATE_NAME "Sensor Simulation"
#define BLYNK_AUTH_TOKEN "FXtY5tr31-wfF8UCcHpDhHeVCInefJu-"
#define BLYNK_PRINT Serial
// #include
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
#include <time.h>
// ===== BLYNK INTERFACE =====
char auth[] = BLYNK_AUTH_TOKEN;
char ssid[] = "Wokwi-GUEST";
char pass[] = "";
// ===== PIN DEFINITIONS =====
#define RAIN_PIN 34
#define WIND_PIN 35
#define GREEN_LED 12
#define RED_LED 13
#define BUZZER_PIN 25
// ===== LIVE TIME =====
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 8 * 3600;
const int daylightOffset_sec = 0;
// ===== LCD AND BLYNK =====
LiquidCrystal_I2C lcd(0x27, 16, 2);
BlynkTimer timer;
// ===== VARIABLES =====
unsigned long lastDisplayChange = 0;
const unsigned long displayInterval = 5000; // Switch every 5 seconds
bool showSensors = true;
bool alert = false;
bool previousAlert = false;
// ===== SERIAL MONITOR =====
unsigned long lastSerialPrint = 0;
const unsigned long serialInterval = 500; // 0.5 second
// ===== RED LED BLINKING =====
unsigned long previousBlinkMillis = 0;
const long blinkInterval = 200; // Blink every 200ms
bool redLedState = false;
// ===== THRESHOLDS =====
int rainThreshold = 2000;
int windThreshold = 2000;
// ===== ALERT COOLDOWN =====
unsigned long lastAlertTime = 0;
const unsigned long alertCooldown = 5000; // 5 seconds between notifications
// ===== STARTUP ANIMATION =====
void startup() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Weather ");
delay(400);
lcd.print("Monitor");
delay(1000);
lcd.setCursor(0, 1);
lcd.print("Starting.");
delay(300);
lcd.print(".");
delay(100);
lcd.print(".");
delay(100);
lcd.print(".");
delay(100);
lcd.print(".");
delay(100);
lcd.print(".");
delay(100);
lcd.print(".");
delay(100);
lcd.print(".");
delay(100);
lcd.clear();
}
void setup() {
Serial.begin(115200);
// blynk interface
Blynk.begin(auth, ssid, pass);
// send sensor data every 2 seconds
timer.setInterval(2000L, sendData);
pinMode(GREEN_LED, OUTPUT);
pinMode(RED_LED, OUTPUT);
digitalWrite(GREEN_LED, HIGH); // System is online
pinMode(BUZZER_PIN, OUTPUT);
noTone(BUZZER_PIN);
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
lcd.init();
lcd.backlight();
delay(1000);
startup();
}
void loop() {
Blynk.run();
timer.run();
unsigned long currentMillis = millis();
int rainValue = analogRead(RAIN_PIN);
int windValue = analogRead(WIND_PIN);
alert = (rainValue > rainThreshold || windValue > windThreshold);
// clear lcd only when alert state changes
if (alert != previousAlert) {
lcd.clear();
previousAlert = alert;
}
// switch display every 5 seconds when no alert
if (!alert && currentMillis - lastDisplayChange >= displayInterval) {
showSensors = !showSensors;
lastDisplayChange = currentMillis;
lcd.clear();
}
// ===== LCD DISPLAY LOGIC =====
if (alert) {
// blink red led every 200ms
if (currentMillis - previousBlinkMillis >= blinkInterval) {
previousBlinkMillis = currentMillis;
redLedState = !redLedState;
digitalWrite(RED_LED, redLedState ? HIGH : LOW);
}
lcd.setCursor(0, 0);
lcd.print(" !! WARNING !! ");
lcd.setCursor(0, 1);
if (rainValue > rainThreshold && windValue > windThreshold) {
lcd.print(" Storm Ahead! ");
} else if (rainValue > rainThreshold) {
lcd.print(" Rain Incoming ");
} else {
lcd.print(" Strong Winds ");
}
} else {
digitalWrite(RED_LED, LOW);
redLedState = false; // reset state for next alert
if (showSensors) {
lcd.setCursor(0, 0);
lcd.print(" Rain: ");
lcd.print(rainValue);
lcd.print(" mm");
lcd.print(" "); // clear trailing characters
lcd.setCursor(0, 1);
lcd.print(" Wind: ");
lcd.print(windValue);
lcd.print(" m/s");
lcd.print(" ");
} else {
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.print(getCurrentTime());
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.print(getCurrentDate());
}
}
// serial monitor output
unsigned long now = millis();
if (now - lastSerialPrint >= serialInterval) {
lastSerialPrint = now;
Serial.print("Rain: ");
Serial.print(rainValue);
Serial.print(" | Wind: ");
Serial.println(windValue);
}
}
// ===== LIVE DATA =====
void sendData() {
int rainValue = analogRead(RAIN_PIN);
int windValue = analogRead(WIND_PIN);
bool rainAlert = rainValue > rainThreshold;
bool windAlert = windValue > windThreshold;
bool currentAlert = rainAlert || windAlert;
Blynk.virtualWrite(V0, rainValue); // rain sensor value
Blynk.virtualWrite(V1, windValue); // wind sensor value
Blynk.virtualWrite(V2, currentAlert ? 1 : 0); // alert led on blynk
// Send notification + alert cooldown
if (currentAlert && (millis() - lastAlertTime > alertCooldown)) {
Serial.println("ALERT SENT TO BLYNK");
if (rainAlert && windAlert) {
Blynk.logEvent("weather_alert", "Heavy rain and strong wind detected! Seek shelter!");
} else if (rainAlert) {
Blynk.logEvent("rain_alert", "Incoming heavy rainfall! Take precautions!");
} else if (windAlert) {
Blynk.logEvent("wind_alert", "Strong winds detected! Remain calm and stay safe!");
}
buzzer();
lastAlertTime = millis();
}
}
// ===== BUZZER =====
void buzzer() {
tone(BUZZER_PIN, 2000, 100);
delay(150);
tone(BUZZER_PIN, 2000, 100);
delay(150);
tone(BUZZER_PIN, 2000, 100);
// noTone not needed with duration parameter
}
// ===== DISPLAY TIME =====
String getCurrentTime() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
return "--:--:--";
}
char buffer[9];
strftime(buffer, sizeof(buffer), "%H:%M:%S", &timeinfo);
return String(buffer);
}
// ===== DISPLAY DATE =====
String getCurrentDate() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
return "--/--/--";
}
char buffer[12];
strftime(buffer, sizeof(buffer), "%d/%m/%y", &timeinfo);
return String(buffer);
}Rain Sensor
Wind Sensor
VCC
GND
ON
Alert