From 5cb5fe5b673b55fecdb2711dea484641d9465ca8 Mon Sep 17 00:00:00 2001 From: Manu <4445816+tr4nt0r@users.noreply.github.com> Date: Fri, 29 Aug 2025 11:37:01 +0200 Subject: [PATCH] Fix direct message notifiers in PlayStation Network (#150548) --- .../playstation_network/__init__.py | 5 +- .../playstation_network/config_flow.py | 17 +- .../playstation_network/coordinator.py | 25 +- .../components/playstation_network/helpers.py | 5 +- .../components/playstation_network/notify.py | 79 ++-- .../playstation_network/strings.json | 10 +- .../playstation_network/conftest.py | 1 + .../snapshots/test_notify.ambr | 14 +- .../snapshots/test_sensor.ambr | 415 +++++++++--------- .../playstation_network/test_config_flow.py | 3 +- .../playstation_network/test_init.py | 21 +- .../playstation_network/test_notify.py | 8 +- 12 files changed, 324 insertions(+), 279 deletions(-) diff --git a/homeassistant/components/playstation_network/__init__.py b/homeassistant/components/playstation_network/__init__.py index c2399c61f93..91214ba9ebe 100644 --- a/homeassistant/components/playstation_network/__init__.py +++ b/homeassistant/components/playstation_network/__init__.py @@ -9,6 +9,7 @@ from .const import CONF_NPSSO from .coordinator import ( PlaystationNetworkConfigEntry, PlaystationNetworkFriendDataCoordinator, + PlaystationNetworkFriendlistCoordinator, PlaystationNetworkGroupsUpdateCoordinator, PlaystationNetworkRuntimeData, PlaystationNetworkTrophyTitlesCoordinator, @@ -40,6 +41,8 @@ async def async_setup_entry( groups = PlaystationNetworkGroupsUpdateCoordinator(hass, psn, entry) await groups.async_config_entry_first_refresh() + friends_list = PlaystationNetworkFriendlistCoordinator(hass, psn, entry) + friends = {} for subentry_id, subentry in entry.subentries.items(): @@ -50,7 +53,7 @@ async def async_setup_entry( friends[subentry_id] = friend_coordinator entry.runtime_data = PlaystationNetworkRuntimeData( - coordinator, trophy_titles, groups, friends + coordinator, trophy_titles, groups, friends, friends_list ) await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) diff --git a/homeassistant/components/playstation_network/config_flow.py b/homeassistant/components/playstation_network/config_flow.py index d7d82292378..72df14dd239 100644 --- a/homeassistant/components/playstation_network/config_flow.py +++ b/homeassistant/components/playstation_network/config_flow.py @@ -10,7 +10,6 @@ from psnawp_api.core.psnawp_exceptions import ( PSNAWPInvalidTokenError, PSNAWPNotFoundError, ) -from psnawp_api.models import User from psnawp_api.utils.misc import parse_npsso_token import voluptuous as vol @@ -169,13 +168,12 @@ class PlaystationNetworkConfigFlow(ConfigFlow, domain=DOMAIN): class FriendSubentryFlowHandler(ConfigSubentryFlow): """Handle subentry flow for adding a friend.""" - friends_list: dict[str, User] - async def async_step_user( self, user_input: dict[str, Any] | None = None ) -> SubentryFlowResult: """Subentry user flow.""" config_entry: PlaystationNetworkConfigEntry = self._get_entry() + friends_list = config_entry.runtime_data.user_data.psn.friends_list if user_input is not None: config_entries = self.hass.config_entries.async_entries(DOMAIN) @@ -190,19 +188,12 @@ class FriendSubentryFlowHandler(ConfigSubentryFlow): return self.async_abort(reason="already_configured") return self.async_create_entry( - title=self.friends_list[user_input[CONF_ACCOUNT_ID]].online_id, + title=friends_list[user_input[CONF_ACCOUNT_ID]].online_id, data={}, unique_id=user_input[CONF_ACCOUNT_ID], ) - self.friends_list = await self.hass.async_add_executor_job( - lambda: { - friend.account_id: friend - for friend in config_entry.runtime_data.user_data.psn.user.friends_list() - } - ) - - if not self.friends_list: + if not friends_list: return self.async_abort(reason="no_friends") options = [ @@ -210,7 +201,7 @@ class FriendSubentryFlowHandler(ConfigSubentryFlow): value=friend.account_id, label=friend.online_id, ) - for friend in self.friends_list.values() + for friend in friends_list.values() ] return self.async_show_form( diff --git a/homeassistant/components/playstation_network/coordinator.py b/homeassistant/components/playstation_network/coordinator.py index 977632de23b..c1872a31613 100644 --- a/homeassistant/components/playstation_network/coordinator.py +++ b/homeassistant/components/playstation_network/coordinator.py @@ -45,6 +45,7 @@ class PlaystationNetworkRuntimeData: trophy_titles: PlaystationNetworkTrophyTitlesCoordinator groups: PlaystationNetworkGroupsUpdateCoordinator friends: dict[str, PlaystationNetworkFriendDataCoordinator] + friends_list: PlaystationNetworkFriendlistCoordinator class PlayStationNetworkBaseCoordinator[_DataT](DataUpdateCoordinator[_DataT]): @@ -134,6 +135,25 @@ class PlaystationNetworkTrophyTitlesCoordinator( return self.psn.trophy_titles +class PlaystationNetworkFriendlistCoordinator( + PlayStationNetworkBaseCoordinator[dict[str, User]] +): + """Friend list data update coordinator for PSN.""" + + _update_interval = timedelta(hours=3) + + async def update_data(self) -> dict[str, User]: + """Update trophy titles data.""" + + self.psn.friends_list = await self.hass.async_add_executor_job( + lambda: { + friend.account_id: friend for friend in self.psn.user.friends_list() + } + ) + await self.config_entry.runtime_data.user_data.async_request_refresh() + return self.psn.friends_list + + class PlaystationNetworkGroupsUpdateCoordinator( PlayStationNetworkBaseCoordinator[dict[str, GroupDetails]] ): @@ -178,7 +198,10 @@ class PlaystationNetworkFriendDataCoordinator( """Set up the coordinator.""" if TYPE_CHECKING: assert self.subentry.unique_id - self.user = self.psn.psn.user(account_id=self.subentry.unique_id) + self.user = self.psn.friends_list.get( + self.subentry.unique_id + ) or self.psn.psn.user(account_id=self.subentry.unique_id) + self.profile = self.user.profile() async def _async_setup(self) -> None: diff --git a/homeassistant/components/playstation_network/helpers.py b/homeassistant/components/playstation_network/helpers.py index 492a011cf78..d456cc110a4 100644 --- a/homeassistant/components/playstation_network/helpers.py +++ b/homeassistant/components/playstation_network/helpers.py @@ -60,7 +60,7 @@ class PlaystationNetwork: self.legacy_profile: dict[str, Any] | None = None self.trophy_titles: list[TrophyTitle] = [] self._title_icon_urls: dict[str, str] = {} - self.friends_list: dict[str, User] | None = None + self.friends_list: dict[str, User] = {} def _setup(self) -> None: """Setup PSN.""" @@ -68,6 +68,9 @@ class PlaystationNetwork: self.client = self.psn.me() self.shareable_profile_link = self.client.get_shareable_profile_link() self.trophy_titles = list(self.user.trophy_titles(page_size=500)) + self.friends_list = { + friend.account_id: friend for friend in self.user.friends_list() + } async def async_setup(self) -> None: """Setup PSN.""" diff --git a/homeassistant/components/playstation_network/notify.py b/homeassistant/components/playstation_network/notify.py index a06359ebffc..25c01960e3f 100644 --- a/homeassistant/components/playstation_network/notify.py +++ b/homeassistant/components/playstation_network/notify.py @@ -18,7 +18,7 @@ from homeassistant.components.notify import ( NotifyEntity, NotifyEntityDescription, ) -from homeassistant.config_entries import ConfigSubentry +from homeassistant.const import CONF_NAME from homeassistant.core import HomeAssistant, callback from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import entity_registry as er @@ -27,7 +27,7 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from .const import DOMAIN from .coordinator import ( PlaystationNetworkConfigEntry, - PlaystationNetworkFriendDataCoordinator, + PlaystationNetworkFriendlistCoordinator, PlaystationNetworkGroupsUpdateCoordinator, ) from .entity import PlaystationNetworkServiceEntity @@ -50,8 +50,10 @@ async def async_setup_entry( """Set up the notify entity platform.""" coordinator = config_entry.runtime_data.groups + friends_list = config_entry.runtime_data.friends_list groups_added: set[str] = set() + friends_added: set[str] = set() entity_registry = er.async_get(hass) @callback @@ -78,16 +80,32 @@ async def async_setup_entry( coordinator.async_add_listener(add_entities) add_entities() - for subentry_id, friend_coordinator in config_entry.runtime_data.friends.items(): - async_add_entities( - [ - PlaystationNetworkDirectMessageNotifyEntity( - friend_coordinator, - config_entry.subentries[subentry_id], - ) - ], - config_subentry_id=subentry_id, - ) + @callback + def add_dm_entities() -> None: + nonlocal friends_added + + new_friends = set(friends_list.psn.friends_list.keys()) - friends_added + if new_friends: + async_add_entities( + [ + PlaystationNetworkDirectMessageNotifyEntity( + friends_list, account_id + ) + for account_id in new_friends + ], + ) + friends_added |= new_friends + deleted_friends = friends_added - set(coordinator.psn.friends_list.keys()) + for account_id in deleted_friends: + if entity_id := entity_registry.async_get_entity_id( + NOTIFY_DOMAIN, + DOMAIN, + f"{coordinator.config_entry.unique_id}_{account_id}_{PlaystationNetworkNotify.DIRECT_MESSAGE}", + ): + entity_registry.async_remove(entity_id) + + friends_list.async_add_listener(add_dm_entities) + add_dm_entities() class PlaystationNetworkNotifyBaseEntity(PlaystationNetworkServiceEntity, NotifyEntity): @@ -95,12 +113,17 @@ class PlaystationNetworkNotifyBaseEntity(PlaystationNetworkServiceEntity, Notify group: Group | None = None - def send_message(self, message: str, title: str | None = None) -> None: - """Send a message.""" + def _send_message(self, message: str) -> None: + """Send message.""" if TYPE_CHECKING: assert self.group + self.group.send_message(message) + + def send_message(self, message: str, title: str | None = None) -> None: + """Send a message.""" + try: - self.group.send_message(message) + self._send_message(message) except PSNAWPNotFoundError as e: raise HomeAssistantError( translation_domain=DOMAIN, @@ -138,7 +161,7 @@ class PlaystationNetworkNotifyEntity(PlaystationNetworkNotifyBaseEntity): key=group_id, translation_key=PlaystationNetworkNotify.GROUP_MESSAGE, translation_placeholders={ - "group_name": group_details["groupName"]["value"] + CONF_NAME: group_details["groupName"]["value"] or ", ".join( member["onlineId"] for member in group_details["members"] @@ -153,27 +176,29 @@ class PlaystationNetworkNotifyEntity(PlaystationNetworkNotifyBaseEntity): class PlaystationNetworkDirectMessageNotifyEntity(PlaystationNetworkNotifyBaseEntity): """Representation of a PlayStation Network notify entity for sending direct messages.""" - coordinator: PlaystationNetworkFriendDataCoordinator + coordinator: PlaystationNetworkFriendlistCoordinator def __init__( self, - coordinator: PlaystationNetworkFriendDataCoordinator, - subentry: ConfigSubentry, + coordinator: PlaystationNetworkFriendlistCoordinator, + account_id: str, ) -> None: """Initialize a notification entity.""" - + self.account_id = account_id self.entity_description = NotifyEntityDescription( - key=PlaystationNetworkNotify.DIRECT_MESSAGE, + key=f"{account_id}_{PlaystationNetworkNotify.DIRECT_MESSAGE}", translation_key=PlaystationNetworkNotify.DIRECT_MESSAGE, + translation_placeholders={ + CONF_NAME: coordinator.psn.friends_list[account_id].online_id + }, + entity_registry_enabled_default=False, ) - super().__init__(coordinator, self.entity_description, subentry) - - def send_message(self, message: str, title: str | None = None) -> None: - """Send a message.""" + super().__init__(coordinator, self.entity_description) + def _send_message(self, message: str) -> None: if not self.group: self.group = self.coordinator.psn.psn.group( - users_list=[self.coordinator.user] + users_list=[self.coordinator.psn.friends_list[self.account_id]] ) - super().send_message(message, title) + super()._send_message(message) diff --git a/homeassistant/components/playstation_network/strings.json b/homeassistant/components/playstation_network/strings.json index 15b83b7cd0d..100e749f436 100644 --- a/homeassistant/components/playstation_network/strings.json +++ b/homeassistant/components/playstation_network/strings.json @@ -82,13 +82,13 @@ "message": "Data retrieval failed when trying to access the PlayStation Network." }, "group_invalid": { - "message": "Failed to send message to group {group_name}. The group is invalid or does not exist." + "message": "Failed to send message to group {name}. The group is invalid or does not exist." }, "send_message_forbidden": { - "message": "Failed to send message to group {group_name}. You are not allowed to send messages to this group." + "message": "Failed to send message to {name}. You are not allowed to send messages to this group or friend." }, "send_message_failed": { - "message": "Failed to send message to group {group_name}. Try again later." + "message": "Failed to send message to {name}. Try again later." }, "user_profile_private": { "message": "Unable to retrieve data for {user}. Privacy settings restrict access to activity." @@ -158,10 +158,10 @@ }, "notify": { "group_message": { - "name": "Group: {group_name}" + "name": "Group: {name}" }, "direct_message": { - "name": "Direct message" + "name": "Direct message: {name}" } } } diff --git a/tests/components/playstation_network/conftest.py b/tests/components/playstation_network/conftest.py index bfbdc9a72bd..f81f3842d80 100644 --- a/tests/components/playstation_network/conftest.py +++ b/tests/components/playstation_network/conftest.py @@ -184,6 +184,7 @@ def mock_psnawpapi(mock_user: MagicMock) -> Generator[MagicMock]: fren = MagicMock( spec=User, account_id="fren-psn-id", online_id="PublicUniversalFriend" ) + fren.get_presence.return_value = mock_user.get_presence.return_value client.user.return_value.friends_list.return_value = [fren] diff --git a/tests/components/playstation_network/snapshots/test_notify.ambr b/tests/components/playstation_network/snapshots/test_notify.ambr index d8c32918433..416b1da46ca 100644 --- a/tests/components/playstation_network/snapshots/test_notify.ambr +++ b/tests/components/playstation_network/snapshots/test_notify.ambr @@ -1,5 +1,5 @@ # serializer version: 1 -# name: test_notify_platform[notify.testuser_direct_message-entry] +# name: test_notify_platform[notify.testuser_direct_message_publicuniversalfriend-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -12,7 +12,7 @@ 'disabled_by': None, 'domain': 'notify', 'entity_category': None, - 'entity_id': 'notify.testuser_direct_message', + 'entity_id': 'notify.testuser_direct_message_publicuniversalfriend', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -24,24 +24,24 @@ }), 'original_device_class': None, 'original_icon': None, - 'original_name': 'Direct message', + 'original_name': 'Direct message: PublicUniversalFriend', 'platform': 'playstation_network', 'previous_unique_id': None, 'suggested_object_id': None, 'supported_features': 0, 'translation_key': , - 'unique_id': 'fren-psn-id_direct_message', + 'unique_id': 'my-psn-id_fren-psn-id_direct_message', 'unit_of_measurement': None, }) # --- -# name: test_notify_platform[notify.testuser_direct_message-state] +# name: test_notify_platform[notify.testuser_direct_message_publicuniversalfriend-state] StateSnapshot({ 'attributes': ReadOnlyDict({ - 'friendly_name': 'testuser Direct message', + 'friendly_name': 'testuser Direct message: PublicUniversalFriend', 'supported_features': , }), 'context': , - 'entity_id': 'notify.testuser_direct_message', + 'entity_id': 'notify.testuser_direct_message_publicuniversalfriend', 'last_changed': , 'last_reported': , 'last_updated': , diff --git a/tests/components/playstation_network/snapshots/test_sensor.ambr b/tests/components/playstation_network/snapshots/test_sensor.ambr index 046989cebe6..9d550e546b0 100644 --- a/tests/components/playstation_network/snapshots/test_sensor.ambr +++ b/tests/components/playstation_network/snapshots/test_sensor.ambr @@ -1,4 +1,211 @@ # serializer version: 1 +# name: test_sensors[sensor.publicuniversalfriend_last_online-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.publicuniversalfriend_last_online', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Last online', + 'platform': 'playstation_network', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': 'fren-psn-id_last_online', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensors[sensor.publicuniversalfriend_last_online-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'timestamp', + 'friendly_name': 'PublicUniversalFriend Last online', + }), + 'context': , + 'entity_id': 'sensor.publicuniversalfriend_last_online', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '2025-06-30T01:42:15+00:00', + }) +# --- +# name: test_sensors[sensor.publicuniversalfriend_now_playing-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.publicuniversalfriend_now_playing', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Now playing', + 'platform': 'playstation_network', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': 'fren-psn-id_now_playing', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensors[sensor.publicuniversalfriend_now_playing-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'PublicUniversalFriend Now playing', + }), + 'context': , + 'entity_id': 'sensor.publicuniversalfriend_now_playing', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'STAR WARS Jedi: Survivorâ„¢', + }) +# --- +# name: test_sensors[sensor.publicuniversalfriend_online_id-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.publicuniversalfriend_online_id', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Online ID', + 'platform': 'playstation_network', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': 'fren-psn-id_online_id', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensors[sensor.publicuniversalfriend_online_id-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'PublicUniversalFriend Online ID', + }), + 'context': , + 'entity_id': 'sensor.publicuniversalfriend_online_id', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'PublicUniversalFriend', + }) +# --- +# name: test_sensors[sensor.publicuniversalfriend_online_status-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'options': list([ + 'offline', + 'availabletoplay', + 'availabletocommunicate', + 'busy', + ]), + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.publicuniversalfriend_online_status', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Online status', + 'platform': 'playstation_network', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': 'fren-psn-id_online_status', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensors[sensor.publicuniversalfriend_online_status-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'enum', + 'friendly_name': 'PublicUniversalFriend Online status', + 'options': list([ + 'offline', + 'availabletoplay', + 'availabletocommunicate', + 'busy', + ]), + }), + 'context': , + 'entity_id': 'sensor.publicuniversalfriend_online_status', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'availabletoplay', + }) +# --- # name: test_sensors[sensor.testuser_bronze_trophies-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -146,55 +353,6 @@ 'state': '2025-06-30T01:42:15+00:00', }) # --- -# name: test_sensors[sensor.testuser_last_online_2-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': None, - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.testuser_last_online_2', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'options': dict({ - }), - 'original_device_class': , - 'original_icon': None, - 'original_name': 'Last online', - 'platform': 'playstation_network', - 'previous_unique_id': None, - 'suggested_object_id': None, - 'supported_features': 0, - 'translation_key': , - 'unique_id': 'fren-psn-id_last_online', - 'unit_of_measurement': None, - }) -# --- -# name: test_sensors[sensor.testuser_last_online_2-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'device_class': 'timestamp', - 'friendly_name': 'testuser Last online', - }), - 'context': , - 'entity_id': 'sensor.testuser_last_online_2', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': '2025-06-30T01:42:15+00:00', - }) -# --- # name: test_sensors[sensor.testuser_next_level-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -292,54 +450,6 @@ 'state': 'STAR WARS Jedi: Survivorâ„¢', }) # --- -# name: test_sensors[sensor.testuser_now_playing_2-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': None, - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.testuser_now_playing_2', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'options': dict({ - }), - 'original_device_class': None, - 'original_icon': None, - 'original_name': 'Now playing', - 'platform': 'playstation_network', - 'previous_unique_id': None, - 'suggested_object_id': None, - 'supported_features': 0, - 'translation_key': , - 'unique_id': 'fren-psn-id_now_playing', - 'unit_of_measurement': None, - }) -# --- -# name: test_sensors[sensor.testuser_now_playing_2-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'friendly_name': 'testuser Now playing', - }), - 'context': , - 'entity_id': 'sensor.testuser_now_playing_2', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'STAR WARS Jedi: Survivorâ„¢', - }) -# --- # name: test_sensors[sensor.testuser_online_id-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -389,55 +499,6 @@ 'state': 'testuser', }) # --- -# name: test_sensors[sensor.testuser_online_id_2-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': None, - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.testuser_online_id_2', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'options': dict({ - }), - 'original_device_class': None, - 'original_icon': None, - 'original_name': 'Online ID', - 'platform': 'playstation_network', - 'previous_unique_id': None, - 'suggested_object_id': None, - 'supported_features': 0, - 'translation_key': , - 'unique_id': 'fren-psn-id_online_id', - 'unit_of_measurement': None, - }) -# --- -# name: test_sensors[sensor.testuser_online_id_2-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'entity_picture': 'http://static-resource.np.community.playstation.net/avatar_xl/WWS_A/UP90001312L24_DD96EB6A4FF5FE883C09_XL.png', - 'friendly_name': 'testuser Online ID', - }), - 'context': , - 'entity_id': 'sensor.testuser_online_id_2', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'testuser', - }) -# --- # name: test_sensors[sensor.testuser_online_status-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -500,68 +561,6 @@ 'state': 'availabletoplay', }) # --- -# name: test_sensors[sensor.testuser_online_status_2-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': dict({ - 'options': list([ - 'offline', - 'availabletoplay', - 'availabletocommunicate', - 'busy', - ]), - }), - 'config_entry_id': , - 'config_subentry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.testuser_online_status_2', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'labels': set({ - }), - 'name': None, - 'options': dict({ - }), - 'original_device_class': , - 'original_icon': None, - 'original_name': 'Online status', - 'platform': 'playstation_network', - 'previous_unique_id': None, - 'suggested_object_id': None, - 'supported_features': 0, - 'translation_key': , - 'unique_id': 'fren-psn-id_online_status', - 'unit_of_measurement': None, - }) -# --- -# name: test_sensors[sensor.testuser_online_status_2-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'device_class': 'enum', - 'friendly_name': 'testuser Online status', - 'options': list([ - 'offline', - 'availabletoplay', - 'availabletocommunicate', - 'busy', - ]), - }), - 'context': , - 'entity_id': 'sensor.testuser_online_status_2', - 'last_changed': , - 'last_reported': , - 'last_updated': , - 'state': 'availabletoplay', - }) -# --- # name: test_sensors[sensor.testuser_platinum_trophies-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ diff --git a/tests/components/playstation_network/test_config_flow.py b/tests/components/playstation_network/test_config_flow.py index 0cd94fe153a..14c5633d384 100644 --- a/tests/components/playstation_network/test_config_flow.py +++ b/tests/components/playstation_network/test_config_flow.py @@ -501,6 +501,7 @@ async def test_add_friend_flow_no_friends( mock_psnawpapi: MagicMock, ) -> None: """Test we abort add friend subentry flow when the user has no friends.""" + mock_psnawpapi.user.return_value.friends_list.return_value = [] config_entry.add_to_hass(hass) assert await hass.config_entries.async_setup(config_entry.entry_id) @@ -508,8 +509,6 @@ async def test_add_friend_flow_no_friends( assert config_entry.state is ConfigEntryState.LOADED - mock_psnawpapi.user.return_value.friends_list.return_value = [] - result = await hass.config_entries.subentries.async_init( (config_entry.entry_id, "friend"), context={"source": SOURCE_USER}, diff --git a/tests/components/playstation_network/test_init.py b/tests/components/playstation_network/test_init.py index 6db4cb6ab6a..e5a361a3cfb 100644 --- a/tests/components/playstation_network/test_init.py +++ b/tests/components/playstation_network/test_init.py @@ -278,10 +278,9 @@ async def test_friends_coordinator_update_data_failed( ) -> None: """Test friends coordinator setup fails in _update_data.""" - mock_psnawpapi.user.return_value.get_presence.side_effect = [ - mock_psnawpapi.user.return_value.get_presence.return_value, - exception, - ] + mock = mock_psnawpapi.user.return_value.friends_list.return_value[0] + mock.get_presence.side_effect = exception + config_entry.add_to_hass(hass) await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() @@ -306,11 +305,9 @@ async def test_friends_coordinator_setup_failed( state: ConfigEntryState, ) -> None: """Test friends coordinator setup fails in _async_setup.""" + mock = mock_psnawpapi.user.return_value.friends_list.return_value[0] + mock.profile.side_effect = exception - mock_psnawpapi.user.side_effect = [ - mock_psnawpapi.user.return_value, - exception, - ] config_entry.add_to_hass(hass) await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() @@ -324,10 +321,10 @@ async def test_friends_coordinator_auth_failed( mock_psnawpapi: MagicMock, ) -> None: """Test friends coordinator starts reauth on authentication error.""" - mock_psnawpapi.user.side_effect = [ - mock_psnawpapi.user.return_value, - PSNAWPAuthenticationError, - ] + + mock = mock_psnawpapi.user.return_value.friends_list.return_value[0] + mock.profile.side_effect = PSNAWPAuthenticationError + config_entry.add_to_hass(hass) await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() diff --git a/tests/components/playstation_network/test_notify.py b/tests/components/playstation_network/test_notify.py index f81e03dfcc4..e99609980ae 100644 --- a/tests/components/playstation_network/test_notify.py +++ b/tests/components/playstation_network/test_notify.py @@ -37,7 +37,7 @@ async def notify_only() -> AsyncGenerator[None]: yield -@pytest.mark.usefixtures("mock_psnawpapi") +@pytest.mark.usefixtures("mock_psnawpapi", "entity_registry_enabled_by_default") async def test_notify_platform( hass: HomeAssistant, config_entry: MockConfigEntry, @@ -57,9 +57,13 @@ async def test_notify_platform( @pytest.mark.parametrize( "entity_id", - ["notify.testuser_group_publicuniversalfriend", "notify.testuser_direct_message"], + [ + "notify.testuser_group_publicuniversalfriend", + "notify.testuser_direct_message_publicuniversalfriend", + ], ) @freeze_time("2025-07-28T00:00:00+00:00") +@pytest.mark.usefixtures("entity_registry_enabled_by_default") async def test_send_message( hass: HomeAssistant, config_entry: MockConfigEntry,