// ==========================================================
// Advanced Weather Monitoring System
// Sensors: DHT22, BMP180, LDR, RGB LED
// Features: Heat Index, Dew Point, Rainfall, LCD Cycling
// ==========================================================
#define BLYNK_TEMPLATE_ID "TMPL3ZbAatth4"
#define BLYNK_TEMPLATE_NAME "Weather Monitor 2"
#define BLYNK_AUTH_TOKEN "qVt_e_EASmxp6Fzk8Lu0JoKK7MO9nZmG"
#include <WiFi.h>
#include <BlynkSimpleEsp32.h>
#include <DHT.h>
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <Adafruit_BMP085.h>
// --- Pin Definitions ---
#define DHTPIN 15
#define DHTTYPE DHT22
#define LDR_PIN 34
#define LED_R 25
#define LED_G 26
#define LED_B 27
#define LCD_ADDRESS 0x27
#define LCD_COLUMNS 16
#define LCD_ROWS 2
// --- Timing ---
#define SENSOR_READ_INTERVAL 2000
#define LCD_PAGE_INTERVAL 5000
// --- LDR Constants ---
#define LDR_RL10 50
#define LDR_GAMMA 0.7
// --- Simple Weather Data Structure ---
struct WeatherData {
float temperature;
float humidity;
float pressure;
float dewPoint; // Replaces altitude
float rainAmount; // Simulated rainfall in mm
float lightLux;
float heatIndex;
bool validDHT;
bool validBMP;
bool validLDR;
};
// --- Global Objects ---
DHT dht(DHTPIN, DHTTYPE);
Adafruit_BMP085 bmp;
LiquidCrystal_I2C lcd(LCD_ADDRESS, LCD_COLUMNS, LCD_ROWS);
// --- RTOS Objects ---
QueueHandle_t weatherQueue = NULL;
SemaphoreHandle_t lcdMutex = NULL;
// --- Status ---
bool wifiConnected = false;
bool blynkConnected = false;
// ==========================================================
// Heat Index Calculation (NOAA formula)
// ==========================================================
float calculateHeatIndex(float tempC, float humidity) {
float tempF = tempC * 9.0 / 5.0 + 32.0;
if (tempF < 80.0) return tempC;
float hi = -42.379 + 2.04901523 * tempF + 10.14333127 * humidity
- 0.22475541 * tempF * humidity - 0.00683783 * tempF * tempF
- 0.05481717 * humidity * humidity + 0.00122874 * tempF * tempF * humidity
+ 0.00085282 * tempF * humidity * humidity
- 0.00000199 * tempF * tempF * humidity * humidity;
if (humidity < 13 && tempF >= 80 && tempF <= 112) {
hi -= ((13 - humidity) / 4) * sqrt((17 - abs(tempF - 95)) / 17);
}
if (humidity > 85 && tempF >= 80 && tempF <= 87) {
hi += ((humidity - 85) / 10) * ((87 - tempF) / 5);
}
return (hi - 32.0) * 5.0 / 9.0;
}
// ==========================================================
// Dew Point Calculation (Magnus formula)
// ==========================================================
float calculateDewPoint(float tempC, float humidity) {
float a = 17.27;
float b = 237.7;
float alpha = ((a * tempC) / (b + tempC)) + log(humidity / 100.0);
return (b * alpha) / (a - alpha);
}
// ==========================================================
// LDR Reading (Lux calculation)
// ==========================================================
float readLux() {
int analogValue = analogRead(LDR_PIN);
float voltage = analogValue / 1024.0 * 5.0;
float resistance = 2000.0 * voltage / (1.0 - voltage / 5.0);
return pow(LDR_RL10 * 1e3 * pow(10, LDR_GAMMA) / resistance, (1.0 / LDR_GAMMA));
}
// ==========================================================
// RGB LED Update (System Status Indicator)
// ==========================================================
void updateLED() {
if (!wifiConnected) {
// Red: No WiFi
digitalWrite(LED_R, LOW);
digitalWrite(LED_G, HIGH);
digitalWrite(LED_B, HIGH);
} else if (!blynkConnected) {
// Yellow: No Blynk
digitalWrite(LED_R, LOW);
digitalWrite(LED_G, LOW);
digitalWrite(LED_B, HIGH);
} else {
// Green: All systems go
digitalWrite(LED_R, HIGH);
digitalWrite(LED_G, LOW);
digitalWrite(LED_B, HIGH);
}
}
// ==========================================================
// Task 1: Sensor Reading
// ==========================================================
void vTaskReadSensor(void *pvParameters) {
WeatherData data;
TickType_t xLastWakeTime = xTaskGetTickCount();
const TickType_t xFrequency = pdMS_TO_TICKS(SENSOR_READ_INTERVAL);
for (;;) {
// --- Read DHT22 ---
float h = dht.readHumidity();
float t = dht.readTemperature();
if (!isnan(h) && !isnan(t) && h >= 0 && h <= 100 && t >= -40 && t <= 80) {
data.humidity = h;
data.temperature = t;
data.validDHT = true;
data.heatIndex = calculateHeatIndex(t, h);
data.dewPoint = calculateDewPoint(t, h);
} else {
data.validDHT = false;
data.dewPoint = 0;
data.heatIndex = 0;
}
// --- Read BMP180 ---
float p = bmp.readPressure() / 100.0;
if (p > 300 && p < 1100) {
data.pressure = p;
data.validBMP = true;
} else {
data.validBMP = false;
}
// --- Simulate Rainfall (based on humidity & pressure) ---
if (data.validDHT && data.validBMP) {
// Humidity factor: 0 to 1 (50-100% humidity)
float humidityFactor = (data.humidity - 50.0) / 50.0;
if (humidityFactor < 0) humidityFactor = 0;
if (humidityFactor > 1) humidityFactor = 1;
// Pressure factor: lower pressure = more rain
float pressureFactor = (1020.0 - data.pressure) / 50.0;
if (pressureFactor < 0) pressureFactor = 0;
if (pressureFactor > 1) pressureFactor = 1;
// Rain amount (0-10mm scale)
data.rainAmount = humidityFactor * pressureFactor * 10.0;
} else {
data.rainAmount = 0;
}
// --- Read LDR ---
float lux = readLux();
data.lightLux = lux;
data.validLDR = (lux >= 0);
// --- Send to Queue ---
if (weatherQueue != NULL) {
WeatherData dummy;
xQueueReceive(weatherQueue, &dummy, 0);
xQueueSend(weatherQueue, &data, 0);
}
// --- Serial Output ---
Serial.printf("T:%.1f H:%.1f P:%.1f DP:%.1f Rain:%.1f L:%.0f\n",
t, h, p, data.dewPoint, data.rainAmount, lux);
vTaskDelayUntil(&xLastWakeTime, xFrequency);
}
}
// ==========================================================
// Task 2: Blynk & LCD Update
// ==========================================================
void vTaskBlynkUpdate(void *pvParameters) {
WeatherData data;
uint8_t lcdPage = 0;
unsigned long lastPageSwitch = 0;
for (;;) {
Blynk.run();
if (xQueueReceive(weatherQueue, &data, pdMS_TO_TICKS(100)) == pdPASS) {
// --- Send to Blynk ---
if (blynkConnected) {
if (data.validDHT) {
Blynk.virtualWrite(V0, data.temperature);
Blynk.virtualWrite(V1, data.humidity);
Blynk.virtualWrite(V3, data.dewPoint); // V3: Dew Point
Blynk.virtualWrite(V5, data.heatIndex);
}
if (data.validBMP) {
Blynk.virtualWrite(V2, data.pressure);
}
Blynk.virtualWrite(V8, data.rainAmount); // V8: Rainfall
if (data.validLDR) {
Blynk.virtualWrite(V4, data.lightLux);
}
}
// --- Update LED ---
updateLED();
// --- Cycle LCD Pages ---
if (millis() - lastPageSwitch > LCD_PAGE_INTERVAL) {
lcdPage = (lcdPage + 1) % 2;
lastPageSwitch = millis();
}
// --- Update LCD ---
if (xSemaphoreTake(lcdMutex, pdMS_TO_TICKS(50)) == pdTRUE) {
lcd.clear();
if (lcdPage == 0) {
// Page 0: Temperature, Heat Index & Humidity
lcd.setCursor(0, 0);
if (data.validDHT) {
lcd.printf("T:%.1fC HI:%.1f", data.temperature, data.heatIndex);
} else {
lcd.print("DHT Error");
}
lcd.setCursor(0, 1);
if (data.validDHT) {
lcd.printf("H:%.1f%% DP:%.1fC", data.humidity, data.dewPoint);
}
} else {
// Page 1: Pressure, Rain & Light
lcd.setCursor(0, 0);
if (data.validBMP) {
lcd.printf("P:%.0fhPa Rain:%.1f", data.pressure, data.rainAmount);
} else {
lcd.print("BMP Error");
}
lcd.setCursor(0, 1);
if (data.lightLux > 10000) {
lcd.printf("Full Sun %.0f", data.lightLux);
} else if (data.lightLux > 2000) {
lcd.printf("Daylight %.0f", data.lightLux);
} else if (data.lightLux > 500) {
lcd.printf("Overcast %.0f", data.lightLux);
} else if (data.lightLux > 100) {
lcd.printf("Twilight %.0f", data.lightLux);
} else if (data.lightLux > 10) {
lcd.printf("Moonlight %.0f", data.lightLux);
} else {
lcd.printf("Dark %.0f", data.lightLux);
}
}
xSemaphoreGive(lcdMutex);
}
}
// --- Update Status ---
wifiConnected = (WiFi.status() == WL_CONNECTED);
blynkConnected = Blynk.connected();
vTaskDelay(pdMS_TO_TICKS(10));
}
}
// ==========================================================
// Setup
// ==========================================================
void setup() {
Serial.begin(115200);
delay(2000);
Serial.println("\n=== WEATHER STATION ===");
// --- Pins ---
pinMode(LED_R, OUTPUT);
pinMode(LED_G, OUTPUT);
pinMode(LED_B, OUTPUT);
digitalWrite(LED_R, HIGH);
digitalWrite(LED_G, HIGH);
digitalWrite(LED_B, HIGH);
// --- I2C ---
Wire.begin(21, 22);
delay(100);
// --- DHT22 ---
dht.begin();
Serial.println("DHT22 OK");
// --- BMP180 ---
if (bmp.begin()) {
Serial.println("BMP180 OK");
} else {
Serial.println("BMP180 FAIL");
}
// --- LCD ---
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Booting...");
Serial.println("LCD OK");
// --- RTOS ---
weatherQueue = xQueueCreate(3, sizeof(WeatherData));
lcdMutex = xSemaphoreCreateMutex();
Serial.println("RTOS OK");
// --- WiFi ---
Serial.print("WiFi: ");
WiFi.begin("Wokwi-GUEST", "");
for (int i = 0; i < 30; i++) {
if (WiFi.status() == WL_CONNECTED) break;
delay(500);
Serial.print(".");
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println(" OK");
wifiConnected = true;
} else {
Serial.println(" FAIL");
}
// --- Blynk ---
if (wifiConnected) {
Blynk.config(BLYNK_AUTH_TOKEN);
Serial.print("Blynk: ");
if (Blynk.connect(5000)) {
Serial.println("OK");
blynkConnected = true;
} else {
Serial.println("FAIL");
}
}
// --- Tasks ---
xTaskCreatePinnedToCore(vTaskReadSensor, "Sensor", 4096, NULL, 2, NULL, 0);
xTaskCreatePinnedToCore(vTaskBlynkUpdate, "BlynkLCD", 8192, NULL, 1, NULL, 1);
// --- Ready ---
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Ready!");
digitalWrite(LED_R, HIGH);
digitalWrite(LED_G, LOW);
digitalWrite(LED_B, HIGH);
Serial.println("=== READY ===\n");
}
// ==========================================================
// Loop
// ==========================================================
void loop() {
vTaskDelay(pdMS_TO_TICKS(5000));
}Loading
bmp180
bmp180