How to build an Arduino Energy Monitor and Data Logger & plot the data

Sridhar Rajagopal
Sep 19, 2017 · 12 min read
Dr. Wattson Energy Monitoring Breakout for Arduino and other micro-controllers
Arduino Energy Logger with Dr. Wattson Energy Monitoring Breakout

Setup

Dr. Wattson Enclosure
Arduino Energy Logger with Dr. Wattson — with CFL Lamp load plugged in

Circuit

Arduino Energy Logger Circuit with Dr. Wattson

Sketch

// see if the card is present and can be initialized:
if (!SD.begin(CHIP_SELECT)) {
Serial.println(F("Card failed, or not present"));
// don't do anything more:
}

wattson.begin(); // Pass in the appropriate address. Defaults to 0x74
// initialize the digital pin as an output.
pinMode(LED, OUTPUT);
#define BUTTON_PIN 4       //Connect a tactile button switch (or something similar)
//from Arduino pin 4 to ground.

#define PULLUP true //To keep things simple, we use the Arduino's internal pullup resistor.
#define INVERT true //Since the pullup resistor will keep the pin high unless the
//switch is closed, this is negative logic, i.e. a high state
//means the button is NOT pressed. (Assuming a normally open switch.)
#define DEBOUNCE_MS 20 //A debounce time of 20 milliseconds usually works well for tactile button switches.
Button myBtn(BUTTON_PIN, PULLUP, INVERT, DEBOUNCE_MS); //Declare the button
char filename[] = "DATA00.CSV";setup() {   ...
// create a new file
for (uint8_t i = 0; i < 100; i++) {
filename[4] = i/10 + '0';
filename[5] = i%10 + '0';
if (! SD.exists(filename)) {
Serial.print(F("Data file is ")); Serial.println(filename);
// only open a new file if it doesn't exist
break; // leave the loop! filename will now be the one we desire
}
}
...
}
  myBtn.read();                    //Read the button
if (myBtn.wasReleased()) { //If the button was released, change the LED state
readData = !readData;
digitalWrite(LED, readData);
}

