Skip to content

Instantly share code, notes, and snippets.

@ItKindaWorks
Last active February 20, 2023 14:56
Show Gist options
  • 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) {
}
@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