From fcd58b7c9bfd304669f448bdd9e144c5751b6af7 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 30 Apr 2020 02:08:56 -0500 Subject: [PATCH] Avoid error when battery appears after homekit has started (#34906) --- .../components/homekit/accessories.py | 10 ++++++- tests/components/homekit/test_accessories.py | 27 ++++++++++++++++--- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/homekit/accessories.py b/homeassistant/components/homekit/accessories.py index a18f42e76b6..4f0a840770c 100644 --- a/homeassistant/components/homekit/accessories.py +++ b/homeassistant/components/homekit/accessories.py @@ -99,6 +99,9 @@ class HomeAccessory(Accessory): self.entity_id = entity_id self.hass = hass self.debounce = {} + self._char_battery = None + self._char_charging = None + self._char_low_battery = None self.linked_battery_sensor = self.config.get(CONF_LINKED_BATTERY_SENSOR) self.linked_battery_charging_sensor = self.config.get( CONF_LINKED_BATTERY_CHARGING_SENSOR @@ -247,6 +250,10 @@ class HomeAccessory(Accessory): Only call this function if self._support_battery_level is True. """ + if not self._char_battery: + # Battery appeared after homekit was started + return + battery_level = convert_to_float(battery_level) if battery_level is not None: if self._char_battery.value != battery_level: @@ -258,7 +265,8 @@ class HomeAccessory(Accessory): "%s: Updated battery level to %d", self.entity_id, battery_level ) - if battery_charging is None: + # Charging state can appear after homekit was started + if battery_charging is None or not self._char_charging: return hk_charging = HK_CHARGING if battery_charging else HK_NOT_CHARGING diff --git a/tests/components/homekit/test_accessories.py b/tests/components/homekit/test_accessories.py index becbcb2d6d4..c4b61f68833 100644 --- a/tests/components/homekit/test_accessories.py +++ b/tests/components/homekit/test_accessories.py @@ -363,9 +363,30 @@ async def test_missing_linked_battery_sensor(hass, hk_driver, caplog): await hass.async_block_till_done() assert not acc.linked_battery_sensor - assert not hasattr(acc, "_char_battery") - assert not hasattr(acc, "_char_low_battery") - assert not hasattr(acc, "_char_charging") + assert acc._char_battery is None + assert acc._char_low_battery is None + assert acc._char_charging is None + + +async def test_battery_appears_after_startup(hass, hk_driver, caplog): + """Test battery level appears after homekit is started.""" + entity_id = "homekit.accessory" + hass.states.async_set(entity_id, None, {}) + await hass.async_block_till_done() + + acc = HomeAccessory( + hass, hk_driver, "Accessory without battery", entity_id, 2, None + ) + acc.update_state = lambda x: None + assert acc._char_battery is None + + await acc.run_handler() + await hass.async_block_till_done() + assert acc._char_battery is None + + hass.states.async_set(entity_id, None, {ATTR_BATTERY_LEVEL: 15}) + await hass.async_block_till_done() + assert acc._char_battery is None async def test_call_service(hass, hk_driver, events):