Skip to content

Support ANT BMS (legacy BLE protocol)#468

Merged
patman15 merged 30 commits into
patman15:mainfrom
krahabb:m3_ant_bms
Sep 11, 2025
Merged

Support ANT BMS (legacy BLE protocol)#468
patman15 merged 30 commits into
patman15:mainfrom
krahabb:m3_ant_bms

Conversation

@krahabb

@krahabb krahabb commented Aug 31, 2025

Copy link
Copy Markdown
Contributor

This PR addresses an issue I'm having with an ANT BMS.
After searching the net I've seen through https://github.com/syssi/esphome-ant-bms that it looks like there are 2 versions of these devices at least on the protocol/software side and the 'legacy' one is nicely managed in the repository (the *_old_ble source files)

By using the advertised data of my ANT BMS I've come around a slightly different matcher with the following keys:

{
  "local_name": "ANT-BLE*",
  "service_uuid": "0000ffe0-0000-1000-8000-00805f9b34fb",
  "manufacturer_id": 1623
},

where, as can be seen, the difference with respect to the actual ANT matcher lies in the manufacturer_id key
I hope this is enough to cover any other ANT implementing this protocol but we'll see...

I've checked ruff and mypy on the code but I'm still in a 'draft' stage at the moment (missing tests for sure)
This early submission is to make you aware I'm working on this and I'd like to discuss some adjustments regarding the BaseBMS model.
More specifically, I've added some custom keys to the _FIELDS definitions in order to leverage the automatic parse of the frame done by BaseBMS._decode_data but these keys are not defined in the BMSsample TypedDict (hence mypy complaining).

If these keys prove to not be relevant in the overall integration architecture I'd quickly cleanup the _FIELDS and do the int.from_bytes locally in the custom plugin.

The keys I'm talking about are:

  • cell_high_voltage
  • cell_low_voltage
  • total_cycled_charge

I think the cell_high_voltage and cell_low_voltage could be interesting for the general architecture. They're related to delta_voltage but providing those two would give more insights about the cells without the need to expose the full array of cells (See #441)

The total_cycled_charge instead is a somewhat duplicate of cycles. It carries the total amount of charge exchanged by the battery/bms in its life and it is then related to cycles with:

cycles = total_cycled_charge / design_capacity

If you like them we could better define these new key names or, if not, as stated, I'll just drop them from the _FIELDS and use them only in internal decoding.

@krahabb krahabb marked this pull request as draft August 31, 2025 20:13
@patman15

patman15 commented Aug 31, 2025

Copy link
Copy Markdown
Owner

Hi! Thanks for your contribution. Just a quick feedback as I'm low on time at the moment: yes, the high/low voltage was already in my thoughts as well, so let's introduce them, but I will need to implement them also for other BMSs (the readout, not the backup). Same for cycles, I do agree, that this calculation makes sense.
Let's put those basic changes into a separate branch/PR from the addition of the BMS.
I restored my PR checks that were somehow disabled. What I need is full test coverage using real-life recorded BMS answers. If you are motivated, please have a look at the other test files on how I did it.
I'll do a review of your PR a bit later.

@krahabb

krahabb commented Sep 1, 2025

Copy link
Copy Markdown
Contributor Author

Hello Patrick,
Thank you for your feedback, and also for this nice integration that finely supports, in a single component, all of the different BMS implementations: this is a great 'pain reliever' for the HA community I guess.

I've taken a bit of time to look at the tests and I see they follow a common structure so I'll just copy/adapt to the new protocol the existing implementation(s). I think I'm going to push this sooner than later so that I can 'pop' this from my tasks stack ;)

BTW, I also have some ideas/requests about the component functionality (i.e. adding BMS config features) but we'll discuss this in a dedicated thread. I see this repository has no 'Discussions' enabled so I'll maybe open an issue for the matter.

Davide

@krahabb krahabb marked this pull request as ready for review September 5, 2025 09:44

@patman15 patman15 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Code already now looks pretty good to me, thanks for the great work! I'm still a bit unsure about the 'data' variables in your _notification_handler but after a hard week I miss the energy to understand your logic. I'll probably come back to that one or fix it later myself. Thanks again and I only request a few changes.

Comment thread custom_components/bms_ble/plugins/ant_legacy_bms.py Outdated
Comment thread custom_components/bms_ble/plugins/ant_legacy_bms.py Outdated
Comment thread custom_components/bms_ble/plugins/ant_legacy_bms.py Outdated
Comment thread custom_components/bms_ble/plugins/ant_legacy_bms.py Outdated
Comment thread custom_components/bms_ble/plugins/ant_legacy_bms.py Outdated
Comment thread custom_components/bms_ble/plugins/ant_legacy_bms.py Outdated
Comment thread tests/test_ant_legacy_bms.py Outdated
Comment thread tests/advertisement_data.py
Comment thread tests/test_ant_legacy_bms.py
@patman15

patman15 commented Sep 6, 2025

Copy link
Copy Markdown
Owner

Hey, for the cycles calculation you could use the changes from #476.
Regarding the min/max voltage, I will add a diagnosis sensor for each of them, but the value can be gathered from the cell voltage array. I do not see a need for another value in the array, as I could not find (so far) any BMS that provides min/max but not the individual ones.

@krahabb krahabb marked this pull request as draft September 7, 2025 10:58
@krahabb krahabb marked this pull request as ready for review September 7, 2025 12:37
@krahabb

krahabb commented Sep 7, 2025

Copy link
Copy Markdown
Contributor Author

mypy should still be complaining but once the code from #476 will be merged in it should be ok.

