Group by endpoints and not by devices for ZHA Zigbee groups (#34583)
* start implementation * handle members correctly * fix group member info * align groupable devices with group members * handle group endpoint adding and removing * update add group * update group and group member * update create group * remove domain check * update test * remove temporary 2nd groupable device api * update test * rename validator - review comment * fix test that was never running * additional testing * fix coordinator descriptors * remove check that was done twice * update test * Use AsyncMock() Co-authored-by: Alexei Chetroi <lexoid@gmail.com>
This commit is contained in:
parent
e54e9279e3
commit
8279efc164
11 changed files with 438 additions and 167 deletions
|
@ -53,6 +53,7 @@ from .core.const import (
|
|||
WARNING_DEVICE_STROBE_HIGH,
|
||||
WARNING_DEVICE_STROBE_YES,
|
||||
)
|
||||
from .core.group import GroupMember
|
||||
from .core.helpers import async_is_bindable_target, get_matched_clusters
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -209,7 +210,7 @@ async def websocket_get_devices(hass, connection, msg):
|
|||
"""Get ZHA devices."""
|
||||
zha_gateway = hass.data[DATA_ZHA][DATA_ZHA_GATEWAY]
|
||||
|
||||
devices = [device.async_get_info() for device in zha_gateway.devices.values()]
|
||||
devices = [device.zha_device_info for device in zha_gateway.devices.values()]
|
||||
|
||||
connection.send_result(msg[ID], devices)
|
||||
|
||||
|
@ -221,13 +222,35 @@ async def websocket_get_groupable_devices(hass, connection, msg):
|
|||
"""Get ZHA devices that can be grouped."""
|
||||
zha_gateway = hass.data[DATA_ZHA][DATA_ZHA_GATEWAY]
|
||||
|
||||
devices = [
|
||||
device.async_get_info()
|
||||
for device in zha_gateway.devices.values()
|
||||
if device.is_groupable or device.is_coordinator
|
||||
]
|
||||
devices = [device for device in zha_gateway.devices.values() if device.is_groupable]
|
||||
groupable_devices = []
|
||||
|
||||
connection.send_result(msg[ID], devices)
|
||||
for device in devices:
|
||||
entity_refs = zha_gateway.device_registry.get(device.ieee)
|
||||
for ep_id in device.async_get_groupable_endpoints():
|
||||
groupable_devices.append(
|
||||
{
|
||||
"endpoint_id": ep_id,
|
||||
"entities": [
|
||||
{
|
||||
"name": zha_gateway.ha_entity_registry.async_get(
|
||||
entity_ref.reference_id
|
||||
).name,
|
||||
"original_name": zha_gateway.ha_entity_registry.async_get(
|
||||
entity_ref.reference_id
|
||||
).original_name,
|
||||
}
|
||||
for entity_ref in entity_refs
|
||||
if list(entity_ref.cluster_channels.values())[
|
||||
0
|
||||
].cluster.endpoint.endpoint_id
|
||||
== ep_id
|
||||
],
|
||||
"device": device.zha_device_info,
|
||||
}
|
||||
)
|
||||
|
||||
connection.send_result(msg[ID], groupable_devices)
|
||||
|
||||
|
||||
@websocket_api.require_admin
|
||||
|
@ -236,7 +259,7 @@ async def websocket_get_groupable_devices(hass, connection, msg):
|
|||
async def websocket_get_groups(hass, connection, msg):
|
||||
"""Get ZHA groups."""
|
||||
zha_gateway = hass.data[DATA_ZHA][DATA_ZHA_GATEWAY]
|
||||
groups = [group.async_get_info() for group in zha_gateway.groups.values()]
|
||||
groups = [group.group_info for group in zha_gateway.groups.values()]
|
||||
connection.send_result(msg[ID], groups)
|
||||
|
||||
|
||||
|
@ -251,7 +274,7 @@ async def websocket_get_device(hass, connection, msg):
|
|||
ieee = msg[ATTR_IEEE]
|
||||
device = None
|
||||
if ieee in zha_gateway.devices:
|
||||
device = zha_gateway.devices[ieee].async_get_info()
|
||||
device = zha_gateway.devices[ieee].zha_device_info
|
||||
if not device:
|
||||
connection.send_message(
|
||||
websocket_api.error_message(
|
||||
|
@ -274,7 +297,7 @@ async def websocket_get_group(hass, connection, msg):
|
|||
group = None
|
||||
|
||||
if group_id in zha_gateway.groups:
|
||||
group = zha_gateway.groups.get(group_id).async_get_info()
|
||||
group = zha_gateway.groups.get(group_id).group_info
|
||||
if not group:
|
||||
connection.send_message(
|
||||
websocket_api.error_message(
|
||||
|
@ -285,13 +308,27 @@ async def websocket_get_group(hass, connection, msg):
|
|||
connection.send_result(msg[ID], group)
|
||||
|
||||
|
||||
def cv_group_member(value: Any) -> GroupMember:
|
||||
"""Validate and transform a group member."""
|
||||
if not isinstance(value, Mapping):
|
||||
raise vol.Invalid("Not a group member")
|
||||
try:
|
||||
group_member = GroupMember(
|
||||
ieee=EUI64.convert(value["ieee"]), endpoint_id=value["endpoint_id"]
|
||||
)
|
||||
except KeyError:
|
||||
raise vol.Invalid("Not a group member")
|
||||
|
||||
return group_member
|
||||
|
||||
|
||||
@websocket_api.require_admin
|
||||
@websocket_api.async_response
|
||||
@websocket_api.websocket_command(
|
||||
{
|
||||
vol.Required(TYPE): "zha/group/add",
|
||||
vol.Required(GROUP_NAME): cv.string,
|
||||
vol.Optional(ATTR_MEMBERS): vol.All(cv.ensure_list, [EUI64.convert]),
|
||||
vol.Optional(ATTR_MEMBERS): vol.All(cv.ensure_list, [cv_group_member]),
|
||||
}
|
||||
)
|
||||
async def websocket_add_group(hass, connection, msg):
|
||||
|
@ -300,7 +337,7 @@ async def websocket_add_group(hass, connection, msg):
|
|||
group_name = msg[GROUP_NAME]
|
||||
members = msg.get(ATTR_MEMBERS)
|
||||
group = await zha_gateway.async_create_zigpy_group(group_name, members)
|
||||
connection.send_result(msg[ID], group.async_get_info())
|
||||
connection.send_result(msg[ID], group.group_info)
|
||||
|
||||
|
||||
@websocket_api.require_admin
|
||||
|
@ -323,7 +360,7 @@ async def websocket_remove_groups(hass, connection, msg):
|
|||
await asyncio.gather(*tasks)
|
||||
else:
|
||||
await zha_gateway.async_remove_zigpy_group(group_ids[0])
|
||||
ret_groups = [group.async_get_info() for group in zha_gateway.groups.values()]
|
||||
ret_groups = [group.group_info for group in zha_gateway.groups.values()]
|
||||
connection.send_result(msg[ID], ret_groups)
|
||||
|
||||
|
||||
|
@ -333,7 +370,7 @@ async def websocket_remove_groups(hass, connection, msg):
|
|||
{
|
||||
vol.Required(TYPE): "zha/group/members/add",
|
||||
vol.Required(GROUP_ID): cv.positive_int,
|
||||
vol.Required(ATTR_MEMBERS): vol.All(cv.ensure_list, [EUI64.convert]),
|
||||
vol.Required(ATTR_MEMBERS): vol.All(cv.ensure_list, [cv_group_member]),
|
||||
}
|
||||
)
|
||||
async def websocket_add_group_members(hass, connection, msg):
|
||||
|
@ -353,7 +390,7 @@ async def websocket_add_group_members(hass, connection, msg):
|
|||
)
|
||||
)
|
||||
return
|
||||
ret_group = zha_group.async_get_info()
|
||||
ret_group = zha_group.group_info
|
||||
connection.send_result(msg[ID], ret_group)
|
||||
|
||||
|
||||
|
@ -363,7 +400,7 @@ async def websocket_add_group_members(hass, connection, msg):
|
|||
{
|
||||
vol.Required(TYPE): "zha/group/members/remove",
|
||||
vol.Required(GROUP_ID): cv.positive_int,
|
||||
vol.Required(ATTR_MEMBERS): vol.All(cv.ensure_list, [EUI64.convert]),
|
||||
vol.Required(ATTR_MEMBERS): vol.All(cv.ensure_list, [cv_group_member]),
|
||||
}
|
||||
)
|
||||
async def websocket_remove_group_members(hass, connection, msg):
|
||||
|
@ -383,7 +420,7 @@ async def websocket_remove_group_members(hass, connection, msg):
|
|||
)
|
||||
)
|
||||
return
|
||||
ret_group = zha_group.async_get_info()
|
||||
ret_group = zha_group.group_info
|
||||
connection.send_result(msg[ID], ret_group)
|
||||
|
||||
|
||||
|
@ -608,7 +645,7 @@ async def websocket_get_bindable_devices(hass, connection, msg):
|
|||
source_device = zha_gateway.get_device(source_ieee)
|
||||
|
||||
devices = [
|
||||
device.async_get_info()
|
||||
device.zha_device_info
|
||||
for device in zha_gateway.devices.values()
|
||||
if async_is_bindable_target(source_device, device)
|
||||
]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue