From 2f6ea71ef606c9aabdc253abb8ef16df3dd92f74 Mon Sep 17 00:00:00 2001 From: Manuel Date: Thu, 18 May 2023 23:55:08 +0200 Subject: [PATCH] Changes 2023.05.18 (#649) * Added: Show specific TimeToSoC points in GUI Only if 0%, 10%, 20%, 80%, 90% and/or 100% are selected * Added: Show specific TimeToSoC points in GUI Only if 0%, 10%, 20%, 80%, 90% and/or 100% are selected * fix black lint error * fix black lint error * Improved JBD BMS soc calculation https://github.com/Louisvdw/dbus-serialbattery/pull/439 * Fix for #397 https://github.com/Louisvdw/dbus-serialbattery/pull/484 * small fixes * sort bms imports * Add support for HLPdata BMS4S https://github.com/Louisvdw/dbus-serialbattery/pull/505 * Add support for Seplos BMS https://github.com/Louisvdw/dbus-serialbattery/pull/530 * change flake8 settings * fix black lint errors * removed wildcard imports * fixed black lint errors * change flake8 settings * remove wildcard import and fix black lint errors * removed wildcard import * fixed black lint check * removed wildcard import, fixed black lint errors * config changes * removed wildcard import, fixed black lint errors * remove old log message in handle_changed_setting() * remove old log message in handle_changed_setting() * simplified condition for Time-To-Go/Soc * simplified condition for Time-To-Go/Soc * fix renogy import * fix renogy import * added BMS info and cleanup * MNB * Revov * Sinowealth * added BMS info and cleanup * MNB * Revov * Sinowealth * moved BMS to subfolder * moved BMS to subfolder * moved BMS to subfolder * corrected installble to run correct script * Added self.unique_identifier to the battery class Used to identify a BMS when multiple BMS are connected planned for future use * Added self.unique_identifier to the battery class Used to identify a BMS when multiple BMS are connected planned for future use * changed ble service name from `dbus-blebattery-$1` to `dbus-blebattery.$1` like the non ble service * fix small errors * read installed capacity at startup * disable ANT BMS by default https://github.com/Louisvdw/dbus-serialbattery/issues/479 * fix cell voltage header parser * rework daly receive routine * improve read cell voltages - only work on sufficient data, drop only the bad package on checksum error, not the complete transmission * allow read_soc to also retry serial transmission * add daly cell balance state info. cells are red only if unbalanced now * bump version * typo * moved read_serialport_data() to daly.py * revert read_serialport_data() to the state before my changes * fix connection log startup message. now voltage/current/soc are displayed correctly * black reformatting * added linear voltage recalculation interval In the config file can now be defined how often CVL, CCL and DCL is recalculated * revert Daly adaption * replaced penalty voltage calculation with automatically calculated penalty voltages to simplify config max voltage is kept until batteries are balanced * flake config change * flake config change * added linear voltage recalculation interval In the config file can now be defined how often CVL, CCL and DCL is recalculated * replaced penalty voltage calculation with automatically calculated penalty voltages to simplify config max voltage is kept until batteries are balanced * fix black lint errors * updated changelog * disabled ANT BMS by default https://github.com/Louisvdw/dbus-serialbattery/issues/479 * updated config.default.ini * fix typo * update nightly install script * Removed line * fixed error in HLPdataBMS4S * fixed wrong variable assignment `str` instead of `int` * fixed wrong variable assignment `str` instead of `int` * updated battery template * updated battery template * Fix for #450 https://github.com/Louisvdw/dbus-serialbattery/issues/450 * Read charge/discharge limit JKBMS https://github.com/Louisvdw/dbus-serialbattery/issues/4 * updated battery template * Progress with config limits reason * updated CELL_VOLTAGE_DIFF_TO_RESET_VOLTAGE_LIMIT default value * added SoC round for LLT/JBD * fixed log typo * updated nightly script * Fix for #450 https://github.com/Louisvdw/dbus-serialbattery/issues/450 * Read charge/discharge limit JKBMS https://github.com/Louisvdw/dbus-serialbattery/issues/4 * reworked installation procedure Bluetooth BMS is now also fetched from config.ini * updated release workflow * updated readme * Merge branch 'master' into jkbms_ble * deploy to github pages only on changes in master or docusaurus branch * cleanup * Merge branch 'master' of into jkbms_ble * GitHub pages config change * GitHub pages config change * cleanup * Renamed scripts for better reading #532 * update docusaurus dependencies * Renamed scripts for better reading #532 * update docusaurus dependencies * change sh with bash * limitation reason cleanup * limitation reason cleanup * changed default config settings FLOAT_CELL_VOLTAGE from 3.350V to 3.375V LINEAR_LIMITATION_ENABLE from False to True * changed default config settings FLOAT_CELL_VOLTAGE from 3.350V to 3.375V LINEAR_LIMITATION_ENABLE from False to True * removed testing line * Cleanup duplicated files Files were moved and not deleted * Cleanup * MOSFET temperature was displayed twice after merge * small typo fixes * updated changelog * updated changelog * Small fixes * fix disconnection behaviour: on disconnect, show '---' after 10s and 'not connected' after 60s * fix flake errors * small fix * fix disconnection behaviour & small fixes * on disconnect, show '---' after 10s and 'not connected' after 60s by @transistorgit * small fixes in shell script * added restart driver script * fixed file permission * Added: apply max voltage if CVCM_ENABLE is False before float voltage was applied * fixed type error * Added: BMS disconnect behaviour * Choose to block charge/discharge on disconnect * Trigger Venus OS alarm * Changed: Remove wildcard import from dbushelper.py * small fixes * Added: apply max voltage if CVCM_ENABLE is False before float voltage was applied * Added: BMS disconnect behaviour * Choose to block charge/discharge on disconnect * Trigger Venus OS alarm * Changed: Remove wildcard import from dbushelper.py * flake8 changes * copied lltjbd_ble from idstein:jdb_ble * Added and adapted LltJbd_Ble ATTENTION: Currently it's untested * small changes * read production date and append to hardware version * Set SOC nightly. Button is working, next is send command to bms * Added: Show additional data in device page * show self.unique_identifier as serial number * show self.production as device name * Added: JKBMS unique identifier & fixed data length * Added: JKBMS BLE unique identifier * Added: Jkbms_Ble connection_name() * Added: Daly unique identifier * Added: JKBMS BLE serial number, user defined field * Added: Show additional data in device page * show self.unique_identifier as serial number * show self.production as device name * Added: JKBMS unique identifier & fixed data length * move config.ini before update * read production date by @tranistorgit this adds the battery production date * read out daly battery code and use as unique id * moved production date and added custom field * clean battery code strip whitespace and replace one or multiple spaces with one underline if no battery code generate unique field * Daly read_capacity change Read capacity from config file, if no value provided by BMS * Daly try to fix no reply * Improvements by @transistorgit * changed value * set SOC (and date time) on button press. * fix battery code parser * format fix * format fix * fix extra long serial timeouts by calculating max time instead of loop counts * Changed: Merged all install files into one * updated install docs for nightly build * Small fixes * changed config backup * updated config file * updated changelog * debug daly * changed release workflow * changed release workflow * changed release workflow * changed release workflow * Updated from master * fix blank screen, debug daly * make Reset SoC a spin box * fix possible read_capacity problem * Daly read_balance_state() add missing return * Daly advanced troubleshooting * Changed: Improved Daily stability by a lot * fixes for disable and uninstall service was not removed and if removed, it was recreated by the serial starter * optimized USB install method * updated changelog * added missing qml to restore-gui.sh * optimized USB install method * Daly improvements * Set SoC on button press by @transistorgit * Improved driver stability by @transistorgit & @mr-manuel * moved production date and added custom field * changed jkbms_ble to dev * changed order * final daly 'broken packages handling' * Last changes for daly read problem by @transistorgit * change version in utils based on GitHub tag * test automatic release version change * Added: Configure voltage drop * test automatic release version change * fix Daly alarms * fixes small errors in bash files * fix missing driver name in restart-driver.sh * linear mode, allow max voltage on soc thesshold * Daly added one retry if failed * fixed LLT/JBD cell balancing display * rename tar after USB install fixes https://github.com/Louisvdw/dbus-serialbattery/issues/638 * add force buttons * force buttons working * fixed removing entries * implement force charge/discharge * little bit cleaner soc preset * use existing serial read/write function * add stop balancong switch * use existing serial read/write function * Changed: Get bg colors from MbStyle for dark mode * prevent short circuit evaluation * fix merge errors * added changelog info * Fix #648 --------- Co-authored-by: Bernd Stahlbock --- CHANGELOG.md | 8 +- etc/dbus-serialbattery/battery.py | 27 ++- etc/dbus-serialbattery/bms/daly.py | 175 ++++++++++++------ etc/dbus-serialbattery/bms/lifepower.py | 2 +- etc/dbus-serialbattery/bms/lltjbd.py | 38 ++++ etc/dbus-serialbattery/config.default.ini | 26 ++- etc/dbus-serialbattery/dbus-serialbattery.py | 4 +- etc/dbus-serialbattery/dbushelper.py | 22 ++- etc/dbus-serialbattery/disable.sh | 24 ++- etc/dbus-serialbattery/install.sh | 4 +- .../qml/PageBatteryCellVoltages.qml | 50 ++--- etc/dbus-serialbattery/qml/PageLynxIonIo.qml | 18 ++ etc/dbus-serialbattery/reinstall-local.sh | 5 +- etc/dbus-serialbattery/restart-driver.sh | 2 +- etc/dbus-serialbattery/uninstall.sh | 52 ++---- etc/dbus-serialbattery/utils.py | 60 ++++-- rc/post-hook.sh | 7 + 17 files changed, 362 insertions(+), 162 deletions(-) mode change 100755 => 100644 etc/dbus-serialbattery/install.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index 30822f96..ad28b18d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,8 +20,10 @@ * Added: Daly BMS - Read production date and build unique identifier by @transistorgit * Added: Daly BMS - Set SoC by @transistorgit * Added: Daly BMS - Show "battery code" field that can be set in the Daly app by @transistorgit +* Added: Daly BMS - Discharge / Charge Mosfet switching over remote console/GUI https://github.com/Louisvdw/dbus-serialbattery/issues/26 by @transistorgit * Added: Device name field (found in the GUI -> SerialBattery -> Device), that show a custom string that can be set in some BMS, if available by @mr-manuel * Added: Driver uninstall script by @mr-manuel +* Added: Rename TAR file after USB/SD card install to not overwrite the data on every reboot https://github.com/Louisvdw/dbus-serialbattery/issues/638 by @mr-manuel * Added: Fix for Venus OS >= v3.00~14 showing unused items https://github.com/Louisvdw/dbus-serialbattery/issues/469 by @mr-manuel * Added: HighInternalTemperature alarm (MOSFET) for JKBMS by @mr-manuel * Added: Improved maintainability (flake8, black lint), introduced code checks and automate release build https://github.com/Louisvdw/dbus-serialbattery/pull/386 by @ppuetsch @@ -38,6 +40,7 @@ * Added: JKBMS BLE - Show serial number and "User Private Data" field that can be set in the JKBMS App to identify the BMS in a multi battery environment by @mr-manuel * Added: JKBMS BLE driver by @baranator * Added: Possibility to add `config.ini` to the root of a USB flash drive on install via the USB method by @mr-manuel +* Added: Possibility to configure a `VOLTAGE_DROP` voltage, if you are using a SmartShunt as battery monitor as there is a little voltage difference https://github.com/Louisvdw/dbus-serialbattery/discussions/632 by @mr-manuel * Added: Post install notes by @mr-manuel * Added: Read charge/discharge limits from JKBMS by @mr-manuel * Added: Recalculation interval in linear mode for CVL, CCL and DCL by @mr-manuel @@ -56,6 +59,7 @@ * Changed: `reinstall-local.sh` to recreate `/data/conf/serial-starter.d`, if deleted by `disable.sh` --> to check if the file `conf/serial-starter.d` could now be removed from the repository by @mr-manuel * Changed: Added QML to `restore-gui.sh` by @mr-manuel * Changed: Bash output by @mr-manuel +* Changed: Daly BMS - Fixed BMS alerts by @mr-manuel * Changed: Daly BMS - Improved driver stability by @transistorgit & @mr-manuel * Changed: Default config file by @ppuetsch * Added missing descriptions to make it much clearer to understand by @mr-manuel @@ -73,8 +77,10 @@ * Changed: Fix for https://github.com/Louisvdw/dbus-serialbattery/issues/397 by @transistorgit * Changed: Fix for https://github.com/Louisvdw/dbus-serialbattery/issues/421 by @mr-manuel * Changed: Fix for https://github.com/Louisvdw/dbus-serialbattery/issues/450 by @mr-manuel +* Changed: Fix for https://github.com/Louisvdw/dbus-serialbattery/issues/648 by @mr-manuel * Changed: Fixed black lint errors by @mr-manuel * Changed: Fixed cell balancing background for cells 17-24 by @mr-manuel +* Changed: Fixed cell balancing display for JBD/LLT BMS https://github.com/Louisvdw/dbus-serialbattery/issues/359 by @mr-manuel * Changed: Fixed Time-To-Go is not working, if `TIME_TO_SOC_VALUE_TYPE` is set to other than `1` https://github.com/Louisvdw/dbus-serialbattery/pull/424#issuecomment-1440511018 by @mr-manuel * Changed: Improved install workflow via USB flash drive by @mr-manuel * Changed: Improved JBD BMS soc calculation https://github.com/Louisvdw/dbus-serialbattery/pull/439 by @aaronreek @@ -83,7 +89,7 @@ * Changed: Moved Bluetooth part to `reinstall-local.sh` by @mr-manuel * Changed: Moved BMS scripts to subfolder by @mr-manuel * Changed: Removed all wildcard imports and fixed black lint errors by @mr-manuel -* Changed: Removed cell voltage penalty. Replaced by automatic voltage calculation. Max voltage is kept until cells are balanced and reset when cells are inbalanced by @mr-manuel +* Changed: CVL calculation improvement. Removed cell voltage penalty. Replaced by automatic voltage calculation. Max voltage is kept until cells are balanced and reset when cells are inbalanced or SoC is below threshold by @mr-manuel * Changed: Renamed scripts for better reading #532 by @mr-manuel * Changed: Reworked and optimized installation scripts by @mr-manuel * Changed: Separate Time-To-Go and Time-To-SoC activation by @mr-manuel diff --git a/etc/dbus-serialbattery/battery.py b/etc/dbus-serialbattery/battery.py index 108cf211..767be09d 100644 --- a/etc/dbus-serialbattery/battery.py +++ b/etc/dbus-serialbattery/battery.py @@ -207,18 +207,21 @@ def manage_charge_voltage_linear(self) -> None: voltageDiff = self.get_max_cell_voltage() - self.get_min_cell_voltage() if self.max_voltage_start_time is None: + # start timer, if max voltage is reached and cells are balanced if ( - utils.MAX_CELL_VOLTAGE * self.cell_count <= voltageSum + (utils.MAX_CELL_VOLTAGE * self.cell_count) - utils.VOLTAGE_DROP + <= voltageSum and voltageDiff <= utils.CELL_VOLTAGE_DIFF_KEEP_MAX_VOLTAGE_UNTIL and self.allow_max_voltage ): self.max_voltage_start_time = time() + + # allow max voltage again, if cells are unbalanced or SoC threshold is reached elif ( - # utils.SOC_LEVEL_TO_RESET_VOLTAGE_LIMIT > self.soc - voltageDiff >= utils.CELL_VOLTAGE_DIFF_TO_RESET_VOLTAGE_LIMIT - and not self.allow_max_voltage - ): + utils.SOC_LEVEL_TO_RESET_VOLTAGE_LIMIT > self.soc + or voltageDiff >= utils.CELL_VOLTAGE_DIFF_TO_RESET_VOLTAGE_LIMIT + ) and not self.allow_max_voltage: self.allow_max_voltage = True else: tDiff = time() - self.max_voltage_start_time @@ -309,9 +312,8 @@ def manage_charge_voltage_step(self) -> None: if self.max_voltage_start_time is None: # check if max voltage is reached and start timer to keep max voltage if ( - utils.MAX_CELL_VOLTAGE * self.cell_count <= voltageSum - and self.allow_max_voltage - ): + utils.MAX_CELL_VOLTAGE * self.cell_count + ) - utils.VOLTAGE_DROP <= voltageSum and self.allow_max_voltage: # example 2 self.max_voltage_start_time = time() @@ -928,3 +930,12 @@ def log_settings(self) -> None: def reset_soc_callback(self, path, value): # callback for handling reset soc request return + + def force_charging_off_callback(self, path, value): + return + + def force_discharging_off_callback(self, path, value): + return + + def turn_balancing_off_callback(self, path, value): + return diff --git a/etc/dbus-serialbattery/bms/daly.py b/etc/dbus-serialbattery/bms/daly.py index b358a886..54226dac 100644 --- a/etc/dbus-serialbattery/bms/daly.py +++ b/etc/dbus-serialbattery/bms/daly.py @@ -21,9 +21,11 @@ def __init__(self, port, baud, address): self.poll_interval = 1000 self.type = self.BATTERYTYPE self.has_settings = 1 - self.reset_soc = 0 + self.reset_soc = 100 self.soc_to_set = None self.runtime = 0 # TROUBLESHOOTING for no reply errors + self.trigger_force_disable_discharge = None + self.trigger_force_disable_charge = None # 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" @@ -40,6 +42,8 @@ def __init__(self, port, baud, address): command_temp = b"\x96" command_cell_balance = b"\x97" # no reply command_alarm = b"\x98" # no reply + command_disable_discharge_mos = b"\xD9" + command_disable_charge_mos = b"\xDA" BATTERYTYPE = "Daly" LENGTH_CHECK = 1 @@ -57,9 +61,6 @@ def test_connection(self): result = self.read_status_data(ser) self.read_soc_data(ser) self.read_battery_code(ser) - self.reset_soc = ( - self.soc - ) # set to meaningful value as preset for the GUI except Exception as err: logger.error(f"Unexpected {err=}, {type(err)=}") @@ -93,7 +94,7 @@ def refresh_data(self): + "s" ) - result = result and self.read_fed_data(ser) + result = self.read_fed_data(ser) and result if self.runtime > 0.200: # TROUBLESHOOTING for no reply errors logger.info( " |- refresh_data: read_fed_data - result: " @@ -103,7 +104,7 @@ def refresh_data(self): + "s" ) - result = result and self.read_cell_voltage_range_data(ser) + result = self.read_cell_voltage_range_data(ser) and result if self.runtime > 0.200: # TROUBLESHOOTING for no reply errors logger.info( " |- refresh_data: read_cell_voltage_range_data - result: " @@ -123,7 +124,7 @@ def refresh_data(self): + "s" ) - result = result and self.read_alarm_data(ser) + result = self.read_alarm_data(ser) and result if self.runtime > 0.200: # TROUBLESHOOTING for no reply errors logger.info( " |- refresh_data: read_alarm_data - result: " @@ -133,7 +134,7 @@ def refresh_data(self): + "s" ) - result = result and self.read_temperature_range_data(ser) + result = self.read_temperature_range_data(ser) and result if self.runtime > 0.200: # TROUBLESHOOTING for no reply errors logger.info( " |- refresh_data: read_temperature_range_data - result: " @@ -143,26 +144,28 @@ def refresh_data(self): + "s" ) - result = result and self.read_cells_volts(ser) + result = self.read_balance_state(ser) and result if self.runtime > 0.200: # TROUBLESHOOTING for no reply errors logger.info( - " |- refresh_data: read_cells_volts - result: " + " |- refresh_data: read_balance_state - result: " + str(result) + " - runtime: " + str(self.runtime) + "s" ) - result = result and self.read_balance_state(ser) + result = self.read_cells_volts(ser) and result if self.runtime > 0.200: # TROUBLESHOOTING for no reply errors logger.info( - " |- refresh_data: read_balance_state - result: " + " |- refresh_data: read_cells_volts - result: " + str(result) + " - runtime: " + str(self.runtime) + "s" ) + self.write_charge_discharge_mos(ser) + except OSError: logger.warning("Couldn't open serial port") @@ -245,57 +248,57 @@ def read_alarm_data(self, ser): if al_volt & 48: # High voltage levels - Alarm - self.voltage_high = 2 + self.protection.voltage_high = 2 elif al_volt & 15: # High voltage Warning levels - Pre-alarm - self.voltage_high = 1 + self.protection.voltage_high = 1 else: - self.voltage_high = 0 + self.protection.voltage_high = 0 if al_volt & 128: # Low voltage level - Alarm - self.voltage_low = 2 + self.protection.voltage_low = 2 elif al_volt & 64: # Low voltage Warning level - Pre-alarm - self.voltage_low = 1 + self.protection.voltage_low = 1 else: - self.voltage_low = 0 + self.protection.voltage_low = 0 if al_temp & 2: # High charge temp - Alarm - self.temp_high_charge = 2 + self.protection.temp_high_charge = 2 elif al_temp & 1: # High charge temp - Pre-alarm - self.temp_high_charge = 1 + self.protection.temp_high_charge = 1 else: - self.temp_high_charge = 0 + self.protection.temp_high_charge = 0 if al_temp & 8: # Low charge temp - Alarm - self.temp_low_charge = 2 + self.protection.temp_low_charge = 2 elif al_temp & 4: # Low charge temp - Pre-alarm - self.temp_low_charge = 1 + self.protection.temp_low_charge = 1 else: - self.temp_low_charge = 0 + self.protection.temp_low_charge = 0 if al_temp & 32: # High discharge temp - Alarm - self.temp_high_discharge = 2 + self.protection.temp_high_discharge = 2 elif al_temp & 16: # High discharge temp - Pre-alarm - self.temp_high_discharge = 1 + self.protection.temp_high_discharge = 1 else: - self.temp_high_discharge = 0 + self.protection.temp_high_discharge = 0 if al_temp & 128: # Low discharge temp - Alarm - self.temp_low_discharge = 2 + self.protection.temp_low_discharge = 2 elif al_temp & 64: # Low discharge temp - Pre-alarm - self.temp_low_discharge = 1 + self.protection.temp_low_discharge = 1 else: - self.temp_low_discharge = 0 + self.protection.temp_low_discharge = 0 # if al_crnt_soc & 2: # # High charge current - Alarm @@ -317,21 +320,21 @@ def read_alarm_data(self, ser): if al_crnt_soc & 2 or al_crnt_soc & 8: # High charge/discharge current - Alarm - self.current_over = 2 + self.protection.current_over = 2 elif al_crnt_soc & 1 or al_crnt_soc & 4: # High charge/discharge current - Pre-alarm - self.current_over = 1 + self.protection.current_over = 1 else: - self.current_over = 0 + self.protection.current_over = 0 if al_crnt_soc & 128: # Low SoC - Alarm - self.soc_low = 2 + self.protection.soc_low = 2 elif al_crnt_soc & 64: # Low SoC Warning level - Pre-alarm - self.soc_low = 1 + self.protection.soc_low = 1 else: - self.soc_low = 0 + self.protection.soc_low = 0 return True @@ -558,8 +561,16 @@ def read_serial_data_daly(self, ser, command): ser, self.generate_command(command), self.LENGTH_POS, self.LENGTH_CHECK ) if data is False: - logger.info("No reply to cmd " + bytes(command).hex()) - return False + # sleep 100 ms and retry. + sleep(0.100) + data = self.read_serialport_data( + ser, self.generate_command(command), self.LENGTH_POS, self.LENGTH_CHECK + ) + if data is False: + logger.info("No reply to cmd " + bytes(command).hex()) + return False + else: + logger.info(" |- Error cleared, received data after one retry.") if len(data) <= 12: logger.debug("Too short reply to cmd " + bytes(command).hex()) @@ -595,7 +606,7 @@ def read_serial_data_daly(self, ser, command): ) return False - # Read data from previously openned serial port + # Read data from previously opened serial port def read_serialport_data( self, ser, @@ -610,6 +621,7 @@ def read_serialport_data( # if you see a lot of errors, try to increase in steps of 0.005 sleep(0.020) + time_run = 0 time_start = time() ser.flushOutput() ser.flushInput() @@ -715,21 +727,78 @@ def write_soc_and_datetime(self, ser): logger.info(f"write soc {self.soc_to_set}%") self.soc_to_set = None # Reset value, so we will set it only once - time_start = time() - ser.flushOutput() - ser.flushInput() - ser.write(cmd) - - toread = ser.inWaiting() - while toread < 13: - sleep(0.005) - toread = ser.inWaiting() - time_run = time() - time_start - if time_run > 0.500: - logger.warning("write soc: no reply, probably failed") - return False + reply = self.read_serialport_data(ser, cmd, self.LENGTH_POS, self.LENGTH_CHECK) - reply = ser.read(toread) if reply[4] != 1: logger.error("write soc failed") return True + + def force_charging_off_callback(self, path, value): + if value is None: + return False + + if value == 0: + self.trigger_force_disable_charge = False + return True + + if value == 1: + self.trigger_force_disable_charge = True + return True + + return False + + def force_discharging_off_callback(self, path, value): + if value is None: + return False + + if value == 0: + self.trigger_force_disable_discharge = False + return True + + if value == 1: + self.trigger_force_disable_discharge = True + return True + + return False + + def write_charge_discharge_mos(self, ser): + if ( + self.trigger_force_disable_charge is None + and self.trigger_force_disable_discharge is None + ): + return False + + cmd = bytearray(self.command_base) + + if self.trigger_force_disable_charge is not None: + cmd[2] = self.command_disable_charge_mos[0] + cmd[4] = 0 if self.trigger_force_disable_charge else 1 + cmd[12] = sum(cmd[:12]) & 0xFF + logger.info( + f"write force disable charging: {'true' if self.trigger_force_disable_charge else 'false'}" + ) + self.trigger_force_disable_charge = None + + reply = self.read_serialport_data( + ser, cmd, self.LENGTH_POS, self.LENGTH_CHECK + ) + if reply is False or reply[4] != cmd[4]: + logger.error("write force disable charge/discharge failed") + return False + + if self.trigger_force_disable_discharge is not None: + cmd[2] = self.command_disable_discharge_mos[0] + cmd[4] = 0 if self.trigger_force_disable_discharge else 1 + cmd[12] = sum(cmd[:12]) & 0xFF + logger.info( + f"write force disable discharging: {'true' if self.trigger_force_disable_discharge else 'false'}" + ) + self.trigger_force_disable_discharge = None + + reply = self.read_serialport_data( + ser, cmd, self.LENGTH_POS, self.LENGTH_CHECK + ) + if reply is False or reply[4] != cmd[4]: + logger.error("write force disable charge/discharge failed") + return False + return True diff --git a/etc/dbus-serialbattery/bms/lifepower.py b/etc/dbus-serialbattery/bms/lifepower.py index 84c93a37..5780d58c 100644 --- a/etc/dbus-serialbattery/bms/lifepower.py +++ b/etc/dbus-serialbattery/bms/lifepower.py @@ -38,7 +38,7 @@ def get_settings(self): # After successful connection get_settings will be call to set up the battery. # Set the current limits, populate cell count, etc # Return True if success, False for failure - self.max_battery_current = utils.MAX_BATTERY_CURRENT + self.max_battery_charge_current = utils.MAX_BATTERY_CHARGE_CURRENT self.max_battery_discharge_current = utils.MAX_BATTERY_DISCHARGE_CURRENT hardware_version = self.read_serial_data_eg4(self.command_hardware_version) if hardware_version: diff --git a/etc/dbus-serialbattery/bms/lltjbd.py b/etc/dbus-serialbattery/bms/lltjbd.py index a74697cc..c1bf2ae3 100644 --- a/etc/dbus-serialbattery/bms/lltjbd.py +++ b/etc/dbus-serialbattery/bms/lltjbd.py @@ -116,6 +116,43 @@ def to_protection_bits(self, byte_data): self.protection.set_short = is_bit_set(tmp[2]) def to_cell_bits(self, byte_data, byte_data_high): + # init the cell array once + if len(self.cells) == 0: + for _ in range(self.cell_count): + print("#" + str(_)) + self.cells.append(Cell(False)) + + # get up to the first 16 cells + tmp = bin(byte_data)[2:].rjust(min(self.cell_count, 16), utils.zero_char) + # 4 cells + # tmp = 0101 + # 16 cells + # tmp = 0101010101010101 + + tmp_reversed = list(reversed(tmp)) + # print(tmp_reversed) --> ['1', '0', '1', '0', '1', '0', '1', '0', '1', '0', '1', '0', '1', '0', '1', '0'] + # [cell1, cell2, cell3, ...] + + if self.cell_count > 16: + tmp2 = bin(byte_data_high)[2:].rjust(self.cell_count - 16, utils.zero_char) + # tmp = 1100110011001100 + tmp_reversed = tmp_reversed + list(reversed(tmp2)) + # print(tmp_reversed) --> [ + # '1', '0', '1', '0', '1', '0', '1', '0', '1', '0', '1', '0', '1', '0', '1', '0', + # '0', '0', '1', '1', '0', '0', '1', '1', '0', '0', '1', '1', '0', '0', '1', '1' + # ] + # [ + # cell1, cell2, ..., cell16, + # cell17, cell18, ..., cell32 + # ] + + for c in range(self.cell_count): + if is_bit_set(tmp_reversed[c]): + self.cells[c].balance = True + else: + self.cells[c].balance = False + + """ # clear the list for c in self.cells: self.cells.remove(c) @@ -128,6 +165,7 @@ def to_cell_bits(self, byte_data, byte_data_high): tmp = bin(byte_data_high)[2:].rjust(self.cell_count - 16, utils.zero_char) for bit in reversed(tmp): self.cells.append(Cell(is_bit_set(bit))) + """ def to_fet_bits(self, byte_data): tmp = bin(byte_data)[2:].rjust(2, utils.zero_char) diff --git a/etc/dbus-serialbattery/config.default.ini b/etc/dbus-serialbattery/config.default.ini index 8018e3bd..4b11e9b5 100644 --- a/etc/dbus-serialbattery/config.default.ini +++ b/etc/dbus-serialbattery/config.default.ini @@ -50,15 +50,18 @@ LINEAR_RECALCULATION_ON_PERC_CHANGE = 5 ; SoC is below SOC_LEVEL_TO_RESET_VOLTAGE_LIMIT it switches back to max voltage. ; Linear mode: After max voltage is reachend and cell voltage difference is smaller or equal to ; CELL_VOLTAGE_DIFF_KEEP_MAX_VOLTAGE_UNTIL it switches to float voltage after 300 (fixed) -; additional seconds. After cell voltage difference is greater or equal to -; CELL_VOLTAGE_DIFF_TO_RESET_VOLTAGE_LIMIT it switches back to max voltage. +; additional seconds. +; After cell voltage difference is greater or equal to CELL_VOLTAGE_DIFF_TO_RESET_VOLTAGE_LIMIT +; OR +; SoC is below SOC_LEVEL_TO_RESET_VOLTAGE_LIMIT +; it switches back to max voltage. ; Example: The battery reached max voltage of 55.2V and hold it for 900 seconds, the the CVL is switched to ; float voltage of 53.6V to don't stress the batteries. Allow max voltage of 55.2V again, if SoC is ; once below 90% ; OR ; The battery reached max voltage of 55.2V and the max cell difference is 0.010V, then switch to float ; voltage of 53.6V after 300 additional seconds to don't stress the batteries. Allow max voltage of -; 55.2V again if max cell difference is above 0.050V +; 55.2V again if max cell difference is above 0.080V or SoC below 90%. ; Charge voltage control management enable (True/False). CVCM_ENABLE = True @@ -218,7 +221,7 @@ SOC_LOW_WARNING = 20 SOC_LOW_ALARM = 10 ; -- Daly settings -; Battery capacity (amps) if the BMS does not support reading it +; Battery capacity (amps), if the BMS does not support reading it BATTERY_CAPACITY = 50 ; Invert Battery Current. Default non-inverted. Set to -1 to invert INVERT_CURRENT_MEASUREMENT = 1 @@ -228,3 +231,18 @@ GREENMETER_ADDRESS = 1 LIPRO_START_ADDRESS = 2 LIPRO_END_ADDRESS = 4 LIPRO_CELL_COUNT = 15 + + +; --------- Battery monitor specific settings --------- +; If you are using a SmartShunt or something else as a battery monitor, the battery voltage reported +; from the BMS and SmartShunt could differ. This causes, that the driver never goapplies the float voltage, +; since max voltage is never reached. +; Example: +; cell count: 16 +; MAX_CELL_VOLTAGE = 3.45 +; max voltage calculated = 16 * 3.45 = 55.20 +; CVL is set to 55.20 and the battery is now charged until the SmartShunt measures 55.20 V. The BMS +; now measures 55.05 V since there is a voltage drop of 0.15 V. Since the dbus-serialbattery measures +; 55.05 V the max voltage is never reached for the driver and max voltage is kept forever. +; Set VOLTAGE_DROP to 0.15 +VOLTAGE_DROP = 0.00 diff --git a/etc/dbus-serialbattery/dbus-serialbattery.py b/etc/dbus-serialbattery/dbus-serialbattery.py index 68265a07..b50c938c 100644 --- a/etc/dbus-serialbattery/dbus-serialbattery.py +++ b/etc/dbus-serialbattery/dbus-serialbattery.py @@ -97,9 +97,7 @@ def get_port() -> str: logger.info("No Port needed") return "/dev/tty/USB9" - logger.info( - "dbus-serialbattery v" + str(utils.DRIVER_VERSION) + utils.DRIVER_SUBVERSION - ) + logger.info("dbus-serialbattery v" + str(utils.DRIVER_VERSION)) port = get_port() battery = None diff --git a/etc/dbus-serialbattery/dbushelper.py b/etc/dbus-serialbattery/dbushelper.py index 555cb1ba..ccf7181e 100644 --- a/etc/dbus-serialbattery/dbushelper.py +++ b/etc/dbus-serialbattery/dbushelper.py @@ -121,9 +121,7 @@ def setup_vedbus(self): self._dbusservice.add_path( "/ProductName", "SerialBattery(" + self.battery.type + ")" ) - self._dbusservice.add_path( - "/FirmwareVersion", str(utils.DRIVER_VERSION) + utils.DRIVER_SUBVERSION - ) + self._dbusservice.add_path("/FirmwareVersion", str(utils.DRIVER_VERSION)) self._dbusservice.add_path("/HardwareVersion", self.battery.hardware_version) self._dbusservice.add_path("/Connected", 1) self._dbusservice.add_path( @@ -253,6 +251,24 @@ def setup_vedbus(self): self._dbusservice.add_path("/Io/AllowToCharge", 0, writeable=True) self._dbusservice.add_path("/Io/AllowToDischarge", 0, writeable=True) self._dbusservice.add_path("/Io/AllowToBalance", 0, writeable=True) + self._dbusservice.add_path( + "/Io/ForceChargingOff", + 0, + writeable=True, + onchangecallback=self.battery.force_charging_off_callback, + ) + self._dbusservice.add_path( + "/Io/ForceDischargingOff", + 0, + writeable=True, + onchangecallback=self.battery.force_discharging_off_callback, + ) + self._dbusservice.add_path( + "/Io/TurnBalancingOff", + 0, + writeable=True, + onchangecallback=self.battery.turn_balancing_off_callback, + ) # self._dbusservice.add_path('/SystemSwitch', 1, writeable=True) # Create the alarms diff --git a/etc/dbus-serialbattery/disable.sh b/etc/dbus-serialbattery/disable.sh index 34304cd5..f1902881 100755 --- a/etc/dbus-serialbattery/disable.sh +++ b/etc/dbus-serialbattery/disable.sh @@ -4,16 +4,27 @@ #set -x # handle read only mounts -sh /opt/victronenergy/swupdate-scripts/remount-rw.sh +bash /opt/victronenergy/swupdate-scripts/remount-rw.sh -# remove files, don't use variables here, since on an error the whole /opt/victronenergy gets deleted +# remove driver from serial starter rm -f /data/conf/serial-starter.d/dbus-serialbattery.conf +# kill serial starter, to reload changes +pkill -f "/opt/victronenergy/serial-starter/serial-starter.sh" + +# remove services rm -rf /service/dbus-serialbattery.* rm -rf /service/dbus-blebattery.* +# kill driver, if running +pkill -f "python .*/dbus-serialbattery.py" +pkill -f "blebattery" + # remove install script from rc.local sed -i "/bash \/data\/etc\/dbus-serialbattery\/reinstall-local.sh/d" /data/rc.local +# remove cronjob +sed -i "/5 0,12 \* \* \* \/etc\/init.d\/bluetooth restart/d" /var/spool/cron/root + ### needed for upgrading from older versions | start ### # remove old drivers before changing from dbus-blebattery-$1 to dbus-blebattery.$1 @@ -25,10 +36,5 @@ sed -i "/sh \/data\/etc\/dbus-serialbattery\/reinstall-local.sh/d" /data/rc.loca sed -i "/sh \/data\/etc\/dbus-serialbattery\/installble.sh/d" /data/rc.local ### needed for upgrading from older versions | end ### - -# kill serial starter, to reload changes -pkill -f "/opt/victronenergy/serial-starter/serial-starter.sh" - -# kill driver, if running -pkill -f "serialbattery" -pkill -f "blebattery" +echo "The dbus-serialbattery driver was disabled". +echo diff --git a/etc/dbus-serialbattery/install.sh b/etc/dbus-serialbattery/install.sh old mode 100755 new mode 100644 index 17a12ed3..c54c92c6 --- a/etc/dbus-serialbattery/install.sh +++ b/etc/dbus-serialbattery/install.sh @@ -49,8 +49,8 @@ fi ## specific version if [ "$version" = "specific version" ]; then # read the url - read -p "Enter the url of the \"venus-data.tar.gz\" you want to install: " tar_url - wget -O /tmp/venus-data.tar.gz $tar_url + read -r -p "Enter the url of the \"venus-data.tar.gz\" you want to install: " tar_url + wget -O /tmp/venus-data.tar.gz "$tar_url" if [ $? -ne 0 ]; then echo "Error during downloading the TAR file. Please check, if the URL is correct." exit diff --git a/etc/dbus-serialbattery/qml/PageBatteryCellVoltages.qml b/etc/dbus-serialbattery/qml/PageBatteryCellVoltages.qml index 112564df..ea723a89 100644 --- a/etc/dbus-serialbattery/qml/PageBatteryCellVoltages.qml +++ b/etc/dbus-serialbattery/qml/PageBatteryCellVoltages.qml @@ -4,6 +4,8 @@ import com.victron.velib 1.0 MbPage { id: root property string bindPrefix + property MbStyle style: MbStyle{} + property VBusItem _b1: VBusItem { bind: service.path("/Balances/Cell1") } property VBusItem _b2: VBusItem { bind: service.path("/Balances/Cell2") } property VBusItem _b3: VBusItem { bind: service.path("/Balances/Cell3") } @@ -52,30 +54,30 @@ MbPage { property VBusItem volt22: VBusItem { bind: service.path("/Voltages/Cell22") } property VBusItem volt23: VBusItem { bind: service.path("/Voltages/Cell23") } property VBusItem volt24: VBusItem { bind: service.path("/Voltages/Cell24") } - property string c1: _b1.valid && _b1.text == "1" ? "#ff0000" : "#ddd" - property string c2: _b2.valid && _b2.text == "1" ? "#ff0000" : "#ddd" - property string c3: _b3.valid && _b3.text == "1" ? "#ff0000" : "#ddd" - property string c4: _b4.valid && _b4.text == "1" ? "#ff0000" : "#ddd" - property string c5: _b5.valid && _b5.text == "1" ? "#ff0000" : "#ddd" - property string c6: _b6.valid && _b6.text == "1" ? "#ff0000" : "#ddd" - property string c7: _b7.valid && _b7.text == "1" ? "#ff0000" : "#ddd" - property string c8: _b8.valid && _b8.text == "1" ? "#ff0000" : "#ddd" - property string c9: _b9.valid && _b9.text == "1" ? "#ff0000" : "#ddd" - property string c10: _b10.valid && _b10.text == "1" ? "#ff0000" : "#ddd" - property string c11: _b11.valid && _b11.text == "1" ? "#ff0000" : "#ddd" - property string c12: _b12.valid && _b12.text == "1" ? "#ff0000" : "#ddd" - property string c13: _b13.valid && _b13.text == "1" ? "#ff0000" : "#ddd" - property string c14: _b14.valid && _b14.text == "1" ? "#ff0000" : "#ddd" - property string c15: _b15.valid && _b15.text == "1" ? "#ff0000" : "#ddd" - property string c16: _b16.valid && _b16.text == "1" ? "#ff0000" : "#ddd" - property string c17: _b17.valid && _b17.text == "1" ? "#ff0000" : "#ddd" - property string c18: _b18.valid && _b18.text == "1" ? "#ff0000" : "#ddd" - property string c19: _b19.valid && _b19.text == "1" ? "#ff0000" : "#ddd" - property string c20: _b20.valid && _b20.text == "1" ? "#ff0000" : "#ddd" - property string c21: _b21.valid && _b21.text == "1" ? "#ff0000" : "#ddd" - property string c22: _b22.valid && _b22.text == "1" ? "#ff0000" : "#ddd" - property string c23: _b23.valid && _b23.text == "1" ? "#ff0000" : "#ddd" - property string c24: _b24.valid && _b24.text == "1" ? "#ff0000" : "#ddd" + property string c1: _b1.valid && _b1.text == "1" ? "#ff0000" : style.borderColor + property string c2: _b2.valid && _b2.text == "1" ? "#ff0000" : style.borderColor + property string c3: _b3.valid && _b3.text == "1" ? "#ff0000" : style.borderColor + property string c4: _b4.valid && _b4.text == "1" ? "#ff0000" : style.borderColor + property string c5: _b5.valid && _b5.text == "1" ? "#ff0000" : style.borderColor + property string c6: _b6.valid && _b6.text == "1" ? "#ff0000" : style.borderColor + property string c7: _b7.valid && _b7.text == "1" ? "#ff0000" : style.borderColor + property string c8: _b8.valid && _b8.text == "1" ? "#ff0000" : style.borderColor + property string c9: _b9.valid && _b9.text == "1" ? "#ff0000" : style.borderColor + property string c10: _b10.valid && _b10.text == "1" ? "#ff0000" : style.borderColor + property string c11: _b11.valid && _b11.text == "1" ? "#ff0000" : style.borderColor + property string c12: _b12.valid && _b12.text == "1" ? "#ff0000" : style.borderColor + property string c13: _b13.valid && _b13.text == "1" ? "#ff0000" : style.borderColor + property string c14: _b14.valid && _b14.text == "1" ? "#ff0000" : style.borderColor + property string c15: _b15.valid && _b15.text == "1" ? "#ff0000" : style.borderColor + property string c16: _b16.valid && _b16.text == "1" ? "#ff0000" : style.borderColor + property string c17: _b17.valid && _b17.text == "1" ? "#ff0000" : style.borderColor + property string c18: _b18.valid && _b18.text == "1" ? "#ff0000" : style.borderColor + property string c19: _b19.valid && _b19.text == "1" ? "#ff0000" : style.borderColor + property string c20: _b20.valid && _b20.text == "1" ? "#ff0000" : style.borderColor + property string c21: _b21.valid && _b21.text == "1" ? "#ff0000" : style.borderColor + property string c22: _b22.valid && _b22.text == "1" ? "#ff0000" : style.borderColor + property string c23: _b23.valid && _b23.text == "1" ? "#ff0000" : style.borderColor + property string c24: _b24.valid && _b24.text == "1" ? "#ff0000" : style.borderColor title: service.description + " | Cell Voltages" model: VisibleItemModel { diff --git a/etc/dbus-serialbattery/qml/PageLynxIonIo.qml b/etc/dbus-serialbattery/qml/PageLynxIonIo.qml index e6ad7106..21bfedf4 100644 --- a/etc/dbus-serialbattery/qml/PageLynxIonIo.qml +++ b/etc/dbus-serialbattery/qml/PageLynxIonIo.qml @@ -49,6 +49,24 @@ MbPage { ] } + MbSwitch { + name: qsTr("Force charging off") + bind: Utils.path(bindPrefix, "/Io/ForceChargingOff") + show: item.valid + } + + MbSwitch { + name: qsTr("Force discharging off") + bind: Utils.path(bindPrefix, "/Io/ForceDischargingOff") + show: item.valid + } + + MbSwitch { + name: qsTr("Turn balancing off") + bind: Utils.path(bindPrefix, "/Io/TurnBalancingOff") + show: item.valid + } + MbItemOptions { description: qsTr("External relay") bind: Utils.path(bindPrefix, "/Io/ExternalRelay") diff --git a/etc/dbus-serialbattery/reinstall-local.sh b/etc/dbus-serialbattery/reinstall-local.sh index f822e026..b082c620 100755 --- a/etc/dbus-serialbattery/reinstall-local.sh +++ b/etc/dbus-serialbattery/reinstall-local.sh @@ -141,9 +141,10 @@ fi # remove old drivers before changing from dbus-blebattery-$1 to dbus-blebattery.$1 rm -rf /service/dbus-blebattery-* # remove old install script from rc.local -sed -i "/sh \/data\/etc\/$DRIVERNAME\/reinstalllocal.sh/d" /data/rc.local +sed -i "/^sh \/data\/etc\/dbus-serialbattery\/reinstalllocal.sh/d" /data/rc.local +sed -i "/^sh \/data\/etc\/dbus-serialbattery\/reinstall-local.sh/d" /data/rc.local # remove old entry from rc.local -sed -i "/sh \/data\/etc\/dbus-serialbattery\/installble.sh/d" /data/rc.local +sed -i "/^sh \/data\/etc\/dbus-serialbattery\/installble.sh/d" /data/rc.local ### needed for upgrading from older versions | end ### diff --git a/etc/dbus-serialbattery/restart-driver.sh b/etc/dbus-serialbattery/restart-driver.sh index 853a8b97..88a15800 100755 --- a/etc/dbus-serialbattery/restart-driver.sh +++ b/etc/dbus-serialbattery/restart-driver.sh @@ -10,7 +10,7 @@ cp -f /data/etc/dbus-serialbattery/config.ini /opt/victronenergy/dbus-serialbatt # svc -d -u /service/dbus-serialbattery # kill driver, if running. It gets restarted by the service daemon -pkill -f "python .*/$DRIVERNAME.py" +pkill -f "python .*/dbus-serialbattery.py" # get BMS list from config file diff --git a/etc/dbus-serialbattery/uninstall.sh b/etc/dbus-serialbattery/uninstall.sh index d11df02f..94100a9d 100755 --- a/etc/dbus-serialbattery/uninstall.sh +++ b/etc/dbus-serialbattery/uninstall.sh @@ -3,41 +3,15 @@ # remove comment for easier troubleshooting #set -x -# handle read only mounts -bash /opt/victronenergy/swupdate-scripts/remount-rw.sh +# disable driver +bash /data/etc/dbus-serialbattery/disable.sh -# remove files, don't use variables here, since on an error the whole /opt/victronenergy gets deleted -rm -f /data/conf/serial-starter.d/dbus-serialbattery.conf + +# remove files in Victron directory. Don't use variables here, +# since on an error the whole /opt/victronenergy gets deleted rm -rf /opt/victronenergy/service/dbus-serialbattery rm -rf /opt/victronenergy/service-templates/dbus-serialbattery rm -rf /opt/victronenergy/dbus-serialbattery -rm -rf /service/dbus-serialbattery.* -rm -rf /service/dbus-blebattery.* - -# remove install-script from rc.local -sed -i "/bash \/data\/etc\/dbus-serialbattery\/reinstall-local.sh/d" /data/rc.local - -# remove cronjob -sed -i "/5 0,12 \* \* \* \/etc\/init.d\/bluetooth restart/d" /var/spool/cron/root - - -### needed for upgrading from older versions | start ### -# remove old drivers before changing from dbus-blebattery-$1 to dbus-blebattery.$1 -rm -rf /service/dbus-blebattery-* -# remove old install script from rc.local -sed -i "/sh \/data\/etc\/dbus-serialbattery\/reinstalllocal.sh/d" /data/rc.local -sed -i "/sh \/data\/etc\/dbus-serialbattery\/reinstall-local.sh/d" /data/rc.local -# remove old entry from rc.local -sed -i "/sh \/data\/etc\/dbus-serialbattery\/installble.sh/d" /data/rc.local -### needed for upgrading from older versions | end ### - - -# kill serial starter, to reload changes -pkill -f "/opt/victronenergy/serial-starter/serial-starter.sh" - -# kill driver, if running -pkill -f "serialbattery" -pkill -f "blebattery" # restore GUI changes @@ -45,10 +19,10 @@ pkill -f "blebattery" # uninstall modules -read -r -p "Do you also want to uninstall bleak, python3-pip and python3-modules? If you don't know select y. [Y/n] " response +read -r -p "Do you want to uninstall bleak, python3-pip and python3-modules? If you don't know just press enter. [y/N] " response echo response=${response,,} # tolower -if [[ $response =~ ^(y| ) ]] || [[ -z $response ]]; then +if [[ $response =~ ^(y) ]]; then echo "Uninstalling modules..." pip3 uninstall bleak opkg remove python3-pip python3-modules @@ -57,5 +31,15 @@ if [[ $response =~ ^(y| ) ]] || [[ -z $response ]]; then fi -echo "The driver was uninstalled. To delete also the install files run \"rm -rf /data/etc/dbus-serialbattery\" now." +read -r -p "Do you want to delete the install and configuration files in \"/data/etc/dbus-serialbattery\"? If you don't know just press enter. [y/N] " response +echo +response=${response,,} # tolower +if [[ $response =~ ^(y) ]]; then + rm -rf /data/etc/dbus-serialbattery + echo "The folder \"/data/etc/dbus-serialbattery\" was removed." + echo +fi + + +echo "The dbus-serialbattery driver was uninstalled. Please reboot." echo diff --git a/etc/dbus-serialbattery/utils.py b/etc/dbus-serialbattery/utils.py index 74aa7d22..e36782da 100644 --- a/etc/dbus-serialbattery/utils.py +++ b/etc/dbus-serialbattery/utils.py @@ -35,8 +35,7 @@ def _get_list_from_config( # if not specified: baud = 9600 # Constants - Need to dynamically get them in future -DRIVER_VERSION = "1.0" -DRIVER_SUBVERSION = ".0 (20230508)" +DRIVER_VERSION = "1.0.20230518dev" zero_char = chr(48) degree_sign = "\N{DEGREE SIGN}" @@ -64,9 +63,10 @@ def _get_list_from_config( # --------- Charge mode --------- # Choose the mode for voltage / current limitations (True / False) -# False is a step mode. This is the default with limitations on hard boundary steps -# True is a linear mode. For CCL and DCL the values between the steps are calculated for smoother values (by WaldemarFech) -# For CVL max battery voltage is calculated dynamically in order that the max cell voltage is not exceeded +# False is a step mode: This is the default with limitations on hard boundary steps +# True is a linear mode: +# For CCL and DCL the values between the steps are calculated for smoother values (by WaldemarFech) +# For CVL max battery voltage is calculated dynamically in order that the max cell voltage is not exceeded LINEAR_LIMITATION_ENABLE = "True" == config["DEFAULT"]["LINEAR_LIMITATION_ENABLE"] # Specify in seconds how often the penalty should be recalculated @@ -79,17 +79,26 @@ def _get_list_from_config( # --------- Charge Voltage limitation (affecting CVL) --------- -# Description: Limit max charging voltage (MAX_CELL_VOLTAGE * cell count), switch from max voltage to float voltage (FLOAT_CELL_VOLTAGE * cell count) and back -# Step mode: After max voltage is reached for MAX_VOLTAGE_TIME_SEC it switches to float voltage. After SoC is below SOC_LEVEL_TO_RESET_VOLTAGE_LIMIT it -# switches back to max voltage. -# Linear mode: After max voltage is reachend and cell voltage difference is smaller or equal to CELL_VOLTAGE_DIFF_KEEP_MAX_VOLTAGE_UNTIL it switches to -# float voltage after 300 (fixed) additional seconds. After cell voltage difference is greater or equal to CELL_VOLTAGE_DIFF_TO_RESET_VOLTAGE_LIMIT -# it switches back to max voltage. -# Example: The battery reached max voltage of 55.2V and hold it for 900 seconds, the the CVL is switched to float voltage of 53.6V to don't stress the batteries. -# Allow max voltage of 55.2V again, if SoC is once below 90% +# Description: Limit max charging voltage (MAX_CELL_VOLTAGE * cell count), switch from max voltage to float +# voltage (FLOAT_CELL_VOLTAGE * cell count) and back +# False: Max charging voltage is always kept +# True: Max charging voltage is reduced based on charge mode +# Step mode: After max voltage is reached for MAX_VOLTAGE_TIME_SEC it switches to float voltage. After +# SoC is below SOC_LEVEL_TO_RESET_VOLTAGE_LIMIT it switches back to max voltage. +# Linear mode: After max voltage is reachend and cell voltage difference is smaller or equal to +# CELL_VOLTAGE_DIFF_KEEP_MAX_VOLTAGE_UNTIL it switches to float voltage after 300 (fixed) +# additional seconds. +# After cell voltage difference is greater or equal to CELL_VOLTAGE_DIFF_TO_RESET_VOLTAGE_LIMIT +# OR +# SoC is below SOC_LEVEL_TO_RESET_VOLTAGE_LIMIT +# it switches back to max voltage. +# Example: The battery reached max voltage of 55.2V and hold it for 900 seconds, the the CVL is switched to +# float voltage of 53.6V to don't stress the batteries. Allow max voltage of 55.2V again, if SoC is +# once below 90% # OR -# The battery reached max voltage of 55.2V and the max cell difference is 0.010V, then switch to float voltage of 53.6V after 300 additional seconds -# to don't stress the batteries. Allow max voltage of 55.2V again if max cell difference is above 0.050V +# The battery reached max voltage of 55.2V and the max cell difference is 0.010V, then switch to float +# voltage of 53.6V after 300 additional seconds to don't stress the batteries. Allow max voltage of +# 55.2V again if max cell difference is above 0.080V or SoC below 90%. # Charge voltage control management enable (True/False). CVCM_ENABLE = "True" == config["DEFAULT"]["CVCM_ENABLE"] @@ -99,14 +108,16 @@ def _get_list_from_config( config["DEFAULT"]["CELL_VOLTAGE_DIFF_KEEP_MAX_VOLTAGE_UNTIL"] ) # Specify cell voltage diff where CVL limit is reset to max voltage, if value get above +# the cells are considered as imbalanced, if the cell diff exceeds 5% of the nominal cell voltage +# e.g. 3.2 V * 5 / 100 = 0.160 V CELL_VOLTAGE_DIFF_TO_RESET_VOLTAGE_LIMIT = float( config["DEFAULT"]["CELL_VOLTAGE_DIFF_TO_RESET_VOLTAGE_LIMIT"] ) # -- CVL Reset based on SoC option -# Reset max voltage after +# Specify how long the max voltage should be kept, if reached then switch to float voltage MAX_VOLTAGE_TIME_SEC = float(config["DEFAULT"]["MAX_VOLTAGE_TIME_SEC"]) -# Specify SoC where CVL limit is reset to max voltage +# Specify SoC where CVL limit is reset to max voltage, if value gets below SOC_LEVEL_TO_RESET_VOLTAGE_LIMIT = float( config["DEFAULT"]["SOC_LEVEL_TO_RESET_VOLTAGE_LIMIT"] ) @@ -305,6 +316,21 @@ def _get_list_from_config( LIPRO_CELL_COUNT = int(config["DEFAULT"]["LIPRO_CELL_COUNT"]) +# --------- Battery monitor specific settings --------- +# If you are using a SmartShunt or something else as a battery monitor, the battery voltage reported +# from the BMS and SmartShunt could differ. This causes, that the driver never goapplies the float voltage, +# since max voltage is never reached. +# Example: +# cell count: 16 +# MAX_CELL_VOLTAGE = 3.45 +# max voltage calculated = 16 * 3.45 = 55.20 +# CVL is set to 55.20 and the battery is now charged until the SmartShunt measures 55.20 V. The BMS +# now measures 55.05 V since there is a voltage drop of 0.15 V. Since the dbus-serialbattery measures +# 55.05 V the max voltage is never reached for the driver and max voltage is kept forever. +# Set VOLTAGE_DROP to 0.15 +VOLTAGE_DROP = float(config["DEFAULT"]["VOLTAGE_DROP"]) + + # --------- Functions --------- def constrain(val, min_val, max_val): if min_val > max_val: diff --git a/rc/post-hook.sh b/rc/post-hook.sh index 37cb7b2b..b4997054 100644 --- a/rc/post-hook.sh +++ b/rc/post-hook.sh @@ -23,3 +23,10 @@ fi # run reinstall local bash /data/etc/dbus-serialbattery/reinstall-local.sh + +# rename the venus-data.tar.gz else the data is overwritten, if the USB is not removed +for dir in /media/*; do + if [ -f "/media/$dir/venus-data.tar.gz" ]; then + mv "/media/$dir/venus-data.tar.gz" "/media/$dir/venus-data_installed.tar.gz" + fi +done