mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 21:27:38 +00:00
Overcome group concurrent setup limitation (#39483)
With a lot of groups the limitation that groups had to be setup one at a time could account for the bulk of startup time.
This commit is contained in:
parent
557684c3ce
commit
3e9963a216
@ -334,17 +334,38 @@ async def async_setup(hass, config):
|
|||||||
|
|
||||||
async def _async_process_config(hass, config, component):
|
async def _async_process_config(hass, config, component):
|
||||||
"""Process group configuration."""
|
"""Process group configuration."""
|
||||||
|
hass.data.setdefault(GROUP_ORDER, 0)
|
||||||
|
|
||||||
|
tasks = []
|
||||||
|
|
||||||
for object_id, conf in config.get(DOMAIN, {}).items():
|
for object_id, conf in config.get(DOMAIN, {}).items():
|
||||||
name = conf.get(CONF_NAME, object_id)
|
name = conf.get(CONF_NAME, object_id)
|
||||||
entity_ids = conf.get(CONF_ENTITIES) or []
|
entity_ids = conf.get(CONF_ENTITIES) or []
|
||||||
icon = conf.get(CONF_ICON)
|
icon = conf.get(CONF_ICON)
|
||||||
mode = conf.get(CONF_ALL)
|
mode = conf.get(CONF_ALL)
|
||||||
|
|
||||||
# Don't create tasks and await them all. The order is important as
|
# We keep track of the order when we are creating the tasks
|
||||||
# groups get a number based on creation order.
|
# in the same way that async_create_group does to make
|
||||||
await Group.async_create_group(
|
# sure we use the same ordering system. This overcomes
|
||||||
hass, name, entity_ids, icon=icon, object_id=object_id, mode=mode
|
# the problem with concurrently creating the groups
|
||||||
|
tasks.append(
|
||||||
|
Group.async_create_group(
|
||||||
|
hass,
|
||||||
|
name,
|
||||||
|
entity_ids,
|
||||||
|
icon=icon,
|
||||||
|
object_id=object_id,
|
||||||
|
mode=mode,
|
||||||
|
order=hass.data[GROUP_ORDER],
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Keep track of the group order without iterating
|
||||||
|
# every state in the state machine every time
|
||||||
|
# we setup a new group
|
||||||
|
hass.data[GROUP_ORDER] += 1
|
||||||
|
|
||||||
|
await asyncio.gather(*tasks)
|
||||||
|
|
||||||
|
|
||||||
class GroupEntity(Entity):
|
class GroupEntity(Entity):
|
||||||
@ -418,11 +439,12 @@ class Group(Entity):
|
|||||||
icon=None,
|
icon=None,
|
||||||
object_id=None,
|
object_id=None,
|
||||||
mode=None,
|
mode=None,
|
||||||
|
order=None,
|
||||||
):
|
):
|
||||||
"""Initialize a group."""
|
"""Initialize a group."""
|
||||||
return asyncio.run_coroutine_threadsafe(
|
return asyncio.run_coroutine_threadsafe(
|
||||||
Group.async_create_group(
|
Group.async_create_group(
|
||||||
hass, name, entity_ids, user_defined, icon, object_id, mode
|
hass, name, entity_ids, user_defined, icon, object_id, mode, order
|
||||||
),
|
),
|
||||||
hass.loop,
|
hass.loop,
|
||||||
).result()
|
).result()
|
||||||
@ -436,28 +458,30 @@ class Group(Entity):
|
|||||||
icon=None,
|
icon=None,
|
||||||
object_id=None,
|
object_id=None,
|
||||||
mode=None,
|
mode=None,
|
||||||
|
order=None,
|
||||||
):
|
):
|
||||||
"""Initialize a group.
|
"""Initialize a group.
|
||||||
|
|
||||||
This method must be run in the event loop.
|
This method must be run in the event loop.
|
||||||
"""
|
"""
|
||||||
|
if order is None:
|
||||||
hass.data.setdefault(GROUP_ORDER, 0)
|
hass.data.setdefault(GROUP_ORDER, 0)
|
||||||
|
order = hass.data[GROUP_ORDER]
|
||||||
|
# Keep track of the group order without iterating
|
||||||
|
# every state in the state machine every time
|
||||||
|
# we setup a new group
|
||||||
|
hass.data[GROUP_ORDER] += 1
|
||||||
|
|
||||||
group = Group(
|
group = Group(
|
||||||
hass,
|
hass,
|
||||||
name,
|
name,
|
||||||
order=hass.data[GROUP_ORDER],
|
order=order,
|
||||||
icon=icon,
|
icon=icon,
|
||||||
user_defined=user_defined,
|
user_defined=user_defined,
|
||||||
entity_ids=entity_ids,
|
entity_ids=entity_ids,
|
||||||
mode=mode,
|
mode=mode,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Keep track of the group order without iterating
|
|
||||||
# every state in the state machine every time
|
|
||||||
# we setup a new group
|
|
||||||
hass.data[GROUP_ORDER] += 1
|
|
||||||
|
|
||||||
group.entity_id = async_generate_entity_id(
|
group.entity_id = async_generate_entity_id(
|
||||||
ENTITY_ID_FORMAT, object_id or name, hass=hass
|
ENTITY_ID_FORMAT, object_id or name, hass=hass
|
||||||
)
|
)
|
||||||
|
@ -512,3 +512,54 @@ async def test_group_order(hass):
|
|||||||
assert hass.states.get("group.group_zero").attributes["order"] == 0
|
assert hass.states.get("group.group_zero").attributes["order"] == 0
|
||||||
assert hass.states.get("group.group_one").attributes["order"] == 1
|
assert hass.states.get("group.group_one").attributes["order"] == 1
|
||||||
assert hass.states.get("group.group_two").attributes["order"] == 2
|
assert hass.states.get("group.group_two").attributes["order"] == 2
|
||||||
|
|
||||||
|
|
||||||
|
async def test_group_order_with_dynamic_creation(hass):
|
||||||
|
"""Test that order gets incremented when creating a new group."""
|
||||||
|
hass.states.async_set("light.bowl", STATE_ON)
|
||||||
|
|
||||||
|
assert await async_setup_component(
|
||||||
|
hass,
|
||||||
|
"group",
|
||||||
|
{
|
||||||
|
"group": {
|
||||||
|
"group_zero": {"entities": "light.Bowl", "icon": "mdi:work"},
|
||||||
|
"group_one": {"entities": "light.Bowl", "icon": "mdi:work"},
|
||||||
|
"group_two": {"entities": "light.Bowl", "icon": "mdi:work"},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert hass.states.get("group.group_zero").attributes["order"] == 0
|
||||||
|
assert hass.states.get("group.group_one").attributes["order"] == 1
|
||||||
|
assert hass.states.get("group.group_two").attributes["order"] == 2
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
group.DOMAIN,
|
||||||
|
group.SERVICE_SET,
|
||||||
|
{"object_id": "new_group", "name": "New Group", "entities": "light.bowl"},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert hass.states.get("group.new_group").attributes["order"] == 3
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
group.DOMAIN,
|
||||||
|
group.SERVICE_REMOVE,
|
||||||
|
{
|
||||||
|
"object_id": "new_group",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert not hass.states.get("group.new_group")
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
group.DOMAIN,
|
||||||
|
group.SERVICE_SET,
|
||||||
|
{"object_id": "new_group2", "name": "New Group 2", "entities": "light.bowl"},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert hass.states.get("group.new_group2").attributes["order"] == 4
|
||||||
|
Loading…
x
Reference in New Issue
Block a user