Skip to content

Instantly share code, notes, and snippets.

@ItKindaWorks
Last active February 20, 2023 14:56
Show Gist options
  • Star 17 You must be signed in to star a gist
  • Fork 11 You must be signed in to fork a gist
  • Save ItKindaWorks/ab4d85bc1ea77c1ff20a46b5dc2a2746 to your computer and use it in GitHub Desktop.
Save ItKindaWorks/ab4d85bc1ea77c1ff20a46b5dc2a2746 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.
/*
powerMonitorArd.ino
Copyright (c) 2017 ItKindaWorks All right reserved.
github.com/ItKindaWorks
powerMonitorArd.ino is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
powerMonitorArd.ino is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with powerMonitorArd.ino. If not, see <http://www.gnu.org/licenses/>.
*/
#include "EmonLib.h"
#define SAMPLE_COUNT 5
#define VOLT_CAL 148.7 //voltage calibration
#define CURRENT_CAL1 62.6 //sensor 1 calibration
#define CURRENT_CAL2 62.8 //sensor 2 calibration
//create 2 instances of the energy monitor lib
EnergyMonitor emon1;
EnergyMonitor emon2;
//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];
const int currentPin1 = 2;
const int currentPin2 = 1;
const int voltagePin = 3;
//counter to keep track of the current sample location
int counter = 0;
void setup()
{
Serial.begin(115200);
Serial1.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.
}
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);
//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;
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;
//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];
}
//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;
//calculate the total amps and watts
double totalAmp = ampAvg1 + ampAvg2;
double totalWatt = wattAvg1 + wattAvg2;
//send the power info to the ESP module through Serial1
sendPowerInfo (voltAvg1, totalAmp, totalWatt);
}
//send the power info to the ESP module through Serial1 (comma separated and starting with *)
void sendPowerInfo(double Volts, double Amps, double Watts){
Serial1.print("*");
Serial1.print(Volts);
Serial1.print(",");
Serial1.print(Amps);
Serial1.print(",");
Serial1.println(Watts);
}
/*
powerMonitorESP.ino
Copyright (c) 2017 ItKindaWorks All right reserved.
github.com/ItKindaWorks
powerMonitorESP.ino is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
powerMonitorESP.ino is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with powerMonitorESP.ino. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ESPHelper.h"
#include <Metro.h>
#define AVG_COUNT 50
const char* voltTopic = "/yourTopic/volt";
const char* ampTopic = "/yourTopic/amp";
const char* wattTopic = "/yourTopic/watt";
const char* hostnameStr = "PWR-Node";
const char* otaPass = "Your OTA Password";
netInfo homeNet = { .mqttHost = "YOUR MQTT-IP", //can be blank if not using MQTT
.mqttUser = "YOUR MQTT USERNAME", //can be blank
.mqttPass = "YOUR MQTT PASSWORD", //can be blank
.mqttPort = 1883, //default port for MQTT is 1883 - only chance if needed.
.ssid = "YOUR SSID",
.pass = "YOUR NETWORK PASS"};
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();
}
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];
//vars to maintain averages for all data points
double wattAvg = 0;
double voltAvg = 0;
double ampAvg = 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();
break;
}
delay(1);
}
//calculate averages
wattAvg = 0;
ampAvg = 0;
voltAvg = 0;
for(int i = 0; i < AVG_COUNT; i++){
wattAvg += watts[i];
voltAvg += volts[i];
ampAvg += amps[i];
}
wattAvg /= AVG_COUNT;
ampAvg /= AVG_COUNT;
voltAvg /= AVG_COUNT;
//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()){
//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);
}
yield();
}
}
void callback(char* topic, uint8_t* payload, unsigned int length) {
}
@Apihplays
Copy link

how to send the data to blynk instead of using mqtt ?

@BullsEye34
Copy link

BullsEye34 commented May 20, 2019

Hi, I have been able to measure the data in the Arduino..... But it is not being transferred to WiFi Chip.... But, WiFi module to connecting to WiFi Router.....

Can you please help me?

@vladakru
Copy link

I have problem how to connect to Thingsboard, There is no option to enter a token. Can u help me pls with code?

@BullsEye34
Copy link

I have problem how to connect to Thingsboard, There is no option to enter a token. Can u help me pls with code?

Hi vladkru, I have forked the current gist, and made some changes to the code.
You can find it here.

https://gist.github.com/BullsEye34/99c4d94ccfc6d9e9644ab20b4620b049

Hope you find it helpful

@vladakru
Copy link

Thx but still no telemetry... I change token and my wifi ssid and pass. Serial monitor print data but thingsboard not receive...

@BullsEye34
Copy link

Thx but still no telemetry... I change token and my wifi ssid and pass. Serial monitor print data but thingsboard not receive...

I have made some changes to the code.... Please check it out.

The data which I send had to be converted to a JSON and sent.
Check the whole code, the bottom part

@shubhammeharkure
Copy link

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