Skip to content

Commit

Permalink
Improve IKEA battery percentage firmware detection (#2998)
Browse files Browse the repository at this point in the history
  • Loading branch information
TheJulianJES authored Feb 23, 2024
1 parent a08f5c2 commit fc1e55f
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 20 deletions.
11 changes: 8 additions & 3 deletions tests/test_ikea.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,14 @@ def mock_read(attributes, manufacturer=None):
@pytest.mark.parametrize(
"firmware, pct_device, pct_correct, expected_pct_updates, expect_log_warning",
(
("2.3.075", 50, 100, 1, False),
("24.4.5", 50, 50, 2, False),
("invalid_fw_string", 50, 50, 2, True),
("1.0.024", 50, 100, 1, False), # old firmware, doubling
("2.3.075", 50, 100, 1, False), # old firmware, doubling
("2.4.5", 50, 50, 2, False), # new firmware, no doubling
("3.0.0", 50, 50, 2, False), # new firmware, no doubling
("24.4.5", 50, 50, 2, False), # new firmware, no doubling
("invalid_fw_string_1", 50, 50, 2, False), # treated as new, no doubling
("invalid.fw.string.2", 50, 50, 2, True), # treated as new, no doubling + log
("", 50, 100, 1, False), # treated as old fw, doubling
),
)
async def test_double_power_config_firmware(
Expand Down
44 changes: 27 additions & 17 deletions zhaquirks/ikea/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,26 +209,36 @@ async def bind(self):
await self.endpoint.basic.read_attributes([Basic.AttributeDefs.sw_build_id.id])
return result

def _is_firmware_old(self):
"""Checks if firmware is old or unknown."""
def _is_firmware_new(self):
"""Checks if new firmware is installed that does not require battery doubling."""
# get sw_build_id from attribute cache if available
sw_build_id = self.endpoint.basic.get(Basic.AttributeDefs.sw_build_id.id, None)

# guard against possible future version formatting which includes more than just numbers
try:
# if first part of sw_build_id is 24 or higher, then firmware is new
if sw_build_id and int(sw_build_id.split(".")[0]) >= 24:
return False
except ValueError:
_LOGGER.warning(
"sw_build_id is not a number: %s for device %s",
sw_build_id,
self.endpoint.device.ieee,
)
# sw_build_id is not a number, so it must be new firmware
# sw_build_id is not cached or empty, so we consider it old firmware for now
if not sw_build_id:
return False

# unknown or old firmware
# split sw_build_id into parts to check for new firmware
split_fw_version = sw_build_id.split(".")
if len(split_fw_version) >= 2:
# guard against possible future version formatting which includes more than just numbers
try:
first_part = int(split_fw_version[0])
second_part = int(split_fw_version[1])

# new firmware is either 24.4.5 or above, or 2.4.5 or above
# old firmware is 2.3.x or below
return first_part >= 3 or (first_part >= 2 and second_part >= 4)
except ValueError:
_LOGGER.warning(
"sw_build_id is not a number: %s for device %s",
sw_build_id,
self.endpoint.device.ieee,
)
# sw_build_id is not a number, so it must be new firmware
return True

# unknown formatting of sw_build_id, so it must be new firmware
return True

async def _read_fw_and_update_battery_pct(self, reported_battery_pct):
Expand All @@ -238,7 +248,7 @@ async def _read_fw_and_update_battery_pct(self, reported_battery_pct):

# check if sw_build_id was read successfully and new firmware is installed
# if so, update cache with reported battery percentage (non-doubled)
if not self._is_firmware_old():
if self._is_firmware_new():
self._update_attribute(
PowerConfiguration.AttributeDefs.battery_percentage_remaining.id,
reported_battery_pct,
Expand All @@ -261,7 +271,7 @@ def _update_attribute(self, attrid, value):
# double percentage if the firmware is old or unknown
# the coroutine above will not have executed yet if the firmware is unknown,
# so we double for now in that case too, and it updates again later if our doubling was wrong
if self._is_firmware_old():
if not self._is_firmware_new():
value = value * 2
super()._update_attribute(attrid, value)

Expand Down

0 comments on commit fc1e55f

Please sign in to comment.