Power meter, using light sensor and interupt.

I am struggling to get my powermeter to work. I taped a light sensor in front of the blinking red led diode on my powermeter.

Here is my code:

/*
  Part 5 – Pulse counting
  
  Many meters have pulse outputs, including electricity meters: single phase, 3-phase, 
  import, export.. Gas meters, Water flow meters etc
  The pulse output may be a flashing LED or a switching relay (usually solid state) or both.
  In the case of an electricity meter a pulse output corresponds to a certain amount of 
  energy passing through the meter (Kwhr/Wh). For single-phase domestic electricity meters
  (eg. Elster A100c) each pulse usually corresponds to 1 Wh (1000 pulses per kwh).  
  The code below detects the falling edge of each pulse and increment pulseCount
  
  It calculated the power by the calculating the time elapsed between pulses.
  
  Read more about pulse counting here:
  http://openenergymonitor.org/emon/buildingblocks/introduction-to-pulse-counting
  -----------------------------------------
  Part of the openenergymonitor.org project
  Licence: GNU GPL V3
*/

long pulseCount = 0;
unsigned long pulseTime,lastTime; // Used to measure time between pulses
double power;
int ppwh = 1;                     // pulses per watt hour - found or set on the meter.

void setup() 
{
  Serial.begin(9600);
  
  // pulse detection interrupt (emontx pulse channel - IRQ0 D3)
  attachInterrupt(1, onPulse, FALLING);
}

void loop() 
{ 
  Serial.print(power);
  Serial.print(' ');
  Serial.println(pulseCount * ppwh);  // watt hour elapsed
  delay(1000);
}

// The interrupt routine - runs each time a falling edge of a pulse is detected
void onPulse()                  
{
  lastTime = pulseTime;
  pulseTime = micros();
  pulseCount++;                                               // count pulse               
  power = int((3600000000.0 / (pulseTime - lastTime))/ppwh);  // calculate power
}

However it seems like the output goes in overflow or something or?

0.00 0
0.00 0
0.00 0
-3400.00 5
-3400.00 5
-3400.00 5
5444.00 7
14628.00 10
14628.00 10
14628.00 10
-3400.00 14
-3400.00 14
-3400.00 14
-3400.00 14
14628.00 19
14628.00 19
14628.00 19
14628.00 19

Please supply a circuit of how you have wired the sensor.

You could write a simple program to blink a LED each time the power meter LED blinks. This would show if it is electronics or programming causing the problem.

Weedpharma

Judging by the printout I suspect you are getting some kind of noise on your edge detection such that you get several interrupts for each genuine pulse. You will see that the pulsecount never advances by 1. This will generate very small intervals leading to overflowing the power calculation.

If your meter has a display of kwh then you can record that value at a particular time, run your program for a few hours then read the kwh value again. Compare the pulse count with the displayed kwh figure and see if it compares to your assumed pulse rate- my guess you will find 3 or 4 times as many pulses as you expect.

If this turns out to be the case you can address it either in hardware by putting a small capacitor in the circuit to smooth the signal or in software by calculating (pulsetime-lasttime) and rejecting any values below a threshold.

