INA228 with ESP32 and ESPHome: Battery Current, Amp-Hours and Energy Monitoring

Monitor bidirectional battery current, voltage, power, amp-hours and watt-hours with an INA228, ESP32, ESPHome and Home Assistant. Includes safe shunt wiring and counter-reset guidance.

A battery-powered ESP32 can report voltage and an estimated state of charge, but those figures do not tell you how much current is entering or leaving the battery. An INA228 adds a precision shunt measurement and hardware counters for charge in amp-hours (Ah) and energy in watt-hours (Wh). With ESPHome, you can publish these readings to Home Assistant and see what your solar charger, battery pack or DC equipment actually does throughout the day.

This guide builds a low-voltage DC monitoring project around an ESP32 and an INA228 I²C breakout. It explains the wiring, a complete ESPHome configuration, the meaning of signed current, shunt selection, counter resets and the limits of using charge accumulation to estimate battery percentage. It builds on our INA226 power-monitoring guide and MAX17043 fuel-gauge guide, while addressing a different use case: measuring how much current flowed over time.

What the INA228 actually measures

The INA228 is a digital power monitor. It measures the small voltage across a series shunt resistor and uses the configured resistance to calculate current. It separately senses bus voltage; from those readings it calculates power and maintains charge and energy accumulators. Its digital interface is I²C, so the ESP32 reads the results without timing individual pulses or performing its own high-resolution analogue measurements.

OutputMeaningImportant limitation
Bus voltage (V)Voltage at the VBUS sense input relative to the monitor groundDo not confuse the 3.3 V logic supply with the battery voltage being measured.
Shunt voltage (mV)Differential voltage between IN+ and IN−Its sign depends on your shunt orientation.
Current (A)Calculated from the shunt voltage and configured resistorPositive and negative represent opposite directions; confirm which is charging.
Power (W)Magnitude of measured electrical powerESPHome documents the INA2xx power output as always positive.
Charge (Ah)Hardware-accumulated current over timeA counter since its reference point, not a self-calibrating battery percentage.
Energy (Wh)Hardware-accumulated power over timeTreat as a monitored energy total, not necessarily a net charge/discharge balance.

Texas Instruments specifies a common-mode and bus-sense range up to 85 V for the INA228 silicon, two selectable shunt-voltage ranges (±163.84 mV or ±40.96 mV), and a 2.7–5.5 V supply range. Those are chip specifications. A particular breakout may have lower permitted voltage or current because of its shunt, connectors, traces, spacing and assembly. An 85 V chip rating is not permission to connect an arbitrary battery stack or mains wiring to a hobby breakout. See the INA228 product specifications and your own module documentation.

INA228 versus INA226 and MAX17043

For a fixed DC load, the INA226 is useful for instantaneous voltage, current and power; its typical ESPHome setup then derives energy over time in software. The INA228 adds an internal high-resolution conversion system and hardware charge and energy accumulators. This is valuable when you want to see Ah delivered by a charger or consumed by a load without depending solely on Home Assistant sampling intervals.

The MAX17043 addresses a different problem. It estimates the remaining percentage of an appropriate single-cell Li-ion/LiPo battery from its fuel-gauge model; it is not a series shunt monitor for measuring external load current. For a project that needs both an estimated battery state of charge and measured charger/load current, you may use the two devices for complementary data if their voltage, power and grounding requirements are satisfied.

Parts and a safe first test

  • ESP32 development board with working USB programming and Wi-Fi; this example uses GPIO21 for SDA and GPIO22 for SCL on a conventional ESP32 DevKit. Check your specific board pinout.
  • INA228 I²C breakout with its actual shunt value documented; the example assumes 0.015 Ω (15 mΩ), a value used on one Adafruit board, not a universal INA228 value.
  • A low-voltage DC supply, an appropriately fused resistive test load and a multimeter. Start with a low-current bench test before placing the monitor in a battery circuit.
  • An independent, properly rated charger and protection system for any rechargeable pack. The INA228 does not charge, balance, isolate or protect cells.
  • Short 3.3 V I²C wiring and high-current wiring sized for the expected current. Do not route battery current through thin Dupont jumpers or solderless-breadboard power rails.

