Track real-time power consumption of household appliances and optimize energy usage.
Key Features
- Real-time power monitoring
- Energy consumption analytics
- Cost calculation
- Historical data logging
- Overload protection alerts
Components Required
Diagram.json:
{
"version": 1,
"author": "ESP32 Energy Monitoring System",
"editor": "wokwi",
"parts": [
{
"type": "wokwi-esp32-devkit-v1",
"id": "esp",
"top": 0,
"left": 0,
"attrs": {}
},
{
"type": "wokwi-potentiometer",
"id": "voltage",
"top": -67.2,
"left": 268.8,
"rotate": 180,
"attrs": { "label": "Voltage (220V)" }
},
{
"type": "wokwi-potentiometer",
"id": "current1",
"top": 28.8,
"left": 268.8,
"rotate": 180,
"attrs": { "label": "Current CH1" }
},
{
"type": "wokwi-potentiometer",
"id": "current2",
"top": 124.8,
"left": 268.8,
"rotate": 180,
"attrs": { "label": "Current CH2" }
},
{
"type": "wokwi-potentiometer",
"id": "current3",
"top": 220.8,
"left": 268.8,
"rotate": 180,
"attrs": { "label": "Current CH3" }
},
{
"type": "wokwi-led",
"id": "relay1",
"top": -124.8,
"left": 441.6,
"attrs": { "color": "green", "lightColor": "green", "label": "Living Room" }
},
{
"type": "wokwi-resistor",
"id": "r1",
"top": -67.2,
"left": 441.6,
"rotate": 90,
"attrs": { "value": "220" }
},
{
"type": "wokwi-led",
"id": "relay2",
"top": -124.8,
"left": 518.4,
"attrs": { "color": "blue", "lightColor": "blue", "label": "Kitchen" }
},
{
"type": "wokwi-resistor",
"id": "r2",
"top": -67.2,
"left": 518.4,
"rotate": 90,
"attrs": { "value": "220" }
},
{
"type": "wokwi-led",
"id": "relay3",
"top": -124.8,
"left": 595.2,
"attrs": { "color": "yellow", "lightColor": "yellow", "label": "Bedroom" }
},
{
"type": "wokwi-resistor",
"id": "r3",
"top": -67.2,
"left": 595.2,
"rotate": 90,
"attrs": { "value": "220" }
},
{
"type": "wokwi-led",
"id": "power_led",
"top": 38.4,
"left": 441.6,
"attrs": { "color": "white", "lightColor": "white", "label": "Power" }
},
{
"type": "wokwi-resistor",
"id": "r4",
"top": 96,
"left": 441.6,
"rotate": 90,
"attrs": { "value": "220" }
},
{
"type": "wokwi-led",
"id": "alert_led",
"top": 38.4,
"left": 518.4,
"attrs": { "color": "red", "lightColor": "red", "label": "Alert" }
},
{
"type": "wokwi-resistor",
"id": "r5",
"top": 96,
"left": 518.4,
"rotate": 90,
"attrs": { "value": "220" }
},
{
"type": "wokwi-buzzer",
"id": "bz1",
"top": 172.8,
"left": 489.6,
"attrs": { "volume": "0.3" }
},
{
"type": "wokwi-ssd1306",
"id": "oled1",
"top": 326.4,
"left": 268.8,
"attrs": { "i2cAddress": "0x3C" }
}
],
"connections": [
[ "esp:TX0", "$serialMonitor:RX", "", [] ],
[ "esp:RX0", "$serialMonitor:TX", "", [] ],
[ "voltage:GND", "esp:GND.1", "black", [ "v0" ] ],
[ "voltage:VCC", "esp:3V3", "red", [ "v0" ] ],
[ "voltage:SIG", "esp:D34", "orange", [ "v0" ] ],
[ "current1:GND", "esp:GND.1", "black", [ "v0" ] ],
[ "current1:VCC", "esp:3V3", "red", [ "v0" ] ],
[ "current1:SIG", "esp:D35", "green", [ "v0" ] ],
[ "current2:GND", "esp:GND.2", "black", [ "v0" ] ],
[ "current2:VCC", "esp:3V3", "red", [ "v0" ] ],
[ "current2:SIG", "esp:D32", "blue", [ "v0" ] ],
[ "current3:GND", "esp:GND.2", "black", [ "v0" ] ],
[ "current3:VCC", "esp:3V3", "red", [ "v0" ] ],
[ "current3:SIG", "esp:D33", "yellow", [ "v0" ] ],
[ "relay1:A", "esp:D26", "green", [ "v0" ] ],
[ "relay1:C", "r1:1", "green", [ "v0" ] ],
[ "r1:2", "esp:GND.1", "black", [ "v0" ] ],
[ "relay2:A", "esp:D27", "blue", [ "v0" ] ],
[ "relay2:C", "r2:1", "blue", [ "v0" ] ],
[ "r2:2", "esp:GND.1", "black", [ "v0" ] ],
[ "relay3:A", "esp:D14", "yellow", [ "v0" ] ],
[ "relay3:C", "r3:1", "yellow", [ "v0" ] ],
[ "r3:2", "esp:GND.1", "black", [ "v0" ] ],
[ "power_led:A", "esp:D13", "white", [ "v0" ] ],
[ "power_led:C", "r4:1", "white", [ "v0" ] ],
[ "r4:2", "esp:GND.2", "black", [ "v0" ] ],
[ "alert_led:A", "esp:D12", "red", [ "v0" ] ],
[ "alert_led:C", "r5:1", "red", [ "v0" ] ],
[ "r5:2", "esp:GND.2", "black", [ "v0" ] ],
[ "bz1:1", "esp:D25", "purple", [ "v0" ] ],
[ "bz1:2", "esp:GND.2", "black", [ "v0" ] ],
[ "oled1:VCC", "esp:3V3", "red", [ "h0" ] ],
[ "oled1:GND", "esp:GND.2", "black", [ "h0" ] ],
[ "oled1:SDA", "esp:D21", "blue", [ "h0" ] ],
[ "oled1:SCL", "esp:D22", "yellow", [ "h0" ] ]
],
"dependencies": {}
}
- ESP32 Board
- PZEM-004T Energy Meter
- CT Sensor (Current Transformer)
- OLED Display
- Cloud platform (Blynk/ThingSpeak)
Applications
- Home energy management
- Industrial monitoring
- Solar panel tracking
- Smart metering
Difficulty Level
Intermediate
Amazing Features:
Multi-Channel Monitoring (3 Channels):
- Living Room - Green LED indicator
- Kitchen - Blue LED indicator
- Bedroom - Yellow LED indicator
Real-Time Measurements:
- Voltage - Monitor AC line voltage (0-250V)
- Current - Track amperage per channel (0-20A)
- Power - Calculate watts (P = V × I × PF)
- Energy - Cumulative kWh consumption
- Cost - Automatic billing at $0.12/kWh
Smart Features:
- Beautiful Web Dashboard - Dark theme, auto-refresh
- Real-Time Charts - Power history tracking
- Alert System - High power warnings
- OLED Display - Local monitoring
- Remote Control - Turn channels ON/OFF
Code:
/*
* IoT Energy Monitoring System
*
* Features:
* - Real-time voltage and current monitoring
* - Power consumption calculation (Watts)
* - Energy usage tracking (kWh)
* - Cost calculation with configurable rates
* - Multiple appliance monitoring (4 channels)
* - OLED display for live readings
* - Web dashboard with charts
* - Power quality monitoring
* - Alerts for high consumption
* - Daily/monthly usage reports
* - Energy saving recommendations
* - Peak/off-peak rate support
*/
#include <WiFi.h>
#include <WebServer.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// WiFi Credentials
const char* ssid = "Wokwi-GUEST";
const char* password = "";
// Web Server
WebServer server(80);
// Pin Definitions
#define VOLTAGE_SENSOR_PIN 34 // Voltage sensor (simulated with potentiometer)
#define CURRENT_CH1_PIN 35 // Current sensor Channel 1 - Living Room
#define CURRENT_CH2_PIN 32 // Current sensor Channel 2 - Kitchen
#define CURRENT_CH3_PIN 33 // Current sensor Channel 3 - Bedroom
#define RELAY_CH1_PIN 26 // Relay control Channel 1
#define RELAY_CH2_PIN 27 // Relay control Channel 2
#define RELAY_CH3_PIN 14 // Relay control Channel 3
#define BUZZER_PIN 25 // Alert buzzer
#define LED_POWER_PIN 13 // Power indicator LED
#define LED_ALERT_PIN 12 // Alert LED
// OLED Display
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Energy Monitoring Configuration
#define VOLTAGE_CALIBRATION 1.0
#define CURRENT_CALIBRATION 1.0
#define POWER_FACTOR 0.95
#define COST_PER_KWH 0.12 // $/kWh (configurable)
// Alert Thresholds
#define MAX_POWER_WATTS 3000
#define HIGH_POWER_WARNING 2000
#define MAX_CURRENT_AMPS 15
// Channel Structure
struct EnergyChannel {
String name;
float voltage;
float current;
float power;
float energy; // kWh
float cost; // $
bool relayState;
unsigned long lastUpdate;
float peakPower;
int alertCount;
};
EnergyChannel channels[3];
// System State
struct SystemState {
float totalPower; // Total watts
float totalEnergy; // Total kWh
float totalCost; // Total $
float averagePower;
unsigned long startTime;
unsigned long lastReset;
int displayMode; // 0=Overview, 1=Channel1, 2=Channel2, 3=Channel3
bool alertActive;
float costPerKWh;
};
SystemState energySystem;
// Historical Data (for graphing)
#define MAX_HISTORY 50
float powerHistory[MAX_HISTORY];
int historyIndex = 0;
// Timing
unsigned long lastSensorRead = 0;
unsigned long lastDisplayUpdate = 0;
unsigned long lastCostUpdate = 0;
const long sensorInterval = 1000; // Read every 1 second
const long displayInterval = 500;
const long costUpdateInterval = 60000; // Update cost every minute
void setup() {
Serial.begin(115200);
// Initialize pins
pinMode(RELAY_CH1_PIN, OUTPUT);
pinMode(RELAY_CH2_PIN, OUTPUT);
pinMode(RELAY_CH3_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(LED_POWER_PIN, OUTPUT);
pinMode(LED_ALERT_PIN, OUTPUT);
pinMode(VOLTAGE_SENSOR_PIN, INPUT);
pinMode(CURRENT_CH1_PIN, INPUT);
pinMode(CURRENT_CH2_PIN, INPUT);
pinMode(CURRENT_CH3_PIN, INPUT);
// Initialize channels
channels[0].name = "Living Room";
channels[1].name = "Kitchen";
channels[2].name = "Bedroom";
for (int i = 0; i < 3; i++) {
channels[i].voltage = 0;
channels[i].current = 0;
channels[i].power = 0;
channels[i].energy = 0;
channels[i].cost = 0;
channels[i].relayState = true;
channels[i].lastUpdate = millis();
channels[i].peakPower = 0;
channels[i].alertCount = 0;
// Turn on all relays initially
digitalWrite(RELAY_CH1_PIN + i, HIGH);
}
// Initialize system
energySystem.totalPower = 0;
energySystem.totalEnergy = 0;
energySystem.totalCost = 0;
energySystem.averagePower = 0;
energySystem.startTime = millis();
energySystem.lastReset = millis();
energySystem.displayMode = 0;
energySystem.alertActive = false;
energySystem.costPerKWh = COST_PER_KWH;
// Initialize OLED
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("OLED failed"));
} else {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("ENERGY MONITOR");
display.println("");
display.println("Initializing...");
display.display();
delay(2000);
}
// Connect to WiFi
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi");
display.clearDisplay();
display.setCursor(0, 0);
display.println("Connecting WiFi...");
display.display();
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\n✓ WiFi connected!");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
// Setup web server routes
server.on("/", handleRoot);
server.on("/status", handleStatus);
server.on("/history", handleHistory);
server.on("/reset", handleReset);
server.on("/relay1/on", []() { controlRelay(0, true); });
server.on("/relay1/off", []() { controlRelay(0, false); });
server.on("/relay2/on", []() { controlRelay(1, true); });
server.on("/relay2/off", []() { controlRelay(1, false); });
server.on("/relay3/on", []() { controlRelay(2, true); });
server.on("/relay3/off", []() { controlRelay(2, false); });
server.begin();
Serial.println("✓ Web server started!");
Serial.println("\n╔════════════════════════════════════╗");
Serial.println("║ ENERGY MONITORING SYSTEM ONLINE ║");
Serial.println("╚════════════════════════════════════╝");
Serial.print("Dashboard: http://");
Serial.println(WiFi.localIP());
Serial.println();
// Power on indicator
digitalWrite(LED_POWER_PIN, HIGH);
tone(BUZZER_PIN, 1000, 100);
delay(150);
tone(BUZZER_PIN, 1500, 100);
updateDisplay();
}
void loop() {
server.handleClient();
unsigned long currentMillis = millis();
// Read sensors
if (currentMillis - lastSensorRead >= sensorInterval) {
lastSensorRead = currentMillis;
readSensors();
calculatePower();
checkAlerts();
}
// Update display
if (currentMillis - lastDisplayUpdate >= displayInterval) {
lastDisplayUpdate = currentMillis;
updateDisplay();
}
// Update energy cost
if (currentMillis - lastCostUpdate >= costUpdateInterval) {
lastCostUpdate = currentMillis;
updateEnergyCost();
}
}
void readSensors() {
// Read voltage (simulated - typically 220V AC)
int voltageRaw = analogRead(VOLTAGE_SENSOR_PIN);
float voltage = map(voltageRaw, 0, 4095, 0, 250) * VOLTAGE_CALIBRATION;
// Read current for each channel
int currentRaw1 = analogRead(CURRENT_CH1_PIN);
int currentRaw2 = analogRead(CURRENT_CH2_PIN);
int currentRaw3 = analogRead(CURRENT_CH3_PIN);
channels[0].current = map(currentRaw1, 0, 4095, 0, 20) * CURRENT_CALIBRATION;
channels[1].current = map(currentRaw2, 0, 4095, 0, 20) * CURRENT_CALIBRATION;
channels[2].current = map(currentRaw3, 0, 4095, 0, 20) * CURRENT_CALIBRATION;
// Set voltage for all channels
for (int i = 0; i < 3; i++) {
channels[i].voltage = voltage;
// If relay is off, current should be zero
if (!channels[i].relayState) {
channels[i].current = 0;
}
}
}
void calculatePower() {
energySystem.totalPower = 0;
for (int i = 0; i < 3; i++) {
// Calculate power (P = V * I * PF)
channels[i].power = channels[i].voltage * channels[i].current * POWER_FACTOR;
// Update peak power
if (channels[i].power > channels[i].peakPower) {
channels[i].peakPower = channels[i].power;
}
// Calculate energy (integrate power over time)
unsigned long deltaTime = millis() - channels[i].lastUpdate;
float hours = deltaTime / 3600000.0; // Convert ms to hours
channels[i].energy += (channels[i].power / 1000.0) * hours; // kWh
channels[i].lastUpdate = millis();
// Calculate cost
channels[i].cost = channels[i].energy * energySystem.costPerKWh;
// Add to total
energySystem.totalPower += channels[i].power;
}
// Calculate total energy
energySystem.totalEnergy = channels[0].energy + channels[1].energy + channels[2].energy;
energySystem.totalCost = energySystem.totalEnergy * energySystem.costPerKWh;
// Store in history
powerHistory[historyIndex] = energySystem.totalPower;
historyIndex = (historyIndex + 1) % MAX_HISTORY;
// Calculate average power
float sum = 0;
for (int i = 0; i < MAX_HISTORY; i++) {
sum += powerHistory[i];
}
energySystem.averagePower = sum / MAX_HISTORY;
}
void checkAlerts() {
bool alertTriggered = false;
// Check total power
if (energySystem.totalPower > MAX_POWER_WATTS) {
Serial.println("\n⚠️ ALERT: Total power exceeds maximum!");
alertTriggered = true;
} else if (energySystem.totalPower > HIGH_POWER_WARNING) {
Serial.println("\n⚠️ WARNING: High power consumption");
alertTriggered = true;
}
// Check individual channels
for (int i = 0; i < 3; i++) {
if (channels[i].current > MAX_CURRENT_AMPS) {
Serial.print("⚠️ ALERT: ");
Serial.print(channels[i].name);
Serial.println(" current too high!");
channels[i].alertCount++;
alertTriggered = true;
}
}
// Handle alert
if (alertTriggered && !energySystem.alertActive) {
energySystem.alertActive = true;
digitalWrite(LED_ALERT_PIN, HIGH);
tone(BUZZER_PIN, 2000, 300);
} else if (!alertTriggered && energySystem.alertActive) {
energySystem.alertActive = false;
digitalWrite(LED_ALERT_PIN, LOW);
}
}
void updateEnergyCost() {
// Recalculate costs (in case rate changed)
for (int i = 0; i < 3; i++) {
channels[i].cost = channels[i].energy * energySystem.costPerKWh;
}
energySystem.totalCost = energySystem.totalEnergy * energySystem.costPerKWh;
// Print summary
printEnergySummary();
}
void printEnergySummary() {
Serial.println("\n╔════════════════════════════════════╗");
Serial.println("║ ENERGY CONSUMPTION REPORT ║");
Serial.println("╠════════════════════════════════════╣");
Serial.print("║ Total Power: ");
Serial.print(energySystem.totalPower, 1);
Serial.println(" W");
Serial.print("║ Total Energy: ");
Serial.print(energySystem.totalEnergy, 3);
Serial.println(" kWh");
Serial.print("║ Total Cost: $");
Serial.println(energySystem.totalCost, 2);
Serial.println("╠════════════════════════════════════╣");
for (int i = 0; i < 3; i++) {
Serial.print("║ ");
Serial.print(channels[i].name);
Serial.print(": ");
Serial.print(channels[i].power, 1);
Serial.print("W");
Serial.println();
}
Serial.println("╚════════════════════════════════════╝\n");
}
void updateDisplay() {
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0, 0);
// Title
display.println("ENERGY MONITOR");
display.drawLine(0, 9, 128, 9, SSD1306_WHITE);
// Total Power
display.setCursor(0, 12);
display.setTextSize(1);
display.print("Power: ");
display.print(energySystem.totalPower, 0);
display.println(" W");
// Total Energy
display.setCursor(0, 22);
display.print("Energy: ");
display.print(energySystem.totalEnergy, 2);
display.println(" kWh");
// Total Cost
display.setCursor(0, 32);
display.print("Cost: $");
display.println(energySystem.totalCost, 2);
// Individual channels
display.setCursor(0, 42);
display.print("L:");
display.print(channels[0].power, 0);
display.print(" K:");
display.print(channels[1].power, 0);
display.print(" B:");
display.print(channels[2].power, 0);
// Alert indicator
if (energySystem.alertActive) {
display.setCursor(0, 54);
display.print("! HIGH POWER !");
} else {
display.setCursor(0, 54);
unsigned long uptime = (millis() - energySystem.startTime) / 1000;
display.print("Up: ");
display.print(uptime / 3600);
display.print("h ");
display.print((uptime % 3600) / 60);
display.print("m");
}
display.display();
}
void controlRelay(int channel, bool state) {
if (channel >= 0 && channel < 3) {
channels[channel].relayState = state;
digitalWrite(RELAY_CH1_PIN + channel, state ? HIGH : LOW);
Serial.print(channels[channel].name);
Serial.print(" relay: ");
Serial.println(state ? "ON" : "OFF");
tone(BUZZER_PIN, state ? 1200 : 800, 100);
}
}
// Web Server Handlers
void handleRoot() {
String html = "<!DOCTYPE html><html><head>";
html += "<meta name='viewport' content='width=device-width,initial-scale=1'>";
html += "<meta http-equiv='refresh' content='5'>";
html += "<title>Energy Monitor</title>";
html += "<style>";
html += "body{margin:0;font-family:Arial;background:#1a1a2e;color:#eee;padding:20px}";
html += ".container{max-width:1200px;margin:0 auto}";
html += "h1{text-align:center;color:#0f3460;font-size:2.5em;margin-bottom:10px}";
html += ".subtitle{text-align:center;opacity:0.8;margin-bottom:30px}";
html += ".stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:20px;margin-bottom:30px}";
html += ".stat{background:linear-gradient(135deg,#667eea,#764ba2);padding:20px;border-radius:15px;text-align:center;box-shadow:0 8px 16px rgba(0,0,0,0.3)}";
html += ".stat-value{font-size:2.5em;font-weight:bold;margin:10px 0}";
html += ".stat-label{font-size:0.9em;opacity:0.9}";
html += ".stat-unit{font-size:0.5em;opacity:0.8}";
html += ".channels{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:20px;margin-bottom:20px}";
html += ".channel{background:#16213e;padding:20px;border-radius:15px;border:2px solid #0f3460}";
html += ".channel h3{margin:0 0 15px 0;color:#667eea}";
html += ".channel-stat{display:flex;justify-content:space-between;padding:8px 0;border-bottom:1px solid rgba(255,255,255,0.1)}";
html += ".progress-bar{background:rgba(255,255,255,0.1);height:10px;border-radius:5px;overflow:hidden;margin:10px 0}";
html += ".progress-fill{height:100%;background:linear-gradient(90deg,#667eea,#764ba2);transition:width 0.3s}";
html += ".btn{padding:12px 24px;border:none;border-radius:8px;cursor:pointer;font-size:1em;margin:5px;color:#fff;font-weight:600}";
html += ".btn-on{background:#4CAF50}";
html += ".btn-off{background:#f44336}";
html += ".btn-reset{background:#2196F3}";
html += ".controls{text-align:center;margin-top:20px}";
html += ".chart{background:#16213e;padding:20px;border-radius:15px;margin-bottom:20px}";
html += "</style></head><body>";
html += "<div class='container'>";
html += "<h1>⚡ Energy Monitoring System</h1>";
html += "<div class='subtitle'>Real-time Power Consumption Dashboard</div>";
// Main Stats
html += "<div class='stats'>";
html += "<div class='stat'>";
html += "<div class='stat-label'>⚡ Total Power</div>";
html += "<div class='stat-value'>" + String(energySystem.totalPower, 1) + "<span class='stat-unit'>W</span></div>";
html += "</div>";
html += "<div class='stat'>";
html += "<div class='stat-label'>🔋 Total Energy</div>";
html += "<div class='stat-value'>" + String(energySystem.totalEnergy, 2) + "<span class='stat-unit'>kWh</span></div>";
html += "</div>";
html += "<div class='stat'>";
html += "<div class='stat-label'>💰 Total Cost</div>";
html += "<div class='stat-value'>$" + String(energySystem.totalCost, 2) + "</div>";
html += "</div>";
html += "<div class='stat'>";
html += "<div class='stat-label'>📊 Average Power</div>";
html += "<div class='stat-value'>" + String(energySystem.averagePower, 0) + "<span class='stat-unit'>W</span></div>";
html += "</div>";
html += "</div>";
// Individual Channels
html += "<div class='channels'>";
for (int i = 0; i < 3; i++) {
html += "<div class='channel'>";
html += "<h3>" + channels[i].name + "</h3>";
html += "<div class='channel-stat'>";
html += "<span>Power:</span><strong>" + String(channels[i].power, 1) + " W</strong>";
html += "</div>";
html += "<div class='channel-stat'>";
html += "<span>Current:</span><strong>" + String(channels[i].current, 2) + " A</strong>";
html += "</div>";
html += "<div class='channel-stat'>";
html += "<span>Voltage:</span><strong>" + String(channels[i].voltage, 1) + " V</strong>";
html += "</div>";
html += "<div class='channel-stat'>";
html += "<span>Energy:</span><strong>" + String(channels[i].energy, 3) + " kWh</strong>";
html += "</div>";
html += "<div class='channel-stat'>";
html += "<span>Cost:</span><strong>$" + String(channels[i].cost, 2) + "</strong>";
html += "</div>";
// Power bar
int powerPercent = constrain((channels[i].power / 1000.0) * 100, 0, 100);
html += "<div class='progress-bar'><div class='progress-fill' style='width:" + String(powerPercent) + "%'></div></div>";
// Relay control
html += "<div style='margin-top:15px;text-align:center'>";
html += "<span>Status: " + String(channels[i].relayState ? "ON" : "OFF") + "</span><br>";
if (channels[i].relayState) {
html += "<button onclick=\"window.location='/relay" + String(i+1) + "/off'\" class='btn btn-off'>Turn OFF</button>";
} else {
html += "<button onclick=\"window.location='/relay" + String(i+1) + "/on'\" class='btn btn-on'>Turn ON</button>";
}
html += "</div>";
html += "</div>";
}
html += "</div>";
// Controls
html += "<div class='controls'>";
html += "<button onclick=\"window.location='/reset'\" class='btn btn-reset'>🔄 Reset Counters</button>";
html += "</div>";
html += "<div style='text-align:center;margin-top:30px;opacity:0.5;font-size:0.9em'>";
unsigned long uptime = (millis() - energySystem.startTime) / 1000;
html += "Uptime: " + String(uptime / 3600) + "h " + String((uptime % 3600) / 60) + "m | ";
html += "Rate: $" + String(energySystem.costPerKWh, 2) + "/kWh | ";
html += "IP: " + WiFi.localIP().toString();
html += "</div>";
html += "</div></body></html>";
server.send(200, "text/html", html);
}
void handleStatus() {
String json = "{";
json += "\"totalPower\":" + String(energySystem.totalPower, 2) + ",";
json += "\"totalEnergy\":" + String(energySystem.totalEnergy, 4) + ",";
json += "\"totalCost\":" + String(energySystem.totalCost, 2) + ",";
json += "\"averagePower\":" + String(energySystem.averagePower, 2) + ",";
json += "\"channels\":[";
for (int i = 0; i < 3; i++) {
if (i > 0) json += ",";
json += "{";
json += "\"name\":\"" + channels[i].name + "\",";
json += "\"voltage\":" + String(channels[i].voltage, 2) + ",";
json += "\"current\":" + String(channels[i].current, 3) + ",";
json += "\"power\":" + String(channels[i].power, 2) + ",";
json += "\"energy\":" + String(channels[i].energy, 4) + ",";
json += "\"cost\":" + String(channels[i].cost, 2) + ",";
json += "\"relay\":" + String(channels[i].relayState ? "true" : "false");
json += "}";
}
json += "]}";
server.send(200, "application/json", json);
}
void handleHistory() {
String json = "[";
for (int i = 0; i < MAX_HISTORY; i++) {
if (i > 0) json += ",";
json += String(powerHistory[i], 1);
}
json += "]";
server.send(200, "application/json", json);
}
void handleReset() {
for (int i = 0; i < 3; i++) {
channels[i].energy = 0;
channels[i].cost = 0;
channels[i].peakPower = 0;
channels[i].alertCount = 0;
}
energySystem.totalEnergy = 0;
energySystem.totalCost = 0;
energySystem.lastReset = millis();
Serial.println("✓ Energy counters reset");
server.sendHeader("Location", "/");
server.send(303);
}
/*
* IoT Energy Monitoring System
*
* Features:
* - Real-time voltage and current monitoring
* - Power consumption calculation (Watts)
* - Energy usage tracking (kWh)
* - Cost calculation with configurable rates
* - Multiple appliance monitoring (4 channels)
* - OLED display for live readings
* - Web dashboard with charts
* - Power quality monitoring
* - Alerts for high consumption
* - Daily/monthly usage reports
* - Energy saving recommendations
* - Peak/off-peak rate support
*/
#include <WiFi.h>
#include <WebServer.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// WiFi Credentials
const char* ssid = "Wokwi-GUEST";
const char* password = "";
// Web Server
WebServer server(80);
// Pin Definitions
#define VOLTAGE_SENSOR_PIN 34 // Voltage sensor (simulated with potentiometer)
#define CURRENT_CH1_PIN 35 // Current sensor Channel 1 - Living Room
#define CURRENT_CH2_PIN 32 // Current sensor Channel 2 - Kitchen
#define CURRENT_CH3_PIN 33 // Current sensor Channel 3 - Bedroom
#define RELAY_CH1_PIN 26 // Relay control Channel 1
#define RELAY_CH2_PIN 27 // Relay control Channel 2
#define RELAY_CH3_PIN 14 // Relay control Channel 3
#define BUZZER_PIN 25 // Alert buzzer
#define LED_POWER_PIN 13 // Power indicator LED
#define LED_ALERT_PIN 12 // Alert LED
// OLED Display
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Energy Monitoring Configuration
#define VOLTAGE_CALIBRATION 1.0
#define CURRENT_CALIBRATION 1.0
#define POWER_FACTOR 0.95
#define COST_PER_KWH 0.12 // $/kWh (configurable)
// Alert Thresholds
#define MAX_POWER_WATTS 3000
#define HIGH_POWER_WARNING 2000
#define MAX_CURRENT_AMPS 15
// Channel Structure
struct EnergyChannel {
String name;
float voltage;
float current;
float power;
float energy; // kWh
float cost; // $
bool relayState;
unsigned long lastUpdate;
float peakPower;
int alertCount;
};
EnergyChannel channels[3];
// System State
struct SystemState {
float totalPower; // Total watts
float totalEnergy; // Total kWh
float totalCost; // Total $
float averagePower;
unsigned long startTime;
unsigned long lastReset;
int displayMode; // 0=Overview, 1=Channel1, 2=Channel2, 3=Channel3
bool alertActive;
float costPerKWh;
};
SystemState energySystem;
// Historical Data (for graphing)
#define MAX_HISTORY 50
float powerHistory[MAX_HISTORY];
int historyIndex = 0;
// Timing
unsigned long lastSensorRead = 0;
unsigned long lastDisplayUpdate = 0;
unsigned long lastCostUpdate = 0;
const long sensorInterval = 1000; // Read every 1 second
const long displayInterval = 500;
const long costUpdateInterval = 60000; // Update cost every minute
void setup() {
Serial.begin(115200);
// Initialize pins
pinMode(RELAY_CH1_PIN, OUTPUT);
pinMode(RELAY_CH2_PIN, OUTPUT);
pinMode(RELAY_CH3_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(LED_POWER_PIN, OUTPUT);
pinMode(LED_ALERT_PIN, OUTPUT);
pinMode(VOLTAGE_SENSOR_PIN, INPUT);
pinMode(CURRENT_CH1_PIN, INPUT);
pinMode(CURRENT_CH2_PIN, INPUT);
pinMode(CURRENT_CH3_PIN, INPUT);
// Initialize channels
channels[0].name = "Living Room";
channels[1].name = "Kitchen";
channels[2].name = "Bedroom";
for (int i = 0; i < 3; i++) {
channels[i].voltage = 0;
channels[i].current = 0;
channels[i].power = 0;
channels[i].energy = 0;
channels[i].cost = 0;
channels[i].relayState = true;
channels[i].lastUpdate = millis();
channels[i].peakPower = 0;
channels[i].alertCount = 0;
// Turn on all relays initially
digitalWrite(RELAY_CH1_PIN + i, HIGH);
}
// Initialize system
energySystem.totalPower = 0;
energySystem.totalEnergy = 0;
energySystem.totalCost = 0;
energySystem.averagePower = 0;
energySystem.startTime = millis();
energySystem.lastReset = millis();
energySystem.displayMode = 0;
energySystem.alertActive = false;
energySystem.costPerKWh = COST_PER_KWH;
// Initialize OLED
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("OLED failed"));
} else {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("ENERGY MONITOR");
display.println("");
display.println("Initializing...");
display.display();
delay(2000);
}
// Connect to WiFi
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi");
display.clearDisplay();
display.setCursor(0, 0);
display.println("Connecting WiFi...");
display.display();
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\n✓ WiFi connected!");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
// Setup web server routes
server.on("/", handleRoot);
server.on("/status", handleStatus);
server.on("/history", handleHistory);
server.on("/reset", handleReset);
server.on("/relay1/on", []() { controlRelay(0, true); });
server.on("/relay1/off", []() { controlRelay(0, false); });
server.on("/relay2/on", []() { controlRelay(1, true); });
server.on("/relay2/off", []() { controlRelay(1, false); });
server.on("/relay3/on", []() { controlRelay(2, true); });
server.on("/relay3/off", []() { controlRelay(2, false); });
server.begin();
Serial.println("✓ Web server started!");
Serial.println("\n╔════════════════════════════════════╗");
Serial.println("║ ENERGY MONITORING SYSTEM ONLINE ║");
Serial.println("╚════════════════════════════════════╝");
Serial.print("Dashboard: http://");
Serial.println(WiFi.localIP());
Serial.println();
// Power on indicator
digitalWrite(LED_POWER_PIN, HIGH);
tone(BUZZER_PIN, 1000, 100);
delay(150);
tone(BUZZER_PIN, 1500, 100);
updateDisplay();
}
void loop() {
server.handleClient();
unsigned long currentMillis = millis();
// Read sensors
if (currentMillis - lastSensorRead >= sensorInterval) {
lastSensorRead = currentMillis;
readSensors();
calculatePower();
checkAlerts();
}
// Update display
if (currentMillis - lastDisplayUpdate >= displayInterval) {
lastDisplayUpdate = currentMillis;
updateDisplay();
}
// Update energy cost
if (currentMillis - lastCostUpdate >= costUpdateInterval) {
lastCostUpdate = currentMillis;
updateEnergyCost();
}
}
void readSensors() {
// Read voltage (simulated - typically 220V AC)
int voltageRaw = analogRead(VOLTAGE_SENSOR_PIN);
float voltage = map(voltageRaw, 0, 4095, 0, 250) * VOLTAGE_CALIBRATION;
// Read current for each channel
int currentRaw1 = analogRead(CURRENT_CH1_PIN);
int currentRaw2 = analogRead(CURRENT_CH2_PIN);
int currentRaw3 = analogRead(CURRENT_CH3_PIN);
channels[0].current = map(currentRaw1, 0, 4095, 0, 20) * CURRENT_CALIBRATION;
channels[1].current = map(currentRaw2, 0, 4095, 0, 20) * CURRENT_CALIBRATION;
channels[2].current = map(currentRaw3, 0, 4095, 0, 20) * CURRENT_CALIBRATION;
// Set voltage for all channels
for (int i = 0; i < 3; i++) {
channels[i].voltage = voltage;
// If relay is off, current should be zero
if (!channels[i].relayState) {
channels[i].current = 0;
}
}
}
void calculatePower() {
energySystem.totalPower = 0;
for (int i = 0; i < 3; i++) {
// Calculate power (P = V * I * PF)
channels[i].power = channels[i].voltage * channels[i].current * POWER_FACTOR;
// Update peak power
if (channels[i].power > channels[i].peakPower) {
channels[i].peakPower = channels[i].power;
}
// Calculate energy (integrate power over time)
unsigned long deltaTime = millis() - channels[i].lastUpdate;
float hours = deltaTime / 3600000.0; // Convert ms to hours
channels[i].energy += (channels[i].power / 1000.0) * hours; // kWh
channels[i].lastUpdate = millis();
// Calculate cost
channels[i].cost = channels[i].energy * energySystem.costPerKWh;
// Add to total
energySystem.totalPower += channels[i].power;
}
// Calculate total energy
energySystem.totalEnergy = channels[0].energy + channels[1].energy + channels[2].energy;
energySystem.totalCost = energySystem.totalEnergy * energySystem.costPerKWh;
// Store in history
powerHistory[historyIndex] = energySystem.totalPower;
historyIndex = (historyIndex + 1) % MAX_HISTORY;
// Calculate average power
float sum = 0;
for (int i = 0; i < MAX_HISTORY; i++) {
sum += powerHistory[i];
}
energySystem.averagePower = sum / MAX_HISTORY;
}
void checkAlerts() {
bool alertTriggered = false;
// Check total power
if (energySystem.totalPower > MAX_POWER_WATTS) {
Serial.println("\n⚠️ ALERT: Total power exceeds maximum!");
alertTriggered = true;
} else if (energySystem.totalPower > HIGH_POWER_WARNING) {
Serial.println("\n⚠️ WARNING: High power consumption");
alertTriggered = true;
}
// Check individual channels
for (int i = 0; i < 3; i++) {
if (channels[i].current > MAX_CURRENT_AMPS) {
Serial.print("⚠️ ALERT: ");
Serial.print(channels[i].name);
Serial.println(" current too high!");
channels[i].alertCount++;
alertTriggered = true;
}
}
// Handle alert
if (alertTriggered && !energySystem.alertActive) {
energySystem.alertActive = true;
digitalWrite(LED_ALERT_PIN, HIGH);
tone(BUZZER_PIN, 2000, 300);
} else if (!alertTriggered && energySystem.alertActive) {
energySystem.alertActive = false;
digitalWrite(LED_ALERT_PIN, LOW);
}
}
void updateEnergyCost() {
// Recalculate costs (in case rate changed)
for (int i = 0; i < 3; i++) {
channels[i].cost = channels[i].energy * energySystem.costPerKWh;
}
energySystem.totalCost = energySystem.totalEnergy * energySystem.costPerKWh;
// Print summary
printEnergySummary();
}
void printEnergySummary() {
Serial.println("\n╔════════════════════════════════════╗");
Serial.println("║ ENERGY CONSUMPTION REPORT ║");
Serial.println("╠════════════════════════════════════╣");
Serial.print("║ Total Power: ");
Serial.print(energySystem.totalPower, 1);
Serial.println(" W");
Serial.print("║ Total Energy: ");
Serial.print(energySystem.totalEnergy, 3);
Serial.println(" kWh");
Serial.print("║ Total Cost: $");
Serial.println(energySystem.totalCost, 2);
Serial.println("╠════════════════════════════════════╣");
for (int i = 0; i < 3; i++) {
Serial.print("║ ");
Serial.print(channels[i].name);
Serial.print(": ");
Serial.print(channels[i].power, 1);
Serial.print("W");
Serial.println();
}
Serial.println("╚════════════════════════════════════╝\n");
}
void updateDisplay() {
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0, 0);
// Title
display.println("ENERGY MONITOR");
display.drawLine(0, 9, 128, 9, SSD1306_WHITE);
// Total Power
display.setCursor(0, 12);
display.setTextSize(1);
display.print("Power: ");
display.print(energySystem.totalPower, 0);
display.println(" W");
// Total Energy
display.setCursor(0, 22);
display.print("Energy: ");
display.print(energySystem.totalEnergy, 2);
display.println(" kWh");
// Total Cost
display.setCursor(0, 32);
display.print("Cost: $");
display.println(energySystem.totalCost, 2);
// Individual channels
display.setCursor(0, 42);
display.print("L:");
display.print(channels[0].power, 0);
display.print(" K:");
display.print(channels[1].power, 0);
display.print(" B:");
display.print(channels[2].power, 0);
// Alert indicator
if (energySystem.alertActive) {
display.setCursor(0, 54);
display.print("! HIGH POWER !");
} else {
display.setCursor(0, 54);
unsigned long uptime = (millis() - energySystem.startTime) / 1000;
display.print("Up: ");
display.print(uptime / 3600);
display.print("h ");
display.print((uptime % 3600) / 60);
display.print("m");
}
display.display();
}
void controlRelay(int channel, bool state) {
if (channel >= 0 && channel < 3) {
channels[channel].relayState = state;
digitalWrite(RELAY_CH1_PIN + channel, state ? HIGH : LOW);
Serial.print(channels[channel].name);
Serial.print(" relay: ");
Serial.println(state ? "ON" : "OFF");
tone(BUZZER_PIN, state ? 1200 : 800, 100);
}
}
// Web Server Handlers
void handleRoot() {
String html = "<!DOCTYPE html><html><head>";
html += "<meta name='viewport' content='width=device-width,initial-scale=1'>";
html += "<meta http-equiv='refresh' content='5'>";
html += "<title>Energy Monitor</title>";
html += "<style>";
html += "body{margin:0;font-family:Arial;background:#1a1a2e;color:#eee;padding:20px}";
html += ".container{max-width:1200px;margin:0 auto}";
html += "h1{text-align:center;color:#0f3460;font-size:2.5em;margin-bottom:10px}";
html += ".subtitle{text-align:center;opacity:0.8;margin-bottom:30px}";
html += ".stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:20px;margin-bottom:30px}";
html += ".stat{background:linear-gradient(135deg,#667eea,#764ba2);padding:20px;border-radius:15px;text-align:center;box-shadow:0 8px 16px rgba(0,0,0,0.3)}";
html += ".stat-value{font-size:2.5em;font-weight:bold;margin:10px 0}";
html += ".stat-label{font-size:0.9em;opacity:0.9}";
html += ".stat-unit{font-size:0.5em;opacity:0.8}";
html += ".channels{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:20px;margin-bottom:20px}";
html += ".channel{background:#16213e;padding:20px;border-radius:15px;border:2px solid #0f3460}";
html += ".channel h3{margin:0 0 15px 0;color:#667eea}";
html += ".channel-stat{display:flex;justify-content:space-between;padding:8px 0;border-bottom:1px solid rgba(255,255,255,0.1)}";
html += ".progress-bar{background:rgba(255,255,255,0.1);height:10px;border-radius:5px;overflow:hidden;margin:10px 0}";
html += ".progress-fill{height:100%;background:linear-gradient(90deg,#667eea,#764ba2);transition:width 0.3s}";
html += ".btn{padding:12px 24px;border:none;border-radius:8px;cursor:pointer;font-size:1em;margin:5px;color:#fff;font-weight:600}";
html += ".btn-on{background:#4CAF50}";
html += ".btn-off{background:#f44336}";
html += ".btn-reset{background:#2196F3}";
html += ".controls{text-align:center;margin-top:20px}";
html += ".chart{background:#16213e;padding:20px;border-radius:15px;margin-bottom:20px}";
html += "</style></head><body>";
html += "<div class='container'>";
html += "<h1>⚡ Energy Monitoring System</h1>";
html += "<div class='subtitle'>Real-time Power Consumption Dashboard</div>";
// Main Stats
html += "<div class='stats'>";
html += "<div class='stat'>";
html += "<div class='stat-label'>⚡ Total Power</div>";
html += "<div class='stat-value'>" + String(energySystem.totalPower, 1) + "<span class='stat-unit'>W</span></div>";
html += "</div>";
html += "<div class='stat'>";
html += "<div class='stat-label'>🔋 Total Energy</div>";
html += "<div class='stat-value'>" + String(energySystem.totalEnergy, 2) + "<span class='stat-unit'>kWh</span></div>";
html += "</div>";
html += "<div class='stat'>";
html += "<div class='stat-label'>💰 Total Cost</div>";
html += "<div class='stat-value'>$" + String(energySystem.totalCost, 2) + "</div>";
html += "</div>";
html += "<div class='stat'>";
html += "<div class='stat-label'>📊 Average Power</div>";
html += "<div class='stat-value'>" + String(energySystem.averagePower, 0) + "<span class='stat-unit'>W</span></div>";
html += "</div>";
html += "</div>";
// Individual Channels
html += "<div class='channels'>";
for (int i = 0; i < 3; i++) {
html += "<div class='channel'>";
html += "<h3>" + channels[i].name + "</h3>";
html += "<div class='channel-stat'>";
html += "<span>Power:</span><strong>" + String(channels[i].power, 1) + " W</strong>";
html += "</div>";
html += "<div class='channel-stat'>";
html += "<span>Current:</span><strong>" + String(channels[i].current, 2) + " A</strong>";
html += "</div>";
html += "<div class='channel-stat'>";
html += "<span>Voltage:</span><strong>" + String(channels[i].voltage, 1) + " V</strong>";
html += "</div>";
html += "<div class='channel-stat'>";
html += "<span>Energy:</span><strong>" + String(channels[i].energy, 3) + " kWh</strong>";
html += "</div>";
html += "<div class='channel-stat'>";
html += "<span>Cost:</span><strong>$" + String(channels[i].cost, 2) + "</strong>";
html += "</div>";
// Power bar
int powerPercent = constrain((channels[i].power / 1000.0) * 100, 0, 100);
html += "<div class='progress-bar'><div class='progress-fill' style='width:" + String(powerPercent) + "%'></div></div>";
// Relay control
html += "<div style='margin-top:15px;text-align:center'>";
html += "<span>Status: " + String(channels[i].relayState ? "ON" : "OFF") + "</span><br>";
if (channels[i].relayState) {
html += "<button onclick=\"window.location='/relay" + String(i+1) + "/off'\" class='btn btn-off'>Turn OFF</button>";
} else {
html += "<button onclick=\"window.location='/relay" + String(i+1) + "/on'\" class='btn btn-on'>Turn ON</button>";
}
html += "</div>";
html += "</div>";
}
html += "</div>";
// Controls
html += "<div class='controls'>";
html += "<button onclick=\"window.location='/reset'\" class='btn btn-reset'>🔄 Reset Counters</button>";
html += "</div>";
html += "<div style='text-align:center;margin-top:30px;opacity:0.5;font-size:0.9em'>";
unsigned long uptime = (millis() - energySystem.startTime) / 1000;
html += "Uptime: " + String(uptime / 3600) + "h " + String((uptime % 3600) / 60) + "m | ";
html += "Rate: $" + String(energySystem.costPerKWh, 2) + "/kWh | ";
html += "IP: " + WiFi.localIP().toString();
html += "</div>";
html += "</div></body></html>";
server.send(200, "text/html", html);
}
void handleStatus() {
String json = "{";
json += "\"totalPower\":" + String(energySystem.totalPower, 2) + ",";
json += "\"totalEnergy\":" + String(energySystem.totalEnergy, 4) + ",";
json += "\"totalCost\":" + String(energySystem.totalCost, 2) + ",";
json += "\"averagePower\":" + String(energySystem.averagePower, 2) + ",";
json += "\"channels\":[";
for (int i = 0; i < 3; i++) {
if (i > 0) json += ",";
json += "{";
json += "\"name\":\"" + channels[i].name + "\",";
json += "\"voltage\":" + String(channels[i].voltage, 2) + ",";
json += "\"current\":" + String(channels[i].current, 3) + ",";
json += "\"power\":" + String(channels[i].power, 2) + ",";
json += "\"energy\":" + String(channels[i].energy, 4) + ",";
json += "\"cost\":" + String(channels[i].cost, 2) + ",";
json += "\"relay\":" + String(channels[i].relayState ? "true" : "false");
json += "}";
}
json += "]}";
server.send(200, "application/json", json);
}
void handleHistory() {
String json = "[";
for (int i = 0; i < MAX_HISTORY; i++) {
if (i > 0) json += ",";
json += String(powerHistory[i], 1);
}
json += "]";
server.send(200, "application/json", json);
}
void handleReset() {
for (int i = 0; i < 3; i++) {
channels[i].energy = 0;
channels[i].cost = 0;
channels[i].peakPower = 0;
channels[i].alertCount = 0;
}
energySystem.totalEnergy = 0;
energySystem.totalCost = 0;
energySystem.lastReset = millis();
Serial.println("✓ Energy counters reset");
server.sendHeader("Location", "/");
server.send(303);
}
How to Test:
1. Simulate Power Consumption:
Rotate "Voltage" to middle → Sets ~220V
Rotate "Current CH1" up → Living Room uses power
Rotate "Current CH2" up → Kitchen uses power
Rotate "Current CH3" up → Bedroom uses power
Watch the system calculate:
Power = Voltage × Current × 0.95
Energy += Power × Time
Cost = Energy × $0.12/kWh2. Monitor on OLED:
ENERGY MONITOR
Power: 1250 W ← Total watts
Energy: 0.52 kWh ← Total energy
Cost: $0.06 ← Total cost
L:450 K:600 B:200 ← Per channel
Up: 0h 25m ← UptimeTrigger Alerts:
Increase current potentiometers
↓
Total power > 2000W
↓
WARNING displayed
Red LED turns ON
Buzzer beeps
Cost Calculation Example:
Living Room: 450W for 1 hour
Energy = 450W / 1000 = 0.45 kWh
Cost = 0.45 kWh × $0.12 = $0.054
Kitchen: 600W for 2 hours
Energy = 600W / 1000 × 2h = 1.2 kWh
Cost = 1.2 kWh × $0.12 = $0.144
Total Cost: $0.198 ≈ $0.20
Power Calculations:
Formula: Power (W) = Voltage (V) × Current (A) × Power Factor
Example:
Voltage: 220V
Current: 5A
Power Factor: 0.95
Power = 220 × 5 × 0.95 = 1045W
Alert System:
Threshold Response 2000W High Power Warning 3000W Critical Alert + Buzzer 15A Overcurrent per channel
When triggered:
- Red Alert LED turns ON
- Buzzer sounds (2000 Hz)
- Serial Monitor shows warning
- Dashboard displays alert
Web Dashboard Features:
Statistics Cards:
- Total Power (real-time watts)
- Total Energy (cumulative kWh)
- Total Cost ($ spent)
- Average Power (mean consumption)
Channel Cards:
Each shows:
- Power, Current, Voltage
- Energy consumed (kWh)
- Cost ($)
- Visual progress bar
- ON/OFF control button
Controls:
- Reset all counters
- Turn channels ON/OFF
- View history data
API Endpoints:
GET /status → JSON with all readings
GET /history → Last 50 power values
GET /relay1/on → Turn Living Room ON
GET /relay2/off → Turn Kitchen OFF
GET /reset → Reset energy counters
Quick Setup:
- Wokwi → New ESP32 Project
- Copy sketch.ino code
- Replace diagram.json
- Add Libraries:
- Adafruit GFX
- Adafruit SSD1306
- Start! → Check IP → Open Dashboard
Perfect For:
- Home energy monitoring
- Appliance power testing
- Electricity bill reduction
- Solar system tracking
- Industrial monitoring
- Smart home integration
- IoT learning projects
Real-World Applications:
Track actual consumption:
- Refrigerator: ~150W
- Air conditioner: ~1500W
- Microwave: ~1200W
- TV: ~100W
- Computer: ~300W
Monthly cost example:
Refrigerator: 150W × 24h × 30d = 108 kWh
Cost: 108 kWh × $0.12 = $12.96/month
The system provides complete energy monitoring with power calculations, cost tracking, and remote control capabilities!
Comments
Post a Comment