#include <WiFi.
h>
#include <WiFiClient.h>
#include <WiFiAP.h>
const char *ssid = "play";
const char *password = "play1234";
WiFiServer server(80);
#include <ArduinoJson.h>
#include <LiquidCrystal_I2C.h>
#include <EEPROM.h>
WiFiClient client;
#define OUTPUT_1_PIN 27
#define OUTPUT_2_PIN 26
#define OUTPUT_3_PIN 25
#define OUTPUT_4_PIN 33
#define PUSH_SWITCH_1 13
#define PUSH_SWITCH_2 15
#define PUSH_SWITCH_3 14
#define PUSH_SWITCH_4 12
#define CURRENT_SENSOR_PIN 34
#define VOLTAGE_SENSOR_PIN 35
#define VOLTAGE_DIVIDER_RATIO 100.0
#define BASE_WATT_VOLTAGE 0.2
#define WATT_INCREMENT_PER_VOLT 0.9
#define ALERT_UNIT_THRESHOLD 10.0
#define NOMINAL_VOLTAGE 220.0
LiquidCrystal_I2C lcd(0x27, 16, 2);
bool outputStates[4] = {false, false, false, false};
bool lastSwitchStates[4] = {false, false, false, false};
float currentReading = 0.0;
float voltageReading = 0.0;
float powerReading = 0.0;
float unitConsumed = 1.0;
float totalUnits = 1.0;
unsigned long lastTime = 0;
bool alertShown = false;
bool clientConnected = false;
String alert = "";
#define UNIT_ADDR 0
#define TOTAL_UNITS_ADDR 4
void setup() {
Serial.begin(115200);
pinMode(OUTPUT_1_PIN, OUTPUT);
pinMode(OUTPUT_2_PIN, OUTPUT);
pinMode(OUTPUT_3_PIN, OUTPUT);
pinMode(OUTPUT_4_PIN, OUTPUT);
pinMode(PUSH_SWITCH_1, INPUT_PULLUP);
pinMode(PUSH_SWITCH_2, INPUT_PULLUP);
pinMode(PUSH_SWITCH_3, INPUT_PULLUP);
pinMode(PUSH_SWITCH_4, INPUT_PULLUP);
digitalWrite(OUTPUT_1_PIN, HIGH);
digitalWrite(OUTPUT_2_PIN, HIGH);
digitalWrite(OUTPUT_3_PIN, HIGH);
digitalWrite(OUTPUT_4_PIN, HIGH);
lcd.init();
lcd.backlight();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Smart Meter");
lcd.setCursor(0, 1);
lcd.print("Initializing...");
EEPROM.begin(512);
loadData();
setupAccessPoint();
updateDisplay();
}
void setupAccessPoint() {
WiFi.softAP(ssid, password);
IPAddress myIP = WiFi.softAPIP();
Serial.print("AP IP address: ");
Serial.println(myIP);
server.begin();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("WiFi AP Ready");
lcd.setCursor(0, 1);
lcd.print("SSID: play");
delay(3000);
}
void loop() {
handleSocketConnection();
if (millis() - lastTime >= 1000) {
readSensors();
calculatePower();
calculateCurrent();
calculateUnits();
checkAlert();
updateDisplay();
sendDataToClient();
lastTime = millis();
handlePushSwitches();
}
}
void handleSocketConnection() {
if (!clientConnected) {
client = server.available();
if (client) {
Serial.println("New client connected");
clientConnected = true;
client.setNoDelay(true);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Client Connected");
delay(2000);
}
} else {
if (!client.connected()) {
Serial.println("Client disconnected");
clientConnected = false;
client.stop();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Client Disconnected");
delay(2000);
} else {
handleClientCommands();
}
}
}
void handleClientCommands() {
if (client.available()) {
String command = client.readStringUntil('\n');
command.trim();
if (command.length() > 0) {
Serial.println("Received command: " + command);
if (command.startsWith("TOGGLE:")) {
int output = command.substring(7).toInt();
if (output >= 0 && output < 4) {
toggleOutput(output);
sendResponse("OK");
} else {
sendResponse("ERROR: Invalid output");
}
} else if (command == "RESET") {
resetUnits();
sendResponse("OK");
} else if (command == "GET_DATA") {
sendDataToClient();
} else if (command == "CALIBRATE") {
calibrateVoltage();
sendResponse("Calibration complete - check Serial Monitor");
} else {
sendResponse("ERROR: Unknown command");
}
}
}
}
void sendResponse(String response) {
if (clientConnected && client.connected()) {
client.println(response);
client.flush();
}
}
void sendDataToClient() {
if (clientConnected && client.connected()) {
StaticJsonDocument<200> doc;
doc["voltage"] = voltageReading;
doc["current"] = currentReading;
doc["power"] = powerReading;
doc["unitConsumed"] = unitConsumed;
doc["totalUnits"] = totalUnits;
doc["output1"] = outputStates[0];
doc["output2"] = outputStates[1];
doc["output3"] = outputStates[2];
doc["output4"] = outputStates[3];
doc["alert"] = alert;
String jsonString;
serializeJson(doc, jsonString);
client.println("DATA:" + jsonString);
client.flush();
}
}
void handlePushSwitches() {
int switchPins[4] = {PUSH_SWITCH_1, PUSH_SWITCH_2, PUSH_SWITCH_3, PUSH_SWITCH_4};
int outputPins[4] = {OUTPUT_1_PIN, OUTPUT_2_PIN, OUTPUT_3_PIN, OUTPUT_4_PIN};
for (int i = 0; i < 4; i++) {
bool currentSwitchState = !digitalRead(switchPins[i]);
if (currentSwitchState && !lastSwitchStates[i]) {
toggleOutput(i);
Serial.print("Output ");
Serial.print(i + 1);
Serial.print(": ");
Serial.println(outputStates[i] ? "ON" : "OFF");
}
lastSwitchStates[i] = currentSwitchState;
}
}
void toggleOutput(int output) {
if (output >= 0 && output < 4) {
outputStates[output] = !outputStates[output];
int outputPins[4] = {OUTPUT_1_PIN, OUTPUT_2_PIN, OUTPUT_3_PIN, OUTPUT_4_PIN};
digitalWrite(outputPins[output], !outputStates[output]);
}
}
float voltageReadings[10] = {0};
int voltageIndex = 0;
float powerReadings[5] = {0};
int powerIndex = 0;
void readSensors() {
int voltageRaw = 0;
for (int i = 0; i < 5; i++) {
voltageRaw += analogRead(VOLTAGE_SENSOR_PIN);
delayMicroseconds(100);
}
voltageRaw = voltageRaw / 5;
float voltage = (voltageRaw / 12.08);
voltageReadings[voltageIndex] = voltage;
voltageIndex = (voltageIndex + 1) % 10;
float sum = 0;
for (int i = 0; i < 10; i++) {
sum += voltageReadings[i];
}
voltageReading = sum / 10.0;
if (voltageReading < 5.0) {
voltageReading = 0.0;
}
static int debugCounter = 0;
debugCounter++;
if (debugCounter >= 10) {
Serial.print("Raw ADC: ");
Serial.print(voltageRaw);
Serial.print(", ADC Voltage: ");
Serial.print(voltage, 2);
Serial.print("V, AC RMS: ");
Serial.print(voltageReading, 1);
Serial.println("V");
debugCounter = 0;
}
}
void calculatePower() {
int temppowerReading = 0;
if ((analogRead(CURRENT_SENSOR_PIN) == 0)) {
if ((outputStates[0] == true) || (outputStates[1] == true) || (outputStates[2]
== true) || (outputStates[3] == true)) {
powerReading = 100.0;
} else {
powerReading = 0.0;
}
} else if ((analogRead(CURRENT_SENSOR_PIN) < 1500) &&
(analogRead(CURRENT_SENSOR_PIN) > 500)) {
powerReading = (analogRead(CURRENT_SENSOR_PIN) + 144) / 6.82;
} else if ((analogRead(CURRENT_SENSOR_PIN) > 1500) &&
(analogRead(CURRENT_SENSOR_PIN) < 2500)) {
powerReading = (analogRead(CURRENT_SENSOR_PIN)) / 8.73;
} else if ((analogRead(CURRENT_SENSOR_PIN) > 2500)) {
powerReading = (analogRead(CURRENT_SENSOR_PIN)) / 9.77;
} else {
powerReading = 0.0;
}
if (powerReading < 2.0) {
powerReading = 0.0;
}
if (powerReading > 450) {
outputStates[0] = false;
outputStates[1] = false;
outputStates[2] = false;
outputStates[3] = false;
digitalWrite(OUTPUT_1_PIN, HIGH);
digitalWrite(OUTPUT_2_PIN, HIGH);
digitalWrite(OUTPUT_3_PIN, HIGH);
digitalWrite(OUTPUT_4_PIN, HIGH);
overloadScreen();
alert = "OVER LOAD";
sendDataToClient();
delay(4000);
alert = "";
}
}
void overloadScreen() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(" Alert! ");
lcd.setCursor(0, 1);
lcd.print(" OVER LOAD ");
}
void calculateCurrent() {
if (voltageReading > 0) {
currentReading = powerReading / voltageReading;
} else {
currentReading = 0.0;
}
if (currentReading > 100.0) currentReading = 100.0;
if (currentReading < 0.0) currentReading = 0.0;
}
void calculateUnits() {
float energyThisSecond = (powerReading / 1000);
Serial.println(energyThisSecond);
unitConsumed = unitConsumed + energyThisSecond;
Serial.println(unitConsumed);
totalUnits = totalUnits + energyThisSecond;
static int saveCounter = 0;
saveCounter++;
if (saveCounter >= 30) {
saveData();
saveCounter = 0;
}
}
void checkAlert() {
if (unitConsumed >= ALERT_UNIT_THRESHOLD && !alertShown) {
showAlert();
alert = "Unit limit exceeded";
sendDataToClient();
alertShown = true;
}
}
void showAlert() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("ALERT!");
lcd.setCursor(0, 1);
lcd.print("Unit: ");
lcd.print(unitConsumed, 3);
lcd.print(" kWh");
delay(3000);
}
void updateDisplay() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("V:");
lcd.print(voltageReading, 1);
lcd.print("VAC I:");
lcd.print(currentReading, 2);
lcd.print("A");
lcd.setCursor(0, 1);
lcd.print("P:");
lcd.print(powerReading, 0);
lcd.print("W U:");
lcd.print(unitConsumed, 3);
}
void resetUnits() {
unitConsumed = 0.0;
alertShown = false;
saveData();
alert = "";
Serial.println("Units reset");
}
void loadData() {
EEPROM.get(UNIT_ADDR, unitConsumed);
EEPROM.get(TOTAL_UNITS_ADDR, totalUnits);
if (isnan(unitConsumed)) {
unitConsumed = 0;
}
if (isnan(totalUnits)) {
totalUnits = 0;
}
}
void saveData() {
EEPROM.put(UNIT_ADDR, unitConsumed);
EEPROM.put(TOTAL_UNITS_ADDR, totalUnits);
EEPROM.commit();
}
void calibrateVoltage() {
Serial.println("=== Voltage Calibration for Pakistan AC (220V) ===");
Serial.println("Connect 220V AC and check readings");
Serial.println("Expected: ADC ~2.2V should show ~220V AC");
for (int i = 0; i < 10; i++) {
int voltageRaw = analogRead(VOLTAGE_SENSOR_PIN);
float voltage = (voltageRaw / 4095.0) * 3.3 * VOLTAGE_DIVIDER_RATIO;
float voltageRMS = voltage / 1.414;
Serial.print("Sample ");
Serial.print(i + 1);
Serial.print(": Raw ADC = ");
Serial.print(voltageRaw);
Serial.print(", ADC Voltage = ");
Serial.print(voltage, 2);
Serial.print("V, AC RMS = ");
Serial.print(voltageRMS, 1);
Serial.println("V");
delay(1000);
}
Serial.println("=== Calibration Complete ===");
Serial.println("For 220V AC, ADC should read ~2.2V");
Serial.println("If incorrect, adjust VOLTAGE_DIVIDER_RATIO");
}