Safety boundary: the example is for appropriately fused, low-voltage DC circuits. Battery packs can deliver destructive fault currents. Power off before moving the shunt connections, place a fuse close to the source as appropriate, and verify the shunt and terminals for both continuous current and transient conditions. Do not use a hobby breakout as the sole protection device or for direct mains/AC measurement.

Wire the ESP32 to the INA228 over I²C

Connect the monitor’s logic-power pins first. Names vary: on an Adafruit breakout the logic-supply input is labelled VIN, while its measured circuit contacts are labelled VIN+ and VIN−. Other modules may label logic power VCC or VDD. Read the actual silkscreen rather than assuming every pin with “VIN” belongs to the high-current path.

Conventional ESP32 DevKitINA228 breakout logic pinNotes
3V33.3 V logic supply (VIN/VCC/VDD as specified)Never feed an ESP32 I/O pin with 5 V logic.
GNDGNDProvides the I²C and bus-voltage measurement reference.
GPIO21SDAUse the board’s actual SDA pin if different.
GPIO22SCLUse the board’s actual SCL pin if different.

The INA228 chip can be supplied at 3.3 V even while measuring a higher-voltage DC bus through its sensing inputs. However, the I²C pull-ups must be compatible with 3.3 V ESP32 GPIO. A breakout with pull-ups to 5 V needs appropriate level shifting or reconfiguration. Some breakouts provide their own pull-ups; do not add several strong pull-up networks in parallel without checking the resulting resistance.

The ground reference deserves special attention. Sharing an I²C ground does not mean the monitored battery is allowed to float at an arbitrary voltage relative to the ESP32. The INA228 sensing terminals have common-mode limits relative to the chip ground; isolation is not built into the normal INA228 breakout. In a separate battery system, first establish whether a safe, permitted common reference exists. Where galvanic isolation is required, choose an isolation-rated measurement system rather than joining unrelated grounds.

Place the shunt in the DC current path

A shunt measures only the current that actually passes through it. For high-side monitoring, place it in series with the positive supply conductor: source positive → IN+ → shunt → IN− → load positive. Return the load negative to the source negative; connect the monitor and ESP32 ground to the appropriate circuit reference. The VBUS sense input must reach the intended positive measurement node as specified by your breakout. On the Adafruit INA228 board, a solder jumper can connect VBUS to VIN+ for high-side measurement; it ships open for low-side use. Other breakouts differ. Check the actual INA228 breakout pinout before applying power.

For a battery at the centre of a charger-and-load system, placing one series shunt in a suitable battery lead can show net battery current. In that arrangement, current flowing into the battery and current flowing out must both pass through the same shunt. If a solar controller and load share a supply bus upstream of the shunt, their direct power exchange may not show up as battery current—which is correct: it did not pass through the battery. If you need independent solar-generation, battery and load values, use separate sensors in the corresponding branches.

For an initial test, use a known low-current DC load before attaching a rechargeable pack. Confirm the bus voltage with a multimeter, then verify that switching the load on changes the reported current by a plausible amount. A negative reading in your chosen current direction usually means the shunt leads are reversed relative to your sign convention; decide what positive should mean and label your dashboard accordingly.

Choose a shunt resistance that matches your current

ESPHome needs the physical shunt resistance, not a value chosen to make an inaccurate reading look right. For a 0.015 Ω shunt at 5 A, the expected drop is V = I × R = 0.075 V, and the heat is P = I² × R = 0.375 W. At 10 A, the drop becomes 0.15 V and dissipation reaches 1.5 W. Those are idealised resistor calculations; terminal and trace heating add further limits. Check the shunt’s own wattage rating and the breakout’s continuous-current rating, and allow margin for the enclosure temperature.

The INA228 offers a wider ±163.84 mV shunt range with adc_range: 0, and a narrower ±40.96 mV range with adc_range: 1. With 15 mΩ, the ideal full-scale current magnitudes are approximately 10.9 A and 2.73 A respectively. These figures describe measurement headroom only; they do not establish a safe current rating for the breakout. For a first project, use the wider range and a test load comfortably inside both the electrical and thermal ratings.