Its best practice to do the minimum possible in your interrupt routine so you should try to move the calculations back into the main loop. (see the Doing several things at once topic for how to do without delay(). You should also use the volatile keyword on the variables you update in the interupt (https://www.arduino.cc/en/Reference/Volatile)

As each pulse is a fixed amount of energy, surely you only need to count pulses. What use is the length of the pulse or time between pulses?

At a load of 1kw, you would get 1000 pulses per hour (assuming that is your meter pulse rate), or, 1 every 3.6 secs. There is a lot of computer time between pulses.

In the interrupt, you only need to return the fact that the pulse has happened. The main loop then counts and displays.

The link takes us to a page full of sensors. Which one are you using?

To be precise, you are counting pulses that represent energy, not power. Power is an instantaneous value, while energy takes into account the time.

Weedpharma

You can use this to test your code or do on-site testing...

/*
   Use this to test Power Meter / Energy Meter code and calculations
   SELF TEST: Connect jumper wire from pin 13 to pin 3 and adjust
   Timer1.initialize value to set pulse rate.
   ON-SITE: Remove jumper and connect optic sensor output to pin 3
*/

#include <TimerOne.h>          // https://github.com/PaulStoffregen/TimerOne

const byte whPerPulse = 1;  // K factor or pulse constant (Wh/pulse) -  meter could be marked with imp/kWh, Kh, Kp or Ki.
volatile byte printFlag = 0;
volatile unsigned long pulseCount = 0;
volatile unsigned long pulseTime, lastTime; // Used to measure time between pulses
double power;
int led = LED_BUILTIN;
int ledState;

void setup()
{
  Timer1.initialize(360000); // µs/pulse (360000 = 10000 Watts, 1000000 = 3600 Watts, 500000 = 7200 Watts, etc.)
  Timer1.attachInterrupt(testPulse);
  attachInterrupt(1, onPulse, FALLING); // pin 3
  Serial.begin(115200);
  pinMode(led, OUTPUT);
}

void loop()
{
  if (printFlag) {
    printFlag = 0;
    power = double((3600000000.0 / (pulseTime - lastTime)) * whPerPulse); // calculate power
    Serial.print(power);
    Serial.print(' ');
    Serial.println(pulseCount * whPerPulse);  // watt hour elapsed
    ledState = !ledState;
    digitalWrite(led, ledState);
  }
}

void onPulse()
{
  lastTime = pulseTime;
  pulseTime = micros();
  if (pulseTime - lastTime > 500) { // > 500 µs since last interrupt
    pulseCount++;
    printFlag = 1;
  }
}

void testPulse(void)
{
  ledState = !ledState;
  digitalWrite(led, ledState);
}

I took two pictures last night of my setup:
The meter
Pulsing frequency

The light sensor also has a potentiometer, maybe i need to adjust this somehow.

For the wiring, I connect VCC to VCC,GND to GND and signal to D3 on arduino Nano.

But what sensor are you using?

Weedpharma

Your submitted code has numerous issues, which is why I submitted test code using a built-in pulse generator. Now I've updated it to do a self-test (jumper wire from pin 13 to pin 3) or an on-site test (pin 3 connected to your optic sensor). See reply#4.

What type of single-phase energy meter are you testing?

Are you using an optical reader for the meter pulse sensor?

The LDR sensor

skatun:
I took two pictures last night of my setup:
The meter
Pulsing frequency

The light sensor also has a potentiometer, maybe i need to adjust this somehow.

For the wiring, I connect VCC to VCC,GND to GND and signal to D3 on arduino Nano.

Well, that's probably the wrong type of sensor for your application. A photo-resistor has a slow response (perhaps up to 50ms) depending on the type of light and its level. Some types of electricity meters will output an impulse on its IRLED output, which can have a small ON interval as short as 2ms. This is to extend its lifespan.

Anyways, perhaps your meter has a pulse interval that has an adequate ON duration. The ON duration will be due to the electronic design and firmware of the meter, the pulse rate will be determined by the load.

You could test for operation of the meter's infrared LED by using a phone camera or digital camera and check for a visible blink on the screen.

To adjust the LDR, turn the pot until point where the signal just switches HIGH. Turn it just a very, very small amount more. When the meter's IRLED blinks, the LDR might respond by switching its output LOW (for the duration that the meter's IRLED is ON. The normal state of the LDR's output will be HIGH.

Similar to dlloyd I tested your code with a signal generator and saw very predictable pulse count changes.

I would be focusing on the sensor and signal produced. It was mentioned in reply#2

Judging by the printout I suspect you are getting some kind of noise on your edge detection such that you get several interrupts for each genuine pulse

The LDR sensor module is just using a LM393 comparator without the feedback used for hysteresis control in a Schmitt trigger configuration and it may be noisy.

Your code, as submitted generates an interrupt on each edge of an input signal, probably because volatile isn't being used for interrupt variables. Also, it only calculates an integer value and it only reads 1/2 power due to the extra interrupt. Also, the code should also limit power calculations to the pulse rate range of the meter ... 0Hz to 5Hz. Also, 0Hz should not overflow the timer and negative readings should not occur. Calculations should not be made in the interrupt routine.

Here, I've taken your code (unaltered) that shows the problems I've mentioned. Look at the Arduno's LED and look at the tx LED and print monitor readings. Extra lines for pulse generator are marked with //***********. Just place a jumper from pin13 to pin3.

/*
  Part 5 - Pulse counting

  Many meters have pulse outputs, including electricity meters: single phase, 3-phase,
  import, export.. Gas meters, Water flow meters etc
  The pulse output may be a flashing LED or a switching relay (usually solid state) or both.
  In the case of an electricity meter a pulse output corresponds to a certain amount of
  energy passing through the meter (Kwhr/Wh). For single-phase domestic electricity meters
  (eg. Elster A100c) each pulse usually corresponds to 1 Wh (1000 pulses per kwh).
  The code below detects the falling edge of each pulse and increment pulseCount

  It calculated the power by the calculating the time elapsed between pulses.

  Read more about pulse counting here:
  http://openenergymonitor.org/emon/buildingblocks/introduction-to-pulse-counting
  -----------------------------------------
  Part of the openenergymonitor.org project
  Licence: GNU GPL V3
*/
#include <TimerOne.h>  //***********

long pulseCount = 0;
unsigned long pulseTime, lastTime; // Used to measure time between pulses
double power;
int ppwh = 1;                     // pulses per watt hour - found or set on the meter.

int led = LED_BUILTIN;  //***********
volatile int ledState;  //***********

void setup()
{
  Timer1.initialize(1000000); // µs/pulse (1000000 = 3600 Watts)  //***********
  Timer1.attachInterrupt(testPulse);  //***********
  pinMode(led, OUTPUT);  //***********

  Serial.begin(9600);

  // pulse detection interrupt (emontx pulse channel - IRQ0 D3)
  attachInterrupt(1, onPulse, FALLING);
}

void loop()
{
  Serial.print(power);
  Serial.print(' ');
  Serial.println(pulseCount * ppwh);  // watt hour elapsed
  delay(1000);
}

// The interrupt routine - runs each time a falling edge of a pulse is detected
void onPulse()
{
  lastTime = pulseTime;
  pulseTime = micros();
  pulseCount++;                                               // count pulse
  power = int((3600000000.0 / (pulseTime - lastTime)) / ppwh); // calculate power
}
void testPulse(void)  //***********
{  //***********
  ledState = !ledState;  //***********
  digitalWrite(led, ledState);  //***********
}  //***********

So I tested @dloyd code this morning:

300000000.00 1
3710.24 2
180000000.00 14
2791.24 15
72756.67 27
300000000.00 27
2791.10 28
300000000.00 40
450000000.00 40
2791.16 41
300000000.00 52
300000000.00 52
300000000.00 54
300000000.00 62
2780.42 63
300000000.00 73
450000000.00 73
300000000.00 75
300000000.00 85
300000000.00 87
300000000.00 96
300000000.00 96
2791.10 97
300000000.00 102
300000000.00 104
300000000.00 115

So it seems it gets the correct value, once in while. Maybe i need to tweek the potentiometer?

I also got a new holder for the breakout board:

holder1
holder 2

The good results are coming in with proper resolution. The extra interrupts are due to noise that is probably combined with some mains frequency ripple on the signal.

rw950431 (reply#2) and cattledog (reply#10) were correct in their suggestions.

Editing the code managed to resolve some issues. The extra speed is evident in the extra interrupts being serviced. The 300000000.00 power reading corresponds to 12µs elapsed time. The longest spacing between good results was 90µs. Note that the 12µs is probably the quickest the Arduino can service the interrupt routine as this corresponds to 83KHz interrupt frequency.

This can be resolved with software debounce code, however this does not stop the interrupts from occurring ... it just changes how the software responds to them.

Hardware filtering will stop the extra interrupts (I suggest this method), which would be as simple as adding an RC filter to the signal. Calculated from here, if you use a series 10K resistor with 100nF capacitor connected from pin3 to GND, the response (RC time constant) would be 1ms.

EDIT: It doesn't have to be one or the other method ... both could be used where the noise component is filtered in hardware and interrupts due to mains ripple are resolved with debounce code.

It was very easy to add debounce to your onPulse() interrupt routine (the required variables are already there) so I've added 500µs debounce to the code in reply#4. Please test. Hardware filtering not required.

Just got home from sailing, but I see what you mention. I will try adjust the potentiometer and I can also test with an IR receiver that I have around.

I will also test the software debounce code. I just read that people used LDR for power measurement thats why I got that kind of sensor.

Kim

When I did this I used a cheap LDR (cant remember the part number but the kind that sells for a few cents each on ebay) and pullup resistor stuck on to my meter with blu-tack. My interrupt code used CHANGE rather than FALLING mode and didnt seem to experience any of the problems you have encountered- maybe I was just lucky.

Ok, The new code from @dlloyd does not print out anything, I tried changing the debounce interval aswell as the potentiometer on the brekout board.

However I managed to install the new holder for it:

New holder

Will try the change method tonight.

Kim

Note that print out will only occur after each interrupt.

If you're adjusting the potentiometer, make sure there is sufficient load through the meter. For example, if the load is only 300W, the pulses will occur at 12 second intervals, which is painfully slow when making an adjustment and waiting a full 12 seconds to see if there's any response.

If an oven or dryer is turned on and the load becomes 3600W, then the pulse rate will be 1Hz, which is much easier to make adjustments and check for response. With 3600W and correct adjustments, printout will occur at 1Hz rate.

So I made some progress, the new holder makes it easy to adjust the potentiometer. So the breakout board has an inbuilt led, so i kept playing around with the settings of the potentiometer, so now its blinking in sync with the diode on the meter.

The problem is that the code still output strange values: I tried both falling and change for all the 3 versions. The codes can be found here.

With code in reply 4 , Power2

368098.15 328
225000000.00 329
225000000.00 330
0.84 331
368701.34 332
225000000.00 333
369306.53 334
369155.03 335
368701.34 336
366598.78 337
225000000.00 338

with my code/ openenergy Power
-5100.00 1
-2183.00 167
-1357.00 327
-2183.00 495
5444.00 661
-1712.00 823
14628.00 976
14628.00 1146
14628.00 1308
14628.00 1468
-3400.00 1634
14628.00 1799
-3400.00 1961
14628.00 2129
5444.00 2286

with dlloyd modified code of mine: Power3
-3400.00 2
-1002.00 157
-3939.00 325
-3939.00 479
-3122.00 636
14628.00 784
-3122.00 938
14628.00 1089
14628.00 1251
14628.00 1403
14628.00 1554
-3005.00 1705
14628.00 1870
14628.00 2022
14628.00 2167
-6252.00 2322
-8418.00 2480
-4868.00 2633
-4405.00 2789
14628.00 2951