CT Clamp - Display Live and Cumulative Data

Hi all,

Working on a simple, mobile clamp meter to display live and cumulative mains power usage data on a 7 segment display.

Have a D1 Mini connected to a mottram labs display and CT board

I want the display to cycle between the live usage in kW and running total in kWh since last power up / reset. I'm struggling with the last element. I've read the 'smoothing' example but am baffled on how to apply it here.

The first part of the loop works as expected but my TotalinKw is obviously nonsense - it's only increasing due to time elapsed. Can anyone give or point to a really simple example on how to keep a running total or average a number of samples that works for kWh?

Thanks!

#include <SPI.h>
#include <MAX7219_Digits.h>
#define MAX7219_CS 15
MAX7219_Digit My_Display(MAX7219_CS);

// Power monitor items
double Calib = 1.7; 
double RMSCurrent;
float RMSPower;
float PeakPower;
int LineVolts = 230;


void ReadPower ()
{
  int Current = 0;
  int MaxCurrent = 0;
  int MinCurrent = 1023;
  int PeakCurrent = 0;

  for (int j = 0 ; j <= 600 ; j++)
  {
    Current =  analogRead(A0); 

    if (Current >= MaxCurrent)
      MaxCurrent = Current;

    if (Current <= MinCurrent)
      MinCurrent = Current;

  }

  PeakCurrent = MaxCurrent - MinCurrent;
  RMSCurrent = (PeakCurrent * 0.3535) / Calib;
  RMSPower = LineVolts * RMSCurrent;

} 


void setup(void) {

Serial.begin(115200);
My_Display.Begin();
My_Display.Brightness(2);
}

void loop() {

ReadPower();

long milisec = millis();
long time = milisec/1000;
float PowerinKW = RMSPower / 1000;
float TotalinKW = (RMSPower * time)/(1000*3600);

Serial.print("Now: "); Serial.print(PowerinKW,2); Serial.println(" kW");
My_Display.Begin();
My_Display.Display_Value(1, PowerinKW, 2, 0x00);
My_Display.MAX7219_Write(7, 128); //red led

delay(7000);

Serial.print("Total: "); Serial.print(TotalinKW,2); Serial.println(" kW");
My_Display.Begin();
My_Display.Display_Value(1, TotalinKW, 2, 0x00);
My_Display.MAX7219_Write(7, 16); //blue led

delay(7000);

} // End of Loop


you need to keep track of how much time has elapsed since the previous reading and add that to your total KWh. In pseudo code

unsigned long now = millis();
unsigned long elapsedTime = now - lastTime;
time = elapsedTime / 1000;
PowerinKW = RMSPower / 1000;
TotalinKW += (RMSPower * elapsedTime)/(1000*3600);
lastTime = now;
...

Many thanks for this. I realised the timing is important - it has to sample each second for the calculation to work.

Also found this page and think I have it working.

I've ditched the delays and am using millis. I have the total watts increasing once per second and the display cycling every seven.

Will leave soaking overnight and compare against esphome / HA. :slight_smile:

#include <SPI.h>
#include <MAX7219_Digits.h>
#define MAX7219_CS 15
MAX7219_Digit My_Display(MAX7219_CS);

// Power monitor items
double Calib = 1.7;
double RMSCurrent;
float RMSPower;
float PeakPower;
int LineVolts = 230;

float TotalinKW;
unsigned long lastTime;
unsigned long delayTime;
float wattseconds;
const long interval = 7000;
int count = 0;

void ReadPower ()
{
  int Current = 0;
  int MaxCurrent = 0;
  int MinCurrent = 1023;
  int PeakCurrent = 0;

  for (int j = 0 ; j <= 600 ; j++)
  {
    Current =  analogRead(A0); 

    if (Current >= MaxCurrent)
      MaxCurrent = Current;

    if (Current <= MinCurrent)
      MinCurrent = Current;

  }

  PeakCurrent = MaxCurrent - MinCurrent;
  RMSCurrent = (PeakCurrent * 0.3535) / Calib;
  RMSPower = LineVolts * RMSCurrent;

} 

void setup(void) {

Serial.begin(115200);
My_Display.Begin();
My_Display.Brightness(2);
}

void loop() {

ReadPower();

float PowerinKW = RMSPower / 1000; // Live value

if ( millis() >= lastTime + 1000 )
    {
      lastTime = millis();
      wattseconds = wattseconds + RMSPower; //increment energy counter by current power
      TotalinKW = wattseconds / 3600000; 
      //Serial.print("WS: "); Serial.println(wattseconds);
    }

if ( millis() - delayTime >= interval )
    {
      delayTime = millis();

        if (count == 0)
          {     
            Serial.print("Now: "); Serial.print(PowerinKW,2); Serial.println(" kW");
            My_Display.Begin();
            My_Display.Display_Value(1, PowerinKW, 2, 0x00);
            My_Display.MAX7219_Write(7, 128); //green led
            count = 1;
          } else {
            Serial.print("Total: "); Serial.print(TotalinKW,6); Serial.println(" kWh");
            My_Display.Begin();
            My_Display.Display_Value(1, TotalinKW, 2, 0x00);
            My_Display.MAX7219_Write(7, 16); //blue led
            count = 0;
          }
    }

} // End of Loop


This is not how to properly perform unsigned math. It will eventually fail. millis() rolls over to zero every ~49.5 days. The only proper way to calculated elapsed time given the fact that millis() may return a value smaller than lastTime is to use subtraction.

if ( millis() - lastTime >= 1000 ) {
  // do your thing
  ...

Thanks for the tip. I've updated the code to use a subtract.

Appears to be working and reasonably accurate. Think I need to look at calibration next as this clamp works better at higher currents.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.