Support songpal wireless-only soundbar identifiers (#65330)
As shown in #64868, a number of newer models don't come wiht a macAddr attributes, so for those fall back to the wireless address. This could be hidden by the python-songpal library but for now this will make it possible to have multiple modern songpal devices on the same network.pull/65956/head
parent
63d3a47599
commit
c6aa526469
|
@ -212,13 +212,18 @@ class SongpalEntity(MediaPlayerEntity):
|
|||
@property
|
||||
def unique_id(self):
|
||||
"""Return a unique ID."""
|
||||
return self._sysinfo.macAddr
|
||||
return self._sysinfo.macAddr or self._sysinfo.wirelessMacAddr
|
||||
|
||||
@property
|
||||
def device_info(self) -> DeviceInfo:
|
||||
"""Return the device info."""
|
||||
connections = set()
|
||||
if self._sysinfo.macAddr:
|
||||
connections.add((dr.CONNECTION_NETWORK_MAC, self._sysinfo.macAddr))
|
||||
if self._sysinfo.wirelessMacAddr:
|
||||
connections.add((dr.CONNECTION_NETWORK_MAC, self._sysinfo.wirelessMacAddr))
|
||||
return DeviceInfo(
|
||||
connections={(dr.CONNECTION_NETWORK_MAC, self._sysinfo.macAddr)},
|
||||
connections=connections,
|
||||
identifiers={(DOMAIN, self.unique_id)},
|
||||
manufacturer="Sony Corporation",
|
||||
model=self._model,
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
from songpal import SongpalException
|
||||
from songpal.containers import Sysinfo
|
||||
|
||||
from homeassistant.components.songpal.const import CONF_ENDPOINT
|
||||
from homeassistant.const import CONF_NAME
|
||||
|
@ -12,6 +13,7 @@ HOST = "0.0.0.0"
|
|||
ENDPOINT = f"http://{HOST}:10000/sony"
|
||||
MODEL = "model"
|
||||
MAC = "mac"
|
||||
WIRELESS_MAC = "wmac"
|
||||
SW_VERSION = "sw_ver"
|
||||
|
||||
CONF_DATA = {
|
||||
|
@ -20,7 +22,7 @@ CONF_DATA = {
|
|||
}
|
||||
|
||||
|
||||
def _create_mocked_device(throw_exception=False):
|
||||
def _create_mocked_device(throw_exception=False, wired_mac=MAC, wireless_mac=None):
|
||||
mocked_device = MagicMock()
|
||||
|
||||
type(mocked_device).get_supported_methods = AsyncMock(
|
||||
|
@ -35,9 +37,15 @@ def _create_mocked_device(throw_exception=False):
|
|||
return_value=interface_info
|
||||
)
|
||||
|
||||
sys_info = MagicMock()
|
||||
sys_info.macAddr = MAC
|
||||
sys_info.version = SW_VERSION
|
||||
sys_info = Sysinfo(
|
||||
bdAddr=None,
|
||||
macAddr=wired_mac,
|
||||
wirelessMacAddr=wireless_mac,
|
||||
bssid=None,
|
||||
ssid=None,
|
||||
bleID=None,
|
||||
version=SW_VERSION,
|
||||
)
|
||||
type(mocked_device).get_system_info = AsyncMock(return_value=sys_info)
|
||||
|
||||
volume1 = MagicMock()
|
||||
|
|
|
@ -29,6 +29,7 @@ from . import (
|
|||
MAC,
|
||||
MODEL,
|
||||
SW_VERSION,
|
||||
WIRELESS_MAC,
|
||||
_create_mocked_device,
|
||||
_patch_media_player_device,
|
||||
)
|
||||
|
@ -126,6 +127,78 @@ async def test_state(hass):
|
|||
assert entity.unique_id == MAC
|
||||
|
||||
|
||||
async def test_state_wireless(hass):
|
||||
"""Test state of the entity with only Wireless MAC."""
|
||||
mocked_device = _create_mocked_device(wired_mac=None, wireless_mac=WIRELESS_MAC)
|
||||
entry = MockConfigEntry(domain=songpal.DOMAIN, data=CONF_DATA)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
with _patch_media_player_device(mocked_device):
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get(ENTITY_ID)
|
||||
assert state.name == FRIENDLY_NAME
|
||||
assert state.state == STATE_ON
|
||||
attributes = state.as_dict()["attributes"]
|
||||
assert attributes["volume_level"] == 0.5
|
||||
assert attributes["is_volume_muted"] is False
|
||||
assert attributes["source_list"] == ["title1", "title2"]
|
||||
assert attributes["source"] == "title2"
|
||||
assert attributes["supported_features"] == SUPPORT_SONGPAL
|
||||
|
||||
device_registry = dr.async_get(hass)
|
||||
device = device_registry.async_get_device(
|
||||
identifiers={(songpal.DOMAIN, WIRELESS_MAC)}
|
||||
)
|
||||
assert device.connections == {(dr.CONNECTION_NETWORK_MAC, WIRELESS_MAC)}
|
||||
assert device.manufacturer == "Sony Corporation"
|
||||
assert device.name == FRIENDLY_NAME
|
||||
assert device.sw_version == SW_VERSION
|
||||
assert device.model == MODEL
|
||||
|
||||
entity_registry = er.async_get(hass)
|
||||
entity = entity_registry.async_get(ENTITY_ID)
|
||||
assert entity.unique_id == WIRELESS_MAC
|
||||
|
||||
|
||||
async def test_state_both(hass):
|
||||
"""Test state of the entity with both Wired and Wireless MAC."""
|
||||
mocked_device = _create_mocked_device(wired_mac=MAC, wireless_mac=WIRELESS_MAC)
|
||||
entry = MockConfigEntry(domain=songpal.DOMAIN, data=CONF_DATA)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
with _patch_media_player_device(mocked_device):
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
state = hass.states.get(ENTITY_ID)
|
||||
assert state.name == FRIENDLY_NAME
|
||||
assert state.state == STATE_ON
|
||||
attributes = state.as_dict()["attributes"]
|
||||
assert attributes["volume_level"] == 0.5
|
||||
assert attributes["is_volume_muted"] is False
|
||||
assert attributes["source_list"] == ["title1", "title2"]
|
||||
assert attributes["source"] == "title2"
|
||||
assert attributes["supported_features"] == SUPPORT_SONGPAL
|
||||
|
||||
device_registry = dr.async_get(hass)
|
||||
device = device_registry.async_get_device(identifiers={(songpal.DOMAIN, MAC)})
|
||||
assert device.connections == {
|
||||
(dr.CONNECTION_NETWORK_MAC, MAC),
|
||||
(dr.CONNECTION_NETWORK_MAC, WIRELESS_MAC),
|
||||
}
|
||||
assert device.manufacturer == "Sony Corporation"
|
||||
assert device.name == FRIENDLY_NAME
|
||||
assert device.sw_version == SW_VERSION
|
||||
assert device.model == MODEL
|
||||
|
||||
entity_registry = er.async_get(hass)
|
||||
entity = entity_registry.async_get(ENTITY_ID)
|
||||
# We prefer the wired mac if present.
|
||||
assert entity.unique_id == MAC
|
||||
|
||||
|
||||
async def test_services(hass):
|
||||
"""Test services."""
|
||||
mocked_device = _create_mocked_device()
|
||||
|
@ -173,11 +246,7 @@ async def test_services(hass):
|
|||
mocked_device.set_sound_settings.assert_called_once_with("name", "value")
|
||||
mocked_device.set_sound_settings.reset_mock()
|
||||
|
||||
mocked_device2 = _create_mocked_device()
|
||||
sys_info = MagicMock()
|
||||
sys_info.macAddr = "mac2"
|
||||
sys_info.version = SW_VERSION
|
||||
type(mocked_device2).get_system_info = AsyncMock(return_value=sys_info)
|
||||
mocked_device2 = _create_mocked_device(wired_mac="mac2")
|
||||
entry2 = MockConfigEntry(
|
||||
domain=songpal.DOMAIN, data={CONF_NAME: "d2", CONF_ENDPOINT: ENDPOINT}
|
||||
)
|
||||
|
@ -194,6 +263,27 @@ async def test_services(hass):
|
|||
)
|
||||
mocked_device.set_sound_settings.assert_called_once_with("name", "value")
|
||||
mocked_device2.set_sound_settings.assert_called_once_with("name", "value")
|
||||
mocked_device.set_sound_settings.reset_mock()
|
||||
mocked_device2.set_sound_settings.reset_mock()
|
||||
|
||||
mocked_device3 = _create_mocked_device(wired_mac=None, wireless_mac=WIRELESS_MAC)
|
||||
entry3 = MockConfigEntry(
|
||||
domain=songpal.DOMAIN, data={CONF_NAME: "d2", CONF_ENDPOINT: ENDPOINT}
|
||||
)
|
||||
entry3.add_to_hass(hass)
|
||||
with _patch_media_player_device(mocked_device3):
|
||||
await hass.config_entries.async_setup(entry3.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
await hass.services.async_call(
|
||||
songpal.DOMAIN,
|
||||
SET_SOUND_SETTING,
|
||||
{"entity_id": "all", "name": "name", "value": "value"},
|
||||
blocking=True,
|
||||
)
|
||||
mocked_device.set_sound_settings.assert_called_once_with("name", "value")
|
||||
mocked_device2.set_sound_settings.assert_called_once_with("name", "value")
|
||||
mocked_device3.set_sound_settings.assert_called_once_with("name", "value")
|
||||
|
||||
|
||||
async def test_websocket_events(hass):
|
||||
|
|
Loading…
Reference in New Issue