Skip to content

Commit

Permalink
Avoid concurrent radio operations with powerview hubs (#114399)
Browse files Browse the repository at this point in the history
Co-authored-by: kingy444 <toddlesking4@hotmail.com>
  • Loading branch information
2 people authored and frenck committed Mar 29, 2024
1 parent bf4e527 commit bc740f9
Show file tree
Hide file tree
Showing 5 changed files with 19 additions and 6 deletions.
3 changes: 2 additions & 1 deletion homeassistant/components/hunterdouglas_powerview/button.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,4 +119,5 @@ def __init__(

async def async_press(self) -> None:
"""Handle the button press."""
await self.entity_description.press_action(self._shade)
async with self.coordinator.radio_operation_lock:
await self.entity_description.press_action(self._shade)
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from __future__ import annotations

import asyncio
from datetime import timedelta
import logging

Expand All @@ -25,6 +26,10 @@ def __init__(self, hass: HomeAssistant, shades: Shades, hub: Hub) -> None:
"""Initialize DataUpdateCoordinator to gather data for specific Powerview Hub."""
self.shades = shades
self.hub = hub
# The hub tends to crash if there are multiple radio operations at the same time
# but it seems to handle all other requests that do not use RF without issue
# so we have a lock to prevent multiple radio operations at the same time
self.radio_operation_lock = asyncio.Lock()
super().__init__(
hass,
_LOGGER,
Expand Down
11 changes: 8 additions & 3 deletions homeassistant/components/hunterdouglas_powerview/cover.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ async def _async_initial_refresh() -> None:

for shade in pv_entry.shade_data.values():
_LOGGER.debug("Initial refresh of shade: %s", shade.name)
await shade.refresh(suppress_timeout=True) # default 15 second timeout
async with coordinator.radio_operation_lock:
await shade.refresh(suppress_timeout=True) # default 15 second timeout

entities: list[ShadeEntity] = []
for shade in pv_entry.shade_data.values():
Expand Down Expand Up @@ -207,7 +208,8 @@ def _get_shade_move(self, target_hass_position: int) -> ShadePosition:
async def _async_execute_move(self, move: ShadePosition) -> None:
"""Execute a move that can affect multiple positions."""
_LOGGER.debug("Move request %s: %s", self.name, move)
response = await self._shade.move(move)
async with self.coordinator.radio_operation_lock:
response = await self._shade.move(move)
_LOGGER.debug("Move response %s: %s", self.name, response)

# Process the response from the hub (including new positions)
Expand Down Expand Up @@ -318,7 +320,10 @@ async def async_update(self) -> None:
# error if are already have one in flight
return
# suppress timeouts caused by hub nightly reboot
await self._shade.refresh(suppress_timeout=True) # default 15 second timeout
async with self.coordinator.radio_operation_lock:
await self._shade.refresh(
suppress_timeout=True
) # default 15 second timeout
_LOGGER.debug("Process update %s: %s", self.name, self._shade.current_position)
self._async_update_shade_data(self._shade.current_position)

Expand Down
3 changes: 2 additions & 1 deletion homeassistant/components/hunterdouglas_powerview/select.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,5 +114,6 @@ async def async_select_option(self, option: str) -> None:
"""Change the selected option."""
await self.entity_description.select_fn(self._shade, option)
# force update data to ensure new info is in coordinator
await self._shade.refresh()
async with self.coordinator.radio_operation_lock:
await self._shade.refresh(suppress_timeout=True)
self.async_write_ha_state()
3 changes: 2 additions & 1 deletion homeassistant/components/hunterdouglas_powerview/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,5 +153,6 @@ def _async_update_shade_from_group(self) -> None:

async def async_update(self) -> None:
"""Refresh sensor entity."""
await self.entity_description.update_fn(self._shade)
async with self.coordinator.radio_operation_lock:
await self.entity_description.update_fn(self._shade)
self.async_write_ha_state()

0 comments on commit bc740f9

Please sign in to comment.