mirror of
https://github.com/sbcshop/UPS-Hat-RPi.git
synced 2024-12-22 21:08:15 +03:00
182 lines
6.8 KiB
Python
182 lines
6.8 KiB
Python
'''
|
||
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)
|