From 2e99a5e2aae7b5ef5ccdb25181c36367fdfb928a Mon Sep 17 00:00:00 2001 From: Manu Date: Sun, 26 Jul 2026 17:59:32 +0200 Subject: [PATCH] Add image platform to Steam integration (#176346) Co-authored-by: Joost Lekkerkerker --- .../components/steam_online/__init__.py | 2 +- .../components/steam_online/const.py | 2 +- .../components/steam_online/entity.py | 16 +- .../components/steam_online/icons.json | 5 + .../components/steam_online/image.py | 190 +++ .../components/steam_online/sensor.py | 6 - .../components/steam_online/strings.json | 32 + .../steam_online/fixtures/GetOwnedGames.json | 14 + .../fixtures/GetPlayerSummaries2.json | 39 + .../steam_online/snapshots/test_image.ambr | 1032 +++++++++++++++++ .../steam_online/snapshots/test_sensor.ambr | 4 +- tests/components/steam_online/test_image.py | 131 +++ 12 files changed, 1459 insertions(+), 14 deletions(-) create mode 100644 homeassistant/components/steam_online/image.py create mode 100644 tests/components/steam_online/fixtures/GetPlayerSummaries2.json create mode 100644 tests/components/steam_online/snapshots/test_image.ambr create mode 100644 tests/components/steam_online/test_image.py diff --git a/homeassistant/components/steam_online/__init__.py b/homeassistant/components/steam_online/__init__.py index 182c0a789372..4024d747efc8 100644 --- a/homeassistant/components/steam_online/__init__.py +++ b/homeassistant/components/steam_online/__init__.py @@ -10,7 +10,7 @@ from homeassistant.helpers import device_registry as dr, entity_registry as er from .const import CONF_ACCOUNTS, DOMAIN, SUBENTRY_TYPE_FRIEND from .coordinator import SteamConfigEntry, SteamDataUpdateCoordinator -PLATFORMS = [Platform.SENSOR] +PLATFORMS = [Platform.IMAGE, Platform.SENSOR] async def async_setup_entry(hass: HomeAssistant, entry: SteamConfigEntry) -> bool: diff --git a/homeassistant/components/steam_online/const.py b/homeassistant/components/steam_online/const.py index c5f1233d3723..7ccc6d1d29c9 100644 --- a/homeassistant/components/steam_online/const.py +++ b/homeassistant/components/steam_online/const.py @@ -30,7 +30,7 @@ STEAM_STATUSES = { 5: STATE_LOOKING_TO_TRADE, 6: STATE_LOOKING_TO_PLAY, } -STEAM_API_URL = "https://steamcdn-a.akamaihd.net/steam/apps/" +STEAM_API_URL = "https://shared.fastly.steamstatic.com/store_item_assets/steam/apps/" STEAM_HEADER_IMAGE_FILE = "header.jpg" STEAM_MAIN_IMAGE_FILE = "capsule_616x353.jpg" STEAM_ICON_URL = "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/apps/" diff --git a/homeassistant/components/steam_online/entity.py b/homeassistant/components/steam_online/entity.py index 2c2732ebfa7a..2e259360b6db 100644 --- a/homeassistant/components/steam_online/entity.py +++ b/homeassistant/components/steam_online/entity.py @@ -1,7 +1,9 @@ """Entity classes for the Steam integration.""" -from homeassistant.components.sensor import SensorEntityDescription +from typing import override + from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo +from homeassistant.helpers.entity import EntityDescription from homeassistant.helpers.update_coordinator import CoordinatorEntity from .const import DOMAIN @@ -17,7 +19,7 @@ class SteamEntity(CoordinatorEntity[SteamDataUpdateCoordinator]): self, coordinator: SteamDataUpdateCoordinator, steamid: str, - description: SensorEntityDescription, + description: EntityDescription, ) -> None: """Initialize a Steam entity.""" super().__init__(coordinator) @@ -25,10 +27,16 @@ class SteamEntity(CoordinatorEntity[SteamDataUpdateCoordinator]): self.entity_description = description self._attr_unique_id = f"{steamid}_{description.key}" self._attr_device_info = DeviceInfo( - configuration_url=str(coordinator.data[steamid].profileurl), + configuration_url=coordinator.data[steamid].profileurl, entry_type=DeviceEntryType.SERVICE, identifiers={(DOMAIN, steamid)}, model="Steam", manufacturer="Valve", - name=str(coordinator.data[steamid].personaname), + name=coordinator.data[steamid].personaname, ) + + @property + @override + def available(self) -> bool: + """Return True if entity is available.""" + return super().available and self._steamid in self.coordinator.data diff --git a/homeassistant/components/steam_online/icons.json b/homeassistant/components/steam_online/icons.json index 9a62815c2bbc..fdbb91fafa94 100644 --- a/homeassistant/components/steam_online/icons.json +++ b/homeassistant/components/steam_online/icons.json @@ -1,5 +1,10 @@ { "entity": { + "image": { + "avatar": { + "default": "mdi:account-circle" + } + }, "sensor": { "account": { "default": "mdi:steam" diff --git a/homeassistant/components/steam_online/image.py b/homeassistant/components/steam_online/image.py new file mode 100644 index 000000000000..6a4f5ed888f2 --- /dev/null +++ b/homeassistant/components/steam_online/image.py @@ -0,0 +1,190 @@ +"""Image platform for the Steam integration.""" + +from collections.abc import Callable +from dataclasses import dataclass +from enum import StrEnum +from typing import TYPE_CHECKING, override + +from homeassistant.components.image import ImageEntity, ImageEntityDescription +from homeassistant.core import HomeAssistant +from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback +from homeassistant.util import dt as dt_util + +from .const import STEAM_API_URL, STEAM_ICON_URL, SUBENTRY_TYPE_FRIEND +from .coordinator import PlayerData, SteamConfigEntry, SteamDataUpdateCoordinator +from .entity import SteamEntity + +PARALLEL_UPDATES = 0 + + +class SteamImage(StrEnum): + """Steam images.""" + + AVATAR = "avatar" + MAIN_CAPSULE = "main_capsule" + HEADER_CAPSULE = "header_capsule" + SMALL_CAPSULE = "small_capsule" + VERTICAL_CAPSULE = "vertical_capsule" + LIBRARY_CAPSULE = "library_capsule" + LIBRARY_HERO = "library_hero" + LIBRARY_LOGO = "library_logo" + PAGE_BACKGROUND = "page_background" + APP_ICON = "app_icon" + + +@dataclass(kw_only=True, frozen=True) +class SteamImageEntityDescription(ImageEntityDescription): + """Steam image description.""" + + image_url_fn: Callable[[PlayerData, dict[str, str]], str | None] + available_fn: Callable[[PlayerData], bool] = lambda x: x.gameid is not None + + +IMAGE_DESCRIPTIONS: tuple[SteamImageEntityDescription, ...] = ( + SteamImageEntityDescription( + key=SteamImage.AVATAR, + translation_key=SteamImage.AVATAR, + image_url_fn=lambda x, _: x.avatarfull, + entity_registry_enabled_default=False, + available_fn=lambda _: True, + ), + SteamImageEntityDescription( + key=SteamImage.MAIN_CAPSULE, + translation_key=SteamImage.MAIN_CAPSULE, + image_url_fn=lambda x, _: ( + f"{STEAM_API_URL}{x.gameid}/capsule_616x353.jpg" if x.gameid else None + ), + ), + SteamImageEntityDescription( + key=SteamImage.HEADER_CAPSULE, + translation_key=SteamImage.HEADER_CAPSULE, + image_url_fn=lambda x, _: ( + f"{STEAM_API_URL}{x.gameid}/header.jpg" if x.gameid else None + ), + ), + SteamImageEntityDescription( + key=SteamImage.APP_ICON, + translation_key=SteamImage.APP_ICON, + image_url_fn=lambda x, icons: ( + f"{STEAM_ICON_URL}{x.gameid}/{i}.jpg" + if x.gameid and (i := icons.get(x.gameid)) + else None + ), + entity_registry_enabled_default=False, + ), + SteamImageEntityDescription( + key=SteamImage.SMALL_CAPSULE, + translation_key=SteamImage.SMALL_CAPSULE, + image_url_fn=lambda x, _: ( + f"{STEAM_API_URL}{x.gameid}/capsule_231x87.jpg" if x.gameid else None + ), + entity_registry_enabled_default=False, + ), + SteamImageEntityDescription( + key=SteamImage.LIBRARY_CAPSULE, + translation_key=SteamImage.LIBRARY_CAPSULE, + image_url_fn=lambda x, _: ( + f"{STEAM_API_URL}{x.gameid}/library_600x900_2x.jpg" if x.gameid else None + ), + ), + SteamImageEntityDescription( + key=SteamImage.LIBRARY_HERO, + translation_key=SteamImage.LIBRARY_HERO, + image_url_fn=lambda x, _: ( + f"{STEAM_API_URL}{x.gameid}/library_hero.jpg" if x.gameid else None + ), + ), + SteamImageEntityDescription( + key=SteamImage.LIBRARY_LOGO, + translation_key=SteamImage.LIBRARY_LOGO, + image_url_fn=lambda x, _: ( + f"{STEAM_API_URL}{x.gameid}/logo.png" if x.gameid else None + ), + ), + SteamImageEntityDescription( + key=SteamImage.PAGE_BACKGROUND, + translation_key=SteamImage.PAGE_BACKGROUND, + image_url_fn=lambda x, _: ( + f"{STEAM_API_URL}{x.gameid}/page_bg_generated_v6b.jpg" if x.gameid else None + ), + ), + SteamImageEntityDescription( + key=SteamImage.VERTICAL_CAPSULE, + translation_key=SteamImage.VERTICAL_CAPSULE, + image_url_fn=lambda x, _: ( + f"{STEAM_API_URL}{x.gameid}/hero_capsule.jpg" if x.gameid else None + ), + ), +) + + +async def async_setup_entry( + hass: HomeAssistant, + entry: SteamConfigEntry, + async_add_entities: AddConfigEntryEntitiesCallback, +) -> None: + """Set up the Steam platform.""" + coordinator = entry.runtime_data + if TYPE_CHECKING: + assert entry.unique_id + + async_add_entities( + SteamImageEntity(hass, coordinator, entry.unique_id, description) + for description in IMAGE_DESCRIPTIONS + if entry.unique_id in coordinator.data + ) + + for subentry in entry.get_subentries_of_type(SUBENTRY_TYPE_FRIEND): + async_add_entities( + [ + SteamImageEntity(hass, coordinator, subentry.unique_id, description) + for description in IMAGE_DESCRIPTIONS + if subentry.unique_id in coordinator.data + ], + config_subentry_id=subentry.subentry_id, + ) + + +class SteamImageEntity(SteamEntity, ImageEntity): + """An image entity.""" + + entity_description: SteamImageEntityDescription + + def __init__( + self, + hass: HomeAssistant, + coordinator: SteamDataUpdateCoordinator, + steamid: str, + entity_description: SteamImageEntityDescription, + ) -> None: + """Initialize the image entity.""" + super().__init__(coordinator, steamid, entity_description) + ImageEntity.__init__(self, hass) + + self._attr_image_url = self.entity_description.image_url_fn( + self.coordinator.data[self._steamid], self.coordinator.game_icons + ) + self._attr_image_last_updated = dt_util.utcnow() + + @override + def _handle_coordinator_update(self) -> None: + """Handle updated data from the coordinator.""" + + url = self.entity_description.image_url_fn( + self.coordinator.data[self._steamid], self.coordinator.game_icons + ) + + if url != self._attr_image_url: + self._attr_image_url = url + self._cached_image = None + self._attr_image_last_updated = dt_util.utcnow() + + super()._handle_coordinator_update() + + @property + @override + def available(self) -> bool: + """Return if entity is available.""" + return super().available and self.entity_description.available_fn( + self.coordinator.data[self._steamid] + ) diff --git a/homeassistant/components/steam_online/sensor.py b/homeassistant/components/steam_online/sensor.py index 45c1cdac4de0..a0d8b19fa24c 100644 --- a/homeassistant/components/steam_online/sensor.py +++ b/homeassistant/components/steam_online/sensor.py @@ -172,9 +172,3 @@ class SteamSensorEntity(SteamEntity, SensorEntity): if (fn := self.entity_description.extra_state_attributes_fn) is not None else super().extra_state_attributes ) - - @property - @override - def available(self) -> bool: - """Return True if entity is available.""" - return super().available and self._steamid in self.coordinator.data diff --git a/homeassistant/components/steam_online/strings.json b/homeassistant/components/steam_online/strings.json index fdb497f21fea..cace946329e3 100644 --- a/homeassistant/components/steam_online/strings.json +++ b/homeassistant/components/steam_online/strings.json @@ -83,6 +83,38 @@ } }, "entity": { + "image": { + "app_icon": { + "name": "App icon" + }, + "avatar": { + "name": "Avatar" + }, + "header_capsule": { + "name": "Header capsule" + }, + "library_capsule": { + "name": "Library capsule" + }, + "library_hero": { + "name": "Library hero capsule" + }, + "library_logo": { + "name": "Library logo" + }, + "main_capsule": { + "name": "Main capsule" + }, + "page_background": { + "name": "Page background" + }, + "small_capsule": { + "name": "Small capsule" + }, + "vertical_capsule": { + "name": "Vertical capsule" + } + }, "sensor": { "account": { "state": { diff --git a/tests/components/steam_online/fixtures/GetOwnedGames.json b/tests/components/steam_online/fixtures/GetOwnedGames.json index c26bfe26fd69..944458e864af 100644 --- a/tests/components/steam_online/fixtures/GetOwnedGames.json +++ b/tests/components/steam_online/fixtures/GetOwnedGames.json @@ -15,6 +15,20 @@ "rtime_last_played": 1782145718, "content_descriptorids": [1, 2, 5], "playtime_disconnected": 0 + }, + { + "appid": 1180660, + "name": "Tell Me Why", + "playtime_forever": 1267, + "img_icon_url": "6eb40e6f71226ce5bea75601a1ec0f9d6f647dd1", + "has_community_visible_stats": true, + "playtime_windows_forever": 1267, + "playtime_mac_forever": 0, + "playtime_linux_forever": 0, + "playtime_deck_forever": 0, + "rtime_last_played": 1642893397, + "content_descriptorids": [5], + "playtime_disconnected": 0 } ] } diff --git a/tests/components/steam_online/fixtures/GetPlayerSummaries2.json b/tests/components/steam_online/fixtures/GetPlayerSummaries2.json new file mode 100644 index 000000000000..0a6025464f02 --- /dev/null +++ b/tests/components/steam_online/fixtures/GetPlayerSummaries2.json @@ -0,0 +1,39 @@ +{ + "response": { + "players": { + "player": [ + { + "steamid": "12345678901234567", + "communityvisibilitystate": 1, + "profilestate": 1, + "personaname": "testaccount1", + "profileurl": "https://steamcommunity.com/profiles/123456789/", + "avatar": "https://avatars.steamstatic.com/fef49e7fa7e1997310d705b2a6158ff8dc1cdfeb.jpg", + "avatarmedium": "https://avatars.steamstatic.com/fef49e7fa7e1997310d705b2a6158ff8dc1cdfeb_medium.jpg", + "avatarfull": "https://avatars.steamstatic.com/fef49e7fa7e1997310d705b2a6158ff8dc1cdfeb_full.jpg", + "avatarhash": "fef49e7fa7e1997310d705b2a6158ff8dc1cdfeb", + "lastlogoff": 1775409487, + "personastate": 1, + "realname": "John Dough", + "personastateflags": 0, + "gameextrainfo": "Tell Me Why", + "gameid": "1180660" + }, + { + "steamid": "12345678912345678", + "communityvisibilitystate": 1, + "profilestate": 1, + "personaname": "testaccount2", + "profileurl": "https://steamcommunity.com/profiles/987654321/", + "avatar": "https://avatars.steamstatic.com/fef49e7fa7e1997310d705b2a6158ff8dc1cdfeb.jpg", + "avatarmedium": "https://avatars.steamstatic.com/fef49e7fa7e1997310d705b2a6158ff8dc1cdfeb_medium.jpg", + "avatarfull": "https://avatars.steamstatic.com/fef49e7fa7e1997310d705b2a6158ff8dc1cdfeb_full.jpg", + "avatarhash": "fef49e7fa7e1997310d705b2a6158ff8dc1cdfeb", + "lastlogoff": 1775409487, + "personastate": 2, + "personastateflags": 0 + } + ] + } + } +} diff --git a/tests/components/steam_online/snapshots/test_image.ambr b/tests/components/steam_online/snapshots/test_image.ambr new file mode 100644 index 000000000000..0213bd4dab8d --- /dev/null +++ b/tests/components/steam_online/snapshots/test_image.ambr @@ -0,0 +1,1032 @@ +# serializer version: 1 +# name: test_images[image.testaccount1_app_icon-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'image', + 'entity_category': None, + 'entity_id': 'image.testaccount1_app_icon', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'App icon', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'App icon', + 'platform': 'steam_online', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': '12345678901234567_app_icon', + 'unit_of_measurement': None, + }) +# --- +# name: test_images[image.testaccount1_app_icon-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : '520', + : '/api/image_proxy/image.testaccount1_app_icon?token=520', + : 'testaccount1 App icon', + }), + 'context': , + 'entity_id': 'image.testaccount1_app_icon', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '2013-12-13T12:13:12+00:00', + }) +# --- +# name: test_images[image.testaccount1_avatar-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'image', + 'entity_category': None, + 'entity_id': 'image.testaccount1_avatar', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Avatar', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Avatar', + 'platform': 'steam_online', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': '12345678901234567_avatar', + 'unit_of_measurement': None, + }) +# --- +# name: test_images[image.testaccount1_avatar-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : '520', + : '/api/image_proxy/image.testaccount1_avatar?token=520', + : 'testaccount1 Avatar', + }), + 'context': , + 'entity_id': 'image.testaccount1_avatar', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '2013-12-13T12:13:12+00:00', + }) +# --- +# name: test_images[image.testaccount1_header_capsule-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'image', + 'entity_category': None, + 'entity_id': 'image.testaccount1_header_capsule', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Header capsule', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Header capsule', + 'platform': 'steam_online', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': '12345678901234567_header_capsule', + 'unit_of_measurement': None, + }) +# --- +# name: test_images[image.testaccount1_header_capsule-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : '520', + : '/api/image_proxy/image.testaccount1_header_capsule?token=520', + : 'testaccount1 Header capsule', + }), + 'context': , + 'entity_id': 'image.testaccount1_header_capsule', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '2013-12-13T12:13:12+00:00', + }) +# --- +# name: test_images[image.testaccount1_library_capsule-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'image', + 'entity_category': None, + 'entity_id': 'image.testaccount1_library_capsule', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Library capsule', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Library capsule', + 'platform': 'steam_online', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': '12345678901234567_library_capsule', + 'unit_of_measurement': None, + }) +# --- +# name: test_images[image.testaccount1_library_capsule-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : '520', + : '/api/image_proxy/image.testaccount1_library_capsule?token=520', + : 'testaccount1 Library capsule', + }), + 'context': , + 'entity_id': 'image.testaccount1_library_capsule', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '2013-12-13T12:13:12+00:00', + }) +# --- +# name: test_images[image.testaccount1_library_hero_capsule-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'image', + 'entity_category': None, + 'entity_id': 'image.testaccount1_library_hero_capsule', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Library hero capsule', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Library hero capsule', + 'platform': 'steam_online', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': '12345678901234567_library_hero', + 'unit_of_measurement': None, + }) +# --- +# name: test_images[image.testaccount1_library_hero_capsule-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : '520', + : '/api/image_proxy/image.testaccount1_library_hero_capsule?token=520', + : 'testaccount1 Library hero capsule', + }), + 'context': , + 'entity_id': 'image.testaccount1_library_hero_capsule', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '2013-12-13T12:13:12+00:00', + }) +# --- +# name: test_images[image.testaccount1_library_logo-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'image', + 'entity_category': None, + 'entity_id': 'image.testaccount1_library_logo', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Library logo', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Library logo', + 'platform': 'steam_online', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': '12345678901234567_library_logo', + 'unit_of_measurement': None, + }) +# --- +# name: test_images[image.testaccount1_library_logo-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : '520', + : '/api/image_proxy/image.testaccount1_library_logo?token=520', + : 'testaccount1 Library logo', + }), + 'context': , + 'entity_id': 'image.testaccount1_library_logo', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '2013-12-13T12:13:12+00:00', + }) +# --- +# name: test_images[image.testaccount1_main_capsule-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'image', + 'entity_category': None, + 'entity_id': 'image.testaccount1_main_capsule', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Main capsule', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Main capsule', + 'platform': 'steam_online', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': '12345678901234567_main_capsule', + 'unit_of_measurement': None, + }) +# --- +# name: test_images[image.testaccount1_main_capsule-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : '520', + : '/api/image_proxy/image.testaccount1_main_capsule?token=520', + : 'testaccount1 Main capsule', + }), + 'context': , + 'entity_id': 'image.testaccount1_main_capsule', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '2013-12-13T12:13:12+00:00', + }) +# --- +# name: test_images[image.testaccount1_page_background-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'image', + 'entity_category': None, + 'entity_id': 'image.testaccount1_page_background', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Page background', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Page background', + 'platform': 'steam_online', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': '12345678901234567_page_background', + 'unit_of_measurement': None, + }) +# --- +# name: test_images[image.testaccount1_page_background-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : '520', + : '/api/image_proxy/image.testaccount1_page_background?token=520', + : 'testaccount1 Page background', + }), + 'context': , + 'entity_id': 'image.testaccount1_page_background', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '2013-12-13T12:13:12+00:00', + }) +# --- +# name: test_images[image.testaccount1_small_capsule-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'image', + 'entity_category': None, + 'entity_id': 'image.testaccount1_small_capsule', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Small capsule', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Small capsule', + 'platform': 'steam_online', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': '12345678901234567_small_capsule', + 'unit_of_measurement': None, + }) +# --- +# name: test_images[image.testaccount1_small_capsule-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : '520', + : '/api/image_proxy/image.testaccount1_small_capsule?token=520', + : 'testaccount1 Small capsule', + }), + 'context': , + 'entity_id': 'image.testaccount1_small_capsule', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '2013-12-13T12:13:12+00:00', + }) +# --- +# name: test_images[image.testaccount1_vertical_capsule-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'image', + 'entity_category': None, + 'entity_id': 'image.testaccount1_vertical_capsule', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Vertical capsule', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Vertical capsule', + 'platform': 'steam_online', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': '12345678901234567_vertical_capsule', + 'unit_of_measurement': None, + }) +# --- +# name: test_images[image.testaccount1_vertical_capsule-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : '520', + : '/api/image_proxy/image.testaccount1_vertical_capsule?token=520', + : 'testaccount1 Vertical capsule', + }), + 'context': , + 'entity_id': 'image.testaccount1_vertical_capsule', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '2013-12-13T12:13:12+00:00', + }) +# --- +# name: test_images[image.testaccount2_app_icon-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'image', + 'entity_category': None, + 'entity_id': 'image.testaccount2_app_icon', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'App icon', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'App icon', + 'platform': 'steam_online', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': '12345678912345678_app_icon', + 'unit_of_measurement': None, + }) +# --- +# name: test_images[image.testaccount2_app_icon-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : '/api/image_proxy/image.testaccount2_app_icon?token=520', + : 'testaccount2 App icon', + }), + 'context': , + 'entity_id': 'image.testaccount2_app_icon', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unavailable', + }) +# --- +# name: test_images[image.testaccount2_avatar-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'image', + 'entity_category': None, + 'entity_id': 'image.testaccount2_avatar', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Avatar', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Avatar', + 'platform': 'steam_online', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': '12345678912345678_avatar', + 'unit_of_measurement': None, + }) +# --- +# name: test_images[image.testaccount2_avatar-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : '520', + : '/api/image_proxy/image.testaccount2_avatar?token=520', + : 'testaccount2 Avatar', + }), + 'context': , + 'entity_id': 'image.testaccount2_avatar', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '2013-12-13T12:13:12+00:00', + }) +# --- +# name: test_images[image.testaccount2_header_capsule-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'image', + 'entity_category': None, + 'entity_id': 'image.testaccount2_header_capsule', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Header capsule', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Header capsule', + 'platform': 'steam_online', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': '12345678912345678_header_capsule', + 'unit_of_measurement': None, + }) +# --- +# name: test_images[image.testaccount2_header_capsule-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : '/api/image_proxy/image.testaccount2_header_capsule?token=520', + : 'testaccount2 Header capsule', + }), + 'context': , + 'entity_id': 'image.testaccount2_header_capsule', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unavailable', + }) +# --- +# name: test_images[image.testaccount2_library_capsule-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'image', + 'entity_category': None, + 'entity_id': 'image.testaccount2_library_capsule', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Library capsule', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Library capsule', + 'platform': 'steam_online', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': '12345678912345678_library_capsule', + 'unit_of_measurement': None, + }) +# --- +# name: test_images[image.testaccount2_library_capsule-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : '/api/image_proxy/image.testaccount2_library_capsule?token=520', + : 'testaccount2 Library capsule', + }), + 'context': , + 'entity_id': 'image.testaccount2_library_capsule', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unavailable', + }) +# --- +# name: test_images[image.testaccount2_library_hero_capsule-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'image', + 'entity_category': None, + 'entity_id': 'image.testaccount2_library_hero_capsule', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Library hero capsule', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Library hero capsule', + 'platform': 'steam_online', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': '12345678912345678_library_hero', + 'unit_of_measurement': None, + }) +# --- +# name: test_images[image.testaccount2_library_hero_capsule-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : '/api/image_proxy/image.testaccount2_library_hero_capsule?token=520', + : 'testaccount2 Library hero capsule', + }), + 'context': , + 'entity_id': 'image.testaccount2_library_hero_capsule', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unavailable', + }) +# --- +# name: test_images[image.testaccount2_library_logo-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'image', + 'entity_category': None, + 'entity_id': 'image.testaccount2_library_logo', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Library logo', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Library logo', + 'platform': 'steam_online', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': '12345678912345678_library_logo', + 'unit_of_measurement': None, + }) +# --- +# name: test_images[image.testaccount2_library_logo-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : '/api/image_proxy/image.testaccount2_library_logo?token=520', + : 'testaccount2 Library logo', + }), + 'context': , + 'entity_id': 'image.testaccount2_library_logo', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unavailable', + }) +# --- +# name: test_images[image.testaccount2_main_capsule-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'image', + 'entity_category': None, + 'entity_id': 'image.testaccount2_main_capsule', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Main capsule', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Main capsule', + 'platform': 'steam_online', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': '12345678912345678_main_capsule', + 'unit_of_measurement': None, + }) +# --- +# name: test_images[image.testaccount2_main_capsule-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : '/api/image_proxy/image.testaccount2_main_capsule?token=520', + : 'testaccount2 Main capsule', + }), + 'context': , + 'entity_id': 'image.testaccount2_main_capsule', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unavailable', + }) +# --- +# name: test_images[image.testaccount2_page_background-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'image', + 'entity_category': None, + 'entity_id': 'image.testaccount2_page_background', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Page background', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Page background', + 'platform': 'steam_online', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': '12345678912345678_page_background', + 'unit_of_measurement': None, + }) +# --- +# name: test_images[image.testaccount2_page_background-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : '/api/image_proxy/image.testaccount2_page_background?token=520', + : 'testaccount2 Page background', + }), + 'context': , + 'entity_id': 'image.testaccount2_page_background', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unavailable', + }) +# --- +# name: test_images[image.testaccount2_small_capsule-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'image', + 'entity_category': None, + 'entity_id': 'image.testaccount2_small_capsule', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Small capsule', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Small capsule', + 'platform': 'steam_online', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': '12345678912345678_small_capsule', + 'unit_of_measurement': None, + }) +# --- +# name: test_images[image.testaccount2_small_capsule-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : '/api/image_proxy/image.testaccount2_small_capsule?token=520', + : 'testaccount2 Small capsule', + }), + 'context': , + 'entity_id': 'image.testaccount2_small_capsule', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unavailable', + }) +# --- +# name: test_images[image.testaccount2_vertical_capsule-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'image', + 'entity_category': None, + 'entity_id': 'image.testaccount2_vertical_capsule', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Vertical capsule', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Vertical capsule', + 'platform': 'steam_online', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': , + 'unique_id': '12345678912345678_vertical_capsule', + 'unit_of_measurement': None, + }) +# --- +# name: test_images[image.testaccount2_vertical_capsule-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + : '/api/image_proxy/image.testaccount2_vertical_capsule?token=520', + : 'testaccount2 Vertical capsule', + }), + 'context': , + 'entity_id': 'image.testaccount2_vertical_capsule', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'unavailable', + }) +# --- diff --git a/tests/components/steam_online/snapshots/test_sensor.ambr b/tests/components/steam_online/snapshots/test_sensor.ambr index cac8d8f57495..ecedc94d93b6 100644 --- a/tests/components/steam_online/snapshots/test_sensor.ambr +++ b/tests/components/steam_online/snapshots/test_sensor.ambr @@ -56,8 +56,8 @@ 'game': 'The Witcher: Enhanced Edition', 'game_icon': 'https://steamcdn-a.akamaihd.net/steamcommunity/public/images/apps/20900/746d1cd48fb2e57d579b05b6e9eccba95859e549.jpg', 'game_id': '20900', - 'game_image_header': 'https://steamcdn-a.akamaihd.net/steam/apps/20900/header.jpg', - 'game_image_main': 'https://steamcdn-a.akamaihd.net/steam/apps/20900/capsule_616x353.jpg', + 'game_image_header': 'https://shared.fastly.steamstatic.com/store_item_assets/steam/apps/20900/header.jpg', + 'game_image_main': 'https://shared.fastly.steamstatic.com/store_item_assets/steam/apps/20900/capsule_616x353.jpg', 'last_online': datetime.datetime(2026, 4, 5, 17, 18, 7, tzinfo=datetime.timezone.utc), 'level': 10, : list([ diff --git a/tests/components/steam_online/test_image.py b/tests/components/steam_online/test_image.py new file mode 100644 index 000000000000..2b620c0e2aa5 --- /dev/null +++ b/tests/components/steam_online/test_image.py @@ -0,0 +1,131 @@ +"""Tests for Steam image platform.""" + +from collections.abc import Generator +from datetime import timedelta +from http import HTTPStatus +from unittest.mock import MagicMock, patch + +from freezegun.api import FrozenDateTimeFactory +import pytest +import respx +from syrupy.assertion import SnapshotAssertion + +from homeassistant.components.steam_online.const import DOMAIN, STEAM_API_URL +from homeassistant.config_entries import ConfigEntryState +from homeassistant.const import Platform +from homeassistant.core import HomeAssistant +from homeassistant.helpers import entity_registry as er + +from tests.common import ( + MockConfigEntry, + async_fire_time_changed, + async_load_json_object_fixture, + snapshot_platform, +) +from tests.typing import ClientSessionGenerator + + +@pytest.fixture(autouse=True) +def image_only() -> Generator[None]: + """Enable only the image platform.""" + with patch( + "homeassistant.components.steam_online.PLATFORMS", + [Platform.IMAGE], + ): + yield + + +@pytest.fixture(autouse=True) +def mock_getrandbits(): + """Mock image access token which normally is randomized.""" + with patch( + "homeassistant.components.image.SystemRandom.getrandbits", + return_value=1312, + ): + yield + + +@pytest.mark.usefixtures("steam_api", "entity_registry_enabled_by_default") +@pytest.mark.freeze_time("2013-12-13 12:13:12") +async def test_images( + hass: HomeAssistant, + config_entry: MockConfigEntry, + snapshot: SnapshotAssertion, + entity_registry: er.EntityRegistry, +) -> None: + """Test setup of the Steam image platform.""" + + config_entry.add_to_hass(hass) + await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + + assert config_entry.state is ConfigEntryState.LOADED + + await snapshot_platform(hass, entity_registry, snapshot, config_entry.entry_id) + + +@respx.mock +@pytest.mark.freeze_time("2013-12-13 12:13:12") +async def test_load_image_from_url( + hass: HomeAssistant, + config_entry: MockConfigEntry, + hass_client: ClientSessionGenerator, + freezer: FrozenDateTimeFactory, + steam_api: MagicMock, +) -> None: + """Test image platform loads image from url.""" + + respx.get(f"{STEAM_API_URL}20900/capsule_616x353.jpg").respond( + status_code=HTTPStatus.OK, content_type="image/jpg", content=b"Test" + ) + config_entry.add_to_hass(hass) + await hass.config_entries.async_setup(config_entry.entry_id) + await hass.async_block_till_done() + + assert config_entry.state is ConfigEntryState.LOADED + + assert (state := hass.states.get("image.testaccount1_main_capsule")) + assert state.state == "2013-12-13T12:13:12+00:00" + + access_token = state.attributes["access_token"] + assert ( + state.attributes["entity_picture"] + == f"/api/image_proxy/image.testaccount1_main_capsule?token={access_token}" + ) + + client = await hass_client() + resp = await client.get(state.attributes["entity_picture"]) + assert resp.status == HTTPStatus.OK + body = await resp.read() + assert body == b"Test" + assert resp.content_type == "image/jpg" + assert resp.content_length == 4 + + steam_api.return_value.GetPlayerSummaries.return_value = ( + await async_load_json_object_fixture(hass, "GetPlayerSummaries2.json", DOMAIN) + ) + + respx.get(f"{STEAM_API_URL}1180660/capsule_616x353.jpg").respond( + status_code=HTTPStatus.OK, content_type="image/jpg", content=b"Test2" + ) + + freezer.tick(timedelta(seconds=30)) + async_fire_time_changed(hass) + await hass.async_block_till_done() + + assert (state := hass.states.get("image.testaccount1_main_capsule")) + assert state.state == "2013-12-13T12:13:42+00:00" + + access_token = state.attributes["access_token"] + assert ( + state.attributes["entity_picture"] + == f"/api/image_proxy/image.testaccount1_main_capsule?token={access_token}" + ) + + client = await hass_client() + resp = await client.get(state.attributes["entity_picture"]) + assert resp.status == HTTPStatus.OK + body = await resp.read() + assert body == b"Test2" + assert resp.content_type == "image/jpg" + assert resp.content_length == 5