Install python3 if it is not installed. There will be a lot of resources available on the Internet.
https://www.waveshare.com/w/upload/6/69/Current-Power_Monitor_HAT_Code.7z (see link in the Information about Current Monitor HAT section if this link not working)
Download the demo code to Raspberry Pi and extract 7z file to a folder.
Change the directory to the RaspberyPi folder in the extracted folder.
Execute Demo code as follows and then you can see the power reading as follows.
If you can see above with proper reading. your hardware setup is ready.
This demo code is logging reading to on-screen only. I did a small modification to the above to write logs into a text file (tab-delimited fields)
Copy ina219.py to your preferred folder. My folder name is esps
See the changed code below.
Now you are good to go live and it will create one text file per day.
Run the modified code from your new folder.
Files will be generated as follows.
Full Python code is as follows.
import datetime
import os
import smbus
import time
# Config Register (R/W)
_REG_CONFIG = 0x00
# SHUNT VOLTAGE REGISTER (R)
_REG_SHUNTVOLTAGE = 0x01
# BUS VOLTAGE REGISTER (R)
_REG_BUSVOLTAGE = 0x02
# POWER REGISTER (R)
_REG_POWER = 0x03
# CURRENT REGISTER (R)
_REG_CURRENT = 0x04
# CALIBRATION REGISTER (R/W)
_REG_CALIBRATION = 0x05
class BusVoltageRange:
"""Constants for ``bus_voltage_range``"""
RANGE_16V = 0x00 # set bus voltage range to 16V
RANGE_32V = 0x01 # set bus voltage range to 32V (default)
class Gain:
"""Constants for ``gain``"""
DIV_1_40MV = 0x00 # shunt prog. gain set to 1, 40 mV range
DIV_2_80MV = 0x01 # shunt prog. gain set to /2, 80 mV range
DIV_4_160MV = 0x02 # shunt prog. gain set to /4, 160 mV range
DIV_8_320MV = 0x03 # shunt prog. gain set to /8, 320 mV range
class ADCResolution:
"""Constants for ``bus_adc_resolution`` or ``shunt_adc_resolution``"""
ADCRES_9BIT_1S = 0x00 # 9bit, 1 sample, 84us
ADCRES_10BIT_1S = 0x01 # 10bit, 1 sample, 148us
ADCRES_11BIT_1S = 0x02 # 11 bit, 1 sample, 276us
ADCRES_12BIT_1S = 0x03 # 12 bit, 1 sample, 532us
ADCRES_12BIT_2S = 0x09 # 12 bit, 2 samples, 1.06ms
ADCRES_12BIT_4S = 0x0A # 12 bit, 4 samples, 2.13ms
ADCRES_12BIT_8S = 0x0B # 12bit, 8 samples, 4.26ms
ADCRES_12BIT_16S = 0x0C # 12bit, 16 samples, 8.51ms
ADCRES_12BIT_32S = 0x0D # 12bit, 32 samples, 17.02ms
ADCRES_12BIT_64S = 0x0E # 12bit, 64 samples, 34.05ms
ADCRES_12BIT_128S = 0x0F # 12bit, 128 samples, 68.10ms
class Mode:
"""Constants for ``mode``"""
POWERDOW = 0x00 # power down
SVOLT_TRIGGERED = 0x01 # shunt voltage triggered
BVOLT_TRIGGERED = 0x02 # bus voltage triggered
SANDBVOLT_TRIGGERED = 0x03 # shunt and bus voltage triggered
ADCOFF = 0x04 # ADC off
SVOLT_CONTINUOUS = 0x05 # shunt voltage continuous
BVOLT_CONTINUOUS = 0x06 # bus voltage continuous
SANDBVOLT_CONTINUOUS = 0x07 # shunt and bus voltage continuous
class INA219:
def __init__(self, i2c_bus=1, addr=0x40):
self.bus = smbus.SMBus(i2c_bus);
self.addr = addr
# Set chip to known config values to start
self._cal_value = 0
self._current_lsb = 0
self._power_lsb = 0
self.set_calibration_32V_2A()
def read(self,address):
data = self.bus.read_i2c_block_data(self.addr, address, 2)
return ((data[0] * 256 ) + data[1])
def write(self,address,data):
temp = [0,0]
temp[1] = data & 0xFF
temp[0] =(data & 0xFF00) >> 8
self.bus.write_i2c_block_data(self.addr,address,temp)
def set_calibration_32V_2A(self):
"""Configures to INA219 to be able to measure up to 32V and 2A of current. Counter
overflow occurs at 3.2A.
..note :: These calculations assume a 0.1 shunt ohm resistor is present
"""
# By default we use a pretty huge range for the input voltage,
# which probably isn't the most appropriate choice for system
# that don't use a lot of power. But all of the calculations
# are shown below if you want to change the settings. You will
# also need to change any relevant register settings, such as
# setting the VBUS_MAX to 16V instead of 32V, etc.
# VBUS_MAX = 32V (Assumes 32V, can also be set to 16V)
# VSHUNT_MAX = 0.32 (Assumes Gain 8, 320mV, can also be 0.16, 0.08, 0.04)
# RSHUNT = 0.1 (Resistor value in ohms)
# 1. Determine max possible current
# MaxPossible_I = VSHUNT_MAX / RSHUNT
# MaxPossible_I = 3.2A
# 2. Determine max expected current
# MaxExpected_I = 2.0A
# 3. Calculate possible range of LSBs (Min = 15-bit, Max = 12-bit)
# MinimumLSB = MaxExpected_I/32767
# MinimumLSB = 0.000061 (61uA per bit)
# MaximumLSB = MaxExpected_I/4096
# MaximumLSB = 0,000488 (488uA per bit)
# 4. Choose an LSB between the min and max values
# (Preferrably a roundish number close to MinLSB)
# CurrentLSB = 0.0001 (100uA per bit)
self._current_lsb = .1 # Current LSB = 100uA per bit
# 5. Compute the calibration register
# Cal = trunc (0.04096 / (Current_LSB * RSHUNT))
# Cal = 4096 (0x1000)
self._cal_value = 4096
# 6. Calculate the power LSB
# PowerLSB = 20 * CurrentLSB
# PowerLSB = 0.002 (2mW per bit)
self._power_lsb = .002 # Power LSB = 2mW per bit
# 7. Compute the maximum current and shunt voltage values before overflow
#
# Max_Current = Current_LSB * 32767
# Max_Current = 3.2767A before overflow
#
# If Max_Current > Max_Possible_I then
# Max_Current_Before_Overflow = MaxPossible_I
# Else
# Max_Current_Before_Overflow = Max_Current
# End If
#
# Max_ShuntVoltage = Max_Current_Before_Overflow * RSHUNT
# Max_ShuntVoltage = 0.32V
#
# If Max_ShuntVoltage >= VSHUNT_MAX
# Max_ShuntVoltage_Before_Overflow = VSHUNT_MAX
# Else
# Max_ShuntVoltage_Before_Overflow = Max_ShuntVoltage
# End If
# 8. Compute the Maximum Power
# MaximumPower = Max_Current_Before_Overflow * VBUS_MAX
# MaximumPower = 3.2 * 32V
# MaximumPower = 102.4W
# Set Calibration register to 'Cal' calculated above
self.write(_REG_CALIBRATION,self._cal_value)
# Set Config register to take into account the settings above
self.bus_voltage_range = BusVoltageRange.RANGE_32V
self.gain = Gain.DIV_8_320MV
self.bus_adc_resolution = ADCResolution.ADCRES_12BIT_32S
self.shunt_adc_resolution = ADCResolution.ADCRES_12BIT_32S
self.mode = Mode.SANDBVOLT_CONTINUOUS
self.config = self.bus_voltage_range << 13 | \
self.gain << 11 | \
self.bus_adc_resolution << 7 | \
self.shunt_adc_resolution << 3 | \
self.mode
self.write(_REG_CONFIG,self.config)
def getShuntVoltage_mV(self):
self.write(_REG_CALIBRATION,self._cal_value)
value = self.read(_REG_SHUNTVOLTAGE)
if value > 32767:
value -= 65535
return value * 0.01
def getBusVoltage_V(self):
self.write(_REG_CALIBRATION,self._cal_value)
self.read(_REG_BUSVOLTAGE)
return (self.read(_REG_BUSVOLTAGE) >> 3) * 0.004
def getCurrent_mA(self):
value = self.read(_REG_CURRENT)
if value > 32767:
value -= 65535
return value * self._current_lsb
def getPower_W(self):
value = self.read(_REG_POWER)
if value > 32767:
value -= 65535
return value * self._power_lsb
def append_lines_solar_gen_log(self, line):
file_name = "solar_gen_{0}.log".format(datetime.datetime.now().strftime("%d_%m_%Y"))
if os.path.isfile(file_name):
with open(file_name, 'a') as file:
file.write(line + '\n')
else:
with open(file_name, 'w') as file:
file.write("Date_Time\tPSU_Voltage_V\tShunt_Voltage\tLoad_Voltage\tPower_W\tCurrent_A\n")
file.write(line + '\n')
if __name__=='__main__':
ina1 = INA219(addr=0x40)
# ina2 = INA219(addr=0x41)
# ina3 = INA219(addr=0x42)
# ina4 = INA219(addr=0x43)
while True:
now = datetime.datetime.now()
bus_voltage1 = ina1.getBusVoltage_V() # voltage on V- (load side)
shunt_voltage1 = ina1.getShuntVoltage_mV() / 1000 # voltage between V+ and V- across the shunt
current1 = ina1.getCurrent_mA() # current in mA
power1 = ina1.getPower_W() # power in watts
# bus_voltage2 = ina2.getBusVoltage_V() # voltage on V- (load side)
# shunt_voltage2 = ina2.getShuntVoltage_mV() / 1000 # voltage between V+ and V- across the shunt
# current2 = ina2.getCurrent_mA() # current in mA
# power2 = ina2.getPower_W() # power in watts
# bus_voltage3 = ina3.getBusVoltage_V() # voltage on V- (load side)
# shunt_voltage3 = ina3.getShuntVoltage_mV() / 1000 # voltage between V+ and V- across the shunt
# current3 = ina3.getCurrent_mA() # current in mA
# power3 = ina3.getPower_W() # power in watts
# bus_voltage4 = ina4.getBusVoltage_V() # voltage on V- (load side)
# shunt_voltage4 = ina4.getShuntVoltage_mV() / 1000 # voltage between V+ and V- across the shunt
# current4 = ina4.getCurrent_mA() # current in mA
# power4 = ina4.getPower_W() # power in watts
# INA219 measure bus voltage on the load side. So PSU voltage = bus_voltage + shunt_voltage
# print("PSU Voltage:{:6.3f}V Shunt Voltage:{:9.6f}V Load Voltage:{:6.3f}V Power:{:9.6f}W Current:{:9.6f}A".format((bus_voltage1 + shunt_voltage1),(shunt_voltage1),(bus_voltage1),(power1),(current1/1000)))
# print("PSU Voltage:{:6.3f}V Shunt Voltage:{:9.6f}V Load Voltage:{:6.3f}V Power:{:9.6f}W Current:{:9.6f}A".format((bus_voltage2 + shunt_voltage2),(shunt_voltage2),(bus_voltage2),(power2),(current2/1000)))
# print("PSU Voltage:{:6.3f}V Shunt Voltage:{:9.6f}V Load Voltage:{:6.3f}V Power:{:9.6f}W Current:{:9.6f}A".format((bus_voltage3 + shunt_voltage3),(shunt_voltage3),(bus_voltage3),(power3),(current3/1000)))
# print("PSU Voltage:{:6.3f}V Shunt Voltage:{:9.6f}V Load Voltage:{:6.3f}V Power:{:9.6f}W Current:{:9.6f}A".format((bus_voltage4 + shunt_voltage4),(shunt_voltage4),(bus_voltage4),(power4),(current3/1000)))
print("")
log_hader = "Date_Time\tPSU_Voltage_V\tShunt_Voltage\tLoad_Voltage\tPower_W\tCurrent_A"
log_entry = "{:}\t{:6.3f}\t{:9.6f}\t{:6.3f}\t{:9.6f}\t{:9.6f}".format(now.strftime("%d/%m/%Y %H:%M:%S"), (bus_voltage1 + shunt_voltage1),(shunt_voltage1),(bus_voltage1),(power1),(current1/1000))
ina1.append_lines_solar_gen_log(log_entry)
print("PSU Voltage:{:6.3f}V Shunt Voltage:{:9.6f}V Load Voltage:{:6.3f}V Power:{:9.6f}W Current:{:9.6f}A".format((bus_voltage1 + shunt_voltage1),(shunt_voltage1),(bus_voltage1),(power1),(current1/1000)))
time.sleep(30)