diff --git a/.github/workflows/release-beta.yml b/.github/workflows/release-beta.yml new file mode 100644 index 00000000..f5a4ed4a --- /dev/null +++ b/.github/workflows/release-beta.yml @@ -0,0 +1,38 @@ +name: Pre-release + +on: + push: + tags: + # only match pre release + # matches: + # v1.0.0alpha20230507 + # v1.0.0-beta20230507 + # v1.0.0-development-20230507 + - "v*.*.[0-9]+-?[a-zA-Z]*" + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: build release archive + run: | + find . -type f -name "*.py" -exec chmod +x {} \; + find . -type f -name "*.sh" -exec chmod +x {} \; + find . -type f -name "run" -exec chmod +x {} \; + tar -czvf venus-data.tar.gz \ + --mode='a+rwX' \ + --exclude __pycache__ \ + --exclude bms/battery_template.py \ + --exclude bms/revov.py \ + --exclude bms/test_max17853.py \ + etc/dbus-serialbattery/ \ + rc/ + + - name: Release + uses: softprops/action-gh-release@v1 + with: + files: venus-data.tar.gz + prerelease: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 672ecf61..0da358dd 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,7 +3,11 @@ name: Release on: push: tags: - - "v*.*.*" + # do not match pre release + # matches: + # v1.0.0 + # v1.0.123 + - "v[0-9]+.[0-9]+.[0-9]+" jobs: build: @@ -23,7 +27,8 @@ jobs: --exclude bms/battery_template.py \ --exclude bms/revov.py \ --exclude bms/test_max17853.py \ - etc/dbus-serialbattery/ + etc/dbus-serialbattery/ \ + rc/ - name: Release uses: softprops/action-gh-release@v1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b4b6a1f..2c08d348 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,16 +17,22 @@ * Added: Create empty `config.ini` for easier user usage by @mr-manuel * Added: Daly BMS - Read capacity https://github.com/Louisvdw/dbus-serialbattery/pull/594 by @transistorgit * 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: 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: 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 * Added: JKBMS - MOS temperature https://github.com/Louisvdw/dbus-serialbattery/pull/440 by @baphomett * Added: JKBMS - Uniqie identifier and show "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: Possibility to add `config.ini` to the root of a USB flash drive on install via the USB method 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 * Added: Reset values to None, if battery goes offline (not reachable for 10s). Fixes https://github.com/Louisvdw/dbus-serialbattery/issues/193 https://github.com/Louisvdw/dbus-serialbattery/issues/64 by @transistorgit * Added: Script to install directly from repository by @mr-manuel +* Added: Serial number field (found in the GUI -> SerialBattery -> Device), that show the serial number or a unique identifier for the BMS, if available by @mr-manuel * Added: Show charge mode (absorption, bulk, ...) in Parameters page by @mr-manuel * Added: Show charge/discharge limitation reason by @mr-manuel * Added: Show MOSFET temperature for JKBMS https://github.com/Louisvdw/dbus-serialbattery/pull/440 by @baphomett @@ -39,7 +45,8 @@ * 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: Default config file 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 * Changed name from `default_config.ini` to `config.default.ini` https://github.com/Louisvdw/dbus-serialbattery/pull/412#issuecomment-1434287942 by @mr-manuel * Changed TimeToSoc default value `TIME_TO_SOC_VALUE_TYPE` from `Both seconds and time string " [d h m s]"` to `1 Seconds` by @mr-manuel @@ -57,11 +64,13 @@ * Changed: Fixed black lint errors by @mr-manuel * Changed: Fixed cell balancing background for cells 17-24 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 * Changed: Logging to get relevant data by @mr-manuel +* Changed: Many code improvements https://github.com/Louisvdw/dbus-serialbattery/pull/393 by @ppuetsch * Changed: Moved BMS scripts to subfolder 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: 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: 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/docs/docs/faq/index.md b/docs/docs/faq/index.md index f9bd7846..27a230ac 100644 --- a/docs/docs/faq/index.md +++ b/docs/docs/faq/index.md @@ -22,6 +22,27 @@ See [this page](../general/install#how-to-change-the-default-limits). See the Victron Energy documentation how to get [root access](https://www.victronenergy.com/live/ccgx:root_access#root_access). + +## How to aggregate multiple batteries? + +You need an additional driver for that. Here are a few listed: + + +### [BatteryAggregator](https://github.com/pulquero/BatteryAggregator) by [pulquero](https://github.com/pulquero) + +Automatically merges connected batteries. Additional configuration for excluded batteries, total capacity and custom merging possible. + +Can be installed through the [SetupHelper](https://github.com/kwindrem/SetupHelper) of [kwindrem](https://github.com/kwindrem). + +### [dbus-aggregate-batteries](https://github.com/Dr-Gigavolt/dbus-aggregate-batteries) by [Dr-Gigavolt](https://github.com/Dr-Gigavolt) + +Automatically merges connected batteries. Takes consideration of SmartShunt, Multies, Quattros, SmartSolars, BlueSolars and MPPT for current calculation. Additional configuration possible. + +### [venus-os_dbus-mqtt-battery](https://github.com/mr-manuel/venus-os_dbus-mqtt-battery) by [mr-manuel](https://github.com/mr-manuel) + +Virtual battery that has to be fed over MQTT in case you want to merge your data how you'd like. Venus OS Large with Node-RED recommended. + + ## Why do I need a BMS for lithium batteries? Lithuim cells are great at storing energy, but they can be dangerous. An overcharged cell can cause a fire. A Battery Management System (BMS) first priority is to protect the cells in your battery from any potential hazards. diff --git a/docs/docs/general/install.md b/docs/docs/general/install.md index c4b8ad45..56c891bc 100644 --- a/docs/docs/general/install.md +++ b/docs/docs/general/install.md @@ -60,9 +60,13 @@ In [VRM](https://vrm.victronenergy.com/) look under the device list for your ins 1. Download and copy the [latest release](https://github.com/Louisvdw/dbus-serialbattery/releases) `venus-data.tar.gz` to the root of a USB flash drive that is in FAT32 format (a SD card is also an option for GX devices, but not for Raspberry Pi). -2. Plug the flash drive/SD into the Venus device and reboot. It will automatically extract and install to the correct locations and try the driver on any connected devices. +2. OPTIONAL (`>= v1.0.0`): Create a `config.ini` file in the root of your USB flash drive with your custom settings. Put `[DEFAULT]` in the first line of the file and add all the values you want to change below. You only have to insert the values you want to change, all other values are fetched from the `config.default.ini`. In the [`config.default.ini`](https://github.com/Louisvdw/dbus-serialbattery/blob/jkbms_ble/etc/dbus-serialbattery/config.default.ini) you find all possible settings that you can copy over and change. -3. Reboot the GX (in the Remote Console go to `Settings` → `General` → `Reboot?`). + > If you put a `config.ini` in the root of the USB flash drive, then an existing `config.ini` will be overwritten. + +3. Plug the flash drive/SD into the Venus device and reboot. It will automatically extract and install to the correct locations and try the driver on any connected devices. + +4. Reboot the GX (in the Remote Console go to `Settings` → `General` → `Reboot?`). ### Install over SSH @@ -74,9 +78,9 @@ In [VRM](https://vrm.victronenergy.com/) look under the device list for your ins 2. Run these commands to install or update to the latest release version. ```bash - wget -O /tmp/install-release.sh https://raw.githubusercontent.com/Louisvdw/dbus-serialbattery/master/etc/dbus-serialbattery/install-release.sh + wget -O /tmp/install.sh https://raw.githubusercontent.com/Louisvdw/dbus-serialbattery/master/etc/dbus-serialbattery/install.sh - bash /tmp/install-release.sh + bash /tmp/install.sh reboot ``` @@ -110,10 +114,10 @@ In [VRM](https://vrm.victronenergy.com/) look under the device list for your ins > This version is installed directly from the repository and can contain errors. Not recommended for production environments unless you know what you do. ```bash -wget -O /tmp/install-nightly.sh https://raw.githubusercontent.com/Louisvdw/dbus-serialbattery/jkbms_ble/etc/dbus-serialbattery/install-nightly.sh && bash /tmp/install-nightly.sh +wget -O /tmp/install.sh https://raw.githubusercontent.com/Louisvdw/dbus-serialbattery/jkbms_ble/etc/dbus-serialbattery/install.sh && bash /tmp/install.sh ``` -Select `2` for `jkbms_ble`. +Select `2` for `nightly build` and then select the branch you want to install from. ### BMS specific settings @@ -218,13 +222,15 @@ bash /data/etc/dbus-serialbattery/reinstall-local.sh ## Uninstall/remove the driver -To uninstall/remove the driver run the uninstall script. The script is included from driver version `> v0.14.3`. +To uninstall the driver run the uninstall script. The script is included from driver version `>= v1.0.0`. ```bash bash /data/etc/dbus-serialbattery/uninstall.sh ``` -To uninstall/remove previous driver versions `<= v0.14.3` run this commands. +To uninstall previous driver versions `<= v0.14.3` run this commands: + +**Uninstall** ```bash # handle read only mounts @@ -239,8 +245,19 @@ rm -rf /opt/victronenergy/dbus-serialbattery # kill driver, if running pkill -f "python .*/dbus-serialbattery.py" -# remove install-script from rc.local -sed -i "/sh \/data\/etc\/dbus-serialbattery\/reinstall-local.sh/d" /data/rc.local +# remove install script from rc.local +sed -i "/sh \/data\/etc\/dbus-serialbattery\/reinstalllocal.sh/d" /data/rc.local + +# restore GUI changes +bash /data/etc/dbus-serialbattery/restore-gui.sh ``` > If after the uninstall for some reason several items in the GUI were red, DO NOT reboot your GX device. See [Uninstalling driver bricked my cerbo #576](https://github.com/Louisvdw/dbus-serialbattery/issues/576) + +**Remove** + +If you want to remove also the install files of the driver run this after you run the uninstall script/commands: + +```bash +rm -rf /data/etc/dbus-serialbattery +``` diff --git a/docs/yarn.lock b/docs/yarn.lock index 00c2befe..0708302a 100644 --- a/docs/yarn.lock +++ b/docs/yarn.lock @@ -2064,9 +2064,9 @@ integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== "@types/node@*": - version "18.16.3" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.16.3.tgz#6bda7819aae6ea0b386ebc5b24bdf602f1b42b01" - integrity sha512-OPs5WnnT1xkCBiuQrZA4+YAV4HEJejmHneyraIaxsbev5yCEr6KMwINNFP9wQeFIw8FWcoTqF3vQsa5CDaI+8Q== + version "20.1.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.1.0.tgz#258805edc37c327cf706e64c6957f241ca4c4c20" + integrity sha512-O+z53uwx64xY7D6roOi4+jApDGFg0qn6WHcxe5QeqjMaTezBO/mxdfFXIVAVVyNWKx84OmPB3L8kbVYOTeN34A== "@types/node@^17.0.5": version "17.0.45" @@ -2125,9 +2125,9 @@ "@types/react" "*" "@types/react@*": - version "18.2.0" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.0.tgz#15cda145354accfc09a18d2f2305f9fc099ada21" - integrity sha512-0FLj93y5USLHdnhIhABk83rm8XEGA7kH3cr+YUlvxoUGp1xNt/DINUMvqPxLyOQMzLmZe8i4RTHbvb8MC7NmrA== + version "18.2.5" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.5.tgz#f9403e1113b12b53f7edcdd9a900c10dd4b49a59" + integrity sha512-RuoMedzJ5AOh23Dvws13LU9jpZHIc/k90AgmK7CecAYeWmSr3553L4u5rk4sWAPBuQosfT7HmTfG4Rg5o4nGEA== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" @@ -2411,9 +2411,9 @@ ajv@^8.0.0, ajv@^8.9.0: uri-js "^4.2.2" algoliasearch-helper@^3.10.0: - version "3.12.0" - resolved "https://registry.yarnpkg.com/algoliasearch-helper/-/algoliasearch-helper-3.12.0.tgz#0fe39d49b0290e4aa5e1fe733bd24d857d258e94" - integrity sha512-/j1U3PEwdan0n6P/QqSnSpNSLC5+cEMvyljd5CnmNmUjDlGrys+vFEOwjVEnqELIiAGMHEA/Nl3CiKVFBUYqyQ== + version "3.13.0" + resolved "https://registry.yarnpkg.com/algoliasearch-helper/-/algoliasearch-helper-3.13.0.tgz#1ccca7056fd27c2b0b5c92dd5c0abf4314bec3b8" + integrity sha512-kV3c1jMQCvkARtGsSDvAwuht4PAMSsQILqPiH4WFiARoa3jXJ/r1TQoBWAjWyWF48rsNYCv7kzxgB4LTxrvvuw== dependencies: "@algolia/events" "^4.0.1" @@ -2789,9 +2789,9 @@ caniuse-api@^3.0.0: lodash.uniq "^4.5.0" caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001449, caniuse-lite@^1.0.30001464: - version "1.0.30001482" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001482.tgz#8b3fad73dc35b2674a5c96df2d4f9f1c561435de" - integrity sha512-F1ZInsg53cegyjroxLNW9DmrEQ1SuGRTO1QlpA0o2/6OpQ0gFeDRoq1yFmnr8Sakn9qwwt9DmbxHB6w167OSuQ== + version "1.0.30001485" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001485.tgz#026bb7319f1e483391872dc303a973d4f513f619" + integrity sha512-8aUpZ7sjhlOyiNsg+pgcrTTPUXKh+rg544QYHSvQErljVEKJzvkYkCR/hUFeeVoEfTToUtY9cUKNRC7+c45YkA== ccount@^1.0.0: version "1.1.0" @@ -3556,9 +3556,9 @@ ee-first@1.1.1: integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== electron-to-chromium@^1.4.284: - version "1.4.380" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.380.tgz#195dc59d930c6b74efbee6f0e6a267ce4af5ed91" - integrity sha512-XKGdI4pWM78eLH2cbXJHiBnWUwFSzZM7XujsB6stDiGu9AeSqziedP6amNLpJzE3i0rLTcfAwdCTs5ecP5yeSg== + version "1.4.385" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.385.tgz#1afd8d6280d510145148777b899ff481c65531ff" + integrity sha512-L9zlje9bIw0h+CwPQumiuVlfMcV4boxRjFIWDcLfFqTZNbkwOExBzfmswytHawObQX4OUhtNv8gIiB21kOurIg== emoji-regex@^8.0.0: version "8.0.0" @@ -6801,9 +6801,9 @@ statuses@2.0.1: integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== std-env@^3.0.1: - version "3.3.2" - resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.3.2.tgz#af27343b001616015534292178327b202b9ee955" - integrity sha512-uUZI65yrV2Qva5gqE0+A7uVAvO40iPo6jGhs7s8keRfHCmtg+uB2X6EiLGCI9IgL1J17xGhvoOqSz79lzICPTA== + version "3.3.3" + resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.3.3.tgz#a54f06eb245fdcfef53d56f3c0251f1d5c3d01fe" + integrity sha512-Rz6yejtVyWnVjC1RFvNmYL10kgjC49EOghxWn0RFqlCHGFpQx+Xe7yW3I4ceK1SGrWIGMjD5Kbue8W/udkbMJg== string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2: version "4.2.3" @@ -7451,9 +7451,9 @@ webpack-sources@^3.2.2, webpack-sources@^3.2.3: integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== webpack@^5.73.0: - version "5.81.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.81.0.tgz#27a2e8466c8b4820d800a8d90f06ef98294f9956" - integrity sha512-AAjaJ9S4hYCVODKLQTgG5p5e11hiMawBwV2v8MYLE0C/6UAGLuAF4n1qa9GOwdxnicaP+5k6M5HrLmD4+gIB8Q== + version "5.82.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.82.0.tgz#3c0d074dec79401db026b4ba0fb23d6333f88e7d" + integrity sha512-iGNA2fHhnDcV1bONdUu554eZx+XeldsaeQ8T67H6KKHl2nUSwX8Zm7cmzOA46ox/X1ARxf7Bjv8wQ/HsB5fxBg== dependencies: "@types/eslint-scope" "^3.7.3" "@types/estree" "^1.0.0" diff --git a/etc/dbus-serialbattery/battery.py b/etc/dbus-serialbattery/battery.py index c45eecce..108cf211 100644 --- a/etc/dbus-serialbattery/battery.py +++ b/etc/dbus-serialbattery/battery.py @@ -67,12 +67,17 @@ def __init__(self, port, baud, address): # max battery charge/discharge current self.max_battery_charge_current = None self.max_battery_discharge_current = None + self.has_settings = 0 self.init_values() # used to identify a BMS when multiple BMS are connected - planned for future use self.unique_identifier = None + # fetched from the BMS from a field where the user can input a custom string + # only if available + self.custom_field = None + def init_values(self): self.voltage = None self.current = None @@ -919,3 +924,7 @@ def log_settings(self) -> None: logger.info(f"Serial Number/Unique Identifier: {self.unique_identifier}") return + + def reset_soc_callback(self, path, value): + # callback for handling reset soc request + return diff --git a/etc/dbus-serialbattery/bms/daly.py b/etc/dbus-serialbattery/bms/daly.py index 9978e648..b358a886 100644 --- a/etc/dbus-serialbattery/bms/daly.py +++ b/etc/dbus-serialbattery/bms/daly.py @@ -2,8 +2,10 @@ from battery import Battery, Cell from utils import open_serial_port, logger import utils -from struct import unpack_from -from time import sleep +from struct import unpack_from, pack_into +from time import sleep, time +from datetime import datetime +from re import sub class Daly(Battery): @@ -17,23 +19,27 @@ def __init__(self, port, baud, address): self.cell_min_no = None self.cell_max_no = None self.poll_interval = 1000 - self.poll_step = 0 self.type = self.BATTERYTYPE + self.has_settings = 1 + self.reset_soc = 0 + self.soc_to_set = None + self.runtime = 0 # TROUBLESHOOTING for no reply errors # 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" + command_set_soc = b"\x21" + command_rated_params = b"\x50" + command_batt_details = b"\x53" + command_batt_code = b"\x57" command_soc = b"\x90" - command_minmax_cell_volts = b"\x91" - command_minmax_temp = b"\x92" - command_fet = b"\x93" + command_minmax_cell_volts = b"\x91" # no reply + command_minmax_temp = b"\x92" # no reply + command_fet = b"\x93" # no reply command_status = b"\x94" command_cell_volts = b"\x95" command_temp = b"\x96" - command_cell_balance = b"\x97" - command_alarm = b"\x98" - command_rated_params = b"\x50" - command_batt_details = b"\x53" + command_cell_balance = b"\x97" # no reply + command_alarm = b"\x98" # no reply BATTERYTYPE = "Daly" LENGTH_CHECK = 1 @@ -48,9 +54,12 @@ def test_connection(self): result = False try: with open_serial_port(self.port, self.baud_rate) as ser: - self.read_production_date(ser) 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)=}") @@ -62,42 +71,110 @@ def get_settings(self): self.capacity = utils.BATTERY_CAPACITY with open_serial_port(self.port, self.baud_rate) as ser: self.read_capacity(ser) + self.read_production_date(ser) - self.unique_identifier = str(self.production) + "_" + str(self.capacity) self.max_battery_charge_current = utils.MAX_BATTERY_CHARGE_CURRENT self.max_battery_discharge_current = utils.MAX_BATTERY_DISCHARGE_CURRENT return True def refresh_data(self): result = False - # Open serial port to be used for all data reads instead of openning multiple times - ser = open_serial_port(self.port, self.baud_rate) - if ser is not None: - result = self.read_soc_data(ser) - result = result and self.read_fed_data(ser) - result = result and self.read_cell_voltage_range_data(ser) - - if self.poll_step == 0: + + # Open serial port to be used for all data reads instead of opening multiple times + try: + with open_serial_port(self.port, self.baud_rate) as ser: + result = self.read_soc_data(ser) + if self.runtime > 0.200: # TROUBLESHOOTING for no reply errors + logger.info( + " |- refresh_data: read_soc_data - result: " + + str(result) + + " - runtime: " + + str(self.runtime) + + "s" + ) + + result = result and self.read_fed_data(ser) + if self.runtime > 0.200: # TROUBLESHOOTING for no reply errors + logger.info( + " |- refresh_data: read_fed_data - result: " + + str(result) + + " - runtime: " + + str(self.runtime) + + "s" + ) + + result = result and self.read_cell_voltage_range_data(ser) + if self.runtime > 0.200: # TROUBLESHOOTING for no reply errors + logger.info( + " |- refresh_data: read_cell_voltage_range_data - result: " + + str(result) + + " - runtime: " + + str(self.runtime) + + "s" + ) + + self.write_soc_and_datetime(ser) + if self.runtime > 0.200: # TROUBLESHOOTING for no reply errors + logger.info( + " |- refresh_data: write_soc_and_datetime - result: " + + str(result) + + " - runtime: " + + str(self.runtime) + + "s" + ) + result = result and self.read_alarm_data(ser) + if self.runtime > 0.200: # TROUBLESHOOTING for no reply errors + logger.info( + " |- refresh_data: read_alarm_data - result: " + + str(result) + + " - runtime: " + + str(self.runtime) + + "s" + ) + result = result and self.read_temperature_range_data(ser) - elif self.poll_step == 1: + if self.runtime > 0.200: # TROUBLESHOOTING for no reply errors + logger.info( + " |- refresh_data: read_temperature_range_data - result: " + + str(result) + + " - runtime: " + + str(self.runtime) + + "s" + ) + result = result and self.read_cells_volts(ser) - result = result and self.read_balance_state(ser) - # else: # A placeholder to remind this is the last step. Add any additional steps before here - # This is last step so reset poll_step - self.poll_step = -1 + if self.runtime > 0.200: # TROUBLESHOOTING for no reply errors + logger.info( + " |- refresh_data: read_cells_volts - result: " + + str(result) + + " - runtime: " + + str(self.runtime) + + "s" + ) - self.poll_step += 1 + result = result and self.read_balance_state(ser) + if self.runtime > 0.200: # TROUBLESHOOTING for no reply errors + logger.info( + " |- refresh_data: read_balance_state - result: " + + str(result) + + " - runtime: " + + str(self.runtime) + + "s" + ) - ser.close() + except OSError: + logger.warning("Couldn't open serial port") + if not result: # TROUBLESHOOTING for no reply errors + logger.info("refresh_data: result: " + str(result)) return result def read_status_data(self, ser): status_data = self.read_serial_data_daly(ser, self.command_status) # check if connection success if status_data is False: - logger.debug("read_status_data") + logger.warning("No data received in read_status_data()") return False ( @@ -112,7 +189,12 @@ def read_status_data(self, ser): self.max_battery_voltage = utils.MAX_CELL_VOLTAGE * self.cell_count self.min_battery_voltage = utils.MIN_CELL_VOLTAGE * self.cell_count - self.hardware_version = "DalyBMS " + str(self.cell_count) + " cells" + self.hardware_version = ( + "DalyBMS " + + str(self.cell_count) + + " cells" + + (" (" + self.production + ")" if self.production else "") + ) logger.info(self.hardware_version) return True @@ -147,7 +229,7 @@ def read_alarm_data(self, ser): alarm_data = self.read_serial_data_daly(ser, self.command_alarm) # check if connection success if alarm_data is False: - logger.warning("read_alarm_data") + logger.warning("No data received in read_alarm_data()") return False ( @@ -255,9 +337,12 @@ def read_alarm_data(self, ser): def read_cells_volts(self, ser): if self.cell_count is not None: - buffer = bytearray(self.cellvolt_buffer) + buffer = bytearray(self.command_base) buffer[1] = self.command_address[0] # Always serial 40 or 80 buffer[2] = self.command_cell_volts[0] + buffer[12] = sum(buffer[:12]) & 0xFF + + # logger.info(f"{bytes(buffer).hex()}") if (int(self.cell_count) % 3) == 0: maxFrame = int(self.cell_count / 3) @@ -271,7 +356,7 @@ def read_cells_volts(self, ser): ser, buffer, self.LENGTH_POS, 0, lenFixed ) if cells_volts_data is False: - logger.warning("read_cells_volts") + logger.warning("No data received in read_cells_volts()") return False frameCell = [0, 0, 0] @@ -323,7 +408,7 @@ def read_cell_voltage_range_data(self, ser): minmax_data = self.read_serial_data_daly(ser, self.command_minmax_cell_volts) # check if connection success if minmax_data is False: - logger.warning("read_cell_voltage_range_data") + logger.warning("No data received in read_cell_voltage_range_data()") return False ( @@ -344,7 +429,7 @@ def read_balance_state(self, ser): balance_data = self.read_serial_data_daly(ser, self.command_cell_balance) # check if connection success if balance_data is False: - logger.debug("read_balance_state") + logger.debug("No data received in read_balance_state()") return False bitdata = unpack_from(">Q", balance_data)[0] @@ -354,11 +439,13 @@ def read_balance_state(self, ser): self.cells[i].balance = True if bitdata & mask else False mask >>= 1 + return True + def read_temperature_range_data(self, ser): minmax_data = self.read_serial_data_daly(ser, self.command_minmax_temp) # check if connection success if minmax_data is False: - logger.debug("read_temperature_range_data") + logger.debug("No data received in read_temperature_range_data()") return False max_temp, max_no, min_temp, min_no = unpack_from(">bbbb", minmax_data) @@ -370,7 +457,7 @@ def read_fed_data(self, ser): fed_data = self.read_serial_data_daly(ser, self.command_fet) # check if connection success if fed_data is False: - logger.debug("read_fed_data") + logger.debug("No data received in read_fed_data()") return False ( @@ -383,26 +470,80 @@ def read_fed_data(self, ser): self.capacity_remain = capacity_remain / 1000 return True + # new def read_capacity(self, ser): capa_data = self.read_serial_data_daly(ser, self.command_rated_params) # check if connection success if capa_data is False: - logger.warning("read_capacity") + logger.warning("No data received in read_capacity()") return False (capacity, cell_volt) = unpack_from(">LL", capa_data) - self.capacity = capacity / 1000 - return True + if capacity and capacity > 0: + self.capacity = capacity / 1000 + return True + else: + return False + # new def read_production_date(self, ser): production = self.read_serial_data_daly(ser, self.command_batt_details) # check if connection success if production is False: - logger.warning("read_production_date") + logger.warning("No data received in read_production_date()") return False (_, _, year, month, day) = unpack_from(">BBBBB", production) - self.production = f"({year + 2000}{month:02d}{day:02d})" + self.production = f"{year + 2000}{month:02d}{day:02d}" + return True + + # new + def read_battery_code(self, ser): + lenFixed = ( + 5 * 13 + ) # batt code field is 35 bytes and we transfer 7 bytes in each telegram + data = self.read_serialport_data( + ser, + self.generate_command(self.command_batt_code), + self.LENGTH_POS, + 0, + lenFixed, + ) + + if data is False: + logger.warning("No data received in read_battery_code()") + return False + + bufIdx = 0 + battery_code = "" + # logger.warning("data " + bytes(cells_volts_data).hex()) + while ( + bufIdx <= len(data) - 13 + ): # we at least need 13 bytes to extract the identifiers + 8 bytes payload + checksum + b1, b2, b3, b4 = unpack_from(">BBBB", data, bufIdx) + if b1 == 0xA5 and b2 == 0x01 and b3 == 0x57 and b4 == 0x08: + _, part, chk = unpack_from(">B7sB", data, bufIdx + 4) + if sum(data[bufIdx : bufIdx + 12]) & 0xFF != chk: + logger.warning( + "bad battery code checksum" + ) # use string anyhow, just warn + battery_code += part.decode("utf-8") + bufIdx += 13 # BBBBB7sB -> 13 byte + else: + bufIdx += 1 # step through buffer to find valid start + logger.warning("bad battery code header") + + if battery_code != "": + self.custom_field = sub( + " +", + " ", + (battery_code.strip()), + ) + self.unique_identifier = self.custom_field.replace(" ", "_") + else: + self.unique_identifier = ( + str(self.production) + "_" + str(int(self.capacity)) + ) return True def generate_command(self, command): @@ -465,6 +606,11 @@ def read_serialport_data( length_size=None, ): try: + # wait shortly, else the Daly is not ready and throws a lot of no reply errors + # if you see a lot of errors, try to increase in steps of 0.005 + sleep(0.020) + + time_start = time() ser.flushOutput() ser.flushInput() ser.write(command) @@ -476,14 +622,14 @@ def read_serialport_data( 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: + time_run = time() - time_start + if time_run > 0.500: + self.runtime = time_run logger.error(">>> ERROR: No reply - returning") return False @@ -500,9 +646,6 @@ def read_serialport_data( 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 = ( @@ -513,10 +656,10 @@ def read_serialport_data( 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: + time_run = time() - time_start + if time_run > 0.500: + self.runtime = time_run logger.error( ">>> ERROR: No reply - returning [len:" + str(len(data)) @@ -526,8 +669,67 @@ def read_serialport_data( ) return False + self.runtime = time_run return data except Exception as e: logger.error(e) return False + + def reset_soc_callback(self, path, value): + if value is None: + return False + + if value < 0 or value > 100: + return False + + self.reset_soc = value + self.soc_to_set = value + return True + + def write_soc_and_datetime(self, ser): + if self.soc_to_set is None: + return False + + cmd = bytearray(13) + now = datetime.now() + + pack_into( + ">BBBBBBBBBBH", + cmd, + 0, + 0xA5, + self.command_address[0], + self.command_set_soc[0], + 8, + now.year - 2000, + now.month, + now.day, + now.hour, + now.minute, + now.second, + int(self.soc_to_set * 10), + ) + cmd[12] = sum(cmd[:12]) & 0xFF + + 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 = ser.read(toread) + if reply[4] != 1: + logger.error("write soc failed") + return True diff --git a/etc/dbus-serialbattery/bms/jkbms.py b/etc/dbus-serialbattery/bms/jkbms.py index 5e09f8e2..0aca8876 100644 --- a/etc/dbus-serialbattery/bms/jkbms.py +++ b/etc/dbus-serialbattery/bms/jkbms.py @@ -39,7 +39,12 @@ def get_settings(self): for _ in range(self.cell_count): self.cells.append(Cell(False)) - self.hardware_version = "JKBMS " + str(self.cell_count) + " cells" + self.hardware_version = ( + "JKBMS " + + str(self.cell_count) + + " cells" + + (" (" + self.production + ")" if self.production else "") + ) return True def refresh_data(self): @@ -151,9 +156,9 @@ def read_status_data(self): unpack_from(">B", self.get_data(status_data, b"\x9D", offset, 1))[0] ) - # User Private Data filed in APP + # "User Private Data" field in APP offset = cellbyte_count + 155 - self.production = sub( + tmp = sub( " +", " ", ( @@ -163,7 +168,14 @@ def read_status_data(self): .strip() ), ) - self.production = self.production if self.production != "Input Us" else None + self.custom_field = tmp if tmp != "Input Us" else None + + # production date + offset = cellbyte_count + 164 + tmp = unpack_from(">4s", self.get_data(status_data, b"\xB5", offset, 4))[ + 0 + ].decode() + self.production = "20" + tmp + "01" if tmp and tmp != "" else None offset = cellbyte_count + 174 self.version = unpack_from( diff --git a/etc/dbus-serialbattery/dbushelper.py b/etc/dbus-serialbattery/dbushelper.py index cb3bc2d0..555cb1ba 100644 --- a/etc/dbus-serialbattery/dbushelper.py +++ b/etc/dbus-serialbattery/dbushelper.py @@ -133,7 +133,7 @@ def setup_vedbus(self): "/Serial", self.battery.unique_identifier, writeable=True ) self._dbusservice.add_path( - "/DeviceName", self.battery.production, writeable=True + "/DeviceName", self.battery.custom_field, writeable=True ) # Create static battery info @@ -325,6 +325,15 @@ def setup_vedbus(self): if utils.PUBLISH_CONFIG_VALUES == 1: publish_config_variables(self._dbusservice) + if self.battery.has_settings: + self._dbusservice.add_path("/Settings/HasSettings", 1, writeable=False) + self._dbusservice.add_path( + "/Settings/ResetSoc", + 0, + writeable=True, + onchangecallback=self.battery.reset_soc_callback, + ) + return True def publish_battery(self, loop): @@ -587,3 +596,6 @@ def publish_dbus(self): if self.battery.soc is not None: logger.debug("logged to dbus [%s]" % str(round(self.battery.soc, 2))) self.battery.log_cell_data() + + if self.battery.has_settings: + self._dbusservice["/Settings/ResetSoc"] = self.battery.reset_soc diff --git a/etc/dbus-serialbattery/install-local.sh b/etc/dbus-serialbattery/install-local.sh deleted file mode 100755 index 61ffccf1..00000000 --- a/etc/dbus-serialbattery/install-local.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/sh - -# remove comment for easier troubleshooting -#set -x - -# backup config.ini -if [ -f "/data/etc/dbus-serialbattery/config.ini" ]; then - mv /data/etc/dbus-serialbattery/config.ini /data/etc/config.ini -fi - -# remove old driver -rm -rf /data/etc/dbus-serialbattery - -# extract driver -tar -zxf ./venus-data.tar.gz -C /data - -# restore config.ini -if [ -f "/data/etc/config.ini" ]; then - mv /data/etc/config.ini /data/etc/dbus-serialbattery/config.ini -fi - -# install driver -sh /data/etc/dbus-serialbattery/reinstall-local.sh diff --git a/etc/dbus-serialbattery/install-nightly.sh b/etc/dbus-serialbattery/install-nightly.sh deleted file mode 100755 index 061699b8..00000000 --- a/etc/dbus-serialbattery/install-nightly.sh +++ /dev/null @@ -1,65 +0,0 @@ -#!/bin/bash - -# remove comment for easier troubleshooting -#set -x - -PS3="Select the branch from wich you want to install the current code (possible bugs included): " - -select branch in master jkbms_ble quit -do - case $branch in - master) - echo "Selected branch: $branch" - #echo "Selected number: $REPLY" - break - ;; - jkbms_ble) - echo "Selected branch: $branch" - #echo "Selected number: $REPLY" - break - ;; - quit) - exit 0 - ;; - *) - echo "Invalid option $REPLY" - ;; - esac -done - - -cd /tmp - -# clean already extracted folder -rm -rf /tmp/dbus-serialbattery-$branch - -# download driver -wget -O $branch.zip https://github.com/Louisvdw/dbus-serialbattery/archive/refs/heads/$branch.zip - -# extract archive -unzip -q $branch.zip - -# backup config.ini -if [ -f "/data/etc/dbus-serialbattery/config.ini" ]; then - mv /data/etc/dbus-serialbattery/config.ini /data/etc/config.ini -fi - -# remove old driver -rm -rf /data/etc/dbus-serialbattery - -# copy driver -cp -rf /tmp/dbus-serialbattery-$branch/etc/dbus-serialbattery/ /data/etc - -# restore config.ini -if [ -f "/data/etc/config.ini" ]; then - mv /data/etc/config.ini /data/etc/dbus-serialbattery/config.ini -fi - -# set permissions -chmod +x /data/etc/dbus-serialbattery/*.sh -chmod +x /data/etc/dbus-serialbattery/*.py -chmod +x /data/etc/dbus-serialbattery/service/run -chmod +x /data/etc/dbus-serialbattery/service/log/run - -# run install script -bash /data/etc/dbus-serialbattery/reinstall-local.sh diff --git a/etc/dbus-serialbattery/install-qml.sh b/etc/dbus-serialbattery/install-qml.sh index 4ce93910..6c155b51 100755 --- a/etc/dbus-serialbattery/install-qml.sh +++ b/etc/dbus-serialbattery/install-qml.sh @@ -40,6 +40,10 @@ fi if [ ! -f /opt/victronenergy/gui/qml/PageBatteryParameters.qml.backup ]; then cp /opt/victronenergy/gui/qml/PageBatteryParameters.qml /opt/victronenergy/gui/qml/PageBatteryParameters.qml.backup fi +# backup old PageBatterySettings.qml once. New firmware upgrade will remove the backup +if [ ! -f /opt/victronenergy/gui/qml/PageBatterySettings.qml.backup ]; then + cp /opt/victronenergy/gui/qml/PageBatterySettings.qml /opt/victronenergy/gui/qml/PageBatterySettings.qml.backup +fi # backup old PageLynxIonIo.qml once. New firmware upgrade will remove the backup if [ ! -f /opt/victronenergy/gui/qml/PageLynxIonIo.qml.backup ]; then cp /opt/victronenergy/gui/qml/PageLynxIonIo.qml /opt/victronenergy/gui/qml/PageLynxIonIo.qml.backup @@ -50,6 +54,8 @@ cp /data/etc/dbus-serialbattery/qml/PageBattery.qml /opt/victronenergy/gui/qml/ cp /data/etc/dbus-serialbattery/qml/PageBatteryCellVoltages.qml /opt/victronenergy/gui/qml/ # copy new PageBatteryParameters.qml cp /data/etc/dbus-serialbattery/qml/PageBatteryParameters.qml /opt/victronenergy/gui/qml/ +# copy new PageBatterySettings.qml +cp /data/etc/dbus-serialbattery/qml/PageBatterySettings.qml /opt/victronenergy/gui/qml/ # copy new PageBatterySetup cp /data/etc/dbus-serialbattery/qml/PageBatterySetup.qml /opt/victronenergy/gui/qml/ # copy new PageLynxIonIo.qml @@ -71,6 +77,7 @@ if (( $venusVersionNumber < $versionNumber )); then fileList="$qmlDir/PageBattery.qml" fileList+=" $qmlDir/PageBatteryCellVoltages.qml" fileList+=" $qmlDir/PageBatteryParameters.qml" + fileList+=" $qmlDir/PageBatterySettings.qml" fileList+=" $qmlDir/PageBatterySetup.qml" fileList+=" $qmlDir/PageLynxIonIo.qml" for file in $fileList ; do diff --git a/etc/dbus-serialbattery/install-release.sh b/etc/dbus-serialbattery/install-release.sh deleted file mode 100755 index 801d0e19..00000000 --- a/etc/dbus-serialbattery/install-release.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash - -# remove comment for easier troubleshooting -#set -x - -# download latest release -curl -s https://api.github.com/repos/Louisvdw/dbus-serialbattery/releases/latest | grep "browser_download_url.*gz" | cut -d : -f 2,3 | tr -d \" | wget -O venus-data.tar.gz -qi - -# extract the latest install-local script to run -tar -zxf ./venus-data.tar.gz -C /data etc/dbus-serialbattery/install-local.sh - -# extract and install driver -sh /data/etc/dbus-serialbattery/install-local.sh diff --git a/etc/dbus-serialbattery/install.sh b/etc/dbus-serialbattery/install.sh new file mode 100755 index 00000000..57e09e6a --- /dev/null +++ b/etc/dbus-serialbattery/install.sh @@ -0,0 +1,168 @@ +#!/bin/bash + +# remove comment for easier troubleshooting +#set -x + +echo "" +PS3="Select which version you want to install and enter the corresponding number [1]: " + +select version in "latest release (recommended)" "nightly build" "local tar file" "specific version" "quit" +do + case $version in + "latest release (recommended)") + echo "Selected: $version" + #echo "Selected number: $REPLY" + break + ;; + "nightly build") + echo "Selected: $version" + #echo "Selected number: $REPLY" + break + ;; + "local tar file") + echo "Selected: $version" + #echo "Selected number: $REPLY" + break + ;; + "specific version") + echo "Selected: $version" + #echo "Selected number: $REPLY" + break + ;; + "quit") + exit 0 + ;; + *) + echo "Invalid option: $REPLY" + echo "Please enter a number" + ;; + esac +done +echo "" + +## latest release +if [ "$version" = "latest release (recommended)" ]; then + # download latest release + curl -s https://api.github.com/repos/Louisvdw/dbus-serialbattery/releases/latest | grep "browser_download_url.*gz" | cut -d : -f 2,3 | tr -d \" | wget -O /tmp/venus-data.tar.gz -qi - +fi + +## local tar file +if [ "$version" = "local tar file" ]; then + echo "Make sure the file is available at \"/var/volatile/tmp/venus-data.tar.gz\"" +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 + if [ $? -ne 0 ]; then + echo "Error during downloading the TAR file. Please check, if the URL is correct." + exit + fi +fi + + + +# backup config.ini +if [ -f "/data/etc/dbus-serialbattery/config.ini" ]; then + mv /data/etc/dbus-serialbattery/config.ini /data/etc/dbus-serialbattery_config.ini.backup +fi + + + +## extract the tar file +if [ "$version" = "latest release (recommended)" ] || [ "$version" = "local tar file" ] || [ "$version" = "specific version" ]; then + + # extract driver + if [ -f "/tmp/venus-data.tar.gz" ]; then + # remove old driver + rm -rf /data/etc/dbus-serialbattery + tar -zxf /tmp/venus-data.tar.gz -C /data + else + echo "There is no file in \"venus-data.tar.gz\"" + # restore config.ini + if [ -f "/data/etc/dbus-serialbattery_config.ini.backup" ]; then + mv /data/etc/dbus-serialbattery_config.ini.backup /data/etc/dbus-serialbattery/config.ini + fi + exit + fi + +fi + + +## nightly build +if [ "$version" = "nightly build" ]; then + + PS3="Select the branch from wich you want to install the current code (possible bugs included): " + + select branch in master jkbms_ble quit + do + case $branch in + master) + echo "Selected branch: $branch" + #echo "Selected number: $REPLY" + break + ;; + jkbms_ble) + echo "Selected branch: $branch" + #echo "Selected number: $REPLY" + break + ;; + quit) + exit 0 + ;; + *) + echo "Invalid option $REPLY" + ;; + esac + done + + + cd /tmp + + # clean already extracted folder + rm -rf /tmp/dbus-serialbattery-$branch + + # download driver + wget -O $branch.zip https://github.com/Louisvdw/dbus-serialbattery/archive/refs/heads/$branch.zip + if [ $? -ne 0 ]; then + echo "Error during downloading the TAR file. Please try again." + # restore config.ini + if [ -f "/data/etc/dbus-serialbattery_config.ini.backup" ]; then + mv /data/etc/dbus-serialbattery_config.ini.backup /data/etc/dbus-serialbattery/config.ini + fi + exit + fi + + # extract archive + unzip -q $branch.zip + + # remove old driver + rm -rf /data/etc/dbus-serialbattery + + # copy driver + cp -rf /tmp/dbus-serialbattery-$branch/etc/dbus-serialbattery/ /data/etc + + # set permissions + chmod +x /data/etc/dbus-serialbattery/*.sh + chmod +x /data/etc/dbus-serialbattery/*.py + chmod +x /data/etc/dbus-serialbattery/service/run + chmod +x /data/etc/dbus-serialbattery/service/log/run + +fi + + +# restore config.ini +if [ -f "/data/etc/dbus-serialbattery_config.ini.backup" ]; then + mv /data/etc/dbus-serialbattery_config.ini.backup /data/etc/dbus-serialbattery/config.ini +fi + + +# run install script >= v1.0.0 +if [ -f "/data/etc/dbus-serialbattery/reinstall-local.sh" ]; then + bash /data/etc/dbus-serialbattery/reinstall-local.sh +# run install script < v1.0.0 +elif [ -f "/data/etc/dbus-serialbattery/reinstalllocal.sh" ]; then + bash /data/etc/dbus-serialbattery/reinstalllocal.sh +fi diff --git a/etc/dbus-serialbattery/qml/PageBatterySettings.qml b/etc/dbus-serialbattery/qml/PageBatterySettings.qml new file mode 100644 index 00000000..60188b99 --- /dev/null +++ b/etc/dbus-serialbattery/qml/PageBatterySettings.qml @@ -0,0 +1,73 @@ +import QtQuick 1.1 +import com.victron.velib 1.0 +import "utils.js" as Utils + +MbPage { + id: root + property string bindPrefix + + model: VisibleItemModel { + MbSubMenu { + id: battery + description: qsTr("Battery bank") + subpage: Component { + PageBatterySettingsBattery { + title: battery.description + bindPrefix: root.bindPrefix + } + } + } + + MbSubMenu { + id: alarms + description: qsTr("Alarms") + subpage: Component { + PageBatterySettingsAlarm { + title: alarms.description + bindPrefix: root.bindPrefix + } + } + } + + MbSubMenu { + id: relay + description: qsTr("Relay (on battery monitor)") + subpage: Component { + PageBatterySettingsRelay { + title: relay.description + bindPrefix: root.bindPrefix + } + } + } + + MbItemOptions { + description: qsTr("Restore factory defaults") + bind: Utils.path(root.bindPrefix, "/Settings/RestoreDefaults") + text: qsTr("Press to restore") + show: valid + possibleValues: [ + MbOption { description: qsTr("Cancel"); value: 0 }, + MbOption { description: qsTr("Restore"); value: 1 } + ] + } + + MbItemNoYes { + description: qsTr("Bluetooth Enabled") + bind: Utils.path(bindPrefix, "/Settings/BluetoothMode") + show: valid + } + + + MbSpinBox { + description: "Reset SoC to" + item.bind: Utils.path(bindPrefix, "/Settings/ResetSoc") + item.min: 0 + item.max: 100 + item.step: 1 + } + + + + + } +} diff --git a/etc/dbus-serialbattery/restore-gui.sh b/etc/dbus-serialbattery/restore-gui.sh index 861f3410..33fcf700 100755 --- a/etc/dbus-serialbattery/restore-gui.sh +++ b/etc/dbus-serialbattery/restore-gui.sh @@ -14,6 +14,11 @@ if [ -f /opt/victronenergy/gui/qml/PageBatteryParameters.qml.backup ]; then echo "PageBatteryParameters.qml was restored." fi # restore original backup +if [ -f /opt/victronenergy/gui/qml/PageBatterySettings.qml.backup ]; then + cp -f /opt/victronenergy/gui/qml/PageBatterySettings.qml.backup /opt/victronenergy/gui/qml/PageBatterySettings.qml + echo "PageBatterySettings.qml was restored." +fi +# restore original backup if [ -f /opt/victronenergy/gui/qml/PageLynxIonIo.qml.backup ]; then cp -f /opt/victronenergy/gui/qml/PageLynxIonIo.qml.backup /opt/victronenergy/gui/qml/PageLynxIonIo.qml echo "PageLynxIonIo.qml was restored." diff --git a/etc/dbus-serialbattery/utils.py b/etc/dbus-serialbattery/utils.py index 77bc4853..74aa7d22 100644 --- a/etc/dbus-serialbattery/utils.py +++ b/etc/dbus-serialbattery/utils.py @@ -36,7 +36,7 @@ def _get_list_from_config( # Constants - Need to dynamically get them in future DRIVER_VERSION = "1.0" -DRIVER_SUBVERSION = ".0 (20230505)" +DRIVER_SUBVERSION = ".0 (20230508)" zero_char = chr(48) degree_sign = "\N{DEGREE SIGN}" diff --git a/rc/post-hook.sh b/rc/post-hook.sh new file mode 100644 index 00000000..37cb7b2b --- /dev/null +++ b/rc/post-hook.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# executed after archive extraction on USB install +# see https://github.com/victronenergy/meta-victronenergy/blob/15fa33c3e5430f7c08a688dc02171f5be9a81c84/meta-venus/recipes-core/initscripts/files/update-data.sh#L43 + + +# search for config.ini in USB root and copy it, if found +for dir in /media/*; do + if [ -f "/media/$dir/config.ini" ]; then + cp -f /media/$dir/config.ini /data/etc/dbus-serialbattery/config.ini + + # remove backup config.ini + if [ -f "/data/etc/dbus-serialbattery_config.ini.backup" ]; then + rm /data/etc/dbus-serialbattery_config.ini.backup + fi + fi +done + +# restore config.ini +if [ -f "/data/etc/dbus-serialbattery_config.ini.backup" ]; then + mv /data/etc/dbus-serialbattery_config.ini.backup /data/etc/dbus-serialbattery/config.ini +fi + +# run reinstall local +bash /data/etc/dbus-serialbattery/reinstall-local.sh diff --git a/rc/pre-hook.sh b/rc/pre-hook.sh new file mode 100644 index 00000000..995a9c94 --- /dev/null +++ b/rc/pre-hook.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +# executed before archive extraction on USB install +# see https://github.com/victronenergy/meta-victronenergy/blob/15fa33c3e5430f7c08a688dc02171f5be9a81c84/meta-venus/recipes-core/initscripts/files/update-data.sh#L42 + + +# backup config.ini +if [ -f "/data/etc/dbus-serialbattery/config.ini" ]; then + mv /data/etc/dbus-serialbattery/config.ini /data/etc/dbus-serialbattery_config.ini.backup +fi + +# remove old driver +if [ -f "/data/etc/dbus-serialbattery" ]; then + rm -rf /data/etc/dbus-serialbattery +fi