Skip to content

Commit

Permalink
Merge branch 'dev' into ogdev
Browse files Browse the repository at this point in the history
  • Loading branch information
ogurevich committed Jun 11, 2023
2 parents 6391341 + 82dfee5 commit 4fc9e43
Show file tree
Hide file tree
Showing 10 changed files with 148 additions and 66 deletions.
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
# Changelog

## v1.0.x
* Added: Bluetooth: Show signal strenght of BMS in log by @mr-manuel
* Added: Bluetooth: Show signal strength of BMS in log by @mr-manuel
* Added: Create unique identifier, if not provided from BMS by @mr-manuel
* Added: Exclude a device from beeing used by the dbus-serialbattery driver by @mr-manuel
* Added: Implement callback function for update by @seidler2547
* Added: JKBMS BLE - Show last five characters from the MAC address in the custom name (which is displayed in the device list) by @mr-manuel
* Added: Save custom name and make it restart persistant by @mr-manuel
* Changed: Enable BMS that are disabled by default by specifying it in the config file. No more need to edit scripts by @mr-manuel
* Changed: Fix Sinowealth not loading https://github.com/Louisvdw/dbus-serialbattery/issues/702 by @mr-manuel
* Changed: Fixed error in `reinstall-local.sh` script for Bluetooth installation by @mr-manuel
* Changed: Fixed that other devices are recognized as ANT BMS by @mr-manuel
* Changed: Fixed that other devices are recognized as Sinowealth BMS by @mr-manuel
* Changed: Fixed typo in `config.ini` sample by @hoschult
* Changed: For BMS_TYPE now multiple BMS can be specified by @mr-manuel
* Changed: Improved driver reinstall when multiple Bluetooth BMS are enabled by @mr-manuel
* Changed: Improved Jkbms_Ble driver by @seidler2547 & @mr-manuel
* Changed: Improved battery error handling on connection loss by @mr-manuel
* Changed: Improved battery voltage handling in linear absorption mode by @ogurevich


## v1.0.20230531
Expand Down
14 changes: 9 additions & 5 deletions etc/dbus-serialbattery/battery.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ def __init__(self, port, baud, address):
self.init_values()

