Measure Current, Power and mAh With an INA219 on an ESP32 (Live OLED Readout) - Compoden

Measure Current, Power and mAh With an INA219 on an ESP32 (Live OLED Readout)

Ever wondered how much current your project actually pulls? Not the number on the datasheet, the real one, while the motor spins up or the Wi-Fi radio wakes. A multimeter tells you for a moment. An INA219 tells you all day, over I2C, and it also gives you bus voltage and power. Today we'll wire one to an ESP32, put the live numbers on a small OLED, and keep a running mAh total so you can see how much charge your build has used.

This takes about 20 minutes on a breadboard.

What you need

How the INA219 works (the 30-second version)

The module has a tiny 0.1 ohm shunt resistor (marked R100). You put it in series with the positive wire of your load. Current through the shunt makes a small voltage across it, the INA219 measures that with a 12-bit ADC, and the math gives you current. It also measures the voltage on the load side, so it can multiply the two and report power. Since it's "high side", your load's ground stays untouched.

With the default settings you get a range of about plus or minus 3.2 A, and the bus voltage must stay under 26 V.

Wiring

Both the INA219 and the OLED share the same I2C bus. The INA219 sits at address 0x40 by default and the OLED at 0x3C, so there's no clash.

From To Notes
INA219 VCC ESP32 3V3 Logic power
INA219 GND ESP32 GND
INA219 SDA ESP32 GPIO21 I2C data
INA219 SCL ESP32 GPIO22 I2C clock
OLED VCC ESP32 3V3
OLED GND ESP32 GND
OLED SDA ESP32 GPIO21 Same bus
OLED SCL ESP32 GPIO22 Same bus
Supply + INA219 VIN+ Current flows in here
INA219 VIN- Load + ...and out to your load
Load - Supply -
Supply - ESP32 GND Common ground, don't skip it

The code

Install two libraries from the Arduino Library Manager: INA219_WE by Wolfgang Ewald and U8g2 by oliver. Select "ESP32 Dev Module" as your board.

#include <Wire.h>
#include <INA219_WE.h>
#include <U8g2lib.h>

INA219_WE ina219(0x40);
U8G2_SSD1306_128X64_NONAME_F_HW_I2C oled(U8G2_R0, U8X8_PIN_NONE);

float mAh = 0;
unsigned long lastMs = 0;

void setup() {
  Serial.begin(115200);
  Wire.begin(21, 22);
  if (!ina219.init()) {
    Serial.println("INA219 not found. Check wiring.");
    while (1) delay(10);
  }
  ina219.setADCMode(INA219_SAMPLE_MODE_16);   // average 16 samples, smoother numbers
  oled.begin();
  lastMs = millis();
}

void loop() {
  float shunt_mV = ina219.getShuntVoltage_mV();
  float bus_V    = ina219.getBusVoltage_V();
  float current  = ina219.getCurrent_mA();
  float power    = ina219.getBusPower();      // mW
  bool overflow  = ina219.getOverflow();

  unsigned long now = millis();
  mAh += current * (now - lastMs) / 3600000.0;  // mA * hours
  lastMs = now;

  Serial.printf("%.2f V  %.1f mA  %.0f mW  %.2f mAh\n", bus_V, current, power, mAh);

  oled.clearBuffer();
  oled.setFont(u8g2_font_7x14B_tf);
  oled.setCursor(0, 14); oled.printf("V: %.2f V", bus_V + shunt_mV / 1000.0);
  oled.setCursor(0, 30); oled.printf("I: %.1f mA", current);
  oled.setCursor(0, 46); oled.printf("P: %.0f mW", power);
  oled.setCursor(0, 62);
  if (overflow) oled.print("OVERFLOW");
  else oled.printf("Q: %.2f mAh", mAh);
  oled.sendBuffer();

  delay(250);
}

Steps

  1. Wire the I2C side first (VCC, GND, SDA, SCL for both boards) and leave the load disconnected.
  2. Upload the sketch. The OLED should show about 0 V and close to 0 mA.
  3. Power off, then add the load path: supply + to VIN+, VIN- to load +, load - back to supply -, and tie supply - to ESP32 GND.
  4. Power up the supply. You'll see voltage, current and power update four times a second, and the mAh counter start climbing.
  5. Open the Serial Monitor at 115200 if you want to copy the numbers into a spreadsheet.

Troubleshooting

  • "INA219 not found": run an I2C scanner sketch. You should see 0x40 and 0x3C. If not, check SDA/SCL aren't swapped and that VCC goes to 3V3.
  • Current reads negative: VIN+ and VIN- are reversed. Swap them, or just enjoy the bi-directional part of the name.
  • Bus voltage looks right but current is zero: the load probably isn't going through the shunt. The current must flow VIN+ to VIN-.
  • Random jumps or garbage: you forgot the common ground between the supply and the ESP32.
  • "OVERFLOW" on screen: the load is pulling more than the shunt range. Stay under about 3.2 A with the stock R100 shunt.
  • Small offset at zero current: normal. The library has setShuntVoltOffset_mV() to trim it.

Where to take it next

Log the readings to an SD card, push them to a phone dashboard over Wi-Fi, or put the INA219 between a battery and your project to see exactly how long it'll last. Swapping delay() for deep sleep and watching the mAh number drop is very satisfying.

Want a build like this designed for you from just an idea? Soldr, Compoden's AI, can do it at soldr.ai.

Back to blog

Open this project in the Soldr app → What is Soldr.ai → parts, wiring and code for what this guide builds