A larger shunt improves voltage signal at small currents but loses more power and reduces measurable current range. A smaller shunt lowers losses but demands cleaner wiring and a sufficiently precise ADC. Four-terminal/Kelvin shunts and purpose-built high-current sense boards are more appropriate where cable drops or large load currents would otherwise compromise accuracy. Avoid replacing an onboard shunt casually: the new resistor, PCB copper, joints and calibration all need engineering review.

Complete ESPHome configuration

The following configuration targets a conventional ESP32 DevKit, a 3.3 V-powered I²C breakout at address 0x40, and a physical 0.015 Ω shunt. Replace Wi-Fi secrets and board pins as appropriate, and edit the resistance and max_current to match the actual hardware. The device name and sensor labels are examples; the file is intended as a starting point for a bench build, not a universal drop-in configuration for every INA228 board.

esphome:
  name: ina228-battery-monitor
  friendly_name: INA228 Battery Monitor

esp32:
  board: esp32dev
  framework:
    type: esp-idf

logger:

api:

ota:
  - platform: esphome

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

captive_portal:

i2c:
  sda: GPIO21
  scl: GPIO22
  scan: true
  frequency: 100kHz

sensor:
  - platform: ina2xx_i2c
    id: battery_monitor
    model: INA228
    address: 0x40
    shunt_resistance: 0.015 ohm  # Check your actual board!
    max_current: 10 A           # Calibration; not a safety limit
    adc_range: 0                # +/-163.84 mV shunt range
    adc_averaging: 128
    update_interval: 15s
    reset_on_boot: false

    bus_voltage:
      name: "Battery Bus Voltage"
      id: battery_bus_voltage

    shunt_voltage:
      name: "Battery Shunt Voltage"

    current:
      name: "Battery Current"
      id: battery_current

    power:
      name: "Battery Power Magnitude"

    charge:
      name: "Battery Charge Counter"

    energy:
      name: "Battery Energy Counter"

    temperature:
      name: "INA228 Die Temperature"

ESPHome’s INA2xx component uses ina2xx_i2c, model: INA228, shunt_resistance and max_current. It offers current, bus_voltage, shunt_voltage, power, charge, energy and die-temperature outputs. Note that the documented power sensor is always positive; use signed current to determine whether the measured circuit is charging or discharging. The separate reset_on_boot: false option asks ESPHome not to reset the monitor’s counters on ESPHome initialisation, as long as the monitor itself stays powered. These settings are documented in the current ESPHome INA2xx reference.

Bring up the monitor before connecting it to the battery

  • Flash the ESP32 over USB and open ESPHome logs. Confirm that the I²C scan detects 0x40 or the address set on your breakout.
  • With the DC test supply safely disconnected from the measurement contacts, confirm the logic board boots consistently and the sensor publishes entities.
  • Apply the low-voltage test circuit and compare INA228 bus voltage with a multimeter at the intended VBUS node. A zero or unexpected value often means VBUS was not connected or the wrong measurement node is being sensed.
  • Switch a known load on and off. Confirm current magnitude, current sign, and a plausible shunt voltage. At 1 A through 15 mΩ, expect about 15 mV.
  • Allow the circuit to run long enough for Ah and Wh counters to change. Do not mistake slowly changing low-current totals for a failed component; amp-hours represent current multiplied by elapsed hours.

If the ESP32 does not detect the INA228, power down and recheck SDA/SCL, the actual logic-supply pin, shared reference, pull-up voltage and address jumpers. A valid I²C scan confirms communication, not the correctness of the high-current wiring. Inspect both sections separately.

Understand charging, discharging and the sign of current

Choose a convention before you interpret the numbers. For example, if positive current means battery discharge, orient the shunt so load current reads positive and charging current reads negative. For a battery charging at −2 A for 30 minutes, the signed change in an ideal current integral is −1 Ah. If you reverse IN+ and IN−, the sign reverses; the underlying electrical behaviour does not. Name the entity “Battery Current — positive is discharge” or provide a dashboard note so that an apparently negative “charging” current is not mistaken for a wiring fault.

The chip’s accumulated-charge output is a running integral referenced to its current counter state. It is not “Ah remaining in the battery” unless you have separately established a correct initial value, use a trustworthy battery-capacity estimate and account for charging/discharging efficiency and unmeasured paths. The ESPHome energy output is documented as a calculated accumulated Wh total; do not assume it is signed battery energy just because current is signed. For an accurate split between charge input and discharge output, place dedicated monitors on the relevant branches or use a verified signed-power integration strategy.