def init_values(self):
"""
Used to reset values, if battery unexpectly disconnects
"""
self.voltage = None
self.current = None
self.capacity_remain = None
Expand Down Expand Up @@ -137,12 +140,13 @@ def unique_identifier(self) -> str:
since it can be changed by small amounts to make a battery unique.
On +/- 5 Ah you can identify 11 batteries
"""
return (
"".join(filter(str.isalnum, self.hardware_version))
+ "_"
+ str(self.capacity)
+ "Ah"
string = (
"".join(filter(str.isalnum, self.hardware_version)) + "_"
if self.hardware_version is not None and self.hardware_version != ""
else ""
)
string += str(self.capacity) + "Ah"
return string

def connection_name(self) -> str:
return "Serial " + self.port
Expand Down
18 changes: 15 additions & 3 deletions etc/dbus-serialbattery/bms/ant.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-

# disable ANT BMS by default as it causes other issues but can be enabled manually
# ANT BMS is disabled by default as it causes issues with other devices
# can be enabled by specifying it in the BMS_TYPE setting in the "config.ini"
# https://github.com/Louisvdw/dbus-serialbattery/issues/479

from battery import Battery
Expand All @@ -9,9 +10,9 @@
from struct import unpack_from


class Ant(Battery):
class ANT(Battery):
def __init__(self, port, baud, address):
super(Ant, self).__init__(port, baud, address)
super(ANT, self).__init__(port, baud, address)
self.type = self.BATTERYTYPE

command_general = b"\xDB\xDB\x00\x00\x00\x00"
Expand All @@ -30,6 +31,7 @@ def test_connection(self):
result = False
try:
result = self.read_status_data()
result = result and self.refresh_data()
except Exception as err:
logger.error(f"Unexpected {err=}, {type(err)=}")
result = False
Expand Down Expand Up @@ -61,8 +63,15 @@ def read_status_data(self):

voltage = unpack_from(">H", status_data, 4)
self.voltage = voltage[0] * 0.1
# check if data is in the thresholds, if not it's very likely that it's not an ANT BMS
if self.voltage < 0 and self.voltage > 100:
return False

current, self.soc = unpack_from(">lB", status_data, 70)
self.current = 0.0 if current == 0 else current / -10
# check if data is in the thresholds, if not it's very likely that it's not an ANT BMS
if self.soc < 0 or self.soc > 100 or abs(self.current) > 1000:
return False

self.cell_count = unpack_from(">b", status_data, 123)[0]
self.max_battery_voltage = utils.MAX_CELL_VOLTAGE * self.cell_count
Expand All @@ -78,6 +87,9 @@ def read_status_data(self):

capacity = unpack_from(">L", status_data, 75)
self.capacity = capacity[0] / 1000000
# check if data is in the thresholds, if not it's very likely that it's not an ANT BMS
if self.capacity < 0 or self.capacity > 1000:
return False

capacity_remain = unpack_from(">L", status_data, 79)
self.capacity_remain = capacity_remain[0] / 1000000
Expand Down
2 changes: 1 addition & 1 deletion etc/dbus-serialbattery/bms/jkbms_ble.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ def refresh_data(self):
logger.info(
f"Jkbms_Ble: Bluetooth connection interrupted. Got no fresh data since {last_update}s."
)
# show Bluetooth signal strenght (RSSI)
# show Bluetooth signal strength (RSSI)
bluetoothctl_info = os.popen(
"bluetoothctl info "
+ self.address
Expand Down
3 changes: 2 additions & 1 deletion etc/dbus-serialbattery/bms/mnb.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-

# disable MNB battery by default
# # MNB is disabled by default
# can be enabled by specifying it in the BMS_TYPE setting in the "config.ini"
# https://github.com/Louisvdw/dbus-serialbattery/commit/65241cbff36feb861ff43dbbcfb2b495f14a01ce
# remove duplicate MNB lines
# https://github.com/Louisvdw/dbus-serialbattery/commit/23afec33c2fd87fd4d4c53516f0a25f290643c82
Expand Down
64 changes: 43 additions & 21 deletions etc/dbus-serialbattery/bms/sinowealth.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-

# disable Sinowealth by default as it causes other issues but can be enabled manually
# Sinowealth is disabled by default as it causes issues with other devices
# can be enabled by specifying it in the BMS_TYPE setting in the "config.ini"
# https://github.com/Louisvdw/dbus-serialbattery/commit/7aab4c850a5c8d9c205efefc155fe62bb527da8e

from battery import Battery, Cell
Expand Down Expand Up @@ -44,8 +45,8 @@ def test_connection(self):
result = False
try:
result = self.read_status_data()
result = result and self.read_remaining_capacity()
result = result and self.read_pack_config_data()
result = result and self.get_settings()
result = result and self.refresh_data()
except Exception as err:
logger.error(f"Unexpected {err=}, {type(err)=}")
result = False
Expand All @@ -64,9 +65,10 @@ def get_settings(self):
self.min_battery_voltage = utils.MIN_CELL_VOLTAGE * self.cell_count

self.hardware_version = "Daly/Sinowealth BMS " + str(self.cell_count) + " cells"
logger.info(self.hardware_version)
logger.debug(self.hardware_version)

self.read_capacity()
if not self.read_capacity():
return False

for c in range(self.cell_count):
self.cells.append(Cell(False))
Expand Down Expand Up @@ -95,7 +97,7 @@ def read_status_data(self):
# [1] - FAST_DSG MID_DSG SLOW_DSG DSGING CHGING DSGMOS CHGMOS
self.discharge_fet = bool(status_data[1] >> 1 & int(1)) # DSGMOS
self.charge_fet = bool(status_data[1] & int(1)) # CHGMOS
logger.info(
logger.debug(
">>> INFO: Discharge fet: %s, charge fet: %s",
self.discharge_fet,
self.charge_fet,
Expand Down Expand Up @@ -145,8 +147,13 @@ def read_soc(self):
# check if connection success
if soc_data is False:
return False
logger.info(">>> INFO: current SOC: %u", soc_data[1])
self.soc = soc_data[1]
logger.debug(">>> INFO: current SOC: %u", soc_data[1])
soc = soc_data[1]
# check if data is in the thresholds, if not it's very likely that it's not a Sinowealth BMS
if soc < 0 or soc > 100:
return False

self.soc = soc
return True

def read_cycle_count(self):
Expand All @@ -156,7 +163,7 @@ def read_cycle_count(self):
if cycle_count is False:
return False
self.cycles = int(unpack_from(">H", cycle_count[:2])[0])
logger.info(">>> INFO: current cycle count: %u", self.cycles)
logger.debug(">>> INFO: current cycle count: %u", self.cycles)
return True

def read_pack_voltage(self):
Expand All @@ -165,7 +172,11 @@ def read_pack_voltage(self):
return False
pack_voltage = unpack_from(">H", pack_voltage_data[:-1])
pack_voltage = pack_voltage[0] / 1000
logger.info(">>> INFO: current pack voltage: %f", pack_voltage)
logger.debug(">>> INFO: current pack voltage: %f", pack_voltage)
# check if data is in the thresholds, if not it's very likely that it's not a Sinowealth BMS
if pack_voltage < 0 or pack_voltage > 100:
return False

self.voltage = pack_voltage
return True

Expand All @@ -175,7 +186,11 @@ def read_pack_current(self):
return False
current = unpack_from(">i", current_data[:-1])
current = current[0] / 1000
logger.info(">>> INFO: current pack current: %f", current)
logger.debug(">>> INFO: current pack current: %f", current)
# check if data is in the thresholds, if not it's very likely that it's not a Sinowealth BMS
if abs(current) > 1000:
return False

self.current = current
return True

Expand All @@ -187,16 +202,23 @@ def read_remaining_capacity(self):
return False
remaining_capacity = unpack_from(">i", remaining_capacity_data[:-1])
self.capacity_remain = remaining_capacity[0] / 1000
logger.info(">>> INFO: remaining battery capacity: %f Ah", self.capacity_remain)
logger.debug(
">>> INFO: remaining battery capacity: %f Ah", self.capacity_remain
)
return True

def read_capacity(self):
capacity_data = self.read_serial_data_sinowealth(self.command_capacity)
if capacity_data is False:
return False
capacity = unpack_from(">i", capacity_data[:-1])
logger.info(">>> INFO: Battery capacity: %f Ah", capacity[0] / 1000)
self.capacity = capacity[0] / 1000
capacity = capacity[0] / 1000
logger.debug(">>> INFO: Battery capacity: %f Ah", capacity)
# check if data is in the thresholds, if not it's very likely that it's not a Sinowealth BMS
if capacity < 0 or capacity > 1000:
return False

self.capacity = capacity
return True

def read_pack_config_data(self):
Expand All @@ -210,12 +232,12 @@ def read_pack_config_data(self):
if self.cell_count < 1 or self.cell_count > 32:
logger.error(">>> ERROR: No valid cell count returnd: %u", self.cell_count)
return False
logger.info(">>> INFO: Number of cells: %u", self.cell_count)
logger.debug(">>> INFO: Number of cells: %u", self.cell_count)
temp_sens_mask = int(~(1 << 6))
self.temp_sensors = (
1 if (pack_config_data[1] & temp_sens_mask) else 2
) # one means two
logger.info(">>> INFO: Number of temperatur sensors: %u", self.temp_sensors)
logger.debug(">>> INFO: Number of temperatur sensors: %u", self.temp_sensors)
return True

def read_cell_data(self):
Expand All @@ -235,7 +257,7 @@ def read_cell_voltage(self, cell_index):
cell_voltage = unpack_from(">H", cell_data[:-1])
cell_voltage = cell_voltage[0] / 1000

logger.info(">>> INFO: Cell %u voltage: %f V", cell_index, cell_voltage)
logger.debug(">>> INFO: Cell %u voltage: %f V", cell_index, cell_voltage)
return cell_voltage

def read_temperature_data(self):
Expand All @@ -248,7 +270,7 @@ def read_temperature_data(self):

temp_ext1 = unpack_from(">H", temp_ext1_data[:-1])
self.to_temp(1, kelvin_to_celsius(temp_ext1[0] / 10))
logger.info(">>> INFO: BMS external temperature 1: %f C", self.temp1)
logger.debug(">>> INFO: BMS external temperature 1: %f C", self.temp1)

if self.temp_sensors == 2:
temp_ext2_data = self.read_serial_data_sinowealth(self.command_temp_ext2)
Expand All @@ -257,15 +279,15 @@ def read_temperature_data(self):

temp_ext2 = unpack_from(">H", temp_ext2_data[:-1])
self.to_temp(2, kelvin_to_celsius(temp_ext2[0] / 10))
logger.info(">>> INFO: BMS external temperature 2: %f C", self.temp2)
logger.debug(">>> INFO: BMS external temperature 2: %f C", self.temp2)

# Internal temperature 1 seems to give a logical value
temp_int1_data = self.read_serial_data_sinowealth(self.command_temp_int1)
if temp_int1_data is False:
return False

temp_int1 = unpack_from(">H", temp_int1_data[:-1])
logger.info(
logger.debug(
">>> INFO: BMS internal temperature 1: %f C",
kelvin_to_celsius(temp_int1[0] / 10),
)
Expand All @@ -276,7 +298,7 @@ def read_temperature_data(self):
return False

temp_int2 = unpack_from(">H", temp_int2_data[:-1])
logger.info(
logger.debug(
">>> INFO: BMS internal temperature 2: %f C",
kelvin_to_celsius(temp_int2[0] / 10),
)
Expand Down
7 changes: 3 additions & 4 deletions etc/dbus-serialbattery/config.default.ini
Original file line number Diff line number Diff line change
Expand Up @@ -183,12 +183,11 @@ TIME_TO_SOC_INC_FROM = False


; --------- Additional settings ---------
; Specify only one BMS type to load else leave empty to try to load all available
; Specify one or more BMS types to load else leave empty to try to load all available
; -- Available BMS:
; Daly, Ecs, HeltecModbus, HLPdataBMS4S, Jkbms, Lifepower, LltJbd, Renogy, Seplos
; -- Available BMS, but disabled by default:
; https://louisvdw.github.io/dbus-serialbattery/general/install#how-to-enable-a-disabled-bms
; Ant, MNB, Sinowealth
; -- Available BMS, but disabled by default (just enter one or more below and it will be enabled):
; ANT, MNB, Sinowealth
BMS_TYPE =

; Exclute this serial devices from the driver startup
Expand Down
Loading

0 comments on commit 4fc9e43

Please sign in to comment.