Make Your Own Power Meter/Logger

133K596146

Intro: Make Your Own Power Meter/Logger

In this project I will show you how I combined an Arduino, an INA219 power monitor IC, an OLED LCD and a Micro SD Card PCB in order to create a power meter/logger that has more functions than the popular USB Power Meter. Let's get started!

STEP 1: Watch the Video!


The video gives you a good overview on how to create your own power meter. In the next steps though I will present you some additional information to make this project even simpler.

STEP 2: Order Your Parts!

STEP 3: Create the Circuit!

Here you can find the schematic for the Arduino Nano version and the portable version of this project. You can also find those schematic on the EasyEDA website:

https://easyeda.com/GreatScott/PowerMeter-b6051723...

https://easyeda.com/GreatScott/PortablePowerMeter-...

You can also use the pictures of my finished board as a reference for your own.

STEP 4: Upload the Code!

Now that your circuit is complete, it is time to upload the code. You can download it here. But don't forget to download and include the following libraries before uploading:

https://github.com/adafruit/Adafruit_INA219

https://github.com/adafruit/Adafruit_SSD1306

https://github.com/greiman/SdFat

You can find an improved version of my code here: https://github.com/gilleshenrard/datalogger

STEP 5: Success!

You did it! You just created your own Power Meter/Logger


Feel free to check out my YouTube channel for more awesome projects:

http://www.youtube.com/user/greatscottlab

You can also follow me on Facebook, Twitter and Google+ for news about upcoming projects and behind the scenes information:

https://twitter.com/GreatScottLab

https://www.facebook.com/greatscottlab

75 Comments

Could someone post a picture of how to correctly connect a device to the powermeter?

I can make up from the video that the + of the device I want to check the power of is connected to the V- of the Ina219 sensor. And the - of the device I want to check the power of is connected to Ground. But what is connected to the V+ on the Ina219? Is that the + of the powersupply of the device I want to check the power of?
I would like to charge and discharge a battery - I have external constant current load and constant current charger for my battery cell that I can switch in and out. My confusion is if the cell is my load it will see current in two directions, one for charge and the other for discharge. How can this circuit handle + and - current flow. Does the INA 219 care which direction current flows? Does it report this out as + or = ???
Hi, I am just starting to learn how to write Arduino Code, I am wondering if this would work on the Arduino Uno as well? I am trying to figure out how to tailor it to the Arduino Uno, if anyone can help me that would be greatly appreciated.
Working Sketch. I spent an hour solving the OLED problem.

#include <Wire.h>
#include <Adafruit_INA219.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>
#include <SPI.h>
#include "SdFat.h"
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
#define OLED_RESET -1
#define ROTATION 0
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Adafruit_INA219 ina219;
unsigned long previousMillis = 0;
unsigned long interval = 100;
const int chipSelect = 10;
float shuntvoltage = 0;
float busvoltage = 0;
float current_mA = 0;
float loadvoltage = 0;
float power_mW = 0;
float energy = 0;
SdFat SD;
File TimeFile;
File VoltFile;
File CurFile;
void setup() {
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay(); // Clear the display
display.display();
display.setRotation(ROTATION); // Set Rotation
display.setTextSize(1); // Set text size
display.setTextColor(WHITE);
delay(2000);
ina219.begin();
SD.begin(chipSelect);
}
void loop() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval)
{
previousMillis = currentMillis;
ina219values();
displaydata(); //subroutines display
TimeFile = SD.open("TIME.txt", FILE_WRITE);
if (TimeFile) {
TimeFile.println(currentMillis);
TimeFile.close();
}
VoltFile = SD.open("VOLT.txt", FILE_WRITE);
if (VoltFile) {
VoltFile.println(loadvoltage);
VoltFile.close();
}
CurFile = SD.open("CUR.txt", FILE_WRITE);
if (CurFile) {
CurFile.println(current_mA);
CurFile.close();
}
}
}
void displaydata() {
display.clearDisplay();
display.setTextColor(WHITE);
display.setTextSize(1);
display.setCursor(0, 0);
display.println(loadvoltage);
display.setCursor(35, 0);
display.println("V");
display.setCursor(50, 0);
display.println(current_mA);
display.setCursor(95, 0);
display.println("mA");
display.setCursor(0, 10);
display.println(loadvoltage * current_mA);
display.setCursor(65, 10);
display.println("mW");
display.setCursor(0, 20);
display.println(energy);
display.setCursor(65, 20);
display.println("mWh");
display.display();
}
void ina219values() {
shuntvoltage = ina219.getShuntVoltage_mV();
busvoltage = ina219.getBusVoltage_V();
current_mA = ina219.getCurrent_mA();
loadvoltage = busvoltage + (shuntvoltage / 1000);
power_mW = ina219.getPower_mW();
energy = energy + loadvoltage * current_mA / 3600;
}
Can we use this project for home power measurement which is about 220V?
ive question

shuntvoltage = ina219.getShuntVoltage_mV();
busvoltage = ina219.getBusVoltage_V();
current_mA = ina219.getCurrent_mA();
loadvoltage = busvoltage + (shuntvoltage / 1000);
energy = energy + loadvoltage * current_mA / 3600;

why shuntvoltage divide by 1000 dan curren_mA is divided by 3600??
Dividing mV by 1,000 gives volts.
Dividing seconds by 3600 (60x60) gives hours.
Hello,
this is a great project! I just reviewed it and I have a quick question about the calculation for the energy. In my understanding, the calculation of the energy is not 100% correct as the time interval is missing. I would propose for the calculation of the energy --> energy = energy + loadvoltage * interval * current_mA / 3600.

What is your opinion about that?
Regards
I agree that is what I thought. If the formula was called every second it would be correct. However the interval is 100ms which is 10 times a second!

