mirror of
https://github.com/home-assistant/core.git
synced 2025-07-21 12:17:07 +00:00
Add sub-device support to Russound RIO (#146763)
This commit is contained in:
parent
e28965770e
commit
1b73acc025
@ -9,6 +9,8 @@ from homeassistant.config_entries import ConfigEntry
|
|||||||
from homeassistant.const import CONF_HOST, CONF_PORT, Platform
|
from homeassistant.const import CONF_HOST, CONF_PORT, Platform
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import ConfigEntryNotReady
|
from homeassistant.exceptions import ConfigEntryNotReady
|
||||||
|
from homeassistant.helpers import device_registry as dr
|
||||||
|
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC
|
||||||
|
|
||||||
from .const import DOMAIN, RUSSOUND_RIO_EXCEPTIONS
|
from .const import DOMAIN, RUSSOUND_RIO_EXCEPTIONS
|
||||||
|
|
||||||
@ -52,6 +54,39 @@ async def async_setup_entry(hass: HomeAssistant, entry: RussoundConfigEntry) ->
|
|||||||
) from err
|
) from err
|
||||||
entry.runtime_data = client
|
entry.runtime_data = client
|
||||||
|
|
||||||
|
device_registry = dr.async_get(hass)
|
||||||
|
|
||||||
|
for controller_id, controller in client.controllers.items():
|
||||||
|
_device_identifier = (
|
||||||
|
controller.mac_address
|
||||||
|
or f"{client.controllers[1].mac_address}-{controller_id}"
|
||||||
|
)
|
||||||
|
connections = None
|
||||||
|
via_device = None
|
||||||
|
configuration_url = None
|
||||||
|
if controller_id != 1:
|
||||||
|
assert client.controllers[1].mac_address
|
||||||
|
via_device = (
|
||||||
|
DOMAIN,
|
||||||
|
client.controllers[1].mac_address,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
assert controller.mac_address
|
||||||
|
connections = {(CONNECTION_NETWORK_MAC, controller.mac_address)}
|
||||||
|
if isinstance(client.connection_handler, RussoundTcpConnectionHandler):
|
||||||
|
configuration_url = f"http://{client.connection_handler.host}"
|
||||||
|
device_registry.async_get_or_create(
|
||||||
|
config_entry_id=entry.entry_id,
|
||||||
|
identifiers={(DOMAIN, _device_identifier)},
|
||||||
|
manufacturer="Russound",
|
||||||
|
name=controller.controller_type,
|
||||||
|
model=controller.controller_type,
|
||||||
|
sw_version=controller.firmware_version,
|
||||||
|
connections=connections,
|
||||||
|
via_device=via_device,
|
||||||
|
configuration_url=configuration_url,
|
||||||
|
)
|
||||||
|
|
||||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
@ -4,11 +4,11 @@ from collections.abc import Awaitable, Callable, Coroutine
|
|||||||
from functools import wraps
|
from functools import wraps
|
||||||
from typing import Any, Concatenate
|
from typing import Any, Concatenate
|
||||||
|
|
||||||
from aiorussound import Controller, RussoundClient, RussoundTcpConnectionHandler
|
from aiorussound import Controller, RussoundClient
|
||||||
from aiorussound.models import CallbackType
|
from aiorussound.models import CallbackType
|
||||||
|
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo
|
from homeassistant.helpers.device_registry import DeviceInfo
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.entity import Entity
|
||||||
|
|
||||||
from .const import DOMAIN, RUSSOUND_RIO_EXCEPTIONS
|
from .const import DOMAIN, RUSSOUND_RIO_EXCEPTIONS
|
||||||
@ -46,6 +46,7 @@ class RussoundBaseEntity(Entity):
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
controller: Controller,
|
controller: Controller,
|
||||||
|
zone_id: int | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize the entity."""
|
"""Initialize the entity."""
|
||||||
self._client = controller.client
|
self._client = controller.client
|
||||||
@ -57,29 +58,21 @@ class RussoundBaseEntity(Entity):
|
|||||||
self._controller.mac_address
|
self._controller.mac_address
|
||||||
or f"{self._primary_mac_address}-{self._controller.controller_id}"
|
or f"{self._primary_mac_address}-{self._controller.controller_id}"
|
||||||
)
|
)
|
||||||
|
if not zone_id:
|
||||||
|
self._attr_device_info = DeviceInfo(
|
||||||
|
identifiers={(DOMAIN, self._device_identifier)},
|
||||||
|
)
|
||||||
|
return
|
||||||
|
zone = controller.zones[zone_id]
|
||||||
self._attr_device_info = DeviceInfo(
|
self._attr_device_info = DeviceInfo(
|
||||||
# Use MAC address of Russound device as identifier
|
identifiers={(DOMAIN, f"{self._device_identifier}-{zone_id}")},
|
||||||
identifiers={(DOMAIN, self._device_identifier)},
|
name=zone.name,
|
||||||
manufacturer="Russound",
|
manufacturer="Russound",
|
||||||
name=controller.controller_type,
|
|
||||||
model=controller.controller_type,
|
model=controller.controller_type,
|
||||||
sw_version=controller.firmware_version,
|
sw_version=controller.firmware_version,
|
||||||
|
suggested_area=zone.name,
|
||||||
|
via_device=(DOMAIN, self._device_identifier),
|
||||||
)
|
)
|
||||||
if isinstance(self._client.connection_handler, RussoundTcpConnectionHandler):
|
|
||||||
self._attr_device_info["configuration_url"] = (
|
|
||||||
f"http://{self._client.connection_handler.host}"
|
|
||||||
)
|
|
||||||
if controller.controller_id != 1:
|
|
||||||
assert self._client.controllers[1].mac_address
|
|
||||||
self._attr_device_info["via_device"] = (
|
|
||||||
DOMAIN,
|
|
||||||
self._client.controllers[1].mac_address,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
assert controller.mac_address
|
|
||||||
self._attr_device_info["connections"] = {
|
|
||||||
(CONNECTION_NETWORK_MAC, controller.mac_address)
|
|
||||||
}
|
|
||||||
|
|
||||||
async def _state_update_callback(
|
async def _state_update_callback(
|
||||||
self, _client: RussoundClient, _callback_type: CallbackType
|
self, _client: RussoundClient, _callback_type: CallbackType
|
||||||
|
@ -60,16 +60,16 @@ class RussoundZoneDevice(RussoundBaseEntity, MediaPlayerEntity):
|
|||||||
| MediaPlayerEntityFeature.SELECT_SOURCE
|
| MediaPlayerEntityFeature.SELECT_SOURCE
|
||||||
| MediaPlayerEntityFeature.SEEK
|
| MediaPlayerEntityFeature.SEEK
|
||||||
)
|
)
|
||||||
|
_attr_name = None
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, controller: Controller, zone_id: int, sources: dict[int, Source]
|
self, controller: Controller, zone_id: int, sources: dict[int, Source]
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize the zone device."""
|
"""Initialize the zone device."""
|
||||||
super().__init__(controller)
|
super().__init__(controller, zone_id)
|
||||||
self._zone_id = zone_id
|
self._zone_id = zone_id
|
||||||
_zone = self._zone
|
_zone = self._zone
|
||||||
self._sources = sources
|
self._sources = sources
|
||||||
self._attr_name = _zone.name
|
|
||||||
self._attr_unique_id = f"{self._primary_mac_address}-{_zone.device_str}"
|
self._attr_unique_id = f"{self._primary_mac_address}-{_zone.device_str}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -17,6 +17,5 @@ MOCK_RECONFIGURATION_CONFIG = {
|
|||||||
CONF_PORT: 9622,
|
CONF_PORT: 9622,
|
||||||
}
|
}
|
||||||
|
|
||||||
DEVICE_NAME = "mca_c5"
|
|
||||||
NAME_ZONE_1 = "backyard"
|
NAME_ZONE_1 = "backyard"
|
||||||
ENTITY_ID_ZONE_1 = f"{MP_DOMAIN}.{DEVICE_NAME}_{NAME_ZONE_1}"
|
ENTITY_ID_ZONE_1 = f"{MP_DOMAIN}.{NAME_ZONE_1}"
|
||||||
|
@ -207,7 +207,7 @@ async def test_invalid_source_service(
|
|||||||
|
|
||||||
with pytest.raises(
|
with pytest.raises(
|
||||||
HomeAssistantError,
|
HomeAssistantError,
|
||||||
match="Error executing async_select_source on entity media_player.mca_c5_backyard",
|
match="Error executing async_select_source on entity media_player.backyard",
|
||||||
):
|
):
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
MP_DOMAIN,
|
MP_DOMAIN,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user