Fix controlling nested groups (#66176)
This commit is contained in:
parent
a0119f7ed0
commit
3f7b7187ab
7 changed files with 155 additions and 9 deletions
|
@ -57,6 +57,8 @@ KEY_POSITION = "position"
|
||||||
|
|
||||||
DEFAULT_NAME = "Cover Group"
|
DEFAULT_NAME = "Cover Group"
|
||||||
|
|
||||||
|
# No limit on parallel updates to enable a group calling another group
|
||||||
|
PARALLEL_UPDATES = 0
|
||||||
|
|
||||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
||||||
{
|
{
|
||||||
|
|
|
@ -52,6 +52,8 @@ SUPPORTED_FLAGS = {SUPPORT_SET_SPEED, SUPPORT_DIRECTION, SUPPORT_OSCILLATE}
|
||||||
|
|
||||||
DEFAULT_NAME = "Fan Group"
|
DEFAULT_NAME = "Fan Group"
|
||||||
|
|
||||||
|
# No limit on parallel updates to enable a group calling another group
|
||||||
|
PARALLEL_UPDATES = 0
|
||||||
|
|
||||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
||||||
{
|
{
|
||||||
|
|
|
@ -58,6 +58,9 @@ from .util import find_state_attributes, mean_tuple, reduce_attribute
|
||||||
|
|
||||||
DEFAULT_NAME = "Light Group"
|
DEFAULT_NAME = "Light Group"
|
||||||
|
|
||||||
|
# No limit on parallel updates to enable a group calling another group
|
||||||
|
PARALLEL_UPDATES = 0
|
||||||
|
|
||||||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
||||||
{
|
{
|
||||||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
"""The tests for the group cover platform."""
|
"""The tests for the group cover platform."""
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
|
import async_timeout
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.cover import (
|
from homeassistant.components.cover import (
|
||||||
|
@ -735,3 +736,52 @@ async def test_is_opening_closing(hass, setup_comp):
|
||||||
assert hass.states.get(DEMO_COVER_TILT).state == STATE_OPENING
|
assert hass.states.get(DEMO_COVER_TILT).state == STATE_OPENING
|
||||||
assert hass.states.get(DEMO_COVER_POS).state == STATE_OPEN
|
assert hass.states.get(DEMO_COVER_POS).state == STATE_OPEN
|
||||||
assert hass.states.get(COVER_GROUP).state == STATE_OPENING
|
assert hass.states.get(COVER_GROUP).state == STATE_OPENING
|
||||||
|
|
||||||
|
|
||||||
|
async def test_nested_group(hass):
|
||||||
|
"""Test nested cover group."""
|
||||||
|
await async_setup_component(
|
||||||
|
hass,
|
||||||
|
DOMAIN,
|
||||||
|
{
|
||||||
|
DOMAIN: [
|
||||||
|
{"platform": "demo"},
|
||||||
|
{
|
||||||
|
"platform": "group",
|
||||||
|
"entities": ["cover.bedroom_group"],
|
||||||
|
"name": "Nested Group",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"platform": "group",
|
||||||
|
CONF_ENTITIES: [DEMO_COVER_POS, DEMO_COVER_TILT],
|
||||||
|
"name": "Bedroom Group",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
await hass.async_start()
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("cover.bedroom_group")
|
||||||
|
assert state is not None
|
||||||
|
assert state.state == STATE_OPEN
|
||||||
|
assert state.attributes.get(ATTR_ENTITY_ID) == [DEMO_COVER_POS, DEMO_COVER_TILT]
|
||||||
|
|
||||||
|
state = hass.states.get("cover.nested_group")
|
||||||
|
assert state is not None
|
||||||
|
assert state.state == STATE_OPEN
|
||||||
|
assert state.attributes.get(ATTR_ENTITY_ID) == ["cover.bedroom_group"]
|
||||||
|
|
||||||
|
# Test controlling the nested group
|
||||||
|
async with async_timeout.timeout(0.5):
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_CLOSE_COVER,
|
||||||
|
{ATTR_ENTITY_ID: "cover.nested_group"},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
assert hass.states.get(DEMO_COVER_POS).state == STATE_CLOSING
|
||||||
|
assert hass.states.get(DEMO_COVER_TILT).state == STATE_CLOSING
|
||||||
|
assert hass.states.get("cover.bedroom_group").state == STATE_CLOSING
|
||||||
|
assert hass.states.get("cover.nested_group").state == STATE_CLOSING
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
"""The tests for the group fan platform."""
|
"""The tests for the group fan platform."""
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
import async_timeout
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant import config as hass_config
|
from homeassistant import config as hass_config
|
||||||
|
@ -497,3 +498,58 @@ async def test_service_calls(hass, setup_comp):
|
||||||
assert percentage_full_fan_state.attributes[ATTR_DIRECTION] == DIRECTION_REVERSE
|
assert percentage_full_fan_state.attributes[ATTR_DIRECTION] == DIRECTION_REVERSE
|
||||||
fan_group_state = hass.states.get(FAN_GROUP)
|
fan_group_state = hass.states.get(FAN_GROUP)
|
||||||
assert fan_group_state.attributes[ATTR_DIRECTION] == DIRECTION_REVERSE
|
assert fan_group_state.attributes[ATTR_DIRECTION] == DIRECTION_REVERSE
|
||||||
|
|
||||||
|
|
||||||
|
async def test_nested_group(hass):
|
||||||
|
"""Test nested fan group."""
|
||||||
|
await async_setup_component(
|
||||||
|
hass,
|
||||||
|
DOMAIN,
|
||||||
|
{
|
||||||
|
DOMAIN: [
|
||||||
|
{"platform": "demo"},
|
||||||
|
{
|
||||||
|
"platform": "group",
|
||||||
|
"entities": ["fan.bedroom_group"],
|
||||||
|
"name": "Nested Group",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"platform": "group",
|
||||||
|
CONF_ENTITIES: [
|
||||||
|
LIVING_ROOM_FAN_ENTITY_ID,
|
||||||
|
PERCENTAGE_FULL_FAN_ENTITY_ID,
|
||||||
|
],
|
||||||
|
"name": "Bedroom Group",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
await hass.async_start()
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
state = hass.states.get("fan.bedroom_group")
|
||||||
|
assert state is not None
|
||||||
|
assert state.state == STATE_OFF
|
||||||
|
assert state.attributes.get(ATTR_ENTITY_ID) == [
|
||||||
|
LIVING_ROOM_FAN_ENTITY_ID,
|
||||||
|
PERCENTAGE_FULL_FAN_ENTITY_ID,
|
||||||
|
]
|
||||||
|
|
||||||
|
state = hass.states.get("fan.nested_group")
|
||||||
|
assert state is not None
|
||||||
|
assert state.state == STATE_OFF
|
||||||
|
assert state.attributes.get(ATTR_ENTITY_ID) == ["fan.bedroom_group"]
|
||||||
|
|
||||||
|
# Test controlling the nested group
|
||||||
|
async with async_timeout.timeout(0.5):
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_TURN_ON,
|
||||||
|
{ATTR_ENTITY_ID: "fan.nested_group"},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
assert hass.states.get(LIVING_ROOM_FAN_ENTITY_ID).state == STATE_ON
|
||||||
|
assert hass.states.get(PERCENTAGE_FULL_FAN_ENTITY_ID).state == STATE_ON
|
||||||
|
assert hass.states.get("fan.bedroom_group").state == STATE_ON
|
||||||
|
assert hass.states.get("fan.nested_group").state == STATE_ON
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
import unittest.mock
|
import unittest.mock
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
|
import async_timeout
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant import config as hass_config
|
from homeassistant import config as hass_config
|
||||||
|
@ -1470,12 +1471,12 @@ async def test_reload_with_base_integration_platform_not_setup(hass):
|
||||||
|
|
||||||
async def test_nested_group(hass):
|
async def test_nested_group(hass):
|
||||||
"""Test nested light group."""
|
"""Test nested light group."""
|
||||||
hass.states.async_set("light.kitchen", "on")
|
|
||||||
await async_setup_component(
|
await async_setup_component(
|
||||||
hass,
|
hass,
|
||||||
LIGHT_DOMAIN,
|
LIGHT_DOMAIN,
|
||||||
{
|
{
|
||||||
LIGHT_DOMAIN: [
|
LIGHT_DOMAIN: [
|
||||||
|
{"platform": "demo"},
|
||||||
{
|
{
|
||||||
"platform": DOMAIN,
|
"platform": DOMAIN,
|
||||||
"entities": ["light.bedroom_group"],
|
"entities": ["light.bedroom_group"],
|
||||||
|
@ -1483,7 +1484,7 @@ async def test_nested_group(hass):
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"platform": DOMAIN,
|
"platform": DOMAIN,
|
||||||
"entities": ["light.kitchen", "light.bedroom"],
|
"entities": ["light.bed_light", "light.kitchen_lights"],
|
||||||
"name": "Bedroom Group",
|
"name": "Bedroom Group",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
@ -1496,9 +1497,25 @@ async def test_nested_group(hass):
|
||||||
state = hass.states.get("light.bedroom_group")
|
state = hass.states.get("light.bedroom_group")
|
||||||
assert state is not None
|
assert state is not None
|
||||||
assert state.state == STATE_ON
|
assert state.state == STATE_ON
|
||||||
assert state.attributes.get(ATTR_ENTITY_ID) == ["light.kitchen", "light.bedroom"]
|
assert state.attributes.get(ATTR_ENTITY_ID) == [
|
||||||
|
"light.bed_light",
|
||||||
|
"light.kitchen_lights",
|
||||||
|
]
|
||||||
|
|
||||||
state = hass.states.get("light.nested_group")
|
state = hass.states.get("light.nested_group")
|
||||||
assert state is not None
|
assert state is not None
|
||||||
assert state.state == STATE_ON
|
assert state.state == STATE_ON
|
||||||
assert state.attributes.get(ATTR_ENTITY_ID) == ["light.bedroom_group"]
|
assert state.attributes.get(ATTR_ENTITY_ID) == ["light.bedroom_group"]
|
||||||
|
|
||||||
|
# Test controlling the nested group
|
||||||
|
async with async_timeout.timeout(0.5):
|
||||||
|
await hass.services.async_call(
|
||||||
|
LIGHT_DOMAIN,
|
||||||
|
SERVICE_TOGGLE,
|
||||||
|
{ATTR_ENTITY_ID: "light.nested_group"},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
assert hass.states.get("light.bed_light").state == STATE_OFF
|
||||||
|
assert hass.states.get("light.kitchen_lights").state == STATE_OFF
|
||||||
|
assert hass.states.get("light.bedroom_group").state == STATE_OFF
|
||||||
|
assert hass.states.get("light.nested_group").state == STATE_OFF
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
"""The tests for the Media group platform."""
|
"""The tests for the Media group platform."""
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
import async_timeout
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.group import DOMAIN
|
from homeassistant.components.group import DOMAIN
|
||||||
|
@ -486,12 +487,12 @@ async def test_service_calls(hass, mock_media_seek):
|
||||||
|
|
||||||
async def test_nested_group(hass):
|
async def test_nested_group(hass):
|
||||||
"""Test nested media group."""
|
"""Test nested media group."""
|
||||||
hass.states.async_set("media_player.player_1", "on")
|
|
||||||
await async_setup_component(
|
await async_setup_component(
|
||||||
hass,
|
hass,
|
||||||
MEDIA_DOMAIN,
|
MEDIA_DOMAIN,
|
||||||
{
|
{
|
||||||
MEDIA_DOMAIN: [
|
MEDIA_DOMAIN: [
|
||||||
|
{"platform": "demo"},
|
||||||
{
|
{
|
||||||
"platform": DOMAIN,
|
"platform": DOMAIN,
|
||||||
"entities": ["media_player.group_1"],
|
"entities": ["media_player.group_1"],
|
||||||
|
@ -499,7 +500,7 @@ async def test_nested_group(hass):
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"platform": DOMAIN,
|
"platform": DOMAIN,
|
||||||
"entities": ["media_player.player_1", "media_player.player_2"],
|
"entities": ["media_player.bedroom", "media_player.kitchen"],
|
||||||
"name": "Group 1",
|
"name": "Group 1",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
@ -511,13 +512,28 @@ async def test_nested_group(hass):
|
||||||
|
|
||||||
state = hass.states.get("media_player.group_1")
|
state = hass.states.get("media_player.group_1")
|
||||||
assert state is not None
|
assert state is not None
|
||||||
assert state.state == STATE_ON
|
assert state.state == STATE_PLAYING
|
||||||
assert state.attributes.get(ATTR_ENTITY_ID) == [
|
assert state.attributes.get(ATTR_ENTITY_ID) == [
|
||||||
"media_player.player_1",
|
"media_player.bedroom",
|
||||||
"media_player.player_2",
|
"media_player.kitchen",
|
||||||
]
|
]
|
||||||
|
|
||||||
state = hass.states.get("media_player.nested_group")
|
state = hass.states.get("media_player.nested_group")
|
||||||
assert state is not None
|
assert state is not None
|
||||||
assert state.state == STATE_ON
|
assert state.state == STATE_PLAYING
|
||||||
assert state.attributes.get(ATTR_ENTITY_ID) == ["media_player.group_1"]
|
assert state.attributes.get(ATTR_ENTITY_ID) == ["media_player.group_1"]
|
||||||
|
|
||||||
|
# Test controlling the nested group
|
||||||
|
async with async_timeout.timeout(0.5):
|
||||||
|
await hass.services.async_call(
|
||||||
|
MEDIA_DOMAIN,
|
||||||
|
SERVICE_TURN_OFF,
|
||||||
|
{ATTR_ENTITY_ID: "media_player.group_1"},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert hass.states.get("media_player.bedroom").state == STATE_OFF
|
||||||
|
assert hass.states.get("media_player.kitchen").state == STATE_OFF
|
||||||
|
assert hass.states.get("media_player.group_1").state == STATE_OFF
|
||||||
|
assert hass.states.get("media_player.nested_group").state == STATE_OFF
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue