Skip to content

Instantly share code, notes, and snippets.

@BullsEye34
Forked from ItKindaWorks/powerMon.fzz
Last active December 22, 2019 14:59
Show Gist options
  • Select an option

  • Save BullsEye34/99c4d94ccfc6d9e9644ab20b4620b049 to your computer and use it in GitHub Desktop.

Select an option

Save BullsEye34/99c4d94ccfc6d9e9644ab20b4620b049 to your computer and use it in GitHub Desktop.
A simple arduino and ESP8266 program to read and average 2 current transformers and a voltage transformer for monitoring whole house power usage.
#include "EmonLib.h"
#include "ESP8266.h"
#include <SoftwareSerial.h>
SoftwareSerial mySerial1(3, 2); /* RX:D3, TX:D2 */
ESP8266 wifi(mySerial1);
#define SAMPLE_COUNT 10
#define VOLT_CAL 157.5 //voltage calibration
#define CURRENT_CAL1 7.2 //sensor 1 calibration -- Solar Generation
#define CURRENT_CAL2 1.3 //sensor 2 calibration -- R
#define CURRENT_CAL3 1.3 //sensor 3 calibration -- B
#define CURRENT_CAL4 1.3 //sensor 3 calibration -- Y
//create 2 instances of the energy monitor lib
EnergyMonitor emon1;
EnergyMonitor emon2;
EnergyMonitor emon3;
EnergyMonitor emon4;
//arrays to hold the sample data
double volts1[SAMPLE_COUNT];
double amps1[SAMPLE_COUNT];
double watts1[SAMPLE_COUNT];
double volts2[SAMPLE_COUNT];
double amps2[SAMPLE_COUNT];
double watts2[SAMPLE_COUNT];
double volts3[SAMPLE_COUNT];
double amps3[SAMPLE_COUNT];
double watts3[SAMPLE_COUNT];
double volts4[SAMPLE_COUNT];
double amps4[SAMPLE_COUNT];
double watts4[SAMPLE_COUNT];
const int currentPin1 = 0; // Solar Generation
const int currentPin2 = 1;
const int currentPin3 = 2;
const int currentPin4 = 3;
const int voltagePin = 4;
//counter to keep track of the current sample location
int counter = 0;
void setup()
{
Serial.begin(115200);
mySerial1.begin(115200);
emon1.voltage(voltagePin, VOLT_CAL, 1.7); // Voltage: input pin, calibration, phase_shift
emon1.current(currentPin1, CURRENT_CAL1); // Current: input pin, calibration.
emon2.voltage(voltagePin, VOLT_CAL, 1.7); // Voltage: input pin, calibration, phase_shift
emon2.current(currentPin2, CURRENT_CAL2); // Current: input pin, calibration.
emon3.voltage(voltagePin, VOLT_CAL, 1.7); // Voltage: input pin, calibration, phase_shift
emon3.current(currentPin3, CURRENT_CAL3); // Current: input pin, calibration.
emon4.voltage(voltagePin, VOLT_CAL, 1.7); // Voltage: input pin, calibration, phase_shift
emon4.current(currentPin4, CURRENT_CAL4); // Current: input pin, calibration.
}
void loop()
{
//reset the var that keeps track of the number of samples taken
//(loop back around to 0 on the array for our running total)
if(counter >= SAMPLE_COUNT){
counter = 0;
}
//calculate the most recent readings
emon1.calcVI(20,5000);
emon2.calcVI(20,5000);
emon3.calcVI(20,5000);
emon4.calcVI(20,5000);
//save the voltage, current, watts to the array for later averaging
amps1[counter] = emon1.Irms;
volts1[counter] = emon1.Vrms;
watts1[counter] = emon1.Vrms * emon1.Irms;
amps2[counter] = emon2.Irms;
volts2[counter] = emon2.Vrms;
watts2[counter] = emon2.Vrms * emon2.Irms;
amps3[counter] = emon3.Irms;
volts3[counter] = emon3.Vrms;
watts3[counter] = emon3.Vrms * emon3.Irms;
amps4[counter] = emon4.Irms;
volts4[counter] = emon4.Vrms;
watts4[counter] = emon4.Vrms * emon4.Irms;
counter++;
//setup the vars to be averaged
double wattAvg1 = 0;
double voltAvg1 = 0;
double ampAvg1 = 0;
double wattAvg2 = 0;
double voltAvg2 = 0;
double ampAvg2 = 0;
double wattAvg3 = 0;
double voltAvg3 = 0;
double ampAvg3 = 0;
double wattAvg4 = 0;
double voltAvg4 = 0;
double ampAvg4 = 0;
//add em up for averaging
for(int i = 0; i < SAMPLE_COUNT; i++){
wattAvg1 += watts1[i];
voltAvg1 += volts1[i];
ampAvg1 += amps1[i];
wattAvg2 += watts2[i];
voltAvg2 += volts2[i];
ampAvg2 += amps2[i];
wattAvg3 += watts3[i];
voltAvg3 += volts3[i];
ampAvg3 += amps3[i];
wattAvg4 += watts4[i];
voltAvg4 += volts4[i];
ampAvg4 += amps4[i];
}
//get the final average by dividing by the # of samples
wattAvg1 /= SAMPLE_COUNT;
ampAvg1 /= SAMPLE_COUNT;
voltAvg1 /= SAMPLE_COUNT;
wattAvg2 /= SAMPLE_COUNT;
ampAvg2 /= SAMPLE_COUNT;
voltAvg2 /= SAMPLE_COUNT;
wattAvg3 /= SAMPLE_COUNT;
ampAvg3 /= SAMPLE_COUNT;
voltAvg3 /= SAMPLE_COUNT;
wattAvg4 /= SAMPLE_COUNT;
ampAvg4 /= SAMPLE_COUNT;
voltAvg4 /= SAMPLE_COUNT;
//calculate the total amps and watts
double totalAmp = ampAvg2 + ampAvg3 + ampAvg4;
double totalWatt = wattAvg2 + wattAvg3 + wattAvg4;
double solarAmp = ampAvg1;
double solarWatt = wattAvg1;
if (voltAvg1 <= 30){
voltAvg1 = 0;
}
if(totalAmp <= 0.01){
totalAmp = 0;
}
if(totalWatt <= 0.05){
totalWatt = 0;
}
Serial.println("Voltage:");
Serial.println(voltAvg1);
Serial.println("Current:");
Serial.println(totalAmp);
Serial.println("Watt:");
Serial.println(totalWatt);
Serial.println("Solar Watt:");
Serial.println(solarWatt);
Serial.println("Solar Amp:");
Serial.println(solarAmp);
Serial.println(" ");
//send the power info to the ESP module through Serial1
sendPowerInfo (voltAvg1, totalAmp, totalWatt, solarAmp, solarWatt);
}
//send the power info to the ESP module through Serial1 (comma separated and starting with *)
void sendPowerInfo(double Volts, double Amps, double Watts, double solarAmp, double solarWatt){
mySerial1.print("*");
mySerial1.print(Volts);
mySerial1.print(",");
mySerial1.print(Amps);
mySerial1.print(",");
mySerial1.println(Watts);
mySerial1.print(",");
mySerial1.println(solarAmp);
mySerial1.print(",");
mySerial1.println(solarWatt);
}
#include "ESPHelper.h"
#include <Metro.h>
#include <ESP8266WiFi.h> //ESP8266 Core WiFi Library (you most likely already have this in your sketch)
#include <DNSServer.h> //Local DNS Server used for redirecting all requests to the configuration portal
#include <ESP8266WebServer.h> //Local WebServer used to serve the configuration portal
#include <WiFiManager.h> //https://github.com/tzapu/WiFiManager WiFi Configuration Magic
#define AVG_COUNT 50
const char* voltTopic = "/v1/devices/me/telemetry/volt";
const char* ampTopic = "/v1/devices/me/telemetry/amp";
const char* wattTopic = "/v1/devices/me/telemetry/watt";
const char* hostnameStr = "PWR-Node";
const char* otaPass = "";
netInfo homeNet = { .mqttHost = "demo.thingsboard.io", //can be blank if not using MQTT
.mqttUser = "kQoASUzOre31eyP", //can be blank(your device token)
.mqttPass = "", //can be blank
.mqttPort = 1883, //default port for MQTT is 1883 - only chance if needed.
.ssid = "snapple", //wifi
.pass = "9845943649"}; //password
ESPHelper myESP(&homeNet);
Metro powerMetro = Metro(30000);
void setup() {
Serial.begin(115200);
myESP.OTA_enable();
myESP.OTA_setPassword(otaPass);
myESP.OTA_setHostnameWithVersion(hostnameStr);
myESP.setHopping(false);
myESP.begin();
WiFiManager wifiManager;
wifiManager.autoConnect("test", "12344321");
}
void loop(){
int count = 0;
//where to store the data to be averaged
double watts[AVG_COUNT];
double volts[AVG_COUNT];
double amps[AVG_COUNT];
double solarAmps[AVG_COUNT];
double solarWatts[AVG_COUNT];
//vars to maintain averages for all data points
double wattAvg = 0;
double voltAvg = 0;
double ampAvg = 0;
double solarAmpAvg = 0;
double solarWattAvg = 0;
//the serial buffer of 64 bytes
char serialBuf[64];
while(1){
//reset the count when we hit the max. The average acts and a rolling average
if(count >= AVG_COUNT){
count = 0;
}
//get data from serial line
while(Serial.available()){
// '*' marks the beginning of a transmission
bool start = Serial.find('*');
//parse out the floats
if(start){
volts[count] = Serial.parseFloat();
amps[count] = Serial.parseFloat();
watts[count] = Serial.parseFloat();
solarAmps[count] = Serial.parseFloat();
solarWatts[count++] = Serial.parseFloat();
break;
}
delay(1);
}
//calculate averages
wattAvg = 0;
ampAvg = 0;
voltAvg = 0;
solarAmpAvg = 0;
solarWattAvg = 0;
for(int i = 0; i < AVG_COUNT; i++){
wattAvg += watts[i];
voltAvg += volts[i];
ampAvg += amps[i];
solarAmpAvg += solarAmps[i];
solarWattAvg += solarWatts[i];
}
wattAvg /= AVG_COUNT;
ampAvg /= AVG_COUNT;
voltAvg /= AVG_COUNT;
solarWattAvg /= AVG_COUNT;
solarAmpAvg /= AVG_COUNT;
if (wattAvg < 3.50){
wattAvg = 0;
}
if (solarWattAvg < 3.50){
solarWattAvg = 0;
}
//only send the data every so often (set by the metro timer) and only when connected to WiFi and MQTT
if(myESP.loop() == FULL_CONNECTION && powerMetro.check()){
if (ampAvg <= 0.03){
ampAvg = 0;
}
//post just watts
char wattStr[10];
dtostrf(wattAvg,4,1,wattStr);
myESP.publish(wattTopic,wattStr, true);
delay(5);
//post just volts
char voltStr[10];
dtostrf(voltAvg,4,1,voltStr);
myESP.publish(voltTopic,voltStr, true);
delay(5);
//post just amps
char ampStr[10];
dtostrf(ampAvg,4,1,ampStr);
myESP.publish(ampTopic,ampStr, true);
delay(5);
String payload = "{";
payload += "\"Consumption\":"; payload += wattAvg; payload += ",";
payload += "\"Volts\":"; payload += voltAvg; payload += ",";
payload += "\"Amps\":"; payload += ampAvg; payload += ",";
payload += "\"Solar Amps\":"; payload += solarAmpAvg;payload += ",";
payload += "\"Solar Generation\":"; payload += solarWattAvg;
payload += "}";
Serial.println(payload);
char attributes[100];
payload.toCharArray( attributes, 100 );
myESP.publish( "v1/devices/me/telemetry", attributes, true );
Serial.println( attributes );
// myESP.publish("v1/devices/me/telemetry", "payload", true);
}
yield();
}
}
void callback(char* topic, uint8_t* payload, unsigned int length) {
}
@vladakru
Copy link

vladakru commented May 26, 2019

Code is here: https://gist.github.com/vladakru/f272ea616d9501bfe22116e632bed091
but only first value from part "//where to store the data to be averaged" show number, others "double volts[AVG_COUNT];
double amps[AVG_COUNT];" show nan instead of the number.

@shubhammeharkure
Copy link

shubhammeharkure commented Dec 22, 2019

Hey Guys, I am unable to use ESPHelper.h and Metro.h libraries for my esp32 and esp8266, please can you help me to figure out this problem...
I have one esp32 (Wroom-32) and esp8266MOD (Powered by Model vendor).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment