diff --git a/homeassistant/components/analytics_insights/__init__.py b/homeassistant/components/analytics_insights/__init__.py index 1c5118ca004..a59d2a1c97c 100644 --- a/homeassistant/components/analytics_insights/__init__.py +++ b/homeassistant/components/analytics_insights/__init__.py @@ -17,7 +17,7 @@ PLATFORMS: list[Platform] = [Platform.SENSOR] @dataclass(frozen=True) -class AnalyticsData: +class AnalyticsInsightsData: """Analytics data class.""" coordinator: HomeassistantAnalyticsDataUpdateCoordinator @@ -41,7 +41,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: await coordinator.async_config_entry_first_refresh() - hass.data.setdefault(DOMAIN, {})[entry.entry_id] = AnalyticsData( + hass.data.setdefault(DOMAIN, {})[entry.entry_id] = AnalyticsInsightsData( coordinator=coordinator, names=names ) diff --git a/homeassistant/components/analytics_insights/coordinator.py b/homeassistant/components/analytics_insights/coordinator.py index f8eefe7db27..0c2a0f16aa9 100644 --- a/homeassistant/components/analytics_insights/coordinator.py +++ b/homeassistant/components/analytics_insights/coordinator.py @@ -1,6 +1,7 @@ """DataUpdateCoordinator for the Homeassistant Analytics integration.""" from __future__ import annotations +from dataclasses import dataclass from datetime import timedelta from python_homeassistant_analytics import ( @@ -16,9 +17,14 @@ from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, Upda from .const import CONF_TRACKED_INTEGRATIONS, DOMAIN, LOGGER -class HomeassistantAnalyticsDataUpdateCoordinator( - DataUpdateCoordinator[dict[str, int]] -): +@dataclass(frozen=True, kw_only=True) +class AnalyticsData: + """Analytics data class.""" + + core_integrations: dict[str, int] + + +class HomeassistantAnalyticsDataUpdateCoordinator(DataUpdateCoordinator[AnalyticsData]): """A Homeassistant Analytics Data Update Coordinator.""" config_entry: ConfigEntry @@ -38,7 +44,7 @@ class HomeassistantAnalyticsDataUpdateCoordinator( CONF_TRACKED_INTEGRATIONS ] - async def _async_update_data(self) -> dict[str, int]: + async def _async_update_data(self) -> AnalyticsData: try: data = await self._client.get_current_analytics() except HomeassistantAnalyticsConnectionError as err: @@ -47,7 +53,8 @@ class HomeassistantAnalyticsDataUpdateCoordinator( ) from err except HomeassistantAnalyticsNotModifiedError: return self.data - return { + core_integrations = { integration: data.integrations.get(integration, 0) for integration in self._tracked_integrations } + return AnalyticsData(core_integrations=core_integrations) diff --git a/homeassistant/components/analytics_insights/icons.json b/homeassistant/components/analytics_insights/icons.json new file mode 100644 index 00000000000..b1358e478b4 --- /dev/null +++ b/homeassistant/components/analytics_insights/icons.json @@ -0,0 +1,9 @@ +{ + "entity": { + "sensor": { + "core_integrations": { + "default": "mdi:puzzle" + } + } + } +} diff --git a/homeassistant/components/analytics_insights/sensor.py b/homeassistant/components/analytics_insights/sensor.py index f8a8b244c60..ae24abd8b07 100644 --- a/homeassistant/components/analytics_insights/sensor.py +++ b/homeassistant/components/analytics_insights/sensor.py @@ -1,16 +1,45 @@ """Sensor for Home Assistant analytics.""" from __future__ import annotations -from homeassistant.components.sensor import SensorEntity, SensorStateClass +from collections.abc import Callable +from dataclasses import dataclass + +from homeassistant.components.sensor import ( + SensorEntity, + SensorEntityDescription, + SensorStateClass, +) from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.helpers.typing import StateType from homeassistant.helpers.update_coordinator import CoordinatorEntity -from . import AnalyticsData +from . import AnalyticsInsightsData from .const import DOMAIN -from .coordinator import HomeassistantAnalyticsDataUpdateCoordinator +from .coordinator import AnalyticsData, HomeassistantAnalyticsDataUpdateCoordinator + + +@dataclass(frozen=True, kw_only=True) +class AnalyticsSensorEntityDescription(SensorEntityDescription): + """Analytics sensor entity description.""" + + value_fn: Callable[[AnalyticsData], StateType] + + +def get_core_integration_entity_description( + domain: str, name: str +) -> AnalyticsSensorEntityDescription: + """Get core integration entity description.""" + return AnalyticsSensorEntityDescription( + key=f"core_{domain}_active_installations", + translation_key="core_integrations", + name=name, + state_class=SensorStateClass.TOTAL, + native_unit_of_measurement="active installations", + value_fn=lambda data: data.core_integrations.get(domain), + ) async def async_setup_entry( @@ -20,14 +49,15 @@ async def async_setup_entry( ) -> None: """Initialize the entries.""" - analytics_data: AnalyticsData = hass.data[DOMAIN][entry.entry_id] + analytics_data: AnalyticsInsightsData = hass.data[DOMAIN][entry.entry_id] async_add_entities( HomeassistantAnalyticsSensor( analytics_data.coordinator, - integration_domain, - analytics_data.names[integration_domain], + get_core_integration_entity_description( + integration_domain, analytics_data.names[integration_domain] + ), ) - for integration_domain in analytics_data.coordinator.data + for integration_domain in analytics_data.coordinator.data.core_integrations ) @@ -37,26 +67,24 @@ class HomeassistantAnalyticsSensor( """Home Assistant Analytics Sensor.""" _attr_has_entity_name = True - _attr_state_class = SensorStateClass.TOTAL - _attr_native_unit_of_measurement = "active installations" + + entity_description: AnalyticsSensorEntityDescription def __init__( self, coordinator: HomeassistantAnalyticsDataUpdateCoordinator, - integration_domain: str, - name: str, + entity_description: AnalyticsSensorEntityDescription, ) -> None: """Initialize the sensor.""" super().__init__(coordinator) - self._attr_name = name - self._attr_unique_id = f"core_{integration_domain}_active_installations" + self.entity_description = entity_description + self._attr_unique_id = entity_description.key self._attr_device_info = DeviceInfo( identifiers={(DOMAIN, DOMAIN)}, entry_type=DeviceEntryType.SERVICE, ) - self._integration_domain = integration_domain @property - def native_value(self) -> int | None: + def native_value(self) -> StateType: """Return the state of the sensor.""" - return self.coordinator.data.get(self._integration_domain) + return self.entity_description.value_fn(self.coordinator.data) diff --git a/tests/components/analytics_insights/snapshots/test_sensor.ambr b/tests/components/analytics_insights/snapshots/test_sensor.ambr index 8a9688cb60c..404850baa4e 100644 --- a/tests/components/analytics_insights/snapshots/test_sensor.ambr +++ b/tests/components/analytics_insights/snapshots/test_sensor.ambr @@ -27,7 +27,7 @@ 'platform': 'analytics_insights', 'previous_unique_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'core_integrations', 'unique_id': 'core_myq_active_installations', 'unit_of_measurement': 'active installations', }) @@ -74,7 +74,7 @@ 'platform': 'analytics_insights', 'previous_unique_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'core_integrations', 'unique_id': 'core_spotify_active_installations', 'unit_of_measurement': 'active installations', }) @@ -121,7 +121,7 @@ 'platform': 'analytics_insights', 'previous_unique_id': None, 'supported_features': 0, - 'translation_key': None, + 'translation_key': 'core_integrations', 'unique_id': 'core_youtube_active_installations', 'unit_of_measurement': 'active installations', })