Initil after Upgrade
This commit is contained in:
@@ -1,17 +1,17 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Awaitable, Callable
|
||||
from datetime import timedelta
|
||||
from datetime import datetime, timedelta
|
||||
from enum import StrEnum
|
||||
import logging
|
||||
import re
|
||||
from typing import Any
|
||||
from typing import Any, TypeVar
|
||||
|
||||
from homeassistant.components.light import DOMAIN as LIGHT_DOMAIN
|
||||
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
|
||||
from homeassistant.config_entries import SOURCE_INTEGRATION_DISCOVERY, SOURCE_USER, ConfigEntry
|
||||
from homeassistant.const import CONF_ENTITY_ID, CONF_PLATFORM, CONF_UNIQUE_ID
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.core import CALLBACK_TYPE, HomeAssistant, callback
|
||||
from homeassistant.helpers import discovery_flow
|
||||
import homeassistant.helpers.device_registry as dr
|
||||
from homeassistant.helpers.entity import EntityCategory
|
||||
@@ -33,13 +33,22 @@ from .const import (
|
||||
MANUFACTURER_WLED,
|
||||
CalculationStrategy,
|
||||
)
|
||||
from .group_include.filter import CategoryFilter, CompositeFilter, DomainFilter, FilterOperator, LambdaFilter, NotFilter, get_filtered_entity_list
|
||||
from .group_include.filter import (
|
||||
CategoryFilter,
|
||||
CompositeFilter,
|
||||
DomainFilter,
|
||||
FilterOperator,
|
||||
LambdaFilter,
|
||||
NotFilter,
|
||||
get_filtered_entity_list,
|
||||
)
|
||||
from .helpers import get_or_create_unique_id
|
||||
from .power_profile.factory import get_power_profile
|
||||
from .power_profile.library import ModelInfo, ProfileLibrary
|
||||
from .power_profile.power_profile import SUPPORTED_DOMAINS, DeviceType, DiscoveryBy, PowerProfile
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
_DiscoverySourceT = TypeVar("_DiscoverySourceT", er.RegistryEntry, dr.DeviceEntry)
|
||||
|
||||
|
||||
async def get_power_profile_by_source_entity(hass: HomeAssistant, source_entity: SourceEntity) -> PowerProfile | None:
|
||||
@@ -102,6 +111,7 @@ class DiscoveryManager:
|
||||
self.library: ProfileLibrary | None = None
|
||||
self._exclude_device_types = exclude_device_types or []
|
||||
self._exclude_self_usage_profiles = exclude_self_usage_profiles or False
|
||||
self._cancel_rediscover_interval: CALLBACK_TYPE | None = None
|
||||
self._status = DiscoveryStatus.NOT_STARTED if enabled else DiscoveryStatus.DISABLED
|
||||
|
||||
async def setup(self) -> None:
|
||||
@@ -112,14 +122,18 @@ class DiscoveryManager:
|
||||
|
||||
await self.start_discovery()
|
||||
|
||||
async def _rediscover(_: Any) -> None: # noqa: ANN401
|
||||
async def _rediscover(_: datetime) -> None:
|
||||
"""Rediscover entities."""
|
||||
await self.update_library_and_rediscover()
|
||||
|
||||
async_track_time_interval(
|
||||
if self._cancel_rediscover_interval: # pragma: no cover
|
||||
self._cancel_rediscover_interval()
|
||||
|
||||
self._cancel_rediscover_interval = async_track_time_interval(
|
||||
self.hass,
|
||||
_rediscover,
|
||||
timedelta(hours=2),
|
||||
cancel_on_shutdown=True,
|
||||
)
|
||||
|
||||
async def update_library_and_rediscover(self) -> None:
|
||||
@@ -130,6 +144,9 @@ class DiscoveryManager:
|
||||
|
||||
async def start_discovery(self) -> None:
|
||||
"""Start the discovery procedure."""
|
||||
if self._status == DiscoveryStatus.DISABLED:
|
||||
_LOGGER.debug("Discovery manager is disabled, skipping discovery run")
|
||||
return
|
||||
if self._status == DiscoveryStatus.IN_PROGRESS:
|
||||
_LOGGER.debug("Discovery already in progress, skipping new discovery run")
|
||||
return
|
||||
@@ -139,10 +156,10 @@ class DiscoveryManager:
|
||||
_LOGGER.debug("Start auto discovery")
|
||||
|
||||
_LOGGER.debug("Start entity discovery")
|
||||
await self.perform_discovery(self.get_entities, self.create_entity_source, DiscoveryBy.ENTITY) # type: ignore[arg-type]
|
||||
await self.perform_discovery(self.get_entities, self.create_entity_source, DiscoveryBy.ENTITY)
|
||||
|
||||
_LOGGER.debug("Start device discovery")
|
||||
await self.perform_discovery(self.get_devices, self.create_device_source, DiscoveryBy.DEVICE) # type: ignore[arg-type]
|
||||
await self.perform_discovery(self.get_devices, self.create_device_source, DiscoveryBy.DEVICE)
|
||||
|
||||
_LOGGER.debug("Done auto discovery")
|
||||
self._status = DiscoveryStatus.FINISHED
|
||||
@@ -158,7 +175,7 @@ class DiscoveryManager:
|
||||
if not entity_id or entity_id == DUMMY_ENTITY_ID:
|
||||
continue
|
||||
|
||||
entity = await create_source_entity(str(entity_id), self.hass)
|
||||
entity = create_source_entity(str(entity_id), self.hass)
|
||||
if entity and entity.device_entry:
|
||||
self.initialized_flows.add(f"pc_{entity.device_entry.id}")
|
||||
self.initialized_flows.add(entity_id)
|
||||
@@ -173,13 +190,13 @@ class DiscoveryManager:
|
||||
|
||||
async def perform_discovery(
|
||||
self,
|
||||
source_provider: Callable[[], Awaitable[list]],
|
||||
source_creator: Callable[[er.RegistryEntry | dr.DeviceEntry], Awaitable[SourceEntity]],
|
||||
source_provider: Callable[[], Awaitable[list[_DiscoverySourceT]]],
|
||||
source_creator: Callable[[_DiscoverySourceT], Awaitable[SourceEntity]],
|
||||
discovery_type: DiscoveryBy,
|
||||
) -> None:
|
||||
"""Generalized discovery procedure for entities and devices."""
|
||||
for source in await source_provider():
|
||||
log_identifier = source.entity_id if discovery_type == DiscoveryBy.ENTITY else source.id
|
||||
log_identifier = str(getattr(source, "entity_id", getattr(source, "id", "unknown")))
|
||||
try:
|
||||
model_info = await self.extract_model_info_from_device_info(source)
|
||||
if not model_info:
|
||||
@@ -229,7 +246,7 @@ class DiscoveryManager:
|
||||
|
||||
async def create_entity_source(self, entity_entry: er.RegistryEntry) -> SourceEntity:
|
||||
"""Create SourceEntity for an entity."""
|
||||
return await create_source_entity(entity_entry.entity_id, self.hass)
|
||||
return create_source_entity(entity_entry.entity_id, self.hass)
|
||||
|
||||
@staticmethod
|
||||
async def create_device_source(device_entry: dr.DeviceEntry) -> SourceEntity:
|
||||
@@ -267,13 +284,19 @@ class DiscoveryManager:
|
||||
|
||||
power_profiles = []
|
||||
for model_info in models:
|
||||
profile = await get_power_profile(self.hass, {}, source_entity, model_info=model_info, process_variables=False)
|
||||
profile = await get_power_profile(
|
||||
self.hass,
|
||||
{},
|
||||
source_entity,
|
||||
model_info=model_info,
|
||||
process_variables=False,
|
||||
)
|
||||
if not profile or profile.discovery_by != discovery_type: # pragma: no cover
|
||||
continue
|
||||
if discovery_type == DiscoveryBy.ENTITY and not profile.is_entity_domain_supported(
|
||||
source_entity.entity_entry, # type: ignore[arg-type]
|
||||
):
|
||||
continue
|
||||
if discovery_type == DiscoveryBy.ENTITY:
|
||||
entity_entry = source_entity.entity_entry
|
||||
if entity_entry is not None and not profile.is_entity_domain_supported(entity_entry):
|
||||
continue
|
||||
if profile.device_type in self._exclude_device_types:
|
||||
continue
|
||||
if self._exclude_self_usage_profiles and profile.only_self_usage:
|
||||
@@ -294,7 +317,11 @@ class DiscoveryManager:
|
||||
"""Initialize the discovery flow for a WLED light."""
|
||||
if DeviceType.LIGHT in self._exclude_device_types:
|
||||
return
|
||||
unique_id = f"pc_{source_entity.device_entry.id}" if source_entity.device_entry else get_or_create_unique_id({}, source_entity, None)
|
||||
unique_id = (
|
||||
f"pc_{source_entity.device_entry.id}"
|
||||
if source_entity.device_entry
|
||||
else get_or_create_unique_id({}, source_entity, None)
|
||||
)
|
||||
if self._is_already_discovered(source_entity, unique_id):
|
||||
_LOGGER.debug(
|
||||
"%s: Already setup with discovery, skipping new discovery (unique_id=%s)",
|
||||
@@ -352,9 +379,9 @@ class DiscoveryManager:
|
||||
],
|
||||
FilterOperator.OR,
|
||||
)
|
||||
return await get_filtered_entity_list(self.hass, NotFilter(entity_filter))
|
||||
return get_filtered_entity_list(self.hass, NotFilter(entity_filter))
|
||||
|
||||
async def get_devices(self) -> list:
|
||||
async def get_devices(self) -> list[dr.DeviceEntry]:
|
||||
"""Fetch device entries."""
|
||||
return list(dr.async_get(self.hass).devices.values())
|
||||
|
||||
@@ -364,6 +391,9 @@ class DiscoveryManager:
|
||||
|
||||
async def disable(self) -> None:
|
||||
"""Disable the discovery."""
|
||||
if self._cancel_rediscover_interval:
|
||||
self._cancel_rediscover_interval()
|
||||
self._cancel_rediscover_interval = None
|
||||
self._status = DiscoveryStatus.DISABLED
|
||||
self.initialized_flows = set()
|
||||
flows = self.hass.config_entries.flow.async_progress_by_handler(DOMAIN)
|
||||
@@ -423,7 +453,9 @@ class DiscoveryManager:
|
||||
# see https://github.com/home-assistant/core/pull/166187
|
||||
manufacturer = str(device_entry.manufacturer).strip()
|
||||
model = str(device_entry.model).strip()
|
||||
model_id = str(device_entry.model_id).strip() if hasattr(device_entry, "model_id") and device_entry.model_id else None
|
||||
model_id = (
|
||||
str(device_entry.model_id).strip() if hasattr(device_entry, "model_id") and device_entry.model_id else None
|
||||
)
|
||||
|
||||
if len(manufacturer) == 0 or len(model) == 0:
|
||||
return None
|
||||
@@ -508,7 +540,9 @@ class DiscoveryManager:
|
||||
# Find entity ids in yaml config (Legacy)
|
||||
if SENSOR_DOMAIN in self.ha_config: # pragma: no cover
|
||||
sensor_config = self.ha_config.get(SENSOR_DOMAIN)
|
||||
platform_entries = [item for item in sensor_config or {} if isinstance(item, dict) and item.get(CONF_PLATFORM) == DOMAIN]
|
||||
platform_entries = [
|
||||
item for item in sensor_config or {} if isinstance(item, dict) and item.get(CONF_PLATFORM) == DOMAIN
|
||||
]
|
||||
for entry in platform_entries:
|
||||
entities.extend(self._find_entity_ids_in_yaml_config(entry))
|
||||
|
||||
@@ -521,7 +555,11 @@ class DiscoveryManager:
|
||||
|
||||
# Add entities from existing config entries
|
||||
entities.extend(
|
||||
[str(entry.data.get(CONF_ENTITY_ID)) for entry in self.hass.config_entries.async_entries(DOMAIN) if entry.source == SOURCE_USER],
|
||||
[
|
||||
str(entry.data.get(CONF_ENTITY_ID))
|
||||
for entry in self.hass.config_entries.async_entries(DOMAIN)
|
||||
if entry.source == SOURCE_USER
|
||||
],
|
||||
)
|
||||
|
||||
return entities
|
||||
|
||||
Reference in New Issue
Block a user