diff --git a/homeassistant/components/songpal/media_player.py b/homeassistant/components/songpal/media_player.py index 7492bd536e3..e161f818c8c 100644 --- a/homeassistant/components/songpal/media_player.py +++ b/homeassistant/components/songpal/media_player.py @@ -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, diff --git a/tests/components/songpal/__init__.py b/tests/components/songpal/__init__.py index f3004ef22e2..a9ca62ecb09 100644 --- a/tests/components/songpal/__init__.py +++ b/tests/components/songpal/__init__.py @@ -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() diff --git a/tests/components/songpal/test_media_player.py b/tests/components/songpal/test_media_player.py index 0fd5644e794..815995814f9 100644 --- a/tests/components/songpal/test_media_player.py +++ b/tests/components/songpal/test_media_player.py @@ -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):