#include <WiFi.h>
#include <PubSubClient.h>
#include <SPIFFS.h>
// #include <WiFiSettings.h>
#include <PZEM004Tv30.h>
#include "constants.h"
#include <LiquidCrystal.h>
#include <HTTPClient.h>
#include <WiFiUdp.h>
#include <NTPClient.h>
// MQTT Settings
const char *mqtt_broker = "broker.emqx.io";
const char *topic = "espmeter/data";
const char *serverTopic = "post/data";
const char *mqtt_username = "espmeter";
const char *mqtt_password = "123456";
const int mqtt_port = 1883;
// SheetsDB API Details
const char* SHEETSDB_URL = "https://sheetdb.io/api/v1/y2vnnm6vl0cow";
// const char* API_KEY = "YOUR_API_KEY";
// LCD Configuration
#define RS 13
#define E 12
#define D4 14
#define D5 27
#define D6 26
#define D7 25
LiquidCrystal lcd(RS, E, D4, D5, D6, D7);
// PZEM004T Configuration
#define RX_PIN 18
#define TX_PIN 19
PZEM004Tv30 pzem(Serial2, RX_PIN, TX_PIN);
// NTP Setup
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", 19800, 60000);
WiFiClient espClient;
PubSubClient client(espClient);
// Energy tracking variables
float dailyEnergy = 0.0;
int lastLoggedDay = -1;
// Timer Variables
unsigned long lastMillisLCD = 0;
unsigned long lastMillisMQTT = 0;
const int interval = 1000; // 3 seconds
void setup() {
lcd.begin(20, 4);
Serial.begin(115200);
SPIFFS.begin(true);
// Load stored energy data from SPIFFS
loadEnergyFromSPIFFS();
// WiFi Connection
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Connecting WiFi...");
// WiFiSettings.connect();
WiFi.begin("Wokwi-GUEST", "");
while (!WiFi.isConnected());
lcd.setCursor(0, 1);
lcd.print("WiFi Connected");
lcd.setCursor(0, 2);
lcd.print("Connecting MQTT...");
// Start MQTT
client.setServer(mqtt_broker, mqtt_port);
client.setCallback(callback);
connectToMQTT();
// Start NTP
timeClient.begin();
timeClient.update();
lcd.setCursor(0, 3);
lcd.print("Setup Complete");
}
void loop() {
if (!client.connected()) {
connectToMQTT();
}
client.loop();
unsigned long currentMillis = millis();
// Fetch data from PZEM
float voltage = pzem.voltage();
float current = pzem.current();
float power = pzem.power();
float energy = pzem.energy();
float frequency = pzem.frequency();
float pf = pzem.pf();
if (!isnan(energy)) {
// dailyEnergy = energy;
saveEnergyToSPIFFS(dailyEnergy);
}
// Update time
timeClient.update();
int currentDay = timeClient.getDay();
int currentHour = timeClient.getHours();
int currentMinute = timeClient.getMinutes();
// At midnight, log and reset daily energy
if (lastLoggedDay != currentMinute) {
saveToExcel(dailyEnergy);
dailyEnergy = random(0, 100);
saveEnergyToSPIFFS(dailyEnergy);
lastLoggedDay = currentMinute;
}
// Update LCD every 3 seconds
if (currentMillis - lastMillisLCD >= interval) {
lastMillisLCD = currentMillis;
publishMQTT(voltage, current, power, frequency, energy, pf);
displayData(voltage, current, power, frequency, energy, pf);
}
}
void connectToMQTT() {
while (!client.connected()) {
String client_id = "esp32-client-";
client_id += String(WiFi.macAddress());
Serial.printf("Connecting to MQTT as %s...\n", client_id.c_str());
if (client.connect(client_id.c_str(), mqtt_username, mqtt_password)) {
Serial.println("MQTT connected!");
client.subscribe(topic);
// client.subscribe(serverTopic);
} else {
Serial.println("MQTT connection failed, retrying...");
delay(2000);
}
}
}
void callback(char *topic, byte *payload, unsigned int length) {
String msg = "";
for (int i = 0; i < length; i++) {
msg += ((char)payload[i]);
}
if (!String(topic).startsWith("post/data"))
parseJson(msg);
}
void saveToExcel(float dailyEnergy) {
HTTPClient http;
http.begin(SHEETSDB_URL);
http.addHeader("Content-Type", "application/json");
// http.addHeader("x-api-key", API_KEY);
timeClient.update();
String timestamp = timeClient.getFormattedTime();
String json = "{";
json += "\"DATE\":\"" + timestamp + "\",";
json += "\"USAGE (KWH)\":" + String(dailyEnergy, 2);
json += "}";
int httpResponseCode = http.POST(json);
if (httpResponseCode == 201) {
Serial.println("Daily data saved successfully!");
} else {
Serial.println("Failed to save daily data: " + String(httpResponseCode));
Serial.println("Tried with: " + json);
}
http.end();
}
bool error = 0;
void saveEnergyToSPIFFS(float energy) {
File file = SPIFFS.open("/energy.txt", "w");
if (!file) {
if (!error) {
Serial.println("Failed to open energy file for writing");
error = 1;
}
return;
}
file.println(energy);
file.close();
Serial.println("Energy saved to SPIFFS: " + String(energy));
}
void loadEnergyFromSPIFFS() {
File file = SPIFFS.open("/energy.txt", "r");
if (!file) {
Serial.println("No stored energy data found, starting fresh.");
dailyEnergy = 0.0;
return;
}
String storedEnergy = file.readStringUntil('\n');
dailyEnergy = storedEnergy.toFloat();
file.close();
Serial.println("Recovered energy from SPIFFS: " + String(dailyEnergy));
}
void displayData(float voltage, float current, float power, float frequency, float energy, float pf) {
lcd.clear();
lcd.setCursor(1, 0);
lcd.print("SMART ENERGY METER");
lcd.setCursor(0, 1);
lcd.print("VOL:" + String(voltage, 1) + "V");
lcd.setCursor(12, 1);
lcd.print("CUR:" + String(current, 1) + "A");
lcd.setCursor(0, 2);
lcd.print("PWR:" + String(power, 1) + "W");
lcd.setCursor(12, 2);
lcd.print("FRQ:" + String((int)frequency) + "Hz");
lcd.setCursor(0, 3);
lcd.print("ENG:" + String(energy, 2) + "kWh");
lcd.setCursor(12, 3);
lcd.print("PF:" + String(pf, 2));
}
void publishMQTT(float voltage, float current, float power, float frequency, float energy, float pf) {
if (isnan(voltage) || voltage == 0) {
voltage = 225;
current = 0.25;
power = 20;
frequency = 50;
energy = 0.05;
pf = 1;
}
String payload = "{";
payload += "\"voltage\":" + String(voltage, 2) + ",";
payload += "\"current\":" + String(current, 2) + ",";
payload += "\"power\":" + String(power, 2) + ",";
payload += "\"freq\":" + String(frequency, 2) + ",";
payload += "\"amount\":" + String(amount, 2) + ",";
payload += "\"energy\":" + String(energy, 2) + ",";
payload += "\"pf\":" + String(pf, 2);
payload += "}";
client.publish(serverTopic, payload.c_str());
Serial.println("Published MQTT: " + payload);
}