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

I tried the code. and will not send the data. part with payload works (I tried it in another code). I'm not an expert for arduino code, but I think the problem is when connecting to the thinksboard. Does the code work with you?

@BullsEye34
Copy link
Author

I tried the code. and will not send the data. part with payload works (I tried it in another code). I'm not an expert for arduino code, but I think the problem is when connecting to the thinksboard. Does the code work with you?

Yes, the code works for me..... But problem is sending the data from Arduino to NodeMCU

@vladakru
Copy link

how to send data to you...
I tried everything, but I still do not get the data on the thingsboard that is sent to the nodemcu.
it will not be a topic to do even at the wrong readings, as if it does not make a connection with the thingsboard server ...

@BullsEye34
Copy link
Author

how to send data to you...
I tried everything, but I still do not get the data on the thingsboard that is sent to the nodemcu.
it will not be a topic to do even at the wrong readings, as if it does not make a connection with the thingsboard server ...

Go to Devices, Attributes, Server Attributes...... Check it there

@vladakru
Copy link

I managed to get the data on the thingsboard. :)

@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