Why the charge counter is not battery percentage

Imagine a nominal 20 Ah pack. A counter that starts at zero and reports 3 Ah discharged does not prove the battery is at 85%. That calculation would only be meaningful if the starting pack charge really were 20 Ah, its currently usable capacity were still 20 Ah, no current bypassed the shunt, and efficiency effects were negligible. All those assumptions can change with temperature, ageing, charge rate and cell chemistry. A monitor cannot infer an unknown starting state from current history alone.

A defensible coulomb-counting state-of-charge system needs an initial reference—for example a chemistry-appropriate, independently verified fully charged condition—plus a realistic capacity figure, sign conventions, tracking across every charging and load path, and periodic recalibration. Never use a home-built percentage estimate as a substitute for a battery-management system’s protective voltage, current and temperature limits. For simple single-cell LiPo percentage estimation, the MAX17043 project demonstrates a purpose-built fuel-gauge approach.

Keep the counters through ESP32 restarts

Two different events are easily confused. A microcontroller software restart may leave the INA228 breakout powered, whereas disconnecting the battery or power rail feeding the breakout removes power from the monitor itself. ESPHome exposes reset_on_boot: false so normal component setup does not deliberately clear retained hardware counters after an ESP32 restart. That does not create non-volatile storage inside the chip: after loss of monitor power, counter continuity is no longer guaranteed.

There is also a measurement gap if the monitor remains powered but its connections or measurement mode are interrupted, or if the circuit carries current outside the shunt. Publishing to Home Assistant every 15 seconds does not inherently mean the INA228 only measures once per 15 seconds; the chip performs conversions and accumulation internally. However, an offline Home Assistant server cannot retroactively recover samples or counter history that the hardware reset has erased. Keep the INA228 supply independent of a software-controlled ESP32 power switch when continuity matters, while accounting for the resulting idle consumption.

If you add a manual counter-reset button, do so only for a defined new measurement session. Resetting without recording the previous value will destroy the baseline needed to compare earlier and later Ah. The component documents a reset_energy_counters() method, but the main example intentionally omits a reset button to prevent accidental loss of accumulated data.

Set up useful Home Assistant views

Once the device is discovered through the ESPHome integration, put the following entities on one dashboard: bus voltage, signed current, power magnitude, accumulated Ah, accumulated Wh, and sensor die temperature. Use a history graph for current with a visible zero line, and a second graph for battery voltage. A charger/load cycle should appear as a sign change in the current plot if you are monitoring the battery branch. A graph of power magnitude alone cannot show current direction.

Use a statistics card or history view to compare resting voltage and load voltage, but expect voltage sag during heavy current. Do not calculate “health” or “capacity” from a few minutes of voltage and Ah data; a meaningful capacity test needs a controlled charge/discharge procedure and battery-manufacturer limits. The die-temperature sensor measures the INA228 chip itself, not cell temperature. Add a suitable battery-temperature probe if your protection, alerting or diagnostic use case requires it.

For an informative low-voltage alert, establish a suitable threshold from your battery chemistry, cell count, load and protection hardware, then trigger on the monitored voltage only if the reading is valid and the monitor is online. Consider delaying transient alerts during motor startup or radio transmission. Do not use an ESP32 automation as the primary low-voltage cut-off or charge-termination safety mechanism for rechargeable batteries.

Daily energy in Home Assistant: avoid false totals

The INA228 hardware counter may restart at zero after a power loss. Home Assistant’s Utility Meter integration can build daily or monthly totals from a suitable energy-source entity, but its periodically resetting and net consumption options need deliberate configuration. A counter that decreases because the monitor rebooted must not be treated as negative energy exported by the battery. Likewise, the native INA2xx power output is always positive, so a utility meter based on it cannot distinguish charging from discharging.

For a simple one-directional DC test load, start by plotting the existing accumulated Wh entity and verifying that it behaves monotonically during the test. Only then create a daily utility-meter helper using that entity, inspect its behaviour across an intentional test restart, and confirm no false jump appears. For a two-direction battery setup, track energy into and out of the battery separately using appropriately designed measurements and distinct dashboard entities. Treat the resulting figures as engineering telemetry, not certified energy billing data.

