mirror of
https://github.com/home-assistant/core.git
synced 2026-09-25 07:51:46 -05:00
Fix Openhome players becoming unavailable between polls (#181238)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
a0759acb9a
commit
f35f3afaec
@@ -2,15 +2,15 @@
|
||||
|
||||
import logging
|
||||
|
||||
import aiohttp
|
||||
from async_upnp_client.client import UpnpError
|
||||
from openhomedevice.device import Device
|
||||
from openhomedevice.exceptions import OpenhomeError
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_HOST, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ConfigEntryNotReady
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
|
||||
from .const import DOMAIN
|
||||
@@ -37,11 +37,11 @@ async def async_setup_entry(
|
||||
"""Set up the configuration config entry."""
|
||||
_LOGGER.debug("Setting up config entry: %s", config_entry.unique_id)
|
||||
|
||||
device = await hass.async_add_executor_job(Device, config_entry.data[CONF_HOST])
|
||||
device = Device(config_entry.data[CONF_HOST], session=async_get_clientsession(hass))
|
||||
|
||||
try:
|
||||
await device.init()
|
||||
except (TimeoutError, aiohttp.ClientError, UpnpError) as exc:
|
||||
except OpenhomeError as exc:
|
||||
raise ConfigEntryNotReady from exc
|
||||
|
||||
_LOGGER.debug("Initialised device: %s", device.uuid())
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"integration_type": "device",
|
||||
"iot_class": "local_polling",
|
||||
"loggers": ["async_upnp_client", "openhomedevice"],
|
||||
"requirements": ["openhomedevice==2.2.0"],
|
||||
"requirements": ["openhomedevice==2.5"],
|
||||
"ssdp": [
|
||||
{
|
||||
"st": "urn:av-openhome-org:service:Product:1"
|
||||
|
||||
@@ -5,8 +5,7 @@ import functools
|
||||
import logging
|
||||
from typing import Any, Concatenate, override
|
||||
|
||||
import aiohttp
|
||||
from async_upnp_client.client import UpnpError
|
||||
from openhomedevice.exceptions import OpenhomeError
|
||||
|
||||
from homeassistant.components import media_source
|
||||
from homeassistant.components.media_player import (
|
||||
@@ -58,7 +57,7 @@ type _ReturnFuncType[_T, **_P, _R] = Callable[
|
||||
def catch_request_errors[_OpenhomeDeviceT: OpenhomeDevice, **_P, _R]() -> Callable[
|
||||
[_FuncType[_OpenhomeDeviceT, _P, _R]], _ReturnFuncType[_OpenhomeDeviceT, _P, _R]
|
||||
]:
|
||||
"""Catch TimeoutError, aiohttp.ClientError, UpnpError errors."""
|
||||
"""Catch OpenhomeError errors."""
|
||||
|
||||
def call_wrapper(
|
||||
func: _FuncType[_OpenhomeDeviceT, _P, _R],
|
||||
@@ -69,11 +68,11 @@ def catch_request_errors[_OpenhomeDeviceT: OpenhomeDevice, **_P, _R]() -> Callab
|
||||
async def wrapper(
|
||||
self: _OpenhomeDeviceT, *args: _P.args, **kwargs: _P.kwargs
|
||||
) -> _R | None:
|
||||
"""Catch TimeoutError, aiohttp.ClientError, UpnpError errors."""
|
||||
"""Catch OpenhomeError errors."""
|
||||
try:
|
||||
return await func(self, *args, **kwargs)
|
||||
except TimeoutError, aiohttp.ClientError, UpnpError:
|
||||
_LOGGER.error("Error during call %s", func.__name__)
|
||||
except OpenhomeError as err:
|
||||
_LOGGER.error("Error during call %s: %s", func.__name__, err)
|
||||
return None
|
||||
|
||||
return wrapper
|
||||
@@ -167,7 +166,9 @@ class OpenhomeDevice(MediaPlayerEntity):
|
||||
self._attr_state = MediaPlayerState.PLAYING
|
||||
|
||||
self._attr_available = True
|
||||
except TimeoutError, aiohttp.ClientError, UpnpError:
|
||||
except OpenhomeError as err:
|
||||
if self._attr_available:
|
||||
_LOGGER.warning("Error updating %s: %s", self.entity_id, err)
|
||||
self._attr_available = False
|
||||
|
||||
# pylint: disable-next=home-assistant-action-swallowed-exception
|
||||
@@ -261,8 +262,8 @@ class OpenhomeDevice(MediaPlayerEntity):
|
||||
await self._device.invoke_pin(pin)
|
||||
else:
|
||||
_LOGGER.error("Pins service not supported")
|
||||
except UpnpError:
|
||||
_LOGGER.error("Error invoking pin %s", pin)
|
||||
except OpenhomeError as err:
|
||||
_LOGGER.error("Error invoking pin %s: %s", pin, err)
|
||||
|
||||
# pylint: disable-next=home-assistant-action-swallowed-exception
|
||||
@catch_request_errors()
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
import logging
|
||||
from typing import Any, override
|
||||
|
||||
import aiohttp
|
||||
from async_upnp_client.client import UpnpError
|
||||
from openhomedevice.exceptions import OpenhomeError
|
||||
|
||||
from homeassistant.components.update import (
|
||||
UpdateDeviceClass,
|
||||
@@ -92,7 +91,7 @@ class OpenhomeUpdateEntity(UpdateEntity):
|
||||
try:
|
||||
if self.latest_version:
|
||||
await self._device.update_firmware()
|
||||
except (TimeoutError, aiohttp.ClientError, UpnpError) as err:
|
||||
except OpenhomeError as err:
|
||||
raise HomeAssistantError(
|
||||
f"Error updating {self._device.device.friendly_name}: {err}"
|
||||
) from err
|
||||
|
||||
Generated
+1
-1
@@ -1815,7 +1815,7 @@ openai==2.45.0
|
||||
openerz-api==0.3.0
|
||||
|
||||
# homeassistant.components.openhome
|
||||
openhomedevice==2.2.0
|
||||
openhomedevice==2.5
|
||||
|
||||
# homeassistant.components.openrgb
|
||||
openrgb-python==0.3.6
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
"""Tests for the Openhome integration setup."""
|
||||
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
from homeassistant.components.openhome.const import DOMAIN
|
||||
from homeassistant.config_entries import ConfigEntryState
|
||||
from homeassistant.const import CONF_HOST
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
HOST = "http://localhost"
|
||||
|
||||
|
||||
async def test_device_uses_shared_session(hass: HomeAssistant) -> None:
|
||||
"""Test the device is given Home Assistant's shared aiohttp session."""
|
||||
entry = MockConfigEntry(domain=DOMAIN, data={CONF_HOST: HOST}, unique_id="uuid")
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
with (
|
||||
patch("homeassistant.components.openhome.PLATFORMS", []),
|
||||
patch("homeassistant.components.openhome.Device", MagicMock()) as mock_device,
|
||||
):
|
||||
mock_device.return_value.init = AsyncMock()
|
||||
mock_device.return_value.uuid = MagicMock(return_value="uuid")
|
||||
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert entry.state is ConfigEntryState.LOADED
|
||||
mock_device.assert_called_once_with(HOST, session=async_get_clientsession(hass))
|
||||
Reference in New Issue
Block a user