Fix status update loop in bluesound integration (#123790)
* Fix retry loop for status update * Use 'available' instead of _is_online * Fix tests
This commit is contained in:
parent
193a7b7360
commit
30994710e6
3 changed files with 55 additions and 21 deletions
|
@ -244,7 +244,6 @@ class BluesoundPlayer(MediaPlayerEntity):
|
|||
self._status: Status | None = None
|
||||
self._inputs: list[Input] = []
|
||||
self._presets: list[Preset] = []
|
||||
self._is_online = False
|
||||
self._muted = False
|
||||
self._master: BluesoundPlayer | None = None
|
||||
self._is_master = False
|
||||
|
@ -312,20 +311,24 @@ class BluesoundPlayer(MediaPlayerEntity):
|
|||
|
||||
async def _start_poll_command(self):
|
||||
"""Loop which polls the status of the player."""
|
||||
try:
|
||||
while True:
|
||||
while True:
|
||||
try:
|
||||
await self.async_update_status()
|
||||
|
||||
except (TimeoutError, ClientError):
|
||||
_LOGGER.error("Node %s:%s is offline, retrying later", self.host, self.port)
|
||||
await asyncio.sleep(NODE_OFFLINE_CHECK_TIMEOUT)
|
||||
self.start_polling()
|
||||
|
||||
except CancelledError:
|
||||
_LOGGER.debug("Stopping the polling of node %s:%s", self.host, self.port)
|
||||
except Exception:
|
||||
_LOGGER.exception("Unexpected error in %s:%s", self.host, self.port)
|
||||
raise
|
||||
except (TimeoutError, ClientError):
|
||||
_LOGGER.error(
|
||||
"Node %s:%s is offline, retrying later", self.host, self.port
|
||||
)
|
||||
await asyncio.sleep(NODE_OFFLINE_CHECK_TIMEOUT)
|
||||
except CancelledError:
|
||||
_LOGGER.debug(
|
||||
"Stopping the polling of node %s:%s", self.host, self.port
|
||||
)
|
||||
return
|
||||
except Exception:
|
||||
_LOGGER.exception(
|
||||
"Unexpected error in %s:%s, retrying later", self.host, self.port
|
||||
)
|
||||
await asyncio.sleep(NODE_OFFLINE_CHECK_TIMEOUT)
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
"""Start the polling task."""
|
||||
|
@ -348,7 +351,7 @@ class BluesoundPlayer(MediaPlayerEntity):
|
|||
|
||||
async def async_update(self) -> None:
|
||||
"""Update internal status of the entity."""
|
||||
if not self._is_online:
|
||||
if not self.available:
|
||||
return
|
||||
|
||||
with suppress(TimeoutError):
|
||||
|
@ -365,7 +368,7 @@ class BluesoundPlayer(MediaPlayerEntity):
|
|||
try:
|
||||
status = await self._player.status(etag=etag, poll_timeout=120, timeout=125)
|
||||
|
||||
self._is_online = True
|
||||
self._attr_available = True
|
||||
self._last_status_update = dt_util.utcnow()
|
||||
self._status = status
|
||||
|
||||
|
@ -394,7 +397,7 @@ class BluesoundPlayer(MediaPlayerEntity):
|
|||
|
||||
self.async_write_ha_state()
|
||||
except (TimeoutError, ClientError):
|
||||
self._is_online = False
|
||||
self._attr_available = False
|
||||
self._last_status_update = None
|
||||
self._status = None
|
||||
self.async_write_ha_state()
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
from collections.abc import Generator
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from pyblu import SyncStatus
|
||||
from pyblu import Status, SyncStatus
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.bluesound.const import DOMAIN
|
||||
|
@ -39,6 +39,35 @@ def sync_status() -> SyncStatus:
|
|||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def status() -> Status:
|
||||
"""Return a status object."""
|
||||
return Status(
|
||||
etag="etag",
|
||||
input_id=None,
|
||||
service=None,
|
||||
state="playing",
|
||||
shuffle=False,
|
||||
album=None,
|
||||
artist=None,
|
||||
name=None,
|
||||
image=None,
|
||||
volume=10,
|
||||
volume_db=22.3,
|
||||
mute=False,
|
||||
mute_volume=None,
|
||||
mute_volume_db=None,
|
||||
seconds=2,
|
||||
total_seconds=123.1,
|
||||
can_seek=False,
|
||||
sleep=0,
|
||||
group_name=None,
|
||||
group_volume=None,
|
||||
indexing=False,
|
||||
stream_url=None,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_setup_entry() -> Generator[AsyncMock]:
|
||||
"""Override async_setup_entry."""
|
||||
|
@ -65,7 +94,7 @@ def mock_config_entry(hass: HomeAssistant) -> MockConfigEntry:
|
|||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_player() -> Generator[AsyncMock]:
|
||||
def mock_player(status: Status) -> Generator[AsyncMock]:
|
||||
"""Mock the player."""
|
||||
with (
|
||||
patch(
|
||||
|
@ -78,7 +107,7 @@ def mock_player() -> Generator[AsyncMock]:
|
|||
):
|
||||
player = mock_player.return_value
|
||||
player.__aenter__.return_value = player
|
||||
player.status.return_value = None
|
||||
player.status.return_value = status
|
||||
player.sync_status.return_value = SyncStatus(
|
||||
etag="etag",
|
||||
id="1.1.1.1:11000",
|
||||
|
|
|
@ -41,7 +41,7 @@ async def test_user_flow_success(
|
|||
|
||||
|
||||
async def test_user_flow_cannot_connect(
|
||||
hass: HomeAssistant, mock_player: AsyncMock
|
||||
hass: HomeAssistant, mock_player: AsyncMock, mock_setup_entry: AsyncMock
|
||||
) -> None:
|
||||
"""Test we handle cannot connect error."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
|
@ -76,6 +76,8 @@ async def test_user_flow_cannot_connect(
|
|||
CONF_PORT: 11000,
|
||||
}
|
||||
|
||||
mock_setup_entry.assert_called_once()
|
||||
|
||||
|
||||
async def test_user_flow_aleady_configured(
|
||||
hass: HomeAssistant,
|
||||
|
|
Loading…
Add table
Reference in a new issue