Accuracy: test the whole chain

An INA228 can be precise and still report the wrong system current if the shunt resistance, sense leads or wiring path are wrong. Validate the chain with at least two known DC loads across the intended operating range. Compare current with a suitably rated independent meter placed in series, and compare bus voltage at the same points. Test with the battery/charger disconnected whenever relocating the current meter would open a high-current circuit.

A consistent scaling error suggests a mismatched shunt_resistance; an offset near zero may reflect noise, temperature drift or leakage; a current value that is consistently smaller than expected may indicate that some of the load bypasses the shunt. For a 15 mΩ resistor, a 2 A load should generate approximately 30 mV across the shunt. If the measured drop is plausible but reported current is not, inspect the configuration. If the drop itself is wrong, inspect the current path and probe points before changing software.

Pay attention to connector resistance and thermal behaviour at higher current. A low-ohm shunt produces a tiny differential signal; thin, long sense wiring laid beside switching-converter leads can inject noise. Keep I²C wiring short and route the power loop sensibly. If your battery system uses long or noisy cables, select a module with proper Kelvin sensing and good mechanical current connections rather than assuming more ADC averaging can fix a poor layout.

Troubleshooting common INA228 problems

The I²C scanner sees nothing at 0x40

Check that the breakout receives the correct logic voltage, not just battery voltage on the sensing terminals. Verify SDA and SCL are not reversed, the logic ground has a valid reference and pull-ups do not reach 5 V at the ESP32 pins. Address jumpers can change the default 0x40 address. If the board is detected only when the high-current circuit is disconnected, investigate grounding, voltage stress or a wiring error before retrying.

Voltage is zero but current changes

The VBUS sense input may be floating, disconnected or connected to a different node. On some boards VIN+ and VBUS are linked only after closing an optional jumper. Confirm the intended measurement topology from the module schematic and measure the VBUS contact with a multimeter relative to monitor ground. Never short arbitrary pins together to “fix” a zero reading.

Current is negative when charging—or never changes sign

Negative current is normal if your chosen positive convention means discharge. If the sign never changes, the charger may be supplying the load without sending current through the battery, or the monitor may be installed in the load branch rather than the battery branch. Review the actual conductor path and compare readings under three test conditions: load only, charger only and both together, all within the safely controlled operating conditions of the system.

Current is wildly high or clips at one value

Confirm the numerical shunt resistance in ohms. A shunt marked 15 mΩ is 0.015 ohm, not 15 Ω or 0.15 Ω. Check the configured ADC shunt range and estimate I × R before selecting it. The max_current parameter configures calibration; it cannot enlarge the physical shunt’s current rating, differential full-scale range or connector capacity.

Ah resets unexpectedly

Determine whether just the ESP32 rebooted or the INA228 lost its own power. reset_on_boot: false can avoid deliberate counter clearing on ESPHome initialisation while the sensor remains energised; it cannot restore a hardware counter after loss of power. Check power wiring, regulator brownouts, aggressive deep-sleep arrangements and any electronic switch that disconnects the monitor.

Home Assistant shows strange daily energy totals

First compare the original ESPHome counter with the derived Home Assistant sensor. A reset at the device, a signed value interpreted as consumption, or a utility-meter setting unsuitable for the source can create implausible daily changes. Correct the source behaviour before relying on statistics; do not conceal a counter discontinuity by multiplying values or applying an arbitrary template offset.

Where this project fits in a larger ESP32 battery system

The INA228 is useful on a solar-battery junction, a DC laboratory supply, a low-voltage UPS branch or a charger-output line when you need measured current history in addition to voltage. It is especially helpful for comparing idle draw against active draw and evaluating whether power-management changes actually save energy. If you need independent figures for three DC branches but do not require native charge accumulation on each one, our INA3221 three-channel guide covers that alternative.

Start with the bench configuration, establish a documented current direction, validate the physical shunt, then design the battery-side wiring and protective hardware. That sequence gives the Home Assistant graphs a clear physical meaning and avoids the most common failure of battery dashboards: precise-looking values that do not measure the intended conductor.

References and further reading

Share your love