@krahabb krahabb marked this pull request as draft September 7, 2025 20:42
@krahabb krahabb marked this pull request as ready for review September 8, 2025 08:54
@patman15 patman15 self-requested a review September 8, 2025 11:18
Comment thread custom_components/bms_ble/plugins/ant_legacy_bms.py Outdated
Comment thread custom_components/bms_ble/plugins/ant_legacy_bms.py Outdated
Comment thread custom_components/bms_ble/plugins/ant_legacy_bms.py Outdated
Comment thread custom_components/bms_ble/plugins/ant_legacy_bms.py Outdated
@krahabb krahabb marked this pull request as draft September 9, 2025 16:59
@krahabb krahabb marked this pull request as ready for review September 9, 2025 21:04
@patman15

Copy link
Copy Markdown
Owner

@krahabb if you give me a final "go" for the changes I pushed (mainly this commit 15f657e) I would merge ...

@krahabb

krahabb commented Sep 10, 2025

Copy link
Copy Markdown
Contributor Author

Good to go!
Thank you

@patman15 patman15 merged commit f87ea89 into patman15:main Sep 11, 2025
5 checks passed
patman15 added a commit that referenced this pull request Sep 12, 2025
* adapt naming

- `AdvertisementPattern` to `MatcherPattern`
- `reconnect` to `keep_alive`

* remove dummy example

* fix removal of 0 values in _temp_values() (#480)

* Add Seplos `SP1??B*` pattern (#482)

* Feature align aiobmsble (#481)

* adapt naming

- `AdvertisementPattern` to `MatcherPattern`
- `reconnect` to `keep_alive`

* remove dummy example

* Add detection of LiTime 24V BMS type based on serial number (#484)

* Fix operator precedence (#485)

* fix removal of 0 values in _temp_values()

* fix operator precedence

* Support ANT BMS (legacy BLE protocol) (#468)

* Support ANT BMS (legacy BLE protocol)

* Refine frame parsing for ant_bms_legacy

* Add basic testing for ant_bms_legacy

* Rename plugin ant_bms_legacy to ant_legacy_bms to comply with component conventions

* Fix ant_legacy_bms test coverage

* Fix compliancy with bms_ble repository design

* Add 'total_charge' value (#476) to results

* Remove 'dead' code

* Remove unused import

* Fix temperature sensors count

* Remove cell high/low voltage parsing and calc 'delta_voltage' from internal '_add_missing_values'

* Remove local reference to self._data in member function body

* Fix 'BaseBMS._temp_values' operator precedence

* Fix imported symbol

* Fix missing comma after manual merge

* fix pylint issues

* fix design_capacity / temp sensors

* add typing

* Update ant_legacy_bms.py

* align constants

* test to check design capacity provision

* rename legacy bms

* Update README.md

---------

Co-authored-by: patman15 <14628713+patman15@users.noreply.github.com>

* update to 1.21.0

---------

Co-authored-by: krahabb <13969600+krahabb@users.noreply.github.com>
patman15 added a commit that referenced this pull request Sep 13, 2025
* migrate to aiobmsble

* disable mypy

* fix device discovery for aiobmsble

* add test for v2 config entry

not yet correct

* complete test coverage

* Update aiobmsble to 0.2.2

* disable fuzz tests

* update for new retry-connector

* update requirements

* Update fuzzing.yaml

* Update manifest.json

* Update README.md

* Feature align aiobmsble (#488)

* adapt naming

- `AdvertisementPattern` to `MatcherPattern`
- `reconnect` to `keep_alive`

* remove dummy example

* fix removal of 0 values in _temp_values() (#480)

* Add Seplos `SP1??B*` pattern (#482)

* Feature align aiobmsble (#481)

* adapt naming

- `AdvertisementPattern` to `MatcherPattern`
- `reconnect` to `keep_alive`

* remove dummy example

* Add detection of LiTime 24V BMS type based on serial number (#484)

* Fix operator precedence (#485)

* fix removal of 0 values in _temp_values()

* fix operator precedence

* Support ANT BMS (legacy BLE protocol) (#468)

* Support ANT BMS (legacy BLE protocol)

* Refine frame parsing for ant_bms_legacy

* Add basic testing for ant_bms_legacy

* Rename plugin ant_bms_legacy to ant_legacy_bms to comply with component conventions

* Fix ant_legacy_bms test coverage

* Fix compliancy with bms_ble repository design

* Add 'total_charge' value (#476) to results

* Remove 'dead' code

* Remove unused import

* Fix temperature sensors count

* Remove cell high/low voltage parsing and calc 'delta_voltage' from internal '_add_missing_values'

* Remove local reference to self._data in member function body

* Fix 'BaseBMS._temp_values' operator precedence

* Fix imported symbol

* Fix missing comma after manual merge

* fix pylint issues

* fix design_capacity / temp sensors

* add typing

* Update ant_legacy_bms.py

* align constants

* test to check design capacity provision

* rename legacy bms

* Update README.md

---------

Co-authored-by: patman15 <14628713+patman15@users.noreply.github.com>

* update to 1.21.0

---------

Co-authored-by: krahabb <13969600+krahabb@users.noreply.github.com>

* fix ant_leg_bms inclusion

* Update CONTRIBUTING.md

* Update README.md

---------

Co-authored-by: krahabb <13969600+krahabb@users.noreply.github.com>
@patman15

patman15 commented Sep 17, 2025

Copy link
Copy Markdown
Owner

@krahabb I moved all plugins to a new library https://github.com/patman15/aiobmsble/
Do you want to be named as an author of this library in the pyproject.toml? I'll move the thanks section in the README anyway. If so, please let me know what to put there!

@krahabb

krahabb commented Sep 17, 2025

Copy link
Copy Markdown
Contributor Author

Thank you @patman15,
I would be honoured but at the time my contribution is so tiny.. Let's see in the future, the README mention is enough at the moment ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants