From a2c5fe67721154c49aa70acde51ec00924ed4b42 Mon Sep 17 00:00:00 2001 From: patman15 <14628713+patman15@users.noreply.github.com> Date: Fri, 22 Nov 2024 19:24:06 +0100 Subject: [PATCH 1/2] add JK balance current as attribute --- README.md | 2 +- custom_components/bms_ble/const.py | 1 + custom_components/bms_ble/plugins/jikong_bms.py | 2 ++ custom_components/bms_ble/sensor.py | 6 ++++++ tests/test_jikong_bms.py | 6 ++++-- tests/test_sensor.py | 8 ++++++++ 6 files changed, 22 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8d38de4..c3d22ff 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Platform | Description | Unit | Details -- | -- | -- | -- `binary_sensor` | battery charging | `bool` | indicates `True` if battery is charging `sensor` | charge cycles | `#` | lifetime number of charge cycles -`sensor` | current | `A` | positive for charging, negative for discharging +`sensor` | current | `A` | positive for charging, negative for discharging; if supported, balance current is available as attribute to this sensor `sensor` | delta voltage | `V` | maximum difference between any two cells; individual cell voltage are available as attribute to this sensor `sensor` | power | `W` | positive for charging, negative for discharging `sensor` | runtime | `s` | remaining discharge time till SoC 0% diff --git a/custom_components/bms_ble/const.py b/custom_components/bms_ble/const.py index a79b6ae..70a92b9 100644 --- a/custom_components/bms_ble/const.py +++ b/custom_components/bms_ble/const.py @@ -26,6 +26,7 @@ UPDATE_INTERVAL: Final = 30 # [s] # attributes (do not change) +ATTR_BALANCE_CUR: Final = "balance_current" # [A] ATTR_CELL_VOLTAGES: Final = "cell_voltages" # [V] ATTR_CURRENT: Final = "current" # [A] ATTR_CYCLE_CAP: Final = "cycle_capacity" # [Wh] diff --git a/custom_components/bms_ble/plugins/jikong_bms.py b/custom_components/bms_ble/plugins/jikong_bms.py index 2174290..0fd0249 100644 --- a/custom_components/bms_ble/plugins/jikong_bms.py +++ b/custom_components/bms_ble/plugins/jikong_bms.py @@ -9,6 +9,7 @@ from bleak.uuids import normalize_uuid_str from custom_components.bms_ble.const import ( + ATTR_BALANCE_CUR, ATTR_BATTERY_CHARGING, ATTR_BATTERY_LEVEL, ATTR_CURRENT, @@ -55,6 +56,7 @@ def __init__(self, ble_device: BLEDevice, reconnect: bool = False) -> None: (ATTR_BATTERY_LEVEL, 173, 1, False, lambda x: x), (ATTR_CYCLE_CHRG, 174, 4, False, lambda x: float(x / 1000)), (ATTR_CYCLES, 182, 4, False, lambda x: x), + (ATTR_BALANCE_CUR, 170, 2, True, lambda x: float(x / 1000)), ] + [ # add temperature sensors (f"{KEY_TEMP_VALUE}{i}", addr, 2, True, lambda x: float(x / 10)) for i, addr in [(0, 144), (1, 162), (2, 164), (3, 256), (4, 258)] diff --git a/custom_components/bms_ble/sensor.py b/custom_components/bms_ble/sensor.py index 520d511..c0438ab 100644 --- a/custom_components/bms_ble/sensor.py +++ b/custom_components/bms_ble/sensor.py @@ -29,6 +29,7 @@ from . import BTBmsConfigEntry from .const import ( + ATTR_BALANCE_CUR, ATTR_CELL_VOLTAGES, ATTR_CURRENT, ATTR_CYCLE_CAP, @@ -196,6 +197,11 @@ def extra_state_attributes(self) -> dict[str, list[float]] | None: # type: igno if k.startswith(KEY_TEMP_VALUE) ] } + if ( + self.entity_description.key == ATTR_CURRENT + and ATTR_BALANCE_CUR in self.coordinator.data + ): + return {ATTR_BALANCE_CUR: [self.coordinator.data[ATTR_BALANCE_CUR]]} return None @property diff --git a/tests/test_jikong_bms.py b/tests/test_jikong_bms.py index 44e190a..12870e1 100644 --- a/tests/test_jikong_bms.py +++ b/tests/test_jikong_bms.py @@ -41,14 +41,14 @@ def _response( b"\x47\x00\x3c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" b"\xb8\x00\x00\x00\x00\x00\x0a\xcc\x00\x00\xcd\x71\x08\x00\x9d\xd6\xff\xff" - b"\xb5\x00\xb6\x00\x00\x00\x00\x00\x00\x00\x00\x2a\x47\xcb\x01\x00\xc0\x45" + b"\xb5\x00\xb6\x00\x00\x00\x00\x00\x01\x00\x00\x2a\x47\xcb\x01\x00\xc0\x45" b"\x04\x00\x02\x00\x00\x00\x15\xb7\x08\x00\x64\x00\x00\x00\x6b\xc7\x06\x00" b"\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\x00" b"\x01\x00\x00\x00\xb2\x03\x00\x00\x1c\x00\x54\x29\x40\x40\x00\x00\x00\x00" b"\x67\x14\x00\x00\x00\x01\x01\x01\x00\x06\x00\x00\xf3\x48\x2e\x00\x00\x00" b"\x00\x00\xb8\x00\xb4\x00\xb7\x00\xb2\x03\xde\xe4\x5b\x08\x2c\x00\x00\x00" b"\x80\x51\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfe" - b"\xff\x7f\xdc\x2f\x01\x01\xb0\x07\x00\x00\x00\xd0" + b"\xff\x7f\xdc\x2f\x01\x01\xb0\x07\x00\x00\x00\xd1" ) # {"temperature": 18.4, "voltage": 52.234, "current": -10.595, "battery_level": 42, "cycle_charge": 117.575, "cycles": 2} return bytearray() @@ -271,6 +271,7 @@ async def test_update(monkeypatch, reconnect_fixture) -> None: result = await bms.async_update() assert result == { + "balance_current": 0.001, "cell_count": 16, "delta_voltage": 0.002, "temperature": 18.2, @@ -345,6 +346,7 @@ async def test_oversized_response(monkeypatch) -> None: result = await bms.async_update() assert result == { + "balance_current": 0, "cell_count": 16, "delta_voltage": 0.002, "temperature": 18.2, diff --git a/tests/test_sensor.py b/tests/test_sensor.py index 9627b4a..3b847d9 100644 --- a/tests/test_sensor.py +++ b/tests/test_sensor.py @@ -3,6 +3,7 @@ from datetime import timedelta from custom_components.bms_ble.const import ( + ATTR_BALANCE_CUR, ATTR_CELL_VOLTAGES, ATTR_CURRENT, ATTR_CYCLES, @@ -30,6 +31,7 @@ async def test_update(monkeypatch, patch_bleakclient, BTdiscovery, hass: HomeAss async def patch_async_update(_self): """Patch async_update to return a specific value.""" return { + "balance_current": -1.234, "voltage": 17.0, "current": 0, "cell#0": 3, @@ -110,3 +112,9 @@ async def patch_async_update(_self): assert temp_state is not None and temp_state.attributes[ ATTR_TEMP_SENSORS ] == [73, 31.4, 27.18] + + # check balance current as attribute + current_state = hass.states.get(f"sensor.smartbat_b12345_{ATTR_CURRENT}") + assert current_state is not None and current_state.attributes[ + ATTR_BALANCE_CUR + ] == [-1.234] \ No newline at end of file From c157861163e614aa5f19aefb4f621da089f8d68d Mon Sep 17 00:00:00 2001 From: patman15 <14628713+patman15@users.noreply.github.com> Date: Thu, 26 Dec 2024 18:18:01 +0100 Subject: [PATCH 2/2] Update test_jikong_bms.py --- tests/test_jikong_bms.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/test_jikong_bms.py b/tests/test_jikong_bms.py index 5af734d..5a730c3 100644 --- a/tests/test_jikong_bms.py +++ b/tests/test_jikong_bms.py @@ -48,14 +48,14 @@ b"\x37\x00\x39\x00\x38\x00\x37\x00\x37\x00\x35\x00\x41\x00\x42\x00\x36\x00\x37\x00\x3a\x00" b"\x38\x00\x34\x00\x36\x00\x37\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" b"\x00\x00\x00\x00\x00\x00\x00\x00\xeb\xce\x00\x00\xc7\x0d\x02\x00\x19\x09\x00\x00\xb5\x00" - b"\xba\x00\xe4\x00\x00\x00\x00\x00\x00\x38\x5d\xba\x01\x00\x10\x15\x03\x00\x3c\x00\x00\x00" + b"\xba\x00\xe4\x00\x00\x00\x02\x00\x00\x38\x5d\xba\x01\x00\x10\x15\x03\x00\x3c\x00\x00\x00" b"\xa4\x65\xb9\x00\x64\x00\xd9\x02\x8b\xe8\x6c\x03\x01\x01\xb3\x06\x00\x00\x00\x00\x00\x00" b"\x00\x00\x00\x00\x00\x00\x07\x00\x01\x00\x00\x00\x23\x04\x0b\x00\x00\x00\x9f\x19\x40\x40" b"\x00\x00\x00\x00\xe2\x04\x00\x00\x00\x00\x00\x01\x00\x03\x00\x00\x83\xd5\x37\x00\x00\x00" b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbb" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xbd" ), }, "JK02_32S": { # JK02_32 (SW: V11.48) @@ -86,14 +86,14 @@ b"\x54\x00\x5c\x00\x69\x00\x76\x00\x7d\x00\x76\x00\x6c\x00\x69\x00\x61\x00\x4b\x00\x47\x00" b"\x3c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb8\x00\x00\x00\x00\x00\x0a\xcc\x00\x00" - b"\xcd\x71\x08\x00\x9d\xd6\xff\xff\xb5\x00\xb6\x00\x00\x00\x00\x00\x00\x00\x00\x2a\x47\xcb" + b"\xcd\x71\x08\x00\x9d\xd6\xff\xff\xb5\x00\xb6\x00\x00\x00\x00\x00\x01\x00\x00\x2a\x47\xcb" b"\x01\x00\xc0\x45\x04\x00\x02\x00\x00\x00\x15\xb7\x08\x00\x64\x00\x00\x00\x6b\xc7\x06\x00" b"\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\x00\x01\x00\x00\x00" b"\xb2\x03\x00\x00\x1c\x00\x54\x29\x40\x40\x00\x00\x00\x00\x67\x14\x00\x00\x00\x01\x01\x01" b"\x00\x06\x00\x00\xf3\x48\x2e\x00\x00\x00\x00\x00\xb8\x00\xb4\x00\xb7\x00\xb2\x03\xde\xe4" b"\x5b\x08\x2c\x00\x00\x00\x80\x51\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" - b"\x00\xfe\xff\x7f\xdc\x2f\x01\x01\xb0\x07\x00\x00\x00\xd0" - ), # {"temperature": 18.4, "voltage": 52.234, "current": -10.595, "battery_level": 42, "cycle_charge": 117.575, "cycles": 2} + b"\x00\xfe\xff\x7f\xdc\x2f\x01\x01\xb0\x07\x00\x00\x00\xd1" + ), # {"temperature": 18.4, "voltage": 52.234, "current": -10.595, "balance_current": 0.001, "battery_level": 42, "cycle_charge": 117.575, "cycles": 2} }, } @@ -104,7 +104,7 @@ "temperature": 19.833, "voltage": 52.971, "current": 2.329, - "balance_current": 0.001, + "balance_current": 0.002, "battery_level": 56, "cycle_charge": 113.245, "cycles": 60, @@ -137,6 +137,7 @@ "temperature": 18.2, "voltage": 52.234, "current": -10.595, + "balance_current": 0.001, "battery_level": 42, "cycle_charge": 117.575, "cycles": 2,