diff --git a/README.md b/README.md index 03325ab..1bff4e7 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,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%, `unavailable` during idle/charging diff --git a/custom_components/bms_ble/const.py b/custom_components/bms_ble/const.py index 13bdbb5..aa595ee 100644 --- a/custom_components/bms_ble/const.py +++ b/custom_components/bms_ble/const.py @@ -29,6 +29,7 @@ UPDATE_INTERVAL: Final[int] = 30 # [s] # attributes (do not change) +ATTR_BALANCE_CUR: Final[str] = "balance_current" # [A] ATTR_CELL_VOLTAGES: Final[str] = "cell_voltages" # [V] ATTR_CURRENT: Final[str] = "current" # [A] ATTR_CYCLE_CAP: Final[str] = "cycle_capacity" # [Wh] diff --git a/custom_components/bms_ble/plugins/jikong_bms.py b/custom_components/bms_ble/plugins/jikong_bms.py index 6dd8005..8f84882 100644 --- a/custom_components/bms_ble/plugins/jikong_bms.py +++ b/custom_components/bms_ble/plugins/jikong_bms.py @@ -8,6 +8,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, @@ -42,6 +43,7 @@ class BMS(BaseBMS): (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)), ] ) diff --git a/custom_components/bms_ble/sensor.py b/custom_components/bms_ble/sensor.py index c874c19..6799b9b 100644 --- a/custom_components/bms_ble/sensor.py +++ b/custom_components/bms_ble/sensor.py @@ -25,6 +25,7 @@ from . import BTBmsConfigEntry from .const import ( + ATTR_BALANCE_CUR, ATTR_CELL_VOLTAGES, ATTR_CURRENT, ATTR_CYCLE_CAP, @@ -194,7 +195,12 @@ def extra_state_attributes(self) -> dict[str, list[float]] | None: # type: igno return {ATTR_TEMP_SENSORS: temp_sensors} if temp := self.coordinator.data.get(ATTR_TEMPERATURE): return {ATTR_TEMP_SENSORS: [temp]} - + # add balance current as attribute to current sensor + 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 c6aed78..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,6 +104,7 @@ "temperature": 19.833, "voltage": 52.971, "current": 2.329, + "balance_current": 0.002, "battery_level": 56, "cycle_charge": 113.245, "cycles": 60, @@ -136,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, diff --git a/tests/test_sensor.py b/tests/test_sensor.py index 8014a26..05fafc4 100644 --- a/tests/test_sensor.py +++ b/tests/test_sensor.py @@ -5,6 +5,7 @@ from pytest_homeassistant_custom_component.common import async_fire_time_changed from custom_components.bms_ble.const import ( + ATTR_BALANCE_CUR, ATTR_CELL_VOLTAGES, ATTR_CURRENT, ATTR_CYCLES, @@ -33,6 +34,7 @@ async def test_update( 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, @@ -118,12 +120,12 @@ async def patch_async_update(_self): temp_state = hass.states.get(f"sensor.smartbat_b12345_{ATTR_TEMPERATURE}") assert ( temp_state is not None - and temp_state.attributes[ATTR_TEMP_SENSORS] - == [ - 73, - 31.4, - 27.18, - ] + and temp_state.attributes[ATTR_TEMP_SENSORS] == [73, 31.4, 27.18] if bool_fixture else [temp_state] ) + # 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 + ]