Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Time to soc #94

Merged
merged 2 commits into from
Feb 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 34 additions & 10 deletions etc/dbus-serialbattery/battery.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ def __init__(self, port, baud):
# max battery charge/discharge current
self.max_battery_current = None
self.max_battery_discharge_current = None

self.time_to_soc_update = TIME_TO_SOC_LOOP_CYCLES

def test_connection(self):
# Each driver must override this function to test if a connection can be made
Expand Down Expand Up @@ -173,24 +175,46 @@ def get_cell_balancing(self, idx):
return 1
return 0

def get_timetosoc(self, socnum):
# def get_timetosoc(self, socnum):
# Update TimeToSoC items
if self.battery.capacity is None or not self.battery.current:
return None
# if self.battery.capacity is None or not self.battery.current:
# return None

# check if we are past socNum when charging
# or discharging
# or on the same SOC (using 0.5% tolerance)
if (self.battery.current > 0 and self.battery.soc > socnum) or \
(self.battery.current < 0 and self.battery.soc < socnum) or \
(self.battery.soc - socnum < 0.5):
return "00:00:00"
# if (self.battery.current > 0 and self.battery.soc > socnum) or \
# (self.battery.current < 0 and self.battery.soc < socnum) or \
# (self.battery.soc - socnum < 0.5):
# return "00:00:00"

# Get Seconds to reach goal Soc using current flow
crntPrctPerSec = (abs(self.battery.current / (self.battery.capacity / 100)) / 3600)
secondstogo = int(abs(socnum - self.battery.soc) / crntPrctPerSec)
# crntPrctPerSec = (abs(self.battery.current / (self.battery.capacity / 100)) / 3600)
# secondstogo = int(abs(socnum - self.battery.soc) / crntPrctPerSec)

# return str(timedelta(seconds=secondstogo))
def get_timetosoc(self, socnum, crntPrctPerSec):
if self.current > 0:
diffSoc = (socnum - self.soc)
else:
diffSoc = (self.soc - socnum)

ttgStr = None
if self.soc != socnum and (diffSoc > 0 or TIME_TO_SOC_INC_FROM is True):
secondstogo = int(diffSoc / crntPrctPerSec)
ttgStr = ""

if (TIME_TO_SOC_VALUE_TYPE & 1):
ttgStr += str(secondstogo)
if (TIME_TO_SOC_VALUE_TYPE & 2):
ttgStr += " ["
if (TIME_TO_SOC_VALUE_TYPE & 2):
ttgStr += str(timedelta(seconds=secondstogo))
if (TIME_TO_SOC_VALUE_TYPE & 1):
ttgStr += "]"

return ttgStr

return str(timedelta(seconds=secondstogo))

def get_min_cell_voltage(self):
min_voltage = None
Expand Down
23 changes: 17 additions & 6 deletions etc/dbus-serialbattery/daly.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ def __init__(self, port,baud,address):
self.cell_max_voltage = None
self.cell_min_no = None
self.cell_max_no = None
self.poll_interval = 2000
self.poll_interval = 1000
self.poll_step = 0
self.type = self.BATTERYTYPE
# command bytes [StartFlag=A5][Address=40][Command=94][DataLength=8][8x zero bytes][checksum]
command_base = b"\xA5\x40\x94\x08\x00\x00\x00\x00\x00\x00\x00\x00\x81"
Expand Down Expand Up @@ -46,11 +47,21 @@ def get_settings(self):

def refresh_data(self):
result = self.read_soc_data()
result = result and self.read_alarm_data()
result = result and self.read_cells_volts()
result = result and self.read_cell_voltage_range_data()
result = result and self.read_temperature_range_data()
result = result and self.read_fed_data()
if self.poll_step == 0:
# This must be listed in step 0 as get_min_cell_voltage and get_max_cell_voltage in battery.py needs it at first cycle for publish_dbus in dbushelper.py
result = result and self.read_cell_voltage_range_data()
elif self.poll_step == 1:
result = result and self.read_alarm_data()
elif self.poll_step == 2:
result = result and self.read_cells_volts()
elif self.poll_step == 3:
result = result and self.read_temperature_range_data()
#else: # A placeholder to remind this is the last step. Add any additional steps before here
# This is last step so reset poll_step
self.poll_step = -1

self.poll_step += 1

return result

Expand Down Expand Up @@ -223,7 +234,7 @@ def read_cells_volts(self):
frame = 0
while frame >= 0 and frame < maxFrame and cellnum < self.cell_count:
startPos = ((frame * 12) + 4)
logger.warning('cell: ' + str(cellnum) + ', startPos: ' + str(startPos) + ', frame: ' + str(frame))
#logger.warning('cell: ' + str(cellnum) + ', startPos: ' + str(startPos) + ', frame: ' + str(frame))
if frame > 0 and frame < 16:
startPos += 1
frame, frameCell[0], frameCell[1], frameCell[2], reserved = unpack_from('>bhhhb', cells_volts_data, startPos)
Expand Down
68 changes: 50 additions & 18 deletions etc/dbus-serialbattery/dbushelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,14 +137,23 @@ def setup_vedbus(self):
self._dbusservice.add_path('/Alarms/LowTemperature', None, writeable=True)

#cell voltages - begining
for i in range(self.battery.cell_count):
self._dbusservice.add_path('/Voltages/Cell%s'%(str(i+1)), None, writeable=True, gettextcallback=lambda p, v: "{:0.3f}V".format(v))
self._dbusservice.add_path('/Balances/Cell%s'%(str(i+1)), None, writeable=True)
self._dbusservice.add_path('/Voltages/Sum', None, writeable=True, gettextcallback=lambda p, v: "{:2.2f}V".format(v))
self._dbusservice.add_path('/Voltages/Diff', None, writeable=True, gettextcallback=lambda p, v: "{:0.3f}V".format(v))
if (BATTERY_CELL_DATA_FORMAT & 1):
for i in range(self.battery.cell_count):
self._dbusservice.add_path('/Voltages/Cell%s'%(str(i+1)), None, writeable=True, gettextcallback=lambda p, v: "{:0.3f}V".format(v))
self._dbusservice.add_path('/Balances/Cell%s'%(str(i+1)), None, writeable=True)
self._dbusservice.add_path('/Voltages/Sum', None, writeable=True, gettextcallback=lambda p, v: "{:2.2f}V".format(v))
self._dbusservice.add_path('/Voltages/Diff', None, writeable=True, gettextcallback=lambda p, v: "{:0.3f}V".format(v))

# Create Cell voltage items
if (BATTERY_CELL_DATA_FORMAT & 2):
for num in range(self.battery.cell_count):
num += 1
self._dbusservice.add_path('/Cell/' + str(num) + '/Volts', None, writeable=True, gettextcallback=lambda p, v: "{:0.2f}".format(v))
self._dbusservice.add_path('/Cell/Sum', None, writeable=True, gettextcallback=lambda p, v: "{:2.2f}V".format(v))
self._dbusservice.add_path('/Cell/Diff', None, writeable=True, gettextcallback=lambda p, v: "{:0.3f}V".format(v))

# Create TimeToSoC items
for num in [100, 95, 90, 85, 80, 75, 70, 65, 60, 55, 50, 45, 40, 35, 30, 25, 20, 15, 10, 5, 0]:
for num in TIME_TO_SOC_POINTS:
self._dbusservice.add_path('/TimeToSoC/' + str(num), None, writeable=True)

return True
Expand Down Expand Up @@ -237,20 +246,43 @@ def publish_dbus(self):
self._dbusservice['/Alarms/LowTemperature'] = self.battery.protection.temp_low_discharge

#cell voltages - begining
voltageSum = 0
for i in range(self.battery.cell_count):
voltage = self.battery.get_cell_voltage(i)
self._dbusservice['/Voltages/Cell%s'%(str(i+1))] = voltage
self._dbusservice['/Balances/Cell%s'%(str(i+1))] = self.battery.get_cell_balancing(i)
if voltage:
voltageSum+=voltage
self._dbusservice['/Voltages/Sum'] = voltageSum
self._dbusservice['/Voltages/Diff'] = self.battery.get_max_cell_voltage() - self.battery.get_min_cell_voltage()
if (BATTERY_CELL_DATA_FORMAT & 1):
voltageSum = 0
for i in range(self.battery.cell_count):
voltage = self.battery.get_cell_voltage(i)
self._dbusservice['/Voltages/Cell%s'%(str(i+1))] = voltage
self._dbusservice['/Balances/Cell%s'%(str(i+1))] = self.battery.get_cell_balancing(i)
if voltage:
voltageSum+=voltage
self._dbusservice['/Voltages/Sum'] = voltageSum
self._dbusservice['/Voltages/Diff'] = self.battery.get_max_cell_voltage() - self.battery.get_min_cell_voltage()

if (BATTERY_CELL_DATA_FORMAT & 2):
# Update Cell voltage items
cellVoltsSum = 0
for num in range(self.battery.cell_count):
cellVolts = None if num >= len(self.battery.cells) or self.battery.cells[num] is None else self.battery.cells[num].voltage
if cellVolts:
cellVoltsSum += cellVolts
num += 1
self._dbusservice['/Cell/' + str(num) + '/Volts'] = cellVolts
self._dbusservice['/Cell/Sum'] = cellVoltsSum
self._dbusservice['/Cell/Diff'] = self.battery.get_max_cell_voltage() - self.battery.get_min_cell_voltage()

# Update TimeToSoC
for num in [100, 95, 90, 85, 80, 75, 70, 65, 60, 55, 50, 45, 40, 35, 30, 25, 20, 15, 10, 5, 0]:
self._dbusservice['/TimeToSoC/' + str(num)] = self.battery.get_timetosoc(num)

if self.battery.capacity is not None and len(TIME_TO_SOC_POINTS) > 0 and self.battery.time_to_soc_update == 0:
self.battery.time_to_soc_update = TIME_TO_SOC_LOOP_CYCLES
if self.battery.current:
crntPrctPerSec = (abs(self.battery.current / (self.battery.capacity / 100)) / 3600)

for num in TIME_TO_SOC_POINTS:
self._dbusservice['/TimeToSoC/' + str(num)] = self.battery.get_timetosoc(num, crntPrctPerSec)
else:
for num in TIME_TO_SOC_POINTS:
self._dbusservice['/TimeToSoC/' + str(num)] = None
else:
self.battery.time_to_soc_update -= 1

logger.debug("logged to dbus ", round(self.battery.voltage / 100, 2),
round(self.battery.current / 100, 2),
round(self.battery.soc, 2))
Expand Down
18 changes: 18 additions & 0 deletions etc/dbus-serialbattery/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,24 @@
BATTERY_CAPACITY = 50
# Invert Battery Current. Default non-inverted. Set to -1 to invert
INVERT_CURRENT_MEASUREMENT = 1
# Set of SoC percentages to report on dbus. The more you specify the more it will impact system performance.
#TIME_TO_SOC_POINTS = [100, 95, 90, 85, 80, 75, 70, 65, 60, 55, 50, 45, 40, 35, 30, 25, 20, 15, 10, 5, 0] # Every 5% SoC
#TIME_TO_SOC_POINTS = [] # No data set
TIME_TO_SOC_POINTS = [100, 95, 90, 85, 75, 50, 25, 20, 10, 0]
# Specify TimeToSoc value type:
#TIME_TO_SOC_VALUE_TYPE = 1 # Seconds
#TIME_TO_SOC_VALUE_TYPE = 2 # Time string HH:MN:SC
TIME_TO_SOC_VALUE_TYPE = 3 # Both Seconds and time str "<seconds> [days, HR:MN:SC]"
# Specify how many loop cycles between each TimeToSoc updates
TIME_TO_SOC_LOOP_CYCLES = 5
# Include TimeToSoC points when moving away from the SoC point. These will be as negative time. Disabling this improves performance slightly.
TIME_TO_SOC_INC_FROM = False
#TIME_TO_SOC_INC_FROM = True
# Select the format of cell data presented on dbus.
BATTERY_CELL_DATA_FORMAT = 1 # Format: /Voltages/Cell# (also available for display on Remote Console)
#BATTERY_CELL_DATA_FORMAT = 2 # Format: /Cell/#/Volts
#BATTERY_CELL_DATA_FORMAT = 3 # Both formats 1 and 2


def is_bit_set(tmp):
return False if tmp == zero_char else True
Expand Down