From 68eb493d3589b9c462de3b171e156790c1240d6c Mon Sep 17 00:00:00 2001 From: transitorgit Date: Tue, 7 Mar 2023 20:35:30 +0000 Subject: [PATCH 1/6] fix daly rs485 communication for cell voltages --- etc/dbus-serialbattery/daly.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/etc/dbus-serialbattery/daly.py b/etc/dbus-serialbattery/daly.py index ae96c723..ab461fce 100644 --- a/etc/dbus-serialbattery/daly.py +++ b/etc/dbus-serialbattery/daly.py @@ -20,7 +20,7 @@ def __init__(self, port, baud, address): # 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" - cellvolt_buffer = b"\xA5\x40\x94\x08\x00\x00\x00\x00\x00\x00\x00\x00\x82\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + cellvolt_buffer = b"\xA5\x40\x94\x08\x00\x00\x00\x00\x00\x00\x00\x00\x82" command_soc = b"\x90" command_minmax_cell_volts = b"\x91" command_minmax_temp = b"\x92" @@ -246,13 +246,16 @@ def read_cells_volts(self, ser): buffer[1] = self.command_address[0] # Always serial 40 or 80 buffer[2] = self.command_cell_volts[0] - maxFrame = int(self.cell_count / 3) + 1 + if (int(self.cell_count) % 3) == 0: + maxFrame = (int(self.cell_count / 3)) + else: + maxFrame = (int(self.cell_count / 3) + 1) lenFixed = ( - maxFrame * 12 - ) # 0xA5, 0x01, 0x95, 0x08 + 1 byte frame + 6 byte data + 1byte reserved + maxFrame * 13 + ) # 0xA5, 0x01, 0x95, 0x08 + 1 byte frame + 6 byte data + 1byte reserved + chksum cells_volts_data = read_serialport_data( - ser, buffer, self.LENGTH_POS, self.LENGTH_CHECK, lenFixed + ser, buffer, self.LENGTH_POS, 0, lenFixed ) if cells_volts_data is False: logger.warning("read_cells_volts") From f452f5f670e3dfa340f1146c7652e045897d17d4 Mon Sep 17 00:00:00 2001 From: transitorgit Date: Wed, 8 Mar 2023 00:44:06 +0000 Subject: [PATCH 2/6] fix read_serialport_data length calculation, fix daly cell voltage packet offset calculation, add checksum check also. Harden general package validity check. --- etc/dbus-serialbattery/daly.py | 19 ++++++++++++------- etc/dbus-serialbattery/utils.py | 6 ++++-- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/etc/dbus-serialbattery/daly.py b/etc/dbus-serialbattery/daly.py index ab461fce..492b0500 100644 --- a/etc/dbus-serialbattery/daly.py +++ b/etc/dbus-serialbattery/daly.py @@ -31,7 +31,7 @@ def __init__(self, port, baud, address): command_cell_balance = b"\x97" command_alarm = b"\x98" BATTERYTYPE = "Daly" - LENGTH_CHECK = 4 + LENGTH_CHECK = 1 LENGTH_POS = 3 CURRENT_ZERO_CONSTANT = 30000 TEMP_ZERO_CONSTANT = 40 @@ -272,14 +272,19 @@ def read_cells_volts(self, ser): for idx in range(self.cell_count): self.cells.append(Cell(True)) + # logger.warning("data " + bytes(cells_volts_data).hex()) + while ( bufIdx < len(cells_volts_data) - 4 ): # we at least need 4 bytes to extract the identifiers b1, b2, b3, b4 = unpack_from(">BBBB", cells_volts_data, bufIdx) if b1 == 0xA5 and b2 == 0x01 and b3 == 0x95 and b4 == 0x08: - frame, frameCell[0], frameCell[1], frameCell[2] = unpack_from( - ">Bhhh", cells_volts_data, bufIdx + 4 + frame, frameCell[0], frameCell[1], frameCell[2], _, chk = unpack_from( + ">BhhhBB", cells_volts_data, bufIdx + 4 ) + if sum(cells_volts_data[bufIdx:bufIdx+12]) & 0xFF != chk: + logger.warning("bad cell voltages checksum") + return False for idx in range(3): cellnum = ( (frame - 1) * 3 @@ -290,9 +295,9 @@ def read_cells_volts(self, ser): self.cells[cellnum].voltage = ( None if cellVoltage < lowMin else cellVoltage ) - bufIdx += 10 # BBBBBhhh -> 11 byte - bufIdx += 1 - + bufIdx += 13 # BBBBBhhhBB -> 13 byte + else: + logger.warning("bad cell voltages header") return True def read_cell_voltage_range_data(self, ser): @@ -362,7 +367,7 @@ def read_serial_data_daly(self, ser, command): start, flag, command_ret, length = unpack_from("BBBB", data) checksum = sum(data[:-1]) & 0xFF - if start == 165 and length == 8 and checksum == data[12]: + if start == 165 and length == 8 and len(data)>12 and checksum == data[12]: return data[4 : length + 4] else: logger.error(">>> ERROR: Incorrect Reply") diff --git a/etc/dbus-serialbattery/utils.py b/etc/dbus-serialbattery/utils.py index 032cfedf..d7d4bde5 100644 --- a/etc/dbus-serialbattery/utils.py +++ b/etc/dbus-serialbattery/utils.py @@ -370,8 +370,10 @@ def read_serialport_data( count = 0 data = bytearray(res) - while len(data) <= length + length_check: - res = ser.read(length + length_check) + + packetlen = length_fixed if length_fixed is not None else length_pos + length_byte_size + length + length_check + while len(data) < packetlen: + res = ser.read(packetlen - len(data)) data.extend(res) # logger.info('serial data length ' + str(len(data))) sleep(0.005) From 6fcd136c27b57de36dc338cd520adc941384406e Mon Sep 17 00:00:00 2001 From: Bernd Stahlbock Date: Mon, 1 May 2023 07:56:14 +0000 Subject: [PATCH 3/6] revert read_serialport_data() to the original state --- etc/dbus-serialbattery/utils.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/etc/dbus-serialbattery/utils.py b/etc/dbus-serialbattery/utils.py index d7d4bde5..db8d89fc 100644 --- a/etc/dbus-serialbattery/utils.py +++ b/etc/dbus-serialbattery/utils.py @@ -321,7 +321,7 @@ def open_serial_port(port, baud): return ser -# Read data from previously openned serial port +# Read data from previously opened serial port def read_serialport_data( ser: serial.Serial, command, @@ -370,10 +370,8 @@ def read_serialport_data( count = 0 data = bytearray(res) - - packetlen = length_fixed if length_fixed is not None else length_pos + length_byte_size + length + length_check - while len(data) < packetlen: - res = ser.read(packetlen - len(data)) + while len(data) <= length + length_check: + res = ser.read(length + length_check) data.extend(res) # logger.info('serial data length ' + str(len(data))) sleep(0.005) From 91026c7a88bd3eb21d75b70b2cb5978ba861822e Mon Sep 17 00:00:00 2001 From: Bernd Stahlbock Date: Mon, 1 May 2023 08:02:05 +0000 Subject: [PATCH 4/6] copy read_serialport_data() to daly.py --- etc/dbus-serialbattery/daly.py | 82 +++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 2 deletions(-) diff --git a/etc/dbus-serialbattery/daly.py b/etc/dbus-serialbattery/daly.py index 492b0500..e83dd1bb 100644 --- a/etc/dbus-serialbattery/daly.py +++ b/etc/dbus-serialbattery/daly.py @@ -254,7 +254,7 @@ def read_cells_volts(self, ser): maxFrame * 13 ) # 0xA5, 0x01, 0x95, 0x08 + 1 byte frame + 6 byte data + 1byte reserved + chksum - cells_volts_data = read_serialport_data( + cells_volts_data = self.read_serialport_data( ser, buffer, self.LENGTH_POS, 0, lenFixed ) if cells_volts_data is False: @@ -358,7 +358,7 @@ def generate_command(self, command): return buffer def read_serial_data_daly(self, ser, command): - data = read_serialport_data( + data = self.read_serialport_data( ser, self.generate_command(command), self.LENGTH_POS, self.LENGTH_CHECK ) if data is False: @@ -372,3 +372,81 @@ def read_serial_data_daly(self, ser, command): else: logger.error(">>> ERROR: Incorrect Reply") return False + + # Read data from previously openned serial port + def read_serialport_data( + self, + ser, + command, + length_pos, + length_check, + length_fixed=None, + length_size=None, + ): + try: + ser.flushOutput() + ser.flushInput() + ser.write(command) + + length_byte_size = 1 + if length_size is not None: + if length_size.upper() == "H": + length_byte_size = 2 + elif length_size.upper() == "I" or length_size.upper() == "L": + length_byte_size = 4 + + count = 0 + toread = ser.inWaiting() + + while toread < (length_pos + length_byte_size): + sleep(0.005) + toread = ser.inWaiting() + count += 1 + if count > 50: + logger.error(">>> ERROR: No reply - returning") + return False + + # logger.info('serial data toread ' + str(toread)) + res = ser.read(toread) + if length_fixed is not None: + length = length_fixed + else: + if len(res) < (length_pos + length_byte_size): + logger.error( + ">>> ERROR: No reply - returning [len:" + str(len(res)) + "]" + ) + return False + length_size = length_size if length_size is not None else "B" + length = unpack_from(">" + length_size, res, length_pos)[0] + + # logger.info('serial data length ' + str(length)) + + count = 0 + data = bytearray(res) + + packetlen = ( + length_fixed + if length_fixed is not None + else length_pos + length_byte_size + length + length_check + ) + while len(data) < packetlen: + res = ser.read(packetlen - len(data)) + data.extend(res) + # logger.info('serial data length ' + str(len(data))) + sleep(0.005) + count += 1 + if count > 150: + logger.error( + ">>> ERROR: No reply - returning [len:" + + str(len(data)) + + "/" + + str(length + length_check) + + "]" + ) + return False + + return data + + except Exception as e: + logger.error(e) + return False \ No newline at end of file From 78914ed2e5cddd218b4b351ae7d48e6cbed858ca Mon Sep 17 00:00:00 2001 From: Bernd Stahlbock Date: Mon, 1 May 2023 08:08:55 +0000 Subject: [PATCH 5/6] fix missing bracket --- etc/dbus-serialbattery/battery.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/dbus-serialbattery/battery.py b/etc/dbus-serialbattery/battery.py index 8de71a79..37f283b3 100644 --- a/etc/dbus-serialbattery/battery.py +++ b/etc/dbus-serialbattery/battery.py @@ -142,7 +142,7 @@ def to_temp(self, sensor: int, value: float) -> None: if sensor == 2: self.temp2 = min(max(value, -20), 100) if sensor == 'mos': - self.temp_mos = min(max(value, -20), 100 + self.temp_mos = min(max(value, -20), 100) def manage_charge_voltage(self) -> None: """ From f5f1c97bf1bf6c27215f36710f9dbc7e518b165a Mon Sep 17 00:00:00 2001 From: Bernd Stahlbock Date: Mon, 1 May 2023 09:32:33 +0000 Subject: [PATCH 6/6] black reformatting --- etc/dbus-serialbattery/battery.py | 5 ++--- etc/dbus-serialbattery/daly.py | 21 +++++++++++++-------- etc/dbus-serialbattery/dbushelper.py | 5 ++--- etc/dbus-serialbattery/jkbms.py | 4 ++-- etc/dbus-serialbattery/minimalmodbus.py | 1 - etc/dbus-serialbattery/util_max17853.py | 1 - etc/dbus-serialbattery/utils.py | 1 - 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/etc/dbus-serialbattery/battery.py b/etc/dbus-serialbattery/battery.py index 37f283b3..24522fe4 100644 --- a/etc/dbus-serialbattery/battery.py +++ b/etc/dbus-serialbattery/battery.py @@ -141,7 +141,7 @@ def to_temp(self, sensor: int, value: float) -> None: self.temp1 = min(max(value, -20), 100) if sensor == 2: self.temp2 = min(max(value, -20), 100) - if sensor == 'mos': + if sensor == "mos": self.temp_mos = min(max(value, -20), 100) def manage_charge_voltage(self) -> None: @@ -574,7 +574,7 @@ def get_max_temp(self) -> Union[float, None]: return self.extract_from_temp_values( extractor=lambda temp1, temp2: max(temp1, temp2) ) - + def get_mos_temp(self) -> Union[float, None]: if self.temp_mos is not None: return self.temp_mos @@ -594,7 +594,6 @@ def log_cell_data(self) -> bool: return True def log_settings(self) -> None: - logger.info(f"Battery {self.type} connected to dbus from {self.port}") logger.info("=== Settings ===") cell_counter = len(self.cells) diff --git a/etc/dbus-serialbattery/daly.py b/etc/dbus-serialbattery/daly.py index e83dd1bb..5d05ad2a 100644 --- a/etc/dbus-serialbattery/daly.py +++ b/etc/dbus-serialbattery/daly.py @@ -247,9 +247,9 @@ def read_cells_volts(self, ser): buffer[2] = self.command_cell_volts[0] if (int(self.cell_count) % 3) == 0: - maxFrame = (int(self.cell_count / 3)) + maxFrame = int(self.cell_count / 3) else: - maxFrame = (int(self.cell_count / 3) + 1) + maxFrame = int(self.cell_count / 3) + 1 lenFixed = ( maxFrame * 13 ) # 0xA5, 0x01, 0x95, 0x08 + 1 byte frame + 6 byte data + 1byte reserved + chksum @@ -279,10 +279,15 @@ def read_cells_volts(self, ser): ): # we at least need 4 bytes to extract the identifiers b1, b2, b3, b4 = unpack_from(">BBBB", cells_volts_data, bufIdx) if b1 == 0xA5 and b2 == 0x01 and b3 == 0x95 and b4 == 0x08: - frame, frameCell[0], frameCell[1], frameCell[2], _, chk = unpack_from( - ">BhhhBB", cells_volts_data, bufIdx + 4 - ) - if sum(cells_volts_data[bufIdx:bufIdx+12]) & 0xFF != chk: + ( + frame, + frameCell[0], + frameCell[1], + frameCell[2], + _, + chk, + ) = unpack_from(">BhhhBB", cells_volts_data, bufIdx + 4) + if sum(cells_volts_data[bufIdx : bufIdx + 12]) & 0xFF != chk: logger.warning("bad cell voltages checksum") return False for idx in range(3): @@ -367,7 +372,7 @@ def read_serial_data_daly(self, ser, command): start, flag, command_ret, length = unpack_from("BBBB", data) checksum = sum(data[:-1]) & 0xFF - if start == 165 and length == 8 and len(data)>12 and checksum == data[12]: + if start == 165 and length == 8 and len(data) > 12 and checksum == data[12]: return data[4 : length + 4] else: logger.error(">>> ERROR: Incorrect Reply") @@ -449,4 +454,4 @@ def read_serialport_data( except Exception as e: logger.error(e) - return False \ No newline at end of file + return False diff --git a/etc/dbus-serialbattery/dbushelper.py b/etc/dbus-serialbattery/dbushelper.py index 7cc6029a..c52c10df 100644 --- a/etc/dbus-serialbattery/dbushelper.py +++ b/etc/dbus-serialbattery/dbushelper.py @@ -298,7 +298,7 @@ def setup_vedbus(self): # Create TimeToSoC items for num in TIME_TO_SOC_POINTS: self._dbusservice.add_path("/TimeToSoC/" + str(num), None, writeable=True) - #Create TimeToGO item + # Create TimeToGO item self._dbusservice.add_path("/TimeToGo", None, writeable=True) logger.info(f"publish config values = {PUBLISH_CONFIG_VALUES}") @@ -338,7 +338,6 @@ def publish_battery(self, loop): loop.quit() def publish_dbus(self): - # Update SOC, DC and System items self._dbusservice["/System/NrOfCellsPerBattery"] = self.battery.cell_count self._dbusservice["/Soc"] = round(self.battery.soc, 2) @@ -488,7 +487,7 @@ def publish_dbus(self): if self.battery.current else None ) - + # Update TimeToGo self._dbusservice["/TimeToGo"] = ( self.battery.get_timetosoc(SOC_LOW_WARNING, crntPrctPerSec) diff --git a/etc/dbus-serialbattery/jkbms.py b/etc/dbus-serialbattery/jkbms.py index c5b09d95..86d8716b 100644 --- a/etc/dbus-serialbattery/jkbms.py +++ b/etc/dbus-serialbattery/jkbms.py @@ -87,11 +87,11 @@ def read_status_data(self): temp2 = unpack_from(">H", self.get_data(status_data, b"\x82", offset, 2))[0] self.to_temp(1, temp1 if temp1 < 99 else (100 - temp1)) self.to_temp(2, temp2 if temp2 < 99 else (100 - temp2)) - + # MOSFET temperature offset = cellbyte_count + 3 temp_mos = unpack_from(">H", self.get_data(status_data, b"\x80", offset, 2))[0] - self.to_temp('mos', temp_mos if temp_mos < 99 else (100 - temp_mos)) + self.to_temp("mos", temp_mos if temp_mos < 99 else (100 - temp_mos)) offset = cellbyte_count + 12 voltage = unpack_from(">H", self.get_data(status_data, b"\x83", offset, 2))[0] diff --git a/etc/dbus-serialbattery/minimalmodbus.py b/etc/dbus-serialbattery/minimalmodbus.py index dc00434b..3519be07 100644 --- a/etc/dbus-serialbattery/minimalmodbus.py +++ b/etc/dbus-serialbattery/minimalmodbus.py @@ -1812,7 +1812,6 @@ def _extract_payload( ) if mode == MODE_ASCII: - # Validate the ASCII header and footer. if response[_BYTEPOSITION_FOR_ASCII_HEADER] != _ASCII_HEADER: raise InvalidResponseError( diff --git a/etc/dbus-serialbattery/util_max17853.py b/etc/dbus-serialbattery/util_max17853.py index 02e06e4a..caaacfbf 100644 --- a/etc/dbus-serialbattery/util_max17853.py +++ b/etc/dbus-serialbattery/util_max17853.py @@ -316,7 +316,6 @@ def v_cell_d(self): b_lim = False for index, v in enumerate(V_Cells): - if v > 3.55: b_lim = True if v > vc_max: diff --git a/etc/dbus-serialbattery/utils.py b/etc/dbus-serialbattery/utils.py index db8d89fc..77685193 100644 --- a/etc/dbus-serialbattery/utils.py +++ b/etc/dbus-serialbattery/utils.py @@ -241,7 +241,6 @@ def calcLinearRelationship(inValue, inArray, outArray): if inArray[0] > inArray[-1]: # change compare-direction in array return calcLinearRelationship(inValue, inArray[::-1], outArray[::-1]) else: - # Handle out of bounds if inValue <= inArray[0]: return outArray[0]