diff --git a/etc/dbus-serialbattery/battery.py b/etc/dbus-serialbattery/battery.py index 09866b75..8cf39acc 100644 --- a/etc/dbus-serialbattery/battery.py +++ b/etc/dbus-serialbattery/battery.py @@ -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 @@ -173,24 +175,29 @@ def get_cell_balancing(self, idx): return 1 return 0 - def get_timetosoc(self, socnum): - # Update TimeToSoC items - 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" - - # 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) - - 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 + def get_min_cell_voltage(self): min_voltage = None diff --git a/etc/dbus-serialbattery/daly.py b/etc/dbus-serialbattery/daly.py index 0fceb17f..d443ea9e 100644 --- a/etc/dbus-serialbattery/daly.py +++ b/etc/dbus-serialbattery/daly.py @@ -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" @@ -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 @@ -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) diff --git a/etc/dbus-serialbattery/dbushelper.py b/etc/dbus-serialbattery/dbushelper.py old mode 100755 new mode 100644 index 06b9ad59..012fd926 --- a/etc/dbus-serialbattery/dbushelper.py +++ b/etc/dbus-serialbattery/dbushelper.py @@ -136,15 +136,19 @@ def setup_vedbus(self): self._dbusservice.add_path('/Alarms/HighTemperature', None, writeable=True) 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)) + #cell voltages + if (BATTERY_CELL_DATA_FORMAT>0): + for i in range(1, self.battery.cell_count+1): + cellpath = '/Cell/%s/Volts' if (BATTERY_CELL_DATA_FORMAT & 2) else '/Voltages/Cell%s' + self._dbusservice.add_path(cellpath%(str(i)), None, writeable=True, gettextcallback=lambda p, v: "{:0.3f}V".format(v)) + if (BATTERY_CELL_DATA_FORMAT & 1): + self._dbusservice.add_path('/Balances/Cell%s'%(str(i)), None, writeable=True) + pathbase = 'Cell' if (BATTERY_CELL_DATA_FORMAT & 2) else 'Voltages' + self._dbusservice.add_path('/%s/Sum'%pathbase, None, writeable=True, gettextcallback=lambda p, v: "{:2.2f}V".format(v)) + self._dbusservice.add_path('/%s/Diff'%pathbase, 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 @@ -164,9 +168,6 @@ def publish_battery(self, loop): if error_count >= 10: self.battery.online = False - - - # This is to mannage CCCL self.battery.manage_charge_current() @@ -236,20 +237,31 @@ def publish_dbus(self): self._dbusservice['/Alarms/HighTemperature'] = self.battery.protection.temp_high_discharge 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() + #cell voltages + if (BATTERY_CELL_DATA_FORMAT>0): + voltageSum = 0 + for i in range(self.battery.cell_count): + voltage = self.battery.get_cell_voltage(i) + cellpath = '/Cell/%s/Volts' if (BATTERY_CELL_DATA_FORMAT & 2) else '/Voltages/Cell%s' + self._dbusservice[cellpath%(str(i+1))] = voltage + if (BATTERY_CELL_DATA_FORMAT & 1): + self._dbusservice['/Balances/Cell%s'%(str(i+1))] = self.battery.get_cell_balancing(i) + if voltage: + voltageSum+=voltage + pathbase = 'Cell' if (BATTERY_CELL_DATA_FORMAT & 2) else 'Voltages' + self._dbusservice['/%s/Sum'%pathbase] = voltageSum + self._dbusservice['/%s/Diff'%pathbase] = 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 + 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) if self.battery.current else None + + else: + self.battery.time_to_soc_update -= 1 + logger.debug("logged to dbus [%s]"%str(round(self.battery.soc, 2))) self.battery.log_cell_data() diff --git a/etc/dbus-serialbattery/utils.py b/etc/dbus-serialbattery/utils.py index fe0364e9..5a4c65df 100644 --- a/etc/dbus-serialbattery/utils.py +++ b/etc/dbus-serialbattery/utils.py @@ -28,6 +28,30 @@ # Invert Battery Current. Default non-inverted. Set to -1 to invert INVERT_CURRENT_MEASUREMENT = 1 +# TIME TO SOC settings [Valid values 0-100, but I don't recommend more that 20 intervals] +# 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 = [100, 95, 90, 85, 75, 50, 25, 20, 10, 0] +TIME_TO_SOC_POINTS = [] # No data set to disable +# Specify TimeToSoc value type: [Valid values 1,2,3] +# 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 " [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. [Valid values True,False] +# These will be as negative time. Disabling this improves performance slightly. +TIME_TO_SOC_INC_FROM = False + + +# Select the format of cell data presented on dbus. [Valid values 0,1,2,3] +# 0 Do not publish all the cells (only the min/max cell data as used by the default GX) +# 1 Format: /Voltages/Cell# (also available for display on Remote Console) +# 2 Format: /Cell/#/Volts +# 3 Both formats 1 and 2 +BATTERY_CELL_DATA_FORMAT = 1 + + def is_bit_set(tmp): return False if tmp == zero_char else True