Speed up creating group entities from YAML (#73649)

* Speed up creating group entities from YAML

- Pass all the entities to async_add_entities in one call to
  avoid multiple levels of gather

* Speed up creating group entities from YAML

- Pass all the entities to async_add_entities in one call to
  avoid multiple levels of gather

* Update homeassistant/components/group/__init__.py

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

* Update homeassistant/components/group/__init__.py

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

* Update homeassistant/components/group/__init__.py

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

* Update homeassistant/components/group/__init__.py

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

* typing

* unbreak

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
J. Nick Koston 2022-06-21 11:56:32 -05:00 committed by GitHub
parent 9fd48da132
commit db9c242723
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -104,6 +104,12 @@ CONFIG_SCHEMA = vol.Schema(
) )
def _async_get_component(hass: HomeAssistant) -> EntityComponent:
if (component := hass.data.get(DOMAIN)) is None:
component = hass.data[DOMAIN] = EntityComponent(_LOGGER, DOMAIN, hass)
return component
class GroupIntegrationRegistry: class GroupIntegrationRegistry:
"""Class to hold a registry of integrations.""" """Class to hold a registry of integrations."""
@ -274,7 +280,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
await async_process_integration_platforms(hass, DOMAIN, _process_group_platform) await async_process_integration_platforms(hass, DOMAIN, _process_group_platform)
await _async_process_config(hass, config, component) await _async_process_config(hass, config)
async def reload_service_handler(service: ServiceCall) -> None: async def reload_service_handler(service: ServiceCall) -> None:
"""Remove all user-defined groups and load new ones from config.""" """Remove all user-defined groups and load new ones from config."""
@ -286,7 +292,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
if (conf := await component.async_prepare_reload()) is None: if (conf := await component.async_prepare_reload()) is None:
return return
await _async_process_config(hass, conf, component) await _async_process_config(hass, conf)
await component.async_add_entities(auto) await component.async_add_entities(auto)
@ -406,31 +412,33 @@ async def _process_group_platform(hass, domain, platform):
platform.async_describe_on_off_states(hass, hass.data[REG_KEY]) platform.async_describe_on_off_states(hass, hass.data[REG_KEY])
async def _async_process_config(hass, config, component): async def _async_process_config(hass: HomeAssistant, config: ConfigType) -> None:
"""Process group configuration.""" """Process group configuration."""
hass.data.setdefault(GROUP_ORDER, 0) hass.data.setdefault(GROUP_ORDER, 0)
tasks = [] entities = []
domain_config: dict[str, dict[str, Any]] = config.get(DOMAIN, {})
for object_id, conf in config.get(DOMAIN, {}).items(): for object_id, conf in domain_config.items():
name = conf.get(CONF_NAME, object_id) name: str = conf.get(CONF_NAME, object_id)
entity_ids = conf.get(CONF_ENTITIES) or [] entity_ids: Iterable[str] = conf.get(CONF_ENTITIES) or []
icon = conf.get(CONF_ICON) icon: str | None = conf.get(CONF_ICON)
mode = conf.get(CONF_ALL) mode = bool(conf.get(CONF_ALL))
order: int = hass.data[GROUP_ORDER]
# We keep track of the order when we are creating the tasks # We keep track of the order when we are creating the tasks
# in the same way that async_create_group does to make # in the same way that async_create_group does to make
# sure we use the same ordering system. This overcomes # sure we use the same ordering system. This overcomes
# the problem with concurrently creating the groups # the problem with concurrently creating the groups
tasks.append( entities.append(
Group.async_create_group( Group.async_create_group_entity(
hass, hass,
name, name,
entity_ids, entity_ids,
icon=icon, icon=icon,
object_id=object_id, object_id=object_id,
mode=mode, mode=mode,
order=hass.data[GROUP_ORDER], order=order,
) )
) )
@ -439,7 +447,8 @@ async def _async_process_config(hass, config, component):
# we setup a new group # we setup a new group
hass.data[GROUP_ORDER] += 1 hass.data[GROUP_ORDER] += 1
await asyncio.gather(*tasks) # If called before the platform async_setup is called (test cases)
await _async_get_component(hass).async_add_entities(entities)
class GroupEntity(Entity): class GroupEntity(Entity):
@ -478,14 +487,14 @@ class Group(Entity):
def __init__( def __init__(
self, self,
hass, hass: HomeAssistant,
name, name: str,
order=None, order: int | None = None,
icon=None, icon: str | None = None,
user_defined=True, user_defined: bool = True,
entity_ids=None, entity_ids: Iterable[str] | None = None,
mode=None, mode: bool | None = None,
): ) -> None:
"""Initialize a group. """Initialize a group.
This Object has factory function for creation. This Object has factory function for creation.
@ -508,15 +517,15 @@ class Group(Entity):
@staticmethod @staticmethod
def create_group( def create_group(
hass, hass: HomeAssistant,
name, name: str,
entity_ids=None, entity_ids: Iterable[str] | None = None,
user_defined=True, user_defined: bool = True,
icon=None, icon: str | None = None,
object_id=None, object_id: str | None = None,
mode=None, mode: bool | None = None,
order=None, order: int | None = None,
): ) -> Group:
"""Initialize a group.""" """Initialize a group."""
return asyncio.run_coroutine_threadsafe( return asyncio.run_coroutine_threadsafe(
Group.async_create_group( Group.async_create_group(
@ -526,20 +535,18 @@ class Group(Entity):
).result() ).result()
@staticmethod @staticmethod
async def async_create_group( @callback
hass, def async_create_group_entity(
name, hass: HomeAssistant,
entity_ids=None, name: str,
user_defined=True, entity_ids: Iterable[str] | None = None,
icon=None, user_defined: bool = True,
object_id=None, icon: str | None = None,
mode=None, object_id: str | None = None,
order=None, mode: bool | None = None,
): order: int | None = None,
"""Initialize a group. ) -> Group:
"""Create a group entity."""
This method must be run in the event loop.
"""
if order is None: if order is None:
hass.data.setdefault(GROUP_ORDER, 0) hass.data.setdefault(GROUP_ORDER, 0)
order = hass.data[GROUP_ORDER] order = hass.data[GROUP_ORDER]
@ -562,12 +569,30 @@ class Group(Entity):
ENTITY_ID_FORMAT, object_id or name, hass=hass ENTITY_ID_FORMAT, object_id or name, hass=hass
) )
return group
@staticmethod
@callback
async def async_create_group(
hass: HomeAssistant,
name: str,
entity_ids: Iterable[str] | None = None,
user_defined: bool = True,
icon: str | None = None,
object_id: str | None = None,
mode: bool | None = None,
order: int | None = None,
) -> Group:
"""Initialize a group.
This method must be run in the event loop.
"""
group = Group.async_create_group_entity(
hass, name, entity_ids, user_defined, icon, object_id, mode, order
)
# If called before the platform async_setup is called (test cases) # If called before the platform async_setup is called (test cases)
if (component := hass.data.get(DOMAIN)) is None: await _async_get_component(hass).async_add_entities([group])
component = hass.data[DOMAIN] = EntityComponent(_LOGGER, DOMAIN, hass)
await component.async_add_entities([group])
return group return group
@property @property