// -------------------- BLYNK CONFIG --------------------
#define BLYNK_TEMPLATE_ID "TMPL3YzmDrt_8"
#define BLYNK_TEMPLATE_NAME "Smart grid ARCopy"
#define BLYNK_AUTH_TOKEN "m39aIsWM_IdyGWwc5-ebED8nrDVpIdtu"
#define BLYNK_SERVER "blynk.cloud"
// -------------------- LIBRARIES ----------------------
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <WiFi.h>
#include <BlynkSimpleEsp32.h>
// -------------------- NETWORK ------------------------
char auth[] = BLYNK_AUTH_TOKEN;
char ssid[] = "Wokwi-GUEST"; // Wokwi simulated WiFi
char pass[] = "";
// -------------------- LCD SETUP ----------------------
LiquidCrystal_I2C lcd(0x27, 16, 2); // Change to 0x3F if not working
// -------------------- PIN MAPPING -------------------
#define VOLTAGE_PIN 36 // ADC1
#define CURRENT_PIN 39 // ADC1
#define LDR_SOLAR_PIN 34 // ADC1
#define WIND_PIN 35 // ADC1
#define HOME_PIN 32 // ADC1
#define INDUSTRY_PIN 33 // ADC1
#define BUTTON_PIN 23 // Digital
#define RED_LED_PIN 12 // PWM
#define GREEN_LED_PIN 13 // PWM
#define BLUE_LED_PIN 14 // PWM
#define OVERLOAD_TOLERANCE 2 // kW margin
// -------------------- VIRTUAL PINS ------------------
#define V_SOLAR V1
#define V_WIND V2
#define V_LOAD V3
#define V_VOLTAGE V4
#define V_CURRENT V5
#define V_ALERT V6
#define V_ADVICE V7
#define V_TRADES V8
// -------------------- GLOBALS -----------------------
unsigned long lastTradeTime = 0;
bool blynkConnected = false;
// -------------------- HELPERS -----------------------
float mapFloat(long x, long in_min, long in_max, long out_min, long out_max) {
return (x - in_min) * (out_max - out_min) / (float)(in_max - in_min) + out_min;
}
String generateSuggestion(bool overload, float industryKW, float solarKW, float windKW, float voltageVal) {
if (overload && industryKW > 7) {
return "Shift 2kW Ind Load";
} else if (solarKW < 2 && windKW > 4) {
return "Use Wind Power Now";
} else if (voltageVal < 210) {
return "Reduce Home Load";
}
return "System Stable ✅";
}
void updateBlynkDashboard(float solarKW, float windKW, float totalLoad,
float voltageVal, float currentVal, bool overload,
String suggestion) {
if (!blynkConnected) return;
Blynk.virtualWrite(V_SOLAR, solarKW);
Blynk.virtualWrite(V_WIND, windKW);
Blynk.virtualWrite(V_LOAD, totalLoad);
Blynk.virtualWrite(V_VOLTAGE, voltageVal);
Blynk.virtualWrite(V_CURRENT, currentVal);
Blynk.virtualWrite(V_ALERT, overload ? "⚠️ OVERLOAD" : "✅ Normal");
Blynk.virtualWrite(V_ADVICE, suggestion);
if (millis() - lastTradeTime > 10000) {
String tradeMsg = "House" + String(random(1,5)) + " sold " +
String(random(1,5)) + "kW";
Blynk.virtualWrite(V_TRADES, tradeMsg);
lastTradeTime = millis();
}
}
void updateLocalDisplay(float totalGen, float totalLoad, bool overload, String suggestion) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("G:");
lcd.print(totalGen, 1);
lcd.print("k L:");
lcd.print(totalLoad, 1);
lcd.print("k");
lcd.setCursor(0, 1);
lcd.print(overload ? "Overload Risk ⚠️" : "Grid Stable ✅ ");
delay(1000);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Advice:");
lcd.setCursor(0, 1);
lcd.print(suggestion.substring(0, 16));
}
void checkDemandResponse(float &industryKW) {
if (digitalRead(BUTTON_PIN) == HIGH) { // Fixed: Added missing parenthesis
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Demand Response!");
lcd.setCursor(0, 1);
lcd.print("Cutting Industry");
industryKW *= 0.5;
if (blynkConnected) {
Blynk.virtualWrite(V_ADVICE, "DR Active");
Blynk.virtualWrite(V_ALERT, "🔵 DR Mode");
}
delay(2000);
}
}
// Blynk connection handler
BLYNK_CONNECTED() {
blynkConnected = true;
lcd.clear();
lcd.print("Blynk Connected!");
delay(1000);
}
// -------------------- SETUP -------------------------
void setup() {
Serial.begin(115200);
Wire.begin();
// Initialize LCD
lcd.init();
lcd.backlight();
lcd.print("Initializing...");
// Initialize pins
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(RED_LED_PIN, OUTPUT);
pinMode(GREEN_LED_PIN, OUTPUT);
pinMode(BLUE_LED_PIN, OUTPUT);
// Connect to WiFi
WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED) {
lcd.setCursor(0, 1);
lcd.print("WiFi...");
delay(500);
}
// Connect to Blynk with timeout
Blynk.config(auth, BLYNK_SERVER, 80);
Blynk.connect(5000); // 5s timeout
if (!Blynk.connected()) {
lcd.clear();
lcd.print("Blynk Failed!");
lcd.setCursor(0, 1);
lcd.print("Using Local Mode");
delay(2000);
}
analogReadResolution(12); // ESP32 12-bit ADC
}
// -------------------- LOOP --------------------------
void loop() {
if (Blynk.connected()) {
Blynk.run();
blynkConnected = true;
} else {
blynkConnected = false;
}
// Read all sensors
float voltageVal = mapFloat(analogRead(VOLTAGE_PIN), 0, 4095, 200, 240);
float currentVal = mapFloat(analogRead(CURRENT_PIN), 0, 4095, 0, 100);
float solarKW = mapFloat(analogRead(LDR_SOLAR_PIN), 0, 4095, 0, 10);
float windKW = mapFloat(analogRead(WIND_PIN), 0, 4095, 0, 8);
float homeKW = mapFloat(analogRead(HOME_PIN), 0, 4095, 1, 5);
float industryKW = mapFloat(analogRead(INDUSTRY_PIN), 0, 4095, 5, 20);
// Print sensor values to Serial Monitor
float totalLoad = homeKW + industryKW;
float totalGen = solarKW + windKW;
bool overload = totalLoad > (totalGen + OVERLOAD_TOLERANCE);
String suggestion = generateSuggestion(overload, industryKW, solarKW, windKW, voltageVal);
// Display on Serial
Serial.println("==== Grid Stats ====");
Serial.printf("Voltage: %.1f V, Current: %.1f A\n", voltageVal, currentVal);
Serial.printf("Solar: %.1f kW, Wind: %.1f kW\n", solarKW, windKW);
Serial.printf("Home: %.1f kW, Industry: %.1f kW\n", homeKW, industryKW);
Serial.printf("Gen: %.1f kW | Load: %.1f kW\n", totalGen, totalLoad);
Serial.println(overload ? "⚠️ OVERLOAD!" : "✅ Load Balanced");
Serial.println("=====================\n");
// Calculate grid status
// Update outputs
updateBlynkDashboard(solarKW, windKW, totalLoad, voltageVal, currentVal, overload, suggestion);
updateLocalDisplay(totalGen, totalLoad, overload, suggestion);
// LED indicators
digitalWrite(RED_LED_PIN, overload);
digitalWrite(GREEN_LED_PIN, !overload);
digitalWrite(BLUE_LED_PIN, digitalRead(BUTTON_PIN));
checkDemandResponse(industryKW);
delay(10000); // Main loop delay
}