if (readData) {
... // read data and save to SD card, etc ....
    MCP39F521Data data;
int readMCPretval = wattson.readMCP39F521(&data, NULL);
unsigned long currentMillis = millis();
      // if the file is available, write to it:
File dataFile = SD.open(filename, FILE_WRITE);
if (dataFile) {
dataFile.print(currentMillis);
dataFile.print(",");
dataFile.print(data.currentRMS);
dataFile.print(",");
dataFile.print(data.activePower);
dataFile.print(",");
dataFile.print(data.reactivePower);
dataFile.print(",");
dataFile.println(data.apparentPower);

// print to the serial port too:
dataFile.close();
}
// if the file isn't open, pop up an error:
else {
Serial.print(F("error opening ")); Serial.println(filename);
}

Action!

Serial.write("\x1B" "c"); // Clear the screen on a regular terminal                               
wattson.printMCP39F521Data(&data);
$ screen /dev/tty.usbmodem1411 9600

Plotting the data in Excel

timestamp, currentRMS, activePower, reactivePower, apparentPower
CFL Current, Active Energy, Reactive Energy, Apparent Energy Data over Time — “cold-start” and “warm-start”

Conclusion

/*************************************************** 
This is a example sketch for Upbeat Labs Dr. Wattson Energy Monitoring Breakout
The communication happens over I2C. 2 pins are required to interface.
There are 4 selectable I2C address possibilities per board (selectable
via two solder jumpers (that select each pin to be high or low). Based
on this, there are 4 possible addresses:
I2C address SJ1 SJ2
0x74 LOW LOW
0x75 LOW HIGH
0x76 HIGH LOW
0x77 HIGH HIGH
Dr. Wattson has two outputs, ZCD or Event, that are
used for notifications, and therefore will usually be
connected to an externally interruptable pin
(like pin2 or pin3 on Arduino Uno). In this example,
ZCD and Event are not used.
Button is connected to pin 4.

* SD card attached to SPI bus as follows:
** MOSI - pin 11
** MISO - pin 12
** CLK - pin 13
** CS - pin 10

LED is connected to pin 9

Written by Sridhar Rajagopal for Upbeat Labs LLC.
BSD license. All text above must be included in any redistribution
*/

#include <Wire.h>
#include "MCP39F521.h"
#include <SD.h>
#include <Button.h> //https://github.com/JChristensen/Button
#define BUTTON_PIN 4 //Connect a tactile button switch (or something similar)
//from Arduino pin 4 to ground.

#define PULLUP true //To keep things simple, we use the Arduino's internal pullup resistor.
#define INVERT true //Since the pullup resistor will keep the pin high unless the
//switch is closed, this is negative logic, i.e. a high state
//means the button is NOT pressed. (Assuming a normally open switch.)
#define DEBOUNCE_MS 20 //A debounce time of 20 milliseconds usually works well for tactile button switches.
Button myBtn(BUTTON_PIN, PULLUP, INVERT, DEBOUNCE_MS); //Declare the button#define LED 9 // Connect an LED (via a 220ohm resistor) from pin 9 (anode) to GND (cathode).#define CHIP_SELECT 10MCP39F521 wattson = MCP39F521();bool readData = false;char filename[] = "DATA00.CSV";void setup() {
Serial.begin(9600); //turn on serial communication
Serial.println(F("**Upbeat Labs Dr. Wattson Example Sketch**"));

// initialize the digital pin as an output.
pinMode(LED, OUTPUT);
pinMode(10, OUTPUT);

// see if the card is present and can be initialized:
if (!SD.begin(CHIP_SELECT)) {
Serial.println(F("Card failed, or not present"));
// don't do anything more:
}

wattson.begin(); // Pass in the appropriate address. Defaults to 0x74
// create a new file
for (uint8_t i = 0; i < 100; i++) {
filename[4] = i/10 + '0';
filename[5] = i%10 + '0';
if (! SD.exists(filename)) {
Serial.print(F("Data file is ")); Serial.println(filename);
// only open a new file if it doesn't exist
break; // leave the loop! filename will now be the one we desire
}
}

Serial.println(F("**initialization complete.**"));

}
// This is what MCP39F521Data looks like, for reference!
//typedef struct MCP39F521Data {
// uint16_t systemStatus;
// uint16_t systemVersion;
// uint16_t voltageRMS;
// uint16_t lineFrequency;
// uint16_t analogInputVoltage;
// int16_t powerFactor;
// uint32_t currentRMS;
// uint32_t activePower;
// uint32_t reactivePower;
// uint32_t apparentPower;
//} MCP39F521Data;

void loop() {
myBtn.read(); //Read the button
if (myBtn.wasReleased()) { //If the button was released, change the LED state
readData = !readData;
digitalWrite(LED, readData);
}

if (readData) {
MCP39F521Data data;
int readMCPretval = wattson.readMCP39F521(&data, NULL);
unsigned long currentMillis = millis();

if (readMCPretval) {
// Print stuff out
Serial.write("\x1B" "c"); // Clear the screen on a regular terminal
wattson.printMCP39F521Data(&data);

// if the file is available, write to it:
File dataFile = SD.open(filename, FILE_WRITE);
if (dataFile) {
dataFile.print(currentMillis);
dataFile.print(",");
dataFile.print(data.currentRMS);
dataFile.print(",");
dataFile.print(data.activePower);
dataFile.print(",");
dataFile.print(data.reactivePower);
dataFile.print(",");
dataFile.println(data.apparentPower);

// print to the serial port too:
dataFile.close();
}
// if the file isn't open, pop up an error:
else {
Serial.print(F("error opening ")); Serial.println(filename);
}

} else {
Serial.println(F("Error!"));
}
}
}

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade