Files
UPS-Hat-RPi/INA219_UPS.py
2022-03-14 10:32:51 +05:30

182 lines
6.8 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'''
The INA219 is a current shunt and power monitor with an I2C- or SMBUS-compatible interface.
The device monitors both shunt voltage drop and bus supply voltage, with programmable conversion times and filtering.
The INA219 operates from 40°C to 125°C.
'''
from serial import SerialException
from oled_091 import SSD1306
from time import sleep
from os import path
import smbus
import time
DIR_PATH = path.abspath(path.dirname(__file__))
DefaultFont = path.join(DIR_PATH, "Fonts/GothamLight.ttf")
def info_print():
oled_display.DirImage(path.join(DIR_PATH, "Images/SB.png"))
oled_display.DrawRect()
oled_display.ShowImage()
sleep(2)
oled_display = SSD1306()
info_print()
_REG_CONFIG = 0x00 # Config Register (R/W)
_REG_SHUNTVOLTAGE = 0x01 # SHUNT VOLTAGE REGISTER (R)
_REG_BUSVOLTAGE = 0x02 # BUS VOLTAGE REGISTER (R)
_REG_POWER = 0x03 # POWER REGISTER (R)
_REG_CURRENT = 0x04 # CURRENT REGISTER (R)
_REG_CALIBRATION = 0x05 # CALIBRATION REGISTER (R/W)
class Bus_Voltage_Range:
"""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 ADC_Resolution:
"""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.calibration()
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 calibration(self): # set calibration 32V ,2A
"""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
"""
self._current_lsb = 0.1 # Current LSB = 100uA per bit
self._cal_value = 4096
self._power_lsb = 0.002 # Power LSB = 2mW per bit
# 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 = Bus_Voltage_Range.RANGE_32V
self.gain = Gain.DIV_8_320MV
self.bus_adc_resolution = ADC_Resolution.ADCRES_12BIT_32S
self.shunt_adc_resolution = ADC_Resolution.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 Shunt_Voltage(self): # shunt voltage in milli volt
self.write(_REG_CALIBRATION,self._cal_value)
value = self.read(_REG_SHUNTVOLTAGE)
if value > 32767:
value -= 65535
return value * 0.01
def Current(self): # current in milli amp
value = self.read(_REG_CURRENT)
if value > 32767:
value -= 65535
return value * self._current_lsb
def Power(self):
self.write(_REG_CALIBRATION,self._cal_value)
value = self.read(_REG_POWER)
if value > 32767:
value -= 65535
return value * self._power_lsb
def Bus_Voltage(self):
self.write(_REG_CALIBRATION,self._cal_value)
self.read(_REG_BUSVOLTAGE)
return (self.read(_REG_BUSVOLTAGE) >> 3) * 0.004
# Create an INA219 instance.
ina219 = INA219(addr=0x42)
while True:
bus_voltage = ina219.Bus_Voltage() # voltage on V- (load side)
shunt_voltage = ina219.Shunt_Voltage() / 1000 # voltage between V+ and V- across the shunt
current = ina219.Current() # current in mA
power = ina219.Power() # power in W
p = (bus_voltage - 6)/2.4*100
if(p > 100):p = 100
if(p < 0):p = 0
print("Load Voltage: {:6.3f} V".format(bus_voltage))
print("Current: {:9.6f} A".format(current/1000))
print("Power: {:6.3f} W".format(power))
print("Percent: {:3.1f}%".format(p))
print("")
# print readings in oled display
oled_display.PrintText("Load Voltage= {:6.3f} V".format(bus_voltage),cords=(0, 0), FontSize=10)
oled_display.PrintText("Current = {:9.6f} A".format(current/1000),cords=(0,8), FontSize=10)
oled_display.PrintText("Power = {:6.3f} W".format(power),cords=(0,16), FontSize=10)
oled_display.PrintText("Percent = {:3.1f}%".format(p),cords=(0,24), FontSize=10)
oled_display.ShowImage()
time.sleep(2)