Skip to content

Commit

Permalink
Add addon support to Home Assistant Analytics Insights (#128806)
Browse files Browse the repository at this point in the history
  • Loading branch information
mib1185 authored Oct 29, 2024
1 parent c9aba28 commit a95c232
Show file tree
Hide file tree
Showing 9 changed files with 187 additions and 5 deletions.
35 changes: 31 additions & 4 deletions homeassistant/components/analytics_insights/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
)

from .const import (
CONF_TRACKED_ADDONS,
CONF_TRACKED_CUSTOM_INTEGRATIONS,
CONF_TRACKED_INTEGRATIONS,
DOMAIN,
Expand Down Expand Up @@ -55,15 +56,20 @@ async def async_step_user(
"""Handle the initial step."""
errors: dict[str, str] = {}
if user_input is not None:
if not user_input.get(CONF_TRACKED_INTEGRATIONS) and not user_input.get(
CONF_TRACKED_CUSTOM_INTEGRATIONS
if all(
[
not user_input.get(CONF_TRACKED_ADDONS),
not user_input.get(CONF_TRACKED_INTEGRATIONS),
not user_input.get(CONF_TRACKED_CUSTOM_INTEGRATIONS),
]
):
errors["base"] = "no_integrations_selected"
else:
return self.async_create_entry(
title="Home Assistant Analytics Insights",
data={},
options={
CONF_TRACKED_ADDONS: user_input.get(CONF_TRACKED_ADDONS, []),
CONF_TRACKED_INTEGRATIONS: user_input.get(
CONF_TRACKED_INTEGRATIONS, []
),
Expand All @@ -77,6 +83,7 @@ async def async_step_user(
session=async_get_clientsession(self.hass)
)
try:
addons = await client.get_addons()
integrations = await client.get_integrations()
custom_integrations = await client.get_custom_integrations()
except HomeassistantAnalyticsConnectionError:
Expand All @@ -99,6 +106,13 @@ async def async_step_user(
errors=errors,
data_schema=vol.Schema(
{
vol.Optional(CONF_TRACKED_ADDONS): SelectSelector(
SelectSelectorConfig(
options=list(addons),
multiple=True,
sort=True,
)
),
vol.Optional(CONF_TRACKED_INTEGRATIONS): SelectSelector(
SelectSelectorConfig(
options=options,
Expand Down Expand Up @@ -127,14 +141,19 @@ async def async_step_init(
"""Manage the options."""
errors: dict[str, str] = {}
if user_input is not None:
if not user_input.get(CONF_TRACKED_INTEGRATIONS) and not user_input.get(
CONF_TRACKED_CUSTOM_INTEGRATIONS
if all(
[
not user_input.get(CONF_TRACKED_ADDONS),
not user_input.get(CONF_TRACKED_INTEGRATIONS),
not user_input.get(CONF_TRACKED_CUSTOM_INTEGRATIONS),
]
):
errors["base"] = "no_integrations_selected"
else:
return self.async_create_entry(
title="",
data={
CONF_TRACKED_ADDONS: user_input.get(CONF_TRACKED_ADDONS, []),
CONF_TRACKED_INTEGRATIONS: user_input.get(
CONF_TRACKED_INTEGRATIONS, []
),
Expand All @@ -148,6 +167,7 @@ async def async_step_init(
session=async_get_clientsession(self.hass)
)
try:
addons = await client.get_addons()
integrations = await client.get_integrations()
custom_integrations = await client.get_custom_integrations()
except HomeassistantAnalyticsConnectionError:
Expand All @@ -168,6 +188,13 @@ async def async_step_init(
data_schema=self.add_suggested_values_to_schema(
vol.Schema(
{
vol.Optional(CONF_TRACKED_ADDONS): SelectSelector(
SelectSelectorConfig(
options=list(addons),
multiple=True,
sort=True,
)
),
vol.Optional(CONF_TRACKED_INTEGRATIONS): SelectSelector(
SelectSelectorConfig(
options=options,
Expand Down
1 change: 1 addition & 0 deletions homeassistant/components/analytics_insights/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

DOMAIN = "analytics_insights"

CONF_TRACKED_ADDONS = "tracked_addons"
CONF_TRACKED_INTEGRATIONS = "tracked_integrations"
CONF_TRACKED_CUSTOM_INTEGRATIONS = "tracked_custom_integrations"

Expand Down
16 changes: 16 additions & 0 deletions homeassistant/components/analytics_insights/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@
HomeassistantAnalyticsConnectionError,
HomeassistantAnalyticsNotModifiedError,
)
from python_homeassistant_analytics.models import Addon

from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed

from .const import (
CONF_TRACKED_ADDONS,
CONF_TRACKED_CUSTOM_INTEGRATIONS,
CONF_TRACKED_INTEGRATIONS,
DOMAIN,
Expand All @@ -33,6 +35,7 @@ class AnalyticsData:

active_installations: int
reports_integrations: int
addons: dict[str, int]
core_integrations: dict[str, int]
custom_integrations: dict[str, int]

Expand All @@ -53,6 +56,7 @@ def __init__(
update_interval=timedelta(hours=12),
)
self._client = client
self._tracked_addons = self.config_entry.options.get(CONF_TRACKED_ADDONS, [])
self._tracked_integrations = self.config_entry.options[
CONF_TRACKED_INTEGRATIONS
]
Expand All @@ -62,6 +66,7 @@ def __init__(

async def _async_update_data(self) -> AnalyticsData:
try:
addons_data = await self._client.get_addons()
data = await self._client.get_current_analytics()
custom_data = await self._client.get_custom_integrations()
except HomeassistantAnalyticsConnectionError as err:
Expand All @@ -70,6 +75,9 @@ async def _async_update_data(self) -> AnalyticsData:
) from err
except HomeassistantAnalyticsNotModifiedError:
return self.data
addons = {
addon: get_addon_value(addons_data, addon) for addon in self._tracked_addons
}
core_integrations = {
integration: data.integrations.get(integration, 0)
for integration in self._tracked_integrations
Expand All @@ -81,11 +89,19 @@ async def _async_update_data(self) -> AnalyticsData:
return AnalyticsData(
data.active_installations,
data.reports_integrations,
addons,
core_integrations,
custom_integrations,
)


def get_addon_value(data: dict[str, Addon], name_slug: str) -> int:
"""Get addon value."""
if name_slug in data:
return data[name_slug].total
return 0


def get_custom_integration_value(
data: dict[str, CustomIntegration], domain: str
) -> int:
Expand Down
21 changes: 21 additions & 0 deletions homeassistant/components/analytics_insights/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,20 @@ class AnalyticsSensorEntityDescription(SensorEntityDescription):
value_fn: Callable[[AnalyticsData], StateType]


def get_addon_entity_description(
name_slug: str,
) -> AnalyticsSensorEntityDescription:
"""Get addon entity description."""
return AnalyticsSensorEntityDescription(
key=f"addon_{name_slug}_active_installations",
translation_key="addons",
name=name_slug,
state_class=SensorStateClass.TOTAL,
native_unit_of_measurement="active installations",
value_fn=lambda data: data.addons.get(name_slug),
)


def get_core_integration_entity_description(
domain: str, name: str
) -> AnalyticsSensorEntityDescription:
Expand Down Expand Up @@ -89,6 +103,13 @@ async def async_setup_entry(
analytics_data.coordinator
)
entities: list[HomeassistantAnalyticsSensor] = []
entities.extend(
HomeassistantAnalyticsSensor(
coordinator,
get_addon_entity_description(addon_name_slug),
)
for addon_name_slug in coordinator.data.addons
)
entities.extend(
HomeassistantAnalyticsSensor(
coordinator,
Expand Down
4 changes: 4 additions & 0 deletions homeassistant/components/analytics_insights/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
"step": {
"user": {
"data": {
"tracked_addons": "Addons",
"tracked_integrations": "Integrations",
"tracked_custom_integrations": "Custom integrations"
},
"data_description": {
"tracked_addons": "Select the addons you want to track",
"tracked_integrations": "Select the integrations you want to track",
"tracked_custom_integrations": "Select the custom integrations you want to track"
}
Expand All @@ -24,10 +26,12 @@
"step": {
"init": {
"data": {
"tracked_addons": "[%key:component::analytics_insights::config::step::user::data::tracked_addons%]",
"tracked_integrations": "[%key:component::analytics_insights::config::step::user::data::tracked_integrations%]",
"tracked_custom_integrations": "[%key:component::analytics_insights::config::step::user::data::tracked_custom_integrations%]"
},
"data_description": {
"tracked_addons": "[%key:component::analytics_insights::config::step::user::data_description::tracked_addons%]",
"tracked_integrations": "[%key:component::analytics_insights::config::step::user::data_description::tracked_integrations%]",
"tracked_custom_integrations": "[%key:component::analytics_insights::config::step::user::data_description::tracked_custom_integrations%]"
}
Expand Down
8 changes: 7 additions & 1 deletion tests/components/analytics_insights/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@

import pytest
from python_homeassistant_analytics import CurrentAnalytics
from python_homeassistant_analytics.models import CustomIntegration, Integration
from python_homeassistant_analytics.models import Addon, CustomIntegration, Integration

from homeassistant.components.analytics_insights.const import (
CONF_TRACKED_ADDONS,
CONF_TRACKED_CUSTOM_INTEGRATIONS,
CONF_TRACKED_INTEGRATIONS,
DOMAIN,
Expand Down Expand Up @@ -43,6 +44,10 @@ def mock_analytics_client() -> Generator[AsyncMock]:
client.get_current_analytics.return_value = CurrentAnalytics.from_json(
load_fixture("analytics_insights/current_data.json")
)
addons = load_json_object_fixture("analytics_insights/addons.json")
client.get_addons.return_value = {
key: Addon.from_dict(value) for key, value in addons.items()
}
integrations = load_json_object_fixture("analytics_insights/integrations.json")
client.get_integrations.return_value = {
key: Integration.from_dict(value) for key, value in integrations.items()
Expand All @@ -65,6 +70,7 @@ def mock_config_entry() -> MockConfigEntry:
title="Homeassistant Analytics",
data={},
options={
CONF_TRACKED_ADDONS: ["core_samba"],
CONF_TRACKED_INTEGRATIONS: ["youtube", "spotify", "myq"],
CONF_TRACKED_CUSTOM_INTEGRATIONS: ["hacs"],
},
Expand Down
31 changes: 31 additions & 0 deletions tests/components/analytics_insights/fixtures/addons.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"core_samba": {
"total": 76357,
"versions": {
"12.3.2": 65875,
"12.2.0": 1313,
"12.3.1": 5018,
"12.1.0": 211,
"10.0.0": 1139,
"9.4.0": 4,
"12.3.0": 704,
"9.3.1": 36,
"10.0.2": 1290,
"9.5.1": 379,
"9.6.1": 66,
"10.0.1": 200,
"9.3.0": 20,
"9.2.0": 9,
"9.5.0": 13,
"12.0.0": 39,
"9.7.0": 20,
"11.0.0": 13,
"3.0": 1,
"9.6.0": 2,
"8.1": 2,
"9.0": 3
},
"protected": 76345,
"auto_update": 32732
}
}
50 changes: 50 additions & 0 deletions tests/components/analytics_insights/snapshots/test_sensor.ambr
Original file line number Diff line number Diff line change
@@ -1,4 +1,54 @@
# serializer version: 1
# name: test_all_entities[sensor.homeassistant_analytics_core_samba-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': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
'entity_id': 'sensor.homeassistant_analytics_core_samba',
'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': 'core_samba',
'platform': 'analytics_insights',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'addons',
'unique_id': 'addon_core_samba_active_installations',
'unit_of_measurement': 'active installations',
})
# ---
# name: test_all_entities[sensor.homeassistant_analytics_core_samba-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Homeassistant Analytics core_samba',
'state_class': <SensorStateClass.TOTAL: 'total'>,
'unit_of_measurement': 'active installations',
}),
'context': <ANY>,
'entity_id': 'sensor.homeassistant_analytics_core_samba',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '76357',
})
# ---
# name: test_all_entities[sensor.homeassistant_analytics_hacs_custom-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
Expand Down
Loading

0 comments on commit a95c232

Please sign in to comment.