diff --git a/homeassistant/components/nyt_games/coordinator.py b/homeassistant/components/nyt_games/coordinator.py index d9e39ff814cb0a2bb241f8b626d6c060a0e877de..75aa79f62ba602d439863101029e2806fdbdd3bf 100644 --- a/homeassistant/components/nyt_games/coordinator.py +++ b/homeassistant/components/nyt_games/coordinator.py @@ -2,10 +2,11 @@ from __future__ import annotations +from dataclasses import dataclass from datetime import timedelta from typing import TYPE_CHECKING -from nyt_games import NYTGamesClient, NYTGamesError, Wordle +from nyt_games import Connections, NYTGamesClient, NYTGamesError, SpellingBee, Wordle from homeassistant.core import HomeAssistant from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed @@ -16,7 +17,16 @@ if TYPE_CHECKING: from . import NYTGamesConfigEntry -class NYTGamesCoordinator(DataUpdateCoordinator[Wordle]): +@dataclass +class NYTGamesData: + """Class for NYT Games data.""" + + wordle: Wordle + spelling_bee: SpellingBee + connections: Connections + + +class NYTGamesCoordinator(DataUpdateCoordinator[NYTGamesData]): """Class to manage fetching NYT Games data.""" config_entry: NYTGamesConfigEntry @@ -31,8 +41,14 @@ class NYTGamesCoordinator(DataUpdateCoordinator[Wordle]): ) self.client = client - async def _async_update_data(self) -> Wordle: + async def _async_update_data(self) -> NYTGamesData: try: - return (await self.client.get_latest_stats()).wordle + stats_data = await self.client.get_latest_stats() + connections_data = await self.client.get_connections() except NYTGamesError as error: raise UpdateFailed(error) from error + return NYTGamesData( + wordle=stats_data.wordle, + spelling_bee=stats_data.spelling_bee, + connections=connections_data, + ) diff --git a/homeassistant/components/nyt_games/entity.py b/homeassistant/components/nyt_games/entity.py index ba4234ab48b78803f4bf8c335ba52345ff8430bf..40ca6ca973fb30a60603c5d38b874f98c014dec7 100644 --- a/homeassistant/components/nyt_games/entity.py +++ b/homeassistant/components/nyt_games/entity.py @@ -12,13 +12,50 @@ class NYTGamesEntity(CoordinatorEntity[NYTGamesCoordinator]): _attr_has_entity_name = True + +class WordleEntity(NYTGamesEntity): + """Defines a NYT Games entity.""" + + def __init__(self, coordinator: NYTGamesCoordinator) -> None: + """Initialize a NYT Games entity.""" + super().__init__(coordinator) + unique_id = coordinator.config_entry.unique_id + assert unique_id is not None + self._attr_device_info = DeviceInfo( + identifiers={(DOMAIN, f"{unique_id}_wordle")}, + entry_type=DeviceEntryType.SERVICE, + manufacturer="New York Times", + name="Wordle", + ) + + +class SpellingBeeEntity(NYTGamesEntity): + """Defines a NYT Games entity.""" + + def __init__(self, coordinator: NYTGamesCoordinator) -> None: + """Initialize a NYT Games entity.""" + super().__init__(coordinator) + unique_id = coordinator.config_entry.unique_id + assert unique_id is not None + self._attr_device_info = DeviceInfo( + identifiers={(DOMAIN, f"{unique_id}_spelling_bee")}, + entry_type=DeviceEntryType.SERVICE, + manufacturer="New York Times", + name="Spelling Bee", + ) + + +class ConnectionsEntity(NYTGamesEntity): + """Defines a NYT Games entity.""" + def __init__(self, coordinator: NYTGamesCoordinator) -> None: """Initialize a NYT Games entity.""" super().__init__(coordinator) unique_id = coordinator.config_entry.unique_id assert unique_id is not None self._attr_device_info = DeviceInfo( - identifiers={(DOMAIN, unique_id)}, + identifiers={(DOMAIN, f"{unique_id}_connections")}, entry_type=DeviceEntryType.SERVICE, manufacturer="New York Times", + name="Connections", ) diff --git a/homeassistant/components/nyt_games/icons.json b/homeassistant/components/nyt_games/icons.json index 9e455cbf9519057279249ab21410e8fed673aee8..1f7b737a51b5fa2bfbf32b0b7abde773ced235cd 100644 --- a/homeassistant/components/nyt_games/icons.json +++ b/homeassistant/components/nyt_games/icons.json @@ -4,14 +4,29 @@ "wordles_played": { "default": "mdi:text-long" }, - "wordles_won": { + "won": { "default": "mdi:trophy-award" }, - "wordles_streak": { + "streak": { "default": "mdi:calendar-range" }, - "wordles_max_streak": { + "max_streak": { "default": "mdi:calendar-month" + }, + "spelling_bees_played": { + "default": "mdi:beehive-outline" + }, + "total_words": { + "default": "mdi:beehive-outline" + }, + "total_pangrams": { + "default": "mdi:beehive-outline" + }, + "connections_played": { + "default": "mdi:table-large" + }, + "last_played": { + "default": "mdi:beehive-outline" } } } diff --git a/homeassistant/components/nyt_games/sensor.py b/homeassistant/components/nyt_games/sensor.py index d677f2d166c4573dff22fbc8507ee68c82063c23..6e243a908b451e2557bdd2dfadb7f177d5faa9e6 100644 --- a/homeassistant/components/nyt_games/sensor.py +++ b/homeassistant/components/nyt_games/sensor.py @@ -2,8 +2,9 @@ from collections.abc import Callable from dataclasses import dataclass +from datetime import date -from nyt_games import Wordle +from nyt_games import Connections, SpellingBee, Wordle from homeassistant.components.sensor import ( SensorDeviceClass, @@ -18,7 +19,7 @@ from homeassistant.helpers.typing import StateType from . import NYTGamesConfigEntry from .coordinator import NYTGamesCoordinator -from .entity import NYTGamesEntity +from .entity import ConnectionsEntity, SpellingBeeEntity, WordleEntity @dataclass(frozen=True, kw_only=True) @@ -28,7 +29,7 @@ class NYTGamesWordleSensorEntityDescription(SensorEntityDescription): value_fn: Callable[[Wordle], StateType] -SENSOR_TYPES: tuple[NYTGamesWordleSensorEntityDescription, ...] = ( +WORDLE_SENSORS: tuple[NYTGamesWordleSensorEntityDescription, ...] = ( NYTGamesWordleSensorEntityDescription( key="wordles_played", translation_key="wordles_played", @@ -38,14 +39,14 @@ SENSOR_TYPES: tuple[NYTGamesWordleSensorEntityDescription, ...] = ( ), NYTGamesWordleSensorEntityDescription( key="wordles_won", - translation_key="wordles_won", + translation_key="won", state_class=SensorStateClass.MEASUREMENT, native_unit_of_measurement="games", value_fn=lambda wordle: wordle.games_won, ), NYTGamesWordleSensorEntityDescription( key="wordles_streak", - translation_key="wordles_streak", + translation_key="streak", state_class=SensorStateClass.TOTAL, native_unit_of_measurement=UnitOfTime.DAYS, device_class=SensorDeviceClass.DURATION, @@ -53,7 +54,7 @@ SENSOR_TYPES: tuple[NYTGamesWordleSensorEntityDescription, ...] = ( ), NYTGamesWordleSensorEntityDescription( key="wordles_max_streak", - translation_key="wordles_max_streak", + translation_key="max_streak", state_class=SensorStateClass.TOTAL_INCREASING, native_unit_of_measurement=UnitOfTime.DAYS, device_class=SensorDeviceClass.DURATION, @@ -62,6 +63,87 @@ SENSOR_TYPES: tuple[NYTGamesWordleSensorEntityDescription, ...] = ( ) +@dataclass(frozen=True, kw_only=True) +class NYTGamesSpellingBeeSensorEntityDescription(SensorEntityDescription): + """Describes a NYT Games Spelling Bee sensor entity.""" + + value_fn: Callable[[SpellingBee], StateType] + + +SPELLING_BEE_SENSORS: tuple[NYTGamesSpellingBeeSensorEntityDescription, ...] = ( + NYTGamesSpellingBeeSensorEntityDescription( + key="spelling_bees_played", + translation_key="spelling_bees_played", + state_class=SensorStateClass.TOTAL, + native_unit_of_measurement="games", + value_fn=lambda spelling_bee: spelling_bee.puzzles_started, + ), + NYTGamesSpellingBeeSensorEntityDescription( + key="spelling_bees_total_words", + translation_key="total_words", + state_class=SensorStateClass.TOTAL, + native_unit_of_measurement="words", + entity_registry_enabled_default=False, + value_fn=lambda spelling_bee: spelling_bee.total_words, + ), + NYTGamesSpellingBeeSensorEntityDescription( + key="spelling_bees_total_pangrams", + translation_key="total_pangrams", + state_class=SensorStateClass.TOTAL, + native_unit_of_measurement="pangrams", + entity_registry_enabled_default=False, + value_fn=lambda spelling_bee: spelling_bee.total_pangrams, + ), +) + + +@dataclass(frozen=True, kw_only=True) +class NYTGamesConnectionsSensorEntityDescription(SensorEntityDescription): + """Describes a NYT Games Connections sensor entity.""" + + value_fn: Callable[[Connections], StateType | date] + + +CONNECTIONS_SENSORS: tuple[NYTGamesConnectionsSensorEntityDescription, ...] = ( + NYTGamesConnectionsSensorEntityDescription( + key="connections_played", + translation_key="connections_played", + state_class=SensorStateClass.TOTAL, + native_unit_of_measurement="games", + value_fn=lambda connections: connections.puzzles_completed, + ), + NYTGamesConnectionsSensorEntityDescription( + key="connections_won", + translation_key="won", + state_class=SensorStateClass.TOTAL, + native_unit_of_measurement="games", + value_fn=lambda connections: connections.puzzles_won, + ), + NYTGamesConnectionsSensorEntityDescription( + key="connections_last_played", + translation_key="last_played", + device_class=SensorDeviceClass.DATE, + value_fn=lambda connections: connections.last_completed, + ), + NYTGamesConnectionsSensorEntityDescription( + key="connections_streak", + translation_key="streak", + state_class=SensorStateClass.TOTAL, + native_unit_of_measurement=UnitOfTime.DAYS, + device_class=SensorDeviceClass.DURATION, + value_fn=lambda connections: connections.current_streak, + ), + NYTGamesConnectionsSensorEntityDescription( + key="connections_max_streak", + translation_key="max_streak", + state_class=SensorStateClass.TOTAL_INCREASING, + native_unit_of_measurement=UnitOfTime.DAYS, + device_class=SensorDeviceClass.DURATION, + value_fn=lambda connections: connections.current_streak, + ), +) + + async def async_setup_entry( hass: HomeAssistant, entry: NYTGamesConfigEntry, @@ -71,12 +153,22 @@ async def async_setup_entry( coordinator = entry.runtime_data - async_add_entities( - NYTGamesSensor(coordinator, description) for description in SENSOR_TYPES + entities: list[SensorEntity] = [ + NYTGamesWordleSensor(coordinator, description) for description in WORDLE_SENSORS + ] + entities.extend( + NYTGamesSpellingBeeSensor(coordinator, description) + for description in SPELLING_BEE_SENSORS + ) + entities.extend( + NYTGamesConnectionsSensor(coordinator, description) + for description in CONNECTIONS_SENSORS ) + async_add_entities(entities) + -class NYTGamesSensor(NYTGamesEntity, SensorEntity): +class NYTGamesWordleSensor(WordleEntity, SensorEntity): """Defines a NYT Games sensor.""" entity_description: NYTGamesWordleSensorEntityDescription @@ -89,9 +181,57 @@ class NYTGamesSensor(NYTGamesEntity, SensorEntity): """Initialize NYT Games sensor.""" super().__init__(coordinator) self.entity_description = description - self._attr_unique_id = f"{coordinator.config_entry.unique_id}-{description.key}" + self._attr_unique_id = ( + f"{coordinator.config_entry.unique_id}-wordle-{description.key}" + ) + + @property + def native_value(self) -> StateType: + """Return the state of the sensor.""" + return self.entity_description.value_fn(self.coordinator.data.wordle) + + +class NYTGamesSpellingBeeSensor(SpellingBeeEntity, SensorEntity): + """Defines a NYT Games sensor.""" + + entity_description: NYTGamesSpellingBeeSensorEntityDescription + + def __init__( + self, + coordinator: NYTGamesCoordinator, + description: NYTGamesSpellingBeeSensorEntityDescription, + ) -> None: + """Initialize NYT Games sensor.""" + super().__init__(coordinator) + self.entity_description = description + self._attr_unique_id = ( + f"{coordinator.config_entry.unique_id}-spelling_bee-{description.key}" + ) @property def native_value(self) -> StateType: """Return the state of the sensor.""" - return self.entity_description.value_fn(self.coordinator.data) + return self.entity_description.value_fn(self.coordinator.data.spelling_bee) + + +class NYTGamesConnectionsSensor(ConnectionsEntity, SensorEntity): + """Defines a NYT Games sensor.""" + + entity_description: NYTGamesConnectionsSensorEntityDescription + + def __init__( + self, + coordinator: NYTGamesCoordinator, + description: NYTGamesConnectionsSensorEntityDescription, + ) -> None: + """Initialize NYT Games sensor.""" + super().__init__(coordinator) + self.entity_description = description + self._attr_unique_id = ( + f"{coordinator.config_entry.unique_id}-connections-{description.key}" + ) + + @property + def native_value(self) -> StateType | date: + """Return the state of the sensor.""" + return self.entity_description.value_fn(self.coordinator.data.connections) diff --git a/homeassistant/components/nyt_games/strings.json b/homeassistant/components/nyt_games/strings.json index 152d523ec5748d45c6ab1c95de126d64d7ec1850..9a3771aebd9cdc3193af7d0a48fba4179108d62f 100644 --- a/homeassistant/components/nyt_games/strings.json +++ b/homeassistant/components/nyt_games/strings.json @@ -22,16 +22,31 @@ "entity": { "sensor": { "wordles_played": { - "name": "Wordles played" + "name": "Played" }, - "wordles_won": { - "name": "Wordles won" + "won": { + "name": "Won" }, - "wordles_streak": { - "name": "Current Wordle streak" + "streak": { + "name": "Current streak" }, - "wordles_max_streak": { - "name": "Highest Wordle streak" + "max_streak": { + "name": "Highest streak" + }, + "spelling_bees_played": { + "name": "[%key:component::nyt_games::entity::sensor::wordles_played::name%]" + }, + "total_words": { + "name": "Total words found" + }, + "total_pangrams": { + "name": "Total pangrams found" + }, + "connections_played": { + "name": "[%key:component::nyt_games::entity::sensor::wordles_played::name%]" + }, + "last_played": { + "name": "Last played" } } } diff --git a/tests/components/nyt_games/conftest.py b/tests/components/nyt_games/conftest.py index 3165021bc5b990a757a93133a6bafebf381aae5a..2999ae115b185ffab31a61a46ec212cd85b5319f 100644 --- a/tests/components/nyt_games/conftest.py +++ b/tests/components/nyt_games/conftest.py @@ -3,7 +3,7 @@ from collections.abc import Generator from unittest.mock import patch -from nyt_games.models import WordleStats +from nyt_games.models import ConnectionsStats, WordleStats import pytest from homeassistant.components.nyt_games.const import DOMAIN @@ -41,6 +41,9 @@ def mock_nyt_games_client() -> Generator[AsyncMock]: load_fixture("latest.json", DOMAIN) ).player.stats client.get_user_id.return_value = 218886794 + client.get_connections.return_value = ConnectionsStats.from_json( + load_fixture("connections.json", DOMAIN) + ).player.stats yield client diff --git a/tests/components/nyt_games/fixtures/connections.json b/tests/components/nyt_games/fixtures/connections.json new file mode 100644 index 0000000000000000000000000000000000000000..8c1ea18199a31a82f8d2d646ed5f7d6742635b75 --- /dev/null +++ b/tests/components/nyt_games/fixtures/connections.json @@ -0,0 +1,24 @@ +{ + "states": [], + "user_id": 218886794, + "player": { + "user_id": 218886794, + "last_updated": 1727097528, + "stats": { + "connections": { + "puzzles_completed": 9, + "puzzles_won": 3, + "last_played_print_date": "2024-09-23", + "current_streak": 0, + "max_streak": 2, + "mistakes": { + "0": 2, + "1": 0, + "2": 1, + "3": 0, + "4": 6 + } + } + } + } +} diff --git a/tests/components/nyt_games/snapshots/test_init.ambr b/tests/components/nyt_games/snapshots/test_init.ambr index 60759f25baff78246f2f7de16dc13013cbd9adf6..383bed0e106d66b99a1fda794841362f8cdb321f 100644 --- a/tests/components/nyt_games/snapshots/test_init.ambr +++ b/tests/components/nyt_games/snapshots/test_init.ambr @@ -1,5 +1,5 @@ # serializer version: 1 -# name: test_device_info +# name: test_device_info[device_connections] DeviceRegistryEntrySnapshot({ 'area_id': None, 'config_entries': <ANY>, @@ -13,7 +13,7 @@ 'identifiers': set({ tuple( 'nyt_games', - '218886794', + '218886794_connections', ), }), 'is_new': False, @@ -22,7 +22,71 @@ 'manufacturer': 'New York Times', 'model': None, 'model_id': None, - 'name': 'NYTGames', + 'name': 'Connections', + 'name_by_user': None, + 'primary_config_entry': <ANY>, + 'serial_number': None, + 'suggested_area': None, + 'sw_version': None, + 'via_device_id': None, + }) +# --- +# name: test_device_info[device_spelling_bee] + DeviceRegistryEntrySnapshot({ + 'area_id': None, + 'config_entries': <ANY>, + 'configuration_url': None, + 'connections': set({ + }), + 'disabled_by': None, + 'entry_type': <DeviceEntryType.SERVICE: 'service'>, + 'hw_version': None, + 'id': <ANY>, + 'identifiers': set({ + tuple( + 'nyt_games', + '218886794_spelling_bee', + ), + }), + 'is_new': False, + 'labels': set({ + }), + 'manufacturer': 'New York Times', + 'model': None, + 'model_id': None, + 'name': 'Spelling Bee', + 'name_by_user': None, + 'primary_config_entry': <ANY>, + 'serial_number': None, + 'suggested_area': None, + 'sw_version': None, + 'via_device_id': None, + }) +# --- +# name: test_device_info[device_wordle] + DeviceRegistryEntrySnapshot({ + 'area_id': None, + 'config_entries': <ANY>, + 'configuration_url': None, + 'connections': set({ + }), + 'disabled_by': None, + 'entry_type': <DeviceEntryType.SERVICE: 'service'>, + 'hw_version': None, + 'id': <ANY>, + 'identifiers': set({ + tuple( + 'nyt_games', + '218886794_wordle', + ), + }), + 'is_new': False, + 'labels': set({ + }), + 'manufacturer': 'New York Times', + 'model': None, + 'model_id': None, + 'name': 'Wordle', 'name_by_user': None, 'primary_config_entry': <ANY>, 'serial_number': None, diff --git a/tests/components/nyt_games/snapshots/test_sensor.ambr b/tests/components/nyt_games/snapshots/test_sensor.ambr index 9f164f7da3b6482db85b72798433abfccb3d2ba5..7c4c2b57253f05e86737d271392f9f5e3311b477 100644 --- a/tests/components/nyt_games/snapshots/test_sensor.ambr +++ b/tests/components/nyt_games/snapshots/test_sensor.ambr @@ -1,5 +1,5 @@ # serializer version: 1 -# name: test_all_entities[sensor.nytgames_current_wordle_streak-entry] +# name: test_all_entities[sensor.connections_current_streak-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -13,7 +13,7 @@ 'disabled_by': None, 'domain': 'sensor', 'entity_category': None, - 'entity_id': 'sensor.nytgames_current_wordle_streak', + 'entity_id': 'sensor.connections_current_streak', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -25,32 +25,431 @@ }), 'original_device_class': <SensorDeviceClass.DURATION: 'duration'>, 'original_icon': None, - 'original_name': 'Current Wordle streak', + 'original_name': 'Current streak', 'platform': 'nyt_games', 'previous_unique_id': None, 'supported_features': 0, - 'translation_key': 'wordles_streak', - 'unique_id': '218886794-wordles_streak', + 'translation_key': 'streak', + 'unique_id': '218886794-connections-connections_streak', 'unit_of_measurement': <UnitOfTime.DAYS: 'd'>, }) # --- -# name: test_all_entities[sensor.nytgames_current_wordle_streak-state] +# name: test_all_entities[sensor.connections_current_streak-state] StateSnapshot({ 'attributes': ReadOnlyDict({ 'device_class': 'duration', - 'friendly_name': 'NYTGames Current Wordle streak', + 'friendly_name': 'Connections Current streak', 'state_class': <SensorStateClass.TOTAL: 'total'>, 'unit_of_measurement': <UnitOfTime.DAYS: 'd'>, }), 'context': <ANY>, - 'entity_id': 'sensor.nytgames_current_wordle_streak', + 'entity_id': 'sensor.connections_current_streak', + 'last_changed': <ANY>, + 'last_reported': <ANY>, + 'last_updated': <ANY>, + 'state': '0', + }) +# --- +# name: test_all_entities[sensor.connections_highest_streak-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>, + }), + 'config_entry_id': <ANY>, + 'device_class': None, + 'device_id': <ANY>, + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.connections_highest_streak', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': <ANY>, + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': <SensorDeviceClass.DURATION: 'duration'>, + 'original_icon': None, + 'original_name': 'Highest streak', + 'platform': 'nyt_games', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'max_streak', + 'unique_id': '218886794-connections-connections_max_streak', + 'unit_of_measurement': <UnitOfTime.DAYS: 'd'>, + }) +# --- +# name: test_all_entities[sensor.connections_highest_streak-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'duration', + 'friendly_name': 'Connections Highest streak', + 'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>, + 'unit_of_measurement': <UnitOfTime.DAYS: 'd'>, + }), + 'context': <ANY>, + 'entity_id': 'sensor.connections_highest_streak', + 'last_changed': <ANY>, + 'last_reported': <ANY>, + 'last_updated': <ANY>, + 'state': '0', + }) +# --- +# name: test_all_entities[sensor.connections_last_played-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': <ANY>, + 'device_class': None, + 'device_id': <ANY>, + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.connections_last_played', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': <ANY>, + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': <SensorDeviceClass.DATE: 'date'>, + 'original_icon': None, + 'original_name': 'Last played', + 'platform': 'nyt_games', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'last_played', + 'unique_id': '218886794-connections-connections_last_played', + 'unit_of_measurement': None, + }) +# --- +# name: test_all_entities[sensor.connections_last_played-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'date', + 'friendly_name': 'Connections Last played', + }), + 'context': <ANY>, + 'entity_id': 'sensor.connections_last_played', + 'last_changed': <ANY>, + 'last_reported': <ANY>, + 'last_updated': <ANY>, + 'state': '2024-09-23', + }) +# --- +# name: test_all_entities[sensor.connections_played-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': <SensorStateClass.TOTAL: 'total'>, + }), + 'config_entry_id': <ANY>, + 'device_class': None, + 'device_id': <ANY>, + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.connections_played', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': <ANY>, + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Played', + 'platform': 'nyt_games', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'connections_played', + 'unique_id': '218886794-connections-connections_played', + 'unit_of_measurement': 'games', + }) +# --- +# name: test_all_entities[sensor.connections_played-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Connections Played', + 'state_class': <SensorStateClass.TOTAL: 'total'>, + 'unit_of_measurement': 'games', + }), + 'context': <ANY>, + 'entity_id': 'sensor.connections_played', + 'last_changed': <ANY>, + 'last_reported': <ANY>, + 'last_updated': <ANY>, + 'state': '9', + }) +# --- +# name: test_all_entities[sensor.connections_won-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': <SensorStateClass.TOTAL: 'total'>, + }), + 'config_entry_id': <ANY>, + 'device_class': None, + 'device_id': <ANY>, + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.connections_won', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': <ANY>, + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Won', + 'platform': 'nyt_games', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'won', + 'unique_id': '218886794-connections-connections_won', + 'unit_of_measurement': 'games', + }) +# --- +# name: test_all_entities[sensor.connections_won-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Connections Won', + 'state_class': <SensorStateClass.TOTAL: 'total'>, + 'unit_of_measurement': 'games', + }), + 'context': <ANY>, + 'entity_id': 'sensor.connections_won', + 'last_changed': <ANY>, + 'last_reported': <ANY>, + 'last_updated': <ANY>, + 'state': '3', + }) +# --- +# name: test_all_entities[sensor.spelling_bee_played-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': <SensorStateClass.TOTAL: 'total'>, + }), + 'config_entry_id': <ANY>, + 'device_class': None, + 'device_id': <ANY>, + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.spelling_bee_played', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': <ANY>, + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Played', + 'platform': 'nyt_games', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'spelling_bees_played', + 'unique_id': '218886794-spelling_bee-spelling_bees_played', + 'unit_of_measurement': 'games', + }) +# --- +# name: test_all_entities[sensor.spelling_bee_played-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Spelling Bee Played', + 'state_class': <SensorStateClass.TOTAL: 'total'>, + 'unit_of_measurement': 'games', + }), + 'context': <ANY>, + 'entity_id': 'sensor.spelling_bee_played', + 'last_changed': <ANY>, + 'last_reported': <ANY>, + 'last_updated': <ANY>, + 'state': '87', + }) +# --- +# name: test_all_entities[sensor.spelling_bee_total_pangrams_found-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': <SensorStateClass.TOTAL: 'total'>, + }), + 'config_entry_id': <ANY>, + 'device_class': None, + 'device_id': <ANY>, + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.spelling_bee_total_pangrams_found', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': <ANY>, + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Total pangrams found', + 'platform': 'nyt_games', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'total_pangrams', + 'unique_id': '218886794-spelling_bee-spelling_bees_total_pangrams', + 'unit_of_measurement': 'pangrams', + }) +# --- +# name: test_all_entities[sensor.spelling_bee_total_pangrams_found-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Spelling Bee Total pangrams found', + 'state_class': <SensorStateClass.TOTAL: 'total'>, + 'unit_of_measurement': 'pangrams', + }), + 'context': <ANY>, + 'entity_id': 'sensor.spelling_bee_total_pangrams_found', + 'last_changed': <ANY>, + 'last_reported': <ANY>, + 'last_updated': <ANY>, + 'state': '15', + }) +# --- +# name: test_all_entities[sensor.spelling_bee_total_words_found-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': <SensorStateClass.TOTAL: 'total'>, + }), + 'config_entry_id': <ANY>, + 'device_class': None, + 'device_id': <ANY>, + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.spelling_bee_total_words_found', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': <ANY>, + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Total words found', + 'platform': 'nyt_games', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'total_words', + 'unique_id': '218886794-spelling_bee-spelling_bees_total_words', + 'unit_of_measurement': 'words', + }) +# --- +# name: test_all_entities[sensor.spelling_bee_total_words_found-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Spelling Bee Total words found', + 'state_class': <SensorStateClass.TOTAL: 'total'>, + 'unit_of_measurement': 'words', + }), + 'context': <ANY>, + 'entity_id': 'sensor.spelling_bee_total_words_found', + 'last_changed': <ANY>, + 'last_reported': <ANY>, + 'last_updated': <ANY>, + 'state': '362', + }) +# --- +# name: test_all_entities[sensor.wordle_current_streak-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': <SensorStateClass.TOTAL: 'total'>, + }), + 'config_entry_id': <ANY>, + 'device_class': None, + 'device_id': <ANY>, + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.wordle_current_streak', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': <ANY>, + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': <SensorDeviceClass.DURATION: 'duration'>, + 'original_icon': None, + 'original_name': 'Current streak', + 'platform': 'nyt_games', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'streak', + 'unique_id': '218886794-wordle-wordles_streak', + 'unit_of_measurement': <UnitOfTime.DAYS: 'd'>, + }) +# --- +# name: test_all_entities[sensor.wordle_current_streak-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'duration', + 'friendly_name': 'Wordle Current streak', + 'state_class': <SensorStateClass.TOTAL: 'total'>, + 'unit_of_measurement': <UnitOfTime.DAYS: 'd'>, + }), + 'context': <ANY>, + 'entity_id': 'sensor.wordle_current_streak', 'last_changed': <ANY>, 'last_reported': <ANY>, 'last_updated': <ANY>, 'state': '1', }) # --- -# name: test_all_entities[sensor.nytgames_highest_wordle_streak-entry] +# name: test_all_entities[sensor.wordle_highest_streak-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -64,7 +463,7 @@ 'disabled_by': None, 'domain': 'sensor', 'entity_category': None, - 'entity_id': 'sensor.nytgames_highest_wordle_streak', + 'entity_id': 'sensor.wordle_highest_streak', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -76,32 +475,32 @@ }), 'original_device_class': <SensorDeviceClass.DURATION: 'duration'>, 'original_icon': None, - 'original_name': 'Highest Wordle streak', + 'original_name': 'Highest streak', 'platform': 'nyt_games', 'previous_unique_id': None, 'supported_features': 0, - 'translation_key': 'wordles_max_streak', - 'unique_id': '218886794-wordles_max_streak', + 'translation_key': 'max_streak', + 'unique_id': '218886794-wordle-wordles_max_streak', 'unit_of_measurement': <UnitOfTime.DAYS: 'd'>, }) # --- -# name: test_all_entities[sensor.nytgames_highest_wordle_streak-state] +# name: test_all_entities[sensor.wordle_highest_streak-state] StateSnapshot({ 'attributes': ReadOnlyDict({ 'device_class': 'duration', - 'friendly_name': 'NYTGames Highest Wordle streak', + 'friendly_name': 'Wordle Highest streak', 'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>, 'unit_of_measurement': <UnitOfTime.DAYS: 'd'>, }), 'context': <ANY>, - 'entity_id': 'sensor.nytgames_highest_wordle_streak', + 'entity_id': 'sensor.wordle_highest_streak', 'last_changed': <ANY>, 'last_reported': <ANY>, 'last_updated': <ANY>, 'state': '5', }) # --- -# name: test_all_entities[sensor.nytgames_wordles_played-entry] +# name: test_all_entities[sensor.wordle_played-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -115,7 +514,7 @@ 'disabled_by': None, 'domain': 'sensor', 'entity_category': None, - 'entity_id': 'sensor.nytgames_wordles_played', + 'entity_id': 'sensor.wordle_played', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -127,31 +526,31 @@ }), 'original_device_class': None, 'original_icon': None, - 'original_name': 'Wordles played', + 'original_name': 'Played', 'platform': 'nyt_games', 'previous_unique_id': None, 'supported_features': 0, 'translation_key': 'wordles_played', - 'unique_id': '218886794-wordles_played', + 'unique_id': '218886794-wordle-wordles_played', 'unit_of_measurement': 'games', }) # --- -# name: test_all_entities[sensor.nytgames_wordles_played-state] +# name: test_all_entities[sensor.wordle_played-state] StateSnapshot({ 'attributes': ReadOnlyDict({ - 'friendly_name': 'NYTGames Wordles played', + 'friendly_name': 'Wordle Played', 'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>, 'unit_of_measurement': 'games', }), 'context': <ANY>, - 'entity_id': 'sensor.nytgames_wordles_played', + 'entity_id': 'sensor.wordle_played', 'last_changed': <ANY>, 'last_reported': <ANY>, 'last_updated': <ANY>, 'state': '33', }) # --- -# name: test_all_entities[sensor.nytgames_wordles_won-entry] +# name: test_all_entities[sensor.wordle_won-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ }), @@ -165,7 +564,7 @@ 'disabled_by': None, 'domain': 'sensor', 'entity_category': None, - 'entity_id': 'sensor.nytgames_wordles_won', + 'entity_id': 'sensor.wordle_won', 'has_entity_name': True, 'hidden_by': None, 'icon': None, @@ -177,24 +576,24 @@ }), 'original_device_class': None, 'original_icon': None, - 'original_name': 'Wordles won', + 'original_name': 'Won', 'platform': 'nyt_games', 'previous_unique_id': None, 'supported_features': 0, - 'translation_key': 'wordles_won', - 'unique_id': '218886794-wordles_won', + 'translation_key': 'won', + 'unique_id': '218886794-wordle-wordles_won', 'unit_of_measurement': 'games', }) # --- -# name: test_all_entities[sensor.nytgames_wordles_won-state] +# name: test_all_entities[sensor.wordle_won-state] StateSnapshot({ 'attributes': ReadOnlyDict({ - 'friendly_name': 'NYTGames Wordles won', + 'friendly_name': 'Wordle Won', 'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>, 'unit_of_measurement': 'games', }), 'context': <ANY>, - 'entity_id': 'sensor.nytgames_wordles_won', + 'entity_id': 'sensor.wordle_won', 'last_changed': <ANY>, 'last_reported': <ANY>, 'last_updated': <ANY>, diff --git a/tests/components/nyt_games/test_init.py b/tests/components/nyt_games/test_init.py index e8286066319d35276dcf022c91e979f2301c38e3..2e1a8c92f90aa72c53e7a49a05692c7ad82819f5 100644 --- a/tests/components/nyt_games/test_init.py +++ b/tests/components/nyt_games/test_init.py @@ -22,8 +22,9 @@ async def test_device_info( ) -> None: """Test device registry integration.""" await setup_integration(hass, mock_config_entry) - device_entry = device_registry.async_get_device( - identifiers={(DOMAIN, mock_config_entry.unique_id)} - ) - assert device_entry is not None - assert device_entry == snapshot + for entity in ("wordle", "spelling_bee", "connections"): + device_entry = device_registry.async_get_device( + identifiers={(DOMAIN, f"{mock_config_entry.unique_id}_{entity}")} + ) + assert device_entry is not None + assert device_entry == snapshot(name=f"device_{entity}") diff --git a/tests/components/nyt_games/test_sensor.py b/tests/components/nyt_games/test_sensor.py index 198164b56f16960cf939547e5e3b95a1128526ad..3866b6afab0cafe2233391d65f4f7a1739940677 100644 --- a/tests/components/nyt_games/test_sensor.py +++ b/tests/components/nyt_games/test_sensor.py @@ -5,6 +5,7 @@ from unittest.mock import AsyncMock from freezegun.api import FrozenDateTimeFactory from nyt_games import NYTGamesError +import pytest from syrupy import SnapshotAssertion from homeassistant.const import STATE_UNAVAILABLE @@ -16,6 +17,7 @@ from . import setup_integration from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform +@pytest.mark.usefixtures("entity_registry_enabled_by_default") async def test_all_entities( hass: HomeAssistant, snapshot: SnapshotAssertion, @@ -44,7 +46,7 @@ async def test_updating_exception( async_fire_time_changed(hass) await hass.async_block_till_done() - assert hass.states.get("sensor.nytgames_wordles_played").state == STATE_UNAVAILABLE + assert hass.states.get("sensor.wordle_played").state == STATE_UNAVAILABLE mock_nyt_games_client.get_latest_stats.side_effect = None @@ -52,4 +54,4 @@ async def test_updating_exception( async_fire_time_changed(hass) await hass.async_block_till_done() - assert hass.states.get("sensor.nytgames_wordles_played").state != STATE_UNAVAILABLE + assert hass.states.get("sensor.wordle_played").state != STATE_UNAVAILABLE