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

Fix #397 wrong cell voltage reading daly bms #484

Merged
merged 8 commits into from
May 2, 2023
7 changes: 3 additions & 4 deletions etc/dbus-serialbattery/battery.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,8 @@ 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':
self.temp_mos = min(max(value, -20), 100
if sensor == "mos":
self.temp_mos = min(max(value, -20), 100)

def manage_charge_voltage(self) -> None:
"""
Expand Down Expand Up @@ -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
Expand All @@ -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)
Expand Down
121 changes: 106 additions & 15 deletions etc/dbus-serialbattery/daly.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Copy link
Contributor Author

@transistorgit transistorgit Mar 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cellvolt buffer makes no sense. the read_serial function returns a new buffer. so it is just a command buffer needed.
In fact, you could use command_base directly and drop cellvolt_buffer complete. forgot to do that, maybe later

command_soc = b"\x90"
command_minmax_cell_volts = b"\x91"
command_minmax_temp = b"\x92"
Expand All @@ -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
Expand Down Expand Up @@ -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
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix sentence length, as there is a checksum


cells_volts_data = read_serialport_data(
ser, buffer, self.LENGTH_POS, self.LENGTH_CHECK, lenFixed
cells_volts_data = self.read_serialport_data(
ser, buffer, self.LENGTH_POS, 0, lenFixed
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the normal call is not working on these multi-sentence transmissions. so just receive the full length and calculate the checksums in the cellvolts function later

)
if cells_volts_data is False:
logger.warning("read_cells_volts")
Expand All @@ -269,14 +272,24 @@ 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
Expand All @@ -287,9 +300,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):
Expand Down Expand Up @@ -350,7 +363,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:
Expand All @@ -359,8 +372,86 @@ 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")
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
5 changes: 2 additions & 3 deletions etc/dbus-serialbattery/dbushelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -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}")
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions etc/dbus-serialbattery/jkbms.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
1 change: 0 additions & 1 deletion etc/dbus-serialbattery/minimalmodbus.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
1 change: 0 additions & 1 deletion etc/dbus-serialbattery/util_max17853.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
3 changes: 1 addition & 2 deletions etc/dbus-serialbattery/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -321,7 +320,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,
Expand Down