ESP32 kWh Monitor

kWh Energy Monitor totally based on Emonlib library and Openenergymonitor website.

Early days experiment pictures

Carousel imageCarousel imageCarousel imageCarousel imageCarousel imageCarousel imageCarousel image

//Libraries

#include <WiFi.h>

#include "time.h"

#include <Arduino.h>

#include "EmonLib.h"

#include <driver/adc.h>

#include <BluetoothSerial.h>


EnergyMonitor emon1; //Declare the instance


#define ADC_INPUT 36 //Current

#define ADC_INPUT4 32 //A4 voltage

#define ADC_BITS 12 //Force EmonLib to use 12 bit ADC resolution

#define ADC_COUNTS (1<<ADC_BITS)

#define emonTxV3 //Force the library to use 3v3 as supply voltage


//Thingspeak parameters

char host[] = "api.thingspeak.com";

const char* writeAPIKey = "XXXXXXXXXXXX";


//Variables

double currentCalibr = 85.7; //Default

double homeVoltage = 236.8; //Default

int calYear = 2020; //Default

double kWhCost = 2.03; //Default

double phaseShift = 1.7; //Default


double kWh = 0;

double calCost = 0;

double Cost = 0;

unsigned long lastmillis;


const char* ntpServer = "pool.ntp.org";

const long gmtOffset_sec = 7200; //7200 seconds to sync with our time

const int daylightOffset_sec = 0; //I ignored this offset

struct tm timeinfo;

int second, minute, hour, day, month, year, weekday;


int retries = 0;

int updatePeriod = 15;


BluetoothSerial SerialBT; //Declare Bluetooth

byte byteRead; //Read incoming bytes from bluetooth

//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

void setup() {


Serial.begin(115200);

SerialBT.begin("kWh Monitor"); //Name the Bluetooth


//Setup the ADC

adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_DB_11); //ADC attenuation

analogReadResolution(ADC_BITS); //Force library to read 12 bit processor

pinMode(ADC_INPUT, INPUT); //Current pin input from current transformer

pinMode(ADC_INPUT4, INPUT); //Voltage pin from AC transformer

pinMode(LED_BUILTIN, OUTPUT);

digitalWrite(LED_BUILTIN, HIGH);


emon1.voltage(ADC_INPUT4, homeVoltage, 1.7); //Voltage: input pin, calibration, phase_shift

emon1.current(ADC_INPUT, currentCalibr); //Current: input pin, calibration.


WiFi.begin("xxxxxx", "xxxxxxx");

Serial.print("Connecting");


while (WiFi.status() != WL_CONNECTED && retries < 15) {

delay(500);

Serial.print(".");

retries++;

}


//If we still couldn't connect to the WiFi, go to deep sleep for a minute and try again.

if (WiFi.status() != WL_CONNECTED) {

esp_sleep_enable_timer_wakeup(1 * 60L * 1000000L);

esp_deep_sleep_start();

}


Serial.println();

Serial.print("Connected, IP address: ");

Serial.println(WiFi.localIP());

Serial.println();

Serial.println("MAC: ");

Serial.println(WiFi.macAddress());


configTime(gmtOffset_sec, daylightOffset_sec, ntpServer); //init and get the time

printLocalTime();

//timeFinishedSetup = millis();

}

//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

void loop() {


printLocalTime();


second = timeinfo.tm_sec;

minute = timeinfo.tm_min;

hour = timeinfo.tm_hour;

day = timeinfo.tm_mday;

month = timeinfo.tm_mon + 1;

year = timeinfo.tm_year + 1900;

//weekday = timeinfo.tm_wday + 1;


if (SerialBT.available()) {

byteRead = SerialBT.read();


//Various bluetooth commands to sub program and change parameters

if (byteRead == 0)kWh = 0; //Reset kWh readings after each particular month

if (byteRead == 2)phaseShift = 1.28;

if (byteRead == 3)currentCalibr = 90.9;

if (byteRead == 5)calYear = 2021;

if (byteRead == 6)ESP.restart();

}


emon1.calcVI(20, 2000); //Calculate all. No.of half wavelengths (crossings), time-out

//emon1.serialprint(); //Print out all variables (realpower, apparent power, Vrms, Irms, power factor)


float realPower = emon1.realPower; //extract Real Power into variable

float apparentPower = emon1.apparentPower; //extract Apparent Power into variable

float powerFactor = emon1.powerFactor; //extract Power Factor into Variable

float supplyVoltage = emon1.Vrms; //extract Vrms into Variable

float Irms = emon1.Irms; //extract Irms into Variable


//Cummalative formula for kWh readings

kWh += (((millis() - lastmillis) * realPower) / 3600000000);

lastmillis = millis();

Cost = kWh * kWhCost;



//All the following if statements to reset cost and kWh readings

if (day == 30 && month == 4 && year == calYear && hour == 23 && minute == 59) {

calCost += Cost; kWh = 0;//April

}

if (day == 31 && month == 5 && year == calYear && hour == 23 && minute == 59) {

calCost += Cost; kWh = 0;//May

}

if (day == 30 && month == 6 && year == calYear && hour == 23 && minute == 59) {

calCost += Cost; kWh = 0;//June

}

if (day == 31 && month == 7 && year == calYear && hour == 23 && minute == 59) {

calCost += Cost; kWh = 0;//July

}

if (day == 31 && month == 8 && year == calYear && hour == 23 && minute == 59) {

calCost += Cost; kWh = 0;//August

}


if (day == 30 && month == 9 && year == calYear && hour == 23 && minute == 59) {

calCost += Cost; kWh = 0;//September

}

if (day == 31 && month == 10 && year == calYear && hour == 23 && minute == 59) {

calCost += Cost; kWh = 0;//October

}

if (day == 30 && month == 11 && year == calYear && hour == 23 && minute == 59) {

calCost += Cost; kWh = 0;//November

}

if (day == 31 && month == 12 && year == calYear && hour == 23 && minute == 59) {

calCost += Cost; kWh = 0; calCost = 0;//December

}

if (day == 31 && month == 1 && year == calYear && hour == 23 && minute == 59) {

calCost += Cost; kWh = 0;//January

}

if (day == 28 && month == 2 && year == calYear && hour == 23 && minute == 59) {

calCost += Cost; kWh = 0;//February

}

if (day == 31 && month == 3 && year == calYear && hour == 23 && minute == 59) {

calCost += Cost; kWh = 0;//March

}


//TCP connection and send strings to Thinspeak accordingly to field channels

WiFiClient client; //Make TCP connections

const int httpPort = 80;

if (!client.connect(host, httpPort)) return;


String url = "/update?key=";

url += writeAPIKey;

url += "&field1=";

url += String(realPower);

url += "&field2=";

url += String(apparentPower);

url += "&field3=";

url += String(supplyVoltage);

url += "&field4=";

url += String(Irms);

url += "&field5=";

url += String(powerFactor);

url += "&field6=";

url += String(kWh);

url += "&field7=";

url += String(Cost);

url += "&field8=";

url += String(calCost);

url += "\r\n";


//Request to the server

client.print(String("GET ") + url + " HTTP/1.1\r\n" +

"Host : " + host + "\r\n" +

"Connection : keep - alive\r\n\r\n");

delay(updatePeriod * 1000UL);

}

//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

void printLocalTime() {


if (!getLocalTime(&timeinfo)) {

//Serial.println("Failed to obtain time");

return;

}

}

Final Working Energy Monitor

Carousel imageCarousel imageCarousel imageCarousel imageCarousel imageCarousel image