Skip to content

Commit

Permalink
Only declare lifx update failure after 3 attempts
Browse files Browse the repository at this point in the history
These devices sometimes flakey and generate a lot of noise
from drop outs since communication is UDP best-effort. We
should only mark them unavailable if its not a momentary blip

fixes home-assistant#78876
  • Loading branch information
bdraco authored and Djelibeybi committed Apr 9, 2023
1 parent 667a00e commit 76b3382
Showing 1 changed file with 51 additions and 35 deletions.
86 changes: 51 additions & 35 deletions homeassistant/components/lifx/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
REQUEST_REFRESH_DELAY = 0.35
LIFX_IDENTIFY_DELAY = 3.0
RSSI_DBM_FW = AwesomeVersion("2.77")
MAX_TIMEOUTS_TO_DECLARE_UPDATE_FAILED = 3


class FirmwareEffect(IntEnum):
Expand Down Expand Up @@ -82,6 +83,8 @@ def __init__(
self._update_rssi: bool = False
self._rssi: int = 0
self.last_used_theme: str = ""
self._timeouts = 0
self._did_first_update = False

super().__init__(
hass,
Expand Down Expand Up @@ -189,41 +192,54 @@ def async_get_entity_id(self, platform: Platform, key: str) -> str | None:
async def _async_update_data(self) -> None:
"""Fetch all device data from the api."""
async with self.lock:
if self.device.host_firmware_version is None:
self.device.get_hostfirmware()
if self.device.product is None:
self.device.get_version()
if self.device.group is None:
self.device.get_group()

response = await async_execute_lifx(self.device.get_color)

if self.device.product is None:
raise UpdateFailed(
f"Failed to fetch get version from device: {self.device.ip_addr}"
)

# device.mac_addr is not the mac_address, its the serial number
if self.device.mac_addr == TARGET_ANY:
self.device.mac_addr = response.target_addr

if self._update_rssi is True:
await self.async_update_rssi()

# Update extended multizone devices
if lifx_features(self.device)["extended_multizone"]:
await self.async_get_extended_color_zones()
await self.async_get_multizone_effect()
# use legacy methods for older devices
elif lifx_features(self.device)["multizone"]:
await self.async_get_color_zones()
await self.async_get_multizone_effect()

if lifx_features(self.device)["hev"]:
await self.async_get_hev_cycle()

if lifx_features(self.device)["infrared"]:
await async_execute_lifx(self.device.get_infrared)
try:
if self.device.host_firmware_version is None:
self.device.get_hostfirmware()
if self.device.product is None:
self.device.get_version()
if self.device.group is None:
self.device.get_group()

response = await async_execute_lifx(self.device.get_color)

if self.device.product is None:
raise UpdateFailed(
f"Failed to fetch get version from device: {self.device.ip_addr}"
)

# device.mac_addr is not the mac_address, its the serial number
if self.device.mac_addr == TARGET_ANY:
self.device.mac_addr = response.target_addr

if self._update_rssi is True:
await self.async_update_rssi()

# Update extended multizone devices
if lifx_features(self.device)["extended_multizone"]:
await async_execute_lifx(self.device.get_extended_color_zones)
await self.async_get_multizone_effect()
# use legacy methods for older devices
elif lifx_features(self.device)["multizone"]:
await self.async_get_color_zones()
await self.async_get_multizone_effect()

if lifx_features(self.device)["hev"]:
await self.async_get_hev_cycle()

if lifx_features(self.device)["infrared"]:
await async_execute_lifx(self.device.get_infrared)
except asyncio.TimeoutError as ex:
self._timeouts += 1
if (
not self._did_first_update
or self._timeouts >= MAX_TIMEOUTS_TO_DECLARE_UPDATE_FAILED
):
raise UpdateFailed(
f"The device failed to respond after {MAX_TIMEOUTS_TO_DECLARE_UPDATE_FAILED} attempts"
) from ex
else:
self._timeouts = 0
self._did_first_update = True

async def async_get_color_zones(self) -> None:
"""Get updated color information for each zone."""
Expand Down

0 comments on commit 76b3382

Please sign in to comment.