This was my formula which can be rearranged but I found it easier to follow in it's current format.

energy = energy + (power / (3600 * (1000/interval)));
I made the circuit all working but I just changed the SD FAT library for the SD arduino IDE itself but when I put the card in the reader it does not write the information just creates the 3 files
Me too, and I don't know how to make it write into the SD card. Please share if you have any solutions.

hi, congrats and thanks for a great video. I want to make a similar project but i need to monitor more current like upto 24 volts and 21 Apms.......what you suggest i do, or replace in the your given circuit? Hope to get a quick reply.

You can modify the INA219 to measure current greater than 3.2 amps. You need to change the sense resistor value. You can Google 'change current measurement of INA219'.
Hi, how about changing voltage up to 54V?
Can this project be used to monitor a larger piece of equipment like for instance a copier?
Old question... but if you want to monitor something that runs on mains AC voltage, it would be much safer to buy an energy monitor like a Kill-A-Watt or a no-name equivalent. $10 and up on eBay for a plug-in style monitor. Around $20 for a panel mount unit that'll handle up to 100A. Just search for energy monitor.
Great project indeed - I write to have support to solve an issue - I have done circuit and develop code according example. All is working up I do not use the library SdFat.h. Basically I can have the meter and OLED working without the SD part in the program. When I introduce SD part all is load in Arduino but OLED screen freeze or show black in particular if I active command SdFat SD. Seems and issue of memory but when compiling program give 77% program memory free and 59% for dynamic variables free and seems not the case. Attached also my sketch. I am using last library available from Arduino IDE.

Adafruit GFX Library 1.7.5
Adafruit INA219 1.0.6
Adafruit SSD1306 2.2.0
SdFat - Adafruit Fork 1.2.3


Thanks for help Regards Alex


===========================================================

#include // Serial Peripheral Interface comunication SD reader writer module
#include // Wire bus comunication I2C on SCL SDA display SD1306 and Ina219
#include // Display SSD1306 library
#include // Display shape library
#include // INA219 board library current voltage reader
#include //SD comunication library

#define SCREEN_WIDTH 128 // OLED display width in pixels
#define SCREEN_HEIGHT 64 // OLED display height in pixels
#define OLED_RESET 4 // Reset pin # (or -1 if sharing Arduino reset pin)
#define ROTATION 0

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Adafruit_INA219 ina219;

unsigned long previousMillis = 0;
unsigned long interval = 100;
const int chipSelect = 10;

float shuntvoltage = 0;
float busvoltage = 0;
float current_mA = 0;
float loadvoltage = 0;
float power_mW = 0;
float energy = 0;

SdFat SD;

File TimeFile;
File VoltFile;
File CurrentFile;


void setup() {
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay(); // Clear the display
display.display(); // Flushes all changes to the display hardware
display.setRotation(ROTATION); // Set Rotation
display.setTextSize(1); // Set text size
display.setTextColor(WHITE);

delay(2000);

ina219.begin();
SD.begin(chipSelect);
}

void loop() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval)
{ previousMillis = currentMillis;

ina219values(); //subroutines reading
displaydata(); //subroutines display

// Write on files - Time - Volt - Current

TimeFile = SD.open("Time.txt", FILE_WRITE);
if (TimeFile) {
TimeFile.println(currentMillis);
TimeFile.close();
}

VoltFile = SD.open("Volt.txt", FILE_WRITE);
if (VoltFile) {
VoltFile.println(loadvoltage);
VoltFile.close();
}

CurrentFile = SD.open("Current.txt", FILE_WRITE);
if (CurrentFile) {
CurrentFile.println(current_mA);
CurrentFile.close();
}
}
}


void ina219values()
{
shuntvoltage = ina219.getShuntVoltage_mV(); // V across shunt V+ and V-
busvoltage = ina219.getBusVoltage_V(); // V across V- and Gnd
current_mA = ina219.getCurrent_mA(); // I across the shunt
loadvoltage = busvoltage + (shuntvoltage / 1000);
power_mW = ina219.getPower_mW();

energy = energy + loadvoltage * current_mA / 3600;
}


void displaydata() {
display.clearDisplay();

display.setCursor(0, 0);
display.println("Voltage:");
display.setCursor(60, 0);
display.println(loadvoltage);
display.setCursor(100, 0);
display.println("V");

display.setCursor(0, 10);
display.println("Current:");
display.setCursor(60, 10);
display.println(current_mA);
display.setCursor(100, 10);
display.println("mA");

display.setCursor(0, 20);
display.println("Power:");
display.setCursor(60, 20);
display.println(loadvoltage * current_mA);
display.setCursor(100, 20);
display.println("mW");

display.setCursor(0, 30);
display.println("Energy:");
display.setCursor(60, 30);
display.println(energy);
display.setCursor(100, 30);
display.println("mWh");

display.display();
}

Alex, I too had memory problems with my 128X64 OLED. I stumbled on a fix that worked: in library file Adafruit_SSD1306.h, selecting "#define SSD1306_128_32" instead of the "#define SSD1306_128_64" seemed to work. (Select by commenting one and uncommenting the other.) Be aware that you may have multiple *.h files. The problem may be because the memory requirements of the *64 font outstrip the memory allocation for the OLED. Changing to the *32 font definition results in a dimmer display as it appears that every other row of pixels are not lighted. That would make sense in that I have a 64 pixel device but using the "define" command for a 32 pixel device. I noticed that you also modified some of the original code and defined SCREEN_WIDTH and SCREEN_HEIGHT, probably to match your 128X64 device. I'm no expert, but that may override the default definitions in the Adafruit_SSD1306.h file. Maybe it would be better to stick closer to the original code. I spent 3 days on this problem and thought I better write this down for others and for my own record.
More Comments