Skip to content

Commit

Permalink
fix daly_bms MOS read timeout (#92)
Browse files Browse the repository at this point in the history
* Capture timeout on MOS query
* add test for MOS unavailable
* Update test_daly_bms.py
  • Loading branch information
patman15 authored Nov 19, 2024
1 parent c39658d commit 406c80b
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 45 deletions.
2 changes: 1 addition & 1 deletion custom_components/bms_ble/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,5 @@
"issue_tracker": "https://github.com/patman15/BMS_BLE-HA/issues",
"loggers": ["bleak_retry_connector"],
"requirements": [],
"version": "1.9.1"
"version": "1.9.2"
}
36 changes: 20 additions & 16 deletions custom_components/bms_ble/plugins/daly_bms.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,24 +123,28 @@ def _notification_handler(self, _sender, data: bytearray) -> None:

async def _async_update(self) -> BMSsample:
"""Update battery status information."""
await self._client.write_gatt_char(
BMS.uuid_tx(), data=self.HEAD_READ + self.MOS_INFO
)
await asyncio.wait_for(self._wait_event(), timeout=BAT_TIMEOUT)

data = {}
if self._data is not None and sum(self._data[self.MOS_TEMP_POS :][:2]):
LOGGER.debug("%s: MOS info: %s", self._ble_device.name, self._data)
data |= {
f"{KEY_TEMP_VALUE}0": float(
int.from_bytes(
self._data[self.MOS_TEMP_POS :][:2],
byteorder="big",
signed=True,
try:
# request MOS temperature (possible outcome: response, empty response, no response)
await self._client.write_gatt_char(
BMS.uuid_tx(), data=self.HEAD_READ + self.MOS_INFO
)
await asyncio.wait_for(self._wait_event(), timeout=BAT_TIMEOUT/5)

if self._data is not None and sum(self._data[self.MOS_TEMP_POS :][:2]):
LOGGER.debug("%s: MOS info: %s", self._ble_device.name, self._data)
data |= {
f"{KEY_TEMP_VALUE}0": float(
int.from_bytes(
self._data[self.MOS_TEMP_POS :][:2],
byteorder="big",
signed=True,
)
- 40
)
- 40
)
}
}
except TimeoutError:
LOGGER.debug("%s: no MOS temperature available.", self.name)

await self._client.write_gatt_char(
BMS.uuid_tx(), data=self.HEAD_READ + self.CMD_INFO
Expand Down
77 changes: 49 additions & 28 deletions tests/test_daly_bms.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ class MockDalyBleakClient(MockBleakClient):

HEAD_READ = bytearray(b"\xD2\x03")
CMD_INFO = bytearray(b"\x00\x00\x00\x3E\xD7\xB9")
MOS_INFO = bytearray(b"\x00\x3E\x00\x09\xF7\xA3")
MOS_INFO = bytearray(b"\x00\x3E\x00\x09\xF7\xA3")
MOS_AVAIL: bool = True

def _response(
self, char_specifier: BleakGATTCharacteristic | int | str | UUID, data: Buffer
Expand All @@ -32,6 +33,8 @@ def _response(
if isinstance(char_specifier, str) and normalize_uuid_str(char_specifier) == normalize_uuid_str("fff2") and data == (
self.HEAD_READ + self.MOS_INFO
):
if not self.MOS_AVAIL:
raise TimeoutError
return bytearray(b"\xd2\x03\x12\x00\x00\x00\x00\x75\x30\x00\x00\x00\x4e\xff\xff\xff\xff\xff\xff\xff\xff\x0b\x4e")

return bytearray()
Expand Down Expand Up @@ -66,12 +69,15 @@ async def disconnect(self) -> bool:
raise BleakError


async def test_update(monkeypatch, reconnect_fixture) -> None:
async def test_update(monkeypatch, bool_fixture, reconnect_fixture) -> None:
"""Test Daly BMS data update."""

monkeypatch.setattr( # patch recoginiation of MOS request to fail
"tests.test_daly_bms.MockDalyBleakClient.MOS_AVAIL", bool_fixture
)

monkeypatch.setattr(
"custom_components.bms_ble.plugins.basebms.BleakClient",
MockDalyBleakClient,
"custom_components.bms_ble.plugins.basebms.BleakClient", MockDalyBleakClient
)

bms = BMS(
Expand All @@ -81,33 +87,48 @@ async def test_update(monkeypatch, reconnect_fixture) -> None:

result = await bms.async_update()

assert result == {
"voltage": 14.0,
"current": 3.0,
"battery_level": 90.0,
"cycles": 57,
"cycle_charge": 345.6,
"cell#0": 4.127,
"cell#1": 4.137,
"cell#2": 4.147,
"cell#3": 4.157,
"cell_count": 4,
"delta_voltage": 0.321,
"temp_sensors": 4,
"temperature": 24.8,
"cycle_capacity": 4838.4,
"power": 42.0,
"temp#0": 38.0,
"temp#1": 20.0,
"temp#2": 21.0,
"temp#3": 22.0,
"temp#4": 23.0,
"battery_charging": True,
}
assert (
result
== {
"voltage": 14.0,
"current": 3.0,
"battery_level": 90.0,
"cycles": 57,
"cycle_charge": 345.6,
"cell#0": 4.127,
"cell#1": 4.137,
"cell#2": 4.147,
"cell#3": 4.157,
"cell_count": 4,
"delta_voltage": 0.321,
"temp_sensors": 4,
"cycle_capacity": 4838.4,
"power": 42.0,
"battery_charging": True,
}
| {
"temperature": 24.8,
"temp#0": 38.0,
"temp#1": 20.0,
"temp#2": 21.0,
"temp#3": 22.0,
"temp#4": 23.0,
}
if bool_fixture
else {
"temperature": 21.5,
"temp#0": 20.0,
"temp#1": 21.0,
"temp#2": 22.0,
"temp#3": 23.0,
}
)

# query again to check already connected state
result = await bms.async_update()
assert bms._client and bms._client.is_connected is not reconnect_fixture # noqa: SLF001
assert (
bms._client and bms._client.is_connected is not reconnect_fixture
) # noqa: SLF001

await bms.disconnect()

Expand Down

0 comments on commit 406c80b

Please sign in to comment.