Created
August 25, 2020 14:25
-
-
Save frankgould/3613f3d17ed24c02058a303f55f46a95 to your computer and use it in GitHub Desktop.
Geekworm UPS3 RPi HAT Modified Example Code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os, smbus, time, logging, atexit | |
from datetime import datetime | |
log_file = '/home/rover_logs/rover-battery-log-' + datetime.now().strftime('%m-%d-%y') + '.txt' | |
logging.basicConfig(filename=log_file,level=logging.DEBUG) | |
logging.info('==================== Rover UPS3 Battery Capacity Communications Client Logging Started ' + datetime.now().strftime('%m-%d-%y %H:%M:%S')) | |
BYTE_CONV_ADC_START = 0b10011101 | |
BYTE_CONV_ADC_STOP = 0b00011101 | |
BYTE_WATCHDOG_STOP = 0b10001101 #Stop Watchdog timer | |
MAX17048_ADDR = 0x36 | |
BQ25895_ADDRESS = 0x6A | |
REG_WATCHDOG = 0x07 | |
REG_ILIM = 0x00 #ILIM register | |
BYTE_ILIM = 0b01111111 #3.25A input current limit | |
REG_ICHG = 0x04 | |
BYTE_ICHG = 0b01111111 #.5A charging current limit | |
REG_BATFET = 0x09 | |
BYTE_BATFET = 0b01001000 #delay before battery == disconnected | |
REG_CONV_ADC = 0x02 | |
REG_STATUS = 0x0B #address of status register | |
REG_BATV = 0x0e | |
BAT_CAPACITY = 2500 #Battery capacity in mah | |
CURRENT_DRAW = 2000 #Current draw in mah | |
disconnectflag = False | |
POWEROFF_POWER = 5 | |
count = 0 | |
def shutdown(*kwarg): | |
logging.info('Shutdown occurred, shutting RPi down now at ' + str(datetime.now().strftime('%H:%M:%S')) + '.') | |
atexit.register(shutdown) | |
def bq25895_int_to_bool_list(num): | |
return [bool(num & (1<<n)) for n in range(8)] | |
def bq25895_translate(val, in_from, in_to, out_from, out_to): | |
out_range = out_to - out_from | |
in_range = in_to - in_from | |
in_val = val - in_from | |
val=(float(in_val)/in_range)*out_range | |
out_val = out_from+val | |
return out_val | |
# Get voltage from max17048 | |
def max17048_getstatus(): | |
global max17048_v, max17048_soc | |
max17048_v_16 = bus.read_word_data(MAX17048_ADDR, 0x02); | |
soc = bus.read_word_data(MAX17048_ADDR, 0x04); | |
max17048_v = (((max17048_v_16 & 0x00FF) << 8) + (max17048_v_16 >> 8)) * 78.125 / 1000000 | |
max17048_soc = (((soc & 0x00FF) << 8) + (soc >> 8)) / 256 | |
bus = smbus.SMBus(1) | |
bus.write_word_data(MAX17048_ADDR, 0xFE ,0xFFFF) | |
bus.write_byte_data(BQ25895_ADDRESS, REG_WATCHDOG, BYTE_WATCHDOG_STOP) | |
bus.write_byte_data(BQ25895_ADDRESS, REG_ILIM, BYTE_ILIM) | |
bus.write_byte_data(BQ25895_ADDRESS, REG_ICHG, BYTE_ICHG) | |
bus.write_byte_data(BQ25895_ADDRESS, REG_BATFET, BYTE_BATFET) | |
# BQ25895 read status | |
def bq25895_read_status(): | |
global disconnectflag, bq25895_status | |
bus.write_byte_data(BQ25895_ADDRESS, REG_CONV_ADC, BYTE_CONV_ADC_START) | |
sample = bus.read_byte_data(BQ25895_ADDRESS, REG_STATUS) | |
status = bq25895_int_to_bool_list(sample) | |
time.sleep(1.2) | |
sample = bus.read_byte_data(BQ25895_ADDRESS, REG_BATV) | |
batvbool = bq25895_int_to_bool_list(sample) | |
bus.write_byte_data(BQ25895_ADDRESS, REG_CONV_ADC, BYTE_CONV_ADC_STOP) | |
vsys_stat = status[0] | |
sdp_stat = status[1] | |
pg_stat = status[2] | |
chrg_stat = status[4] * 2 + status[3] | |
vbus_stat = status[7] * 4 + status[6] * 2 + status[5] | |
if status[2]: | |
power = "Connected" | |
else: | |
power = "Disconnected" | |
if status[3] and status[4]: | |
charge = "Charging done" | |
elif status[4] and not status[3]: | |
charge = "Charging" | |
elif not status[4] and status[3]: | |
charge = "Pre-Charge" | |
else: | |
charge = "Discharging" | |
#convert batv register to volts | |
batv = 2.304 | |
batv += batvbool[6] * 1.280 | |
batv += batvbool[5] * 0.640 | |
batv += batvbool[4] * 0.320 | |
batv += batvbool[3] * 0.160 | |
batv += batvbool[2] * 0.08 | |
batv += batvbool[1] * 0.04 | |
batv += batvbool[0] * 0.02 | |
batpercent = bq25895_translate(batv,3.5,4.184,0,1) | |
if batpercent<0 : | |
batpercent = 0 | |
elif batpercent >1 : | |
batpercent = 1 | |
timeleftmin = int( batpercent * 60* BAT_CAPACITY / CURRENT_DRAW) | |
if timeleftmin < 0 : | |
timeleftmin = 0 | |
if power == "Connected" : | |
timeleftmin = -1 | |
if power == "Disconnected" and disconnectflag == False : | |
disconnectflag = True | |
message = "***** Battery at " + str(int(batpercent * 100)) + "%. Power Disconnected, system will shutdown in " + str((timeleftmin)) + " minutes!" | |
print(message) | |
logging.info(message) | |
if power == "Connected" and disconnectflag == True : | |
disconnectflag = False | |
message = "***** Power Restored, battery at " + str(int(batpercent * 100)) + "%." | |
print(message) | |
logging.info(message) | |
bq25895_status = { | |
'Input': power, | |
'ChargeStatus' : charge, | |
'BatteryVoltage' : '%.2f' % batv, | |
"BatteryPercentage" : int(batpercent*100), | |
'TimeRemaining' : int(timeleftmin) | |
} | |
if(batv < 3.5): | |
bus.write_byte_data(BQ25895_ADDRESS, REG_BATFET_DIS, BYTE_BATFET_DIS) | |
max17048_getstatus() | |
bq25895_read_status() | |
print ("Input: " , bq25895_status['Input']) | |
print ("State: " , bq25895_status['ChargeStatus']) | |
print ("Voltage: " , bq25895_status['BatteryVoltage']) | |
print ("Capacity: " + str(bq25895_status['BatteryPercentage']) + "%") | |
print ("max17048_soc: " + str(max17048_soc)) | |
try: | |
while (True): | |
max17048_getstatus() | |
bq25895_read_status() | |
if ((bq25895_status['Input'] != 'Connected') and (max17048_soc < POWEROFF_POWER)): | |
count += 1 | |
message = "**** Shutting down in " + str(50-(count*5)) + " seconds. Value max17048_soc = " + str(max17048_soc) + " *****" | |
print(message) | |
logging.info(message) | |
if count == 10: | |
os.system("sudo halt -h") | |
if str(bq25895_status['Input']) == 'Connected': | |
message = str(datetime.now().strftime('%H:%M:%S')) + " - Input: " + str(bq25895_status['Input']) + ", State: " + str(bq25895_status['ChargeStatus']) + ", Voltage: " + str(bq25895_status['BatteryVoltage']) + ", Capacity: " + str(bq25895_status['BatteryPercentage']) + "%. Value max17048_soc = " + str(max17048_soc) | |
else: | |
message = str(datetime.now().strftime('%H:%M:%S')) + " - Input: " + str(bq25895_status['Input']) + ", State: " + str(bq25895_status['ChargeStatus']) + ", Voltage: " + str(bq25895_status['BatteryVoltage']) + ", max17048_soc: " + str(max17048_soc) + ", TimeRemaining: " + str(bq25895_status['TimeRemaining']) + " minutes." | |
print (message) | |
logging.info(message) | |
time.sleep(5) | |
except Exception as err: | |
message = 'Exception error: ' + str(err) | |
print (message) | |
logging.info(message) | |
exit |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment