forked from home-assistant/core
Add method to generate devices analytics payload
This commit is contained in:
@@ -27,8 +27,8 @@ from homeassistant.config_entries import SOURCE_IGNORE
|
|||||||
from homeassistant.const import ATTR_DOMAIN, __version__ as HA_VERSION
|
from homeassistant.const import ATTR_DOMAIN, __version__ as HA_VERSION
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
|
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||||
import homeassistant.helpers.entity_registry as er
|
|
||||||
from homeassistant.helpers.hassio import is_hassio
|
from homeassistant.helpers.hassio import is_hassio
|
||||||
from homeassistant.helpers.storage import Store
|
from homeassistant.helpers.storage import Store
|
||||||
from homeassistant.helpers.system_info import async_get_system_info
|
from homeassistant.helpers.system_info import async_get_system_info
|
||||||
@@ -370,3 +370,69 @@ class Analytics:
|
|||||||
for entry in entries
|
for entry in entries
|
||||||
if entry.source != SOURCE_IGNORE and entry.disabled_by is None
|
if entry.source != SOURCE_IGNORE and entry.disabled_by is None
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def async_devices_payload(hass: HomeAssistant) -> dict:
|
||||||
|
"""Return the devices payload."""
|
||||||
|
integrations_without_model_id: set[str] = set()
|
||||||
|
devices: list[dict[str, Any]] = []
|
||||||
|
dev_reg = dr.async_get(hass)
|
||||||
|
ignored_integrations = {
|
||||||
|
"bluetooth",
|
||||||
|
"esphome",
|
||||||
|
"hassio",
|
||||||
|
"mqtt",
|
||||||
|
}
|
||||||
|
# Devices that need via device info set
|
||||||
|
new_indexes: dict[str, int] = {}
|
||||||
|
via_devices: dict[str, str] = {}
|
||||||
|
|
||||||
|
for device in dev_reg.devices.values():
|
||||||
|
# Ignore services
|
||||||
|
if device.entry_type:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not device.primary_config_entry:
|
||||||
|
continue
|
||||||
|
|
||||||
|
config_entry = hass.config_entries.async_get_entry(device.primary_config_entry)
|
||||||
|
|
||||||
|
if config_entry is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if config_entry.domain in ignored_integrations:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not device.model_id:
|
||||||
|
integrations_without_model_id.add(config_entry.domain)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not device.manufacturer:
|
||||||
|
continue
|
||||||
|
|
||||||
|
new_indexes[device.id] = len(devices)
|
||||||
|
devices.append(
|
||||||
|
{
|
||||||
|
"manufacturer": device.manufacturer,
|
||||||
|
"model_id": device.model_id,
|
||||||
|
"model": device.model,
|
||||||
|
"sw_version": device.sw_version,
|
||||||
|
"hw_version": device.hw_version,
|
||||||
|
"has_suggested_area": device.suggested_area is not None,
|
||||||
|
"has_configuration_url": device.configuration_url is not None,
|
||||||
|
"via_device": None,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if device.via_device_id:
|
||||||
|
via_devices[device.id] = device.via_device_id
|
||||||
|
|
||||||
|
for from_device, via_device in via_devices.items():
|
||||||
|
if via_device not in new_indexes:
|
||||||
|
continue
|
||||||
|
devices[new_indexes[from_device]]["via_device"] = new_indexes[via_device]
|
||||||
|
|
||||||
|
return {
|
||||||
|
"no_model_id": sorted(integrations_without_model_id),
|
||||||
|
"devices": devices,
|
||||||
|
}
|
||||||
|
@@ -10,7 +10,10 @@ import pytest
|
|||||||
from syrupy import SnapshotAssertion
|
from syrupy import SnapshotAssertion
|
||||||
from syrupy.matchers import path_type
|
from syrupy.matchers import path_type
|
||||||
|
|
||||||
from homeassistant.components.analytics.analytics import Analytics
|
from homeassistant.components.analytics.analytics import (
|
||||||
|
Analytics,
|
||||||
|
async_devices_payload,
|
||||||
|
)
|
||||||
from homeassistant.components.analytics.const import (
|
from homeassistant.components.analytics.const import (
|
||||||
ANALYTICS_ENDPOINT_URL,
|
ANALYTICS_ENDPOINT_URL,
|
||||||
ANALYTICS_ENDPOINT_URL_DEV,
|
ANALYTICS_ENDPOINT_URL_DEV,
|
||||||
@@ -22,6 +25,7 @@ from homeassistant.components.analytics.const import (
|
|||||||
from homeassistant.config_entries import ConfigEntryDisabler, ConfigEntryState
|
from homeassistant.config_entries import ConfigEntryDisabler, ConfigEntryState
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
|
from homeassistant.helpers import device_registry as dr
|
||||||
from homeassistant.loader import IntegrationNotFound
|
from homeassistant.loader import IntegrationNotFound
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
@@ -920,3 +924,101 @@ async def test_not_check_config_entries_if_yaml(
|
|||||||
assert submitted_data["integrations"] == ["default_config"]
|
assert submitted_data["integrations"] == ["default_config"]
|
||||||
assert submitted_data == logged_data
|
assert submitted_data == logged_data
|
||||||
assert snapshot == submitted_data
|
assert snapshot == submitted_data
|
||||||
|
|
||||||
|
|
||||||
|
async def test_devices_payload(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
device_registry: dr.DeviceRegistry,
|
||||||
|
) -> None:
|
||||||
|
"""Test devices payload."""
|
||||||
|
assert async_devices_payload(hass) == {
|
||||||
|
"no_model_id": [],
|
||||||
|
"devices": [],
|
||||||
|
}
|
||||||
|
|
||||||
|
mock_config_entry = MockConfigEntry()
|
||||||
|
mock_config_entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
# Normal entry
|
||||||
|
device_registry.async_get_or_create(
|
||||||
|
config_entry_id=mock_config_entry.entry_id,
|
||||||
|
identifiers={("device", "1")},
|
||||||
|
sw_version="test-sw-version",
|
||||||
|
hw_version="test-hw-version",
|
||||||
|
name="test-name",
|
||||||
|
manufacturer="test-manufacturer",
|
||||||
|
model="test-model",
|
||||||
|
model_id="test-model-id",
|
||||||
|
suggested_area="Game Room",
|
||||||
|
configuration_url="http://example.com/config",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Ignored because service type
|
||||||
|
device_registry.async_get_or_create(
|
||||||
|
config_entry_id=mock_config_entry.entry_id,
|
||||||
|
identifiers={("device", "2")},
|
||||||
|
manufacturer="test-manufacturer",
|
||||||
|
model_id="test-model-id",
|
||||||
|
entry_type=dr.DeviceEntryType.SERVICE,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Ignored because config entry is ignore list
|
||||||
|
ignored_config_entry = MockConfigEntry(domain="esphome")
|
||||||
|
ignored_config_entry.add_to_hass(hass)
|
||||||
|
device_registry.async_get_or_create(
|
||||||
|
config_entry_id=ignored_config_entry.entry_id,
|
||||||
|
identifiers={("device", "3")},
|
||||||
|
manufacturer="test-manufacturer",
|
||||||
|
model_id="test-model-id",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Ignored because no model id
|
||||||
|
no_model_id_config_entry = MockConfigEntry(domain="no_model_id")
|
||||||
|
no_model_id_config_entry.add_to_hass(hass)
|
||||||
|
device_registry.async_get_or_create(
|
||||||
|
config_entry_id=no_model_id_config_entry.entry_id,
|
||||||
|
identifiers={("device", "4")},
|
||||||
|
manufacturer="test-manufacturer",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Ignored because no manufacturer
|
||||||
|
device_registry.async_get_or_create(
|
||||||
|
config_entry_id=mock_config_entry.entry_id,
|
||||||
|
identifiers={("device", "5")},
|
||||||
|
model_id="test-model-id",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Entry with via device
|
||||||
|
device_registry.async_get_or_create(
|
||||||
|
config_entry_id=mock_config_entry.entry_id,
|
||||||
|
identifiers={("device", "6")},
|
||||||
|
manufacturer="test-manufacturer6",
|
||||||
|
model_id="test-model-id6",
|
||||||
|
via_device=("device", "1"),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert async_devices_payload(hass) == {
|
||||||
|
"no_model_id": ["no_model_id"],
|
||||||
|
"devices": [
|
||||||
|
{
|
||||||
|
"manufacturer": "test-manufacturer",
|
||||||
|
"model_id": "test-model-id",
|
||||||
|
"model": "test-model",
|
||||||
|
"sw_version": "test-sw-version",
|
||||||
|
"hw_version": "test-hw-version",
|
||||||
|
"has_suggested_area": True,
|
||||||
|
"has_configuration_url": True,
|
||||||
|
"via_device": None,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"manufacturer": "test-manufacturer6",
|
||||||
|
"model_id": "test-model-id6",
|
||||||
|
"model": None,
|
||||||
|
"sw_version": None,
|
||||||
|
"hw_version": None,
|
||||||
|
"has_suggested_area": False,
|
||||||
|
"has_configuration_url": False,
|
||||||
|
"via_device": 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user