Add suggested area to hue (#47056)

This commit is contained in:
J. Nick Koston 2021-02-26 10:35:09 -06:00 committed by GitHub
parent d8633f94f6
commit 7ab2d91bf0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 191 additions and 64 deletions

View File

@ -15,3 +15,8 @@ CONF_ALLOW_HUE_GROUPS = "allow_hue_groups"
DEFAULT_ALLOW_HUE_GROUPS = False DEFAULT_ALLOW_HUE_GROUPS = False
DEFAULT_SCENE_TRANSITION = 4 DEFAULT_SCENE_TRANSITION = 4
GROUP_TYPE_LIGHT_GROUP = "LightGroup"
GROUP_TYPE_ROOM = "Room"
GROUP_TYPE_LUMINAIRE = "Luminaire"
GROUP_TYPE_LIGHT_SOURCE = "LightSource"

View File

@ -36,7 +36,14 @@ from homeassistant.helpers.update_coordinator import (
) )
from homeassistant.util import color from homeassistant.util import color
from .const import DOMAIN as HUE_DOMAIN, REQUEST_REFRESH_DELAY from .const import (
DOMAIN as HUE_DOMAIN,
GROUP_TYPE_LIGHT_GROUP,
GROUP_TYPE_LIGHT_SOURCE,
GROUP_TYPE_LUMINAIRE,
GROUP_TYPE_ROOM,
REQUEST_REFRESH_DELAY,
)
from .helpers import remove_devices from .helpers import remove_devices
SCAN_INTERVAL = timedelta(seconds=5) SCAN_INTERVAL = timedelta(seconds=5)
@ -74,24 +81,35 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
""" """
def create_light(item_class, coordinator, bridge, is_group, api, item_id): def create_light(item_class, coordinator, bridge, is_group, rooms, api, item_id):
"""Create the light.""" """Create the light."""
api_item = api[item_id]
if is_group: if is_group:
supported_features = 0 supported_features = 0
for light_id in api[item_id].lights: for light_id in api_item.lights:
if light_id not in bridge.api.lights: if light_id not in bridge.api.lights:
continue continue
light = bridge.api.lights[light_id] light = bridge.api.lights[light_id]
supported_features |= SUPPORT_HUE.get(light.type, SUPPORT_HUE_EXTENDED) supported_features |= SUPPORT_HUE.get(light.type, SUPPORT_HUE_EXTENDED)
supported_features = supported_features or SUPPORT_HUE_EXTENDED supported_features = supported_features or SUPPORT_HUE_EXTENDED
else: else:
supported_features = SUPPORT_HUE.get(api[item_id].type, SUPPORT_HUE_EXTENDED) supported_features = SUPPORT_HUE.get(api_item.type, SUPPORT_HUE_EXTENDED)
return item_class(coordinator, bridge, is_group, api[item_id], supported_features) return item_class(
coordinator, bridge, is_group, api_item, supported_features, rooms
)
async def async_setup_entry(hass, config_entry, async_add_entities): async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the Hue lights from a config entry.""" """Set up the Hue lights from a config entry."""
bridge = hass.data[HUE_DOMAIN][config_entry.entry_id] bridge = hass.data[HUE_DOMAIN][config_entry.entry_id]
api_version = tuple(int(v) for v in bridge.api.config.apiversion.split("."))
rooms = {}
allow_groups = bridge.allow_groups
supports_groups = api_version >= GROUP_MIN_API_VERSION
if allow_groups and not supports_groups:
_LOGGER.warning("Please update your Hue bridge to support groups")
light_coordinator = DataUpdateCoordinator( light_coordinator = DataUpdateCoordinator(
hass, hass,
@ -111,27 +129,20 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
if not light_coordinator.last_update_success: if not light_coordinator.last_update_success:
raise PlatformNotReady raise PlatformNotReady
update_lights = partial( if not supports_groups:
async_update_items, update_lights_without_group_support = partial(
bridge, async_update_items,
bridge.api.lights, bridge,
{}, bridge.api.lights,
async_add_entities, {},
partial(create_light, HueLight, light_coordinator, bridge, False), async_add_entities,
) partial(create_light, HueLight, light_coordinator, bridge, False, rooms),
None,
# We add a listener after fetching the data, so manually trigger listener )
bridge.reset_jobs.append(light_coordinator.async_add_listener(update_lights)) # We add a listener after fetching the data, so manually trigger listener
update_lights() bridge.reset_jobs.append(
light_coordinator.async_add_listener(update_lights_without_group_support)
api_version = tuple(int(v) for v in bridge.api.config.apiversion.split(".")) )
allow_groups = bridge.allow_groups
if allow_groups and api_version < GROUP_MIN_API_VERSION:
_LOGGER.warning("Please update your Hue bridge to support groups")
allow_groups = False
if not allow_groups:
return return
group_coordinator = DataUpdateCoordinator( group_coordinator = DataUpdateCoordinator(
@ -145,17 +156,69 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
), ),
) )
update_groups = partial( if allow_groups:
update_groups = partial(
async_update_items,
bridge,
bridge.api.groups,
{},
async_add_entities,
partial(create_light, HueLight, group_coordinator, bridge, True, None),
None,
)
bridge.reset_jobs.append(group_coordinator.async_add_listener(update_groups))
cancel_update_rooms_listener = None
@callback
def _async_update_rooms():
"""Update rooms."""
nonlocal cancel_update_rooms_listener
rooms.clear()
for item_id in bridge.api.groups:
group = bridge.api.groups[item_id]
if group.type != GROUP_TYPE_ROOM:
continue
for light_id in group.lights:
rooms[light_id] = group.name
# Once we do a rooms update, we cancel the listener
# until the next time lights are added
bridge.reset_jobs.remove(cancel_update_rooms_listener)
cancel_update_rooms_listener() # pylint: disable=not-callable
cancel_update_rooms_listener = None
@callback
def _setup_rooms_listener():
nonlocal cancel_update_rooms_listener
if cancel_update_rooms_listener is not None:
# If there are new lights added before _async_update_rooms
# is called we should not add another listener
return
cancel_update_rooms_listener = group_coordinator.async_add_listener(
_async_update_rooms
)
bridge.reset_jobs.append(cancel_update_rooms_listener)
_setup_rooms_listener()
await group_coordinator.async_refresh()
update_lights_with_group_support = partial(
async_update_items, async_update_items,
bridge, bridge,
bridge.api.groups, bridge.api.lights,
{}, {},
async_add_entities, async_add_entities,
partial(create_light, HueLight, group_coordinator, bridge, True), partial(create_light, HueLight, light_coordinator, bridge, False, rooms),
_setup_rooms_listener,
) )
# We add a listener after fetching the data, so manually trigger listener
bridge.reset_jobs.append(group_coordinator.async_add_listener(update_groups)) bridge.reset_jobs.append(
await group_coordinator.async_refresh() light_coordinator.async_add_listener(update_lights_with_group_support)
)
update_lights_with_group_support()
async def async_safe_fetch(bridge, fetch_method): async def async_safe_fetch(bridge, fetch_method):
@ -171,7 +234,9 @@ async def async_safe_fetch(bridge, fetch_method):
@callback @callback
def async_update_items(bridge, api, current, async_add_entities, create_item): def async_update_items(
bridge, api, current, async_add_entities, create_item, new_items_callback
):
"""Update items.""" """Update items."""
new_items = [] new_items = []
@ -185,6 +250,9 @@ def async_update_items(bridge, api, current, async_add_entities, create_item):
bridge.hass.async_create_task(remove_devices(bridge, api, current)) bridge.hass.async_create_task(remove_devices(bridge, api, current))
if new_items: if new_items:
# This is currently used to setup the listener to update rooms
if new_items_callback:
new_items_callback()
async_add_entities(new_items) async_add_entities(new_items)
@ -201,13 +269,14 @@ def hass_to_hue_brightness(value):
class HueLight(CoordinatorEntity, LightEntity): class HueLight(CoordinatorEntity, LightEntity):
"""Representation of a Hue light.""" """Representation of a Hue light."""
def __init__(self, coordinator, bridge, is_group, light, supported_features): def __init__(self, coordinator, bridge, is_group, light, supported_features, rooms):
"""Initialize the light.""" """Initialize the light."""
super().__init__(coordinator) super().__init__(coordinator)
self.light = light self.light = light
self.bridge = bridge self.bridge = bridge
self.is_group = is_group self.is_group = is_group
self._supported_features = supported_features self._supported_features = supported_features
self._rooms = rooms
if is_group: if is_group:
self.is_osram = False self.is_osram = False
@ -355,10 +424,15 @@ class HueLight(CoordinatorEntity, LightEntity):
@property @property
def device_info(self): def device_info(self):
"""Return the device info.""" """Return the device info."""
if self.light.type in ("LightGroup", "Room", "Luminaire", "LightSource"): if self.light.type in (
GROUP_TYPE_LIGHT_GROUP,
GROUP_TYPE_ROOM,
GROUP_TYPE_LUMINAIRE,
GROUP_TYPE_LIGHT_SOURCE,
):
return None return None
return { info = {
"identifiers": {(HUE_DOMAIN, self.device_id)}, "identifiers": {(HUE_DOMAIN, self.device_id)},
"name": self.name, "name": self.name,
"manufacturer": self.light.manufacturername, "manufacturer": self.light.manufacturername,
@ -370,6 +444,11 @@ class HueLight(CoordinatorEntity, LightEntity):
"via_device": (HUE_DOMAIN, self.bridge.api.config.bridgeid), "via_device": (HUE_DOMAIN, self.bridge.api.config.bridgeid),
} }
if self.light.id in self._rooms:
info["suggested_area"] = self._rooms[self.light.id]
return info
async def async_turn_on(self, **kwargs): async def async_turn_on(self, **kwargs):
"""Turn the specified or all lights on.""" """Turn the specified or all lights on."""
command = {"on": True} command = {"on": True}

View File

@ -7,6 +7,12 @@ import aiohue
from homeassistant import config_entries from homeassistant import config_entries
from homeassistant.components import hue from homeassistant.components import hue
from homeassistant.components.hue import light as hue_light from homeassistant.components.hue import light as hue_light
from homeassistant.helpers.device_registry import (
async_get_registry as async_get_device_registry,
)
from homeassistant.helpers.entity_registry import (
async_get_registry as async_get_entity_registry,
)
from homeassistant.util import color from homeassistant.util import color
HUE_LIGHT_NS = "homeassistant.components.light.hue." HUE_LIGHT_NS = "homeassistant.components.light.hue."
@ -211,8 +217,10 @@ async def test_no_lights_or_groups(hass, mock_bridge):
async def test_lights(hass, mock_bridge): async def test_lights(hass, mock_bridge):
"""Test the update_lights function with some lights.""" """Test the update_lights function with some lights."""
mock_bridge.mock_light_responses.append(LIGHT_RESPONSE) mock_bridge.mock_light_responses.append(LIGHT_RESPONSE)
mock_bridge.mock_group_responses.append(GROUP_RESPONSE)
await setup_bridge(hass, mock_bridge) await setup_bridge(hass, mock_bridge)
assert len(mock_bridge.mock_requests) == 1 assert len(mock_bridge.mock_requests) == 2
# 2 lights # 2 lights
assert len(hass.states.async_all()) == 2 assert len(hass.states.async_all()) == 2
@ -230,6 +238,8 @@ async def test_lights(hass, mock_bridge):
async def test_lights_color_mode(hass, mock_bridge): async def test_lights_color_mode(hass, mock_bridge):
"""Test that lights only report appropriate color mode.""" """Test that lights only report appropriate color mode."""
mock_bridge.mock_light_responses.append(LIGHT_RESPONSE) mock_bridge.mock_light_responses.append(LIGHT_RESPONSE)
mock_bridge.mock_group_responses.append(GROUP_RESPONSE)
await setup_bridge(hass, mock_bridge) await setup_bridge(hass, mock_bridge)
lamp_1 = hass.states.get("light.hue_lamp_1") lamp_1 = hass.states.get("light.hue_lamp_1")
@ -249,8 +259,8 @@ async def test_lights_color_mode(hass, mock_bridge):
await hass.services.async_call( await hass.services.async_call(
"light", "turn_on", {"entity_id": "light.hue_lamp_2"}, blocking=True "light", "turn_on", {"entity_id": "light.hue_lamp_2"}, blocking=True
) )
# 2x light update, 1 turn on request # 2x light update, 1 group update, 1 turn on request
assert len(mock_bridge.mock_requests) == 3 assert len(mock_bridge.mock_requests) == 4
lamp_1 = hass.states.get("light.hue_lamp_1") lamp_1 = hass.states.get("light.hue_lamp_1")
assert lamp_1 is not None assert lamp_1 is not None
@ -332,9 +342,10 @@ async def test_new_group_discovered(hass, mock_bridge):
async def test_new_light_discovered(hass, mock_bridge): async def test_new_light_discovered(hass, mock_bridge):
"""Test if 2nd update has a new light.""" """Test if 2nd update has a new light."""
mock_bridge.mock_light_responses.append(LIGHT_RESPONSE) mock_bridge.mock_light_responses.append(LIGHT_RESPONSE)
mock_bridge.mock_group_responses.append(GROUP_RESPONSE)
await setup_bridge(hass, mock_bridge) await setup_bridge(hass, mock_bridge)
assert len(mock_bridge.mock_requests) == 1 assert len(mock_bridge.mock_requests) == 2
assert len(hass.states.async_all()) == 2 assert len(hass.states.async_all()) == 2
new_light_response = dict(LIGHT_RESPONSE) new_light_response = dict(LIGHT_RESPONSE)
@ -366,8 +377,8 @@ async def test_new_light_discovered(hass, mock_bridge):
await hass.services.async_call( await hass.services.async_call(
"light", "turn_on", {"entity_id": "light.hue_lamp_1"}, blocking=True "light", "turn_on", {"entity_id": "light.hue_lamp_1"}, blocking=True
) )
# 2x light update, 1 turn on request # 2x light update, 1 group update, 1 turn on request
assert len(mock_bridge.mock_requests) == 3 assert len(mock_bridge.mock_requests) == 4
assert len(hass.states.async_all()) == 3 assert len(hass.states.async_all()) == 3
light = hass.states.get("light.hue_lamp_3") light = hass.states.get("light.hue_lamp_3")
@ -407,9 +418,10 @@ async def test_group_removed(hass, mock_bridge):
async def test_light_removed(hass, mock_bridge): async def test_light_removed(hass, mock_bridge):
"""Test if 2nd update has removed light.""" """Test if 2nd update has removed light."""
mock_bridge.mock_light_responses.append(LIGHT_RESPONSE) mock_bridge.mock_light_responses.append(LIGHT_RESPONSE)
mock_bridge.mock_group_responses.append(GROUP_RESPONSE)
await setup_bridge(hass, mock_bridge) await setup_bridge(hass, mock_bridge)
assert len(mock_bridge.mock_requests) == 1 assert len(mock_bridge.mock_requests) == 2
assert len(hass.states.async_all()) == 2 assert len(hass.states.async_all()) == 2
mock_bridge.mock_light_responses.clear() mock_bridge.mock_light_responses.clear()
@ -420,8 +432,8 @@ async def test_light_removed(hass, mock_bridge):
"light", "turn_on", {"entity_id": "light.hue_lamp_1"}, blocking=True "light", "turn_on", {"entity_id": "light.hue_lamp_1"}, blocking=True
) )
# 2x light update, 1 turn on request # 2x light update, 1 group update, 1 turn on request
assert len(mock_bridge.mock_requests) == 3 assert len(mock_bridge.mock_requests) == 4
assert len(hass.states.async_all()) == 1 assert len(hass.states.async_all()) == 1
light = hass.states.get("light.hue_lamp_1") light = hass.states.get("light.hue_lamp_1")
@ -487,9 +499,10 @@ async def test_other_group_update(hass, mock_bridge):
async def test_other_light_update(hass, mock_bridge): async def test_other_light_update(hass, mock_bridge):
"""Test changing one light that will impact state of other light.""" """Test changing one light that will impact state of other light."""
mock_bridge.mock_light_responses.append(LIGHT_RESPONSE) mock_bridge.mock_light_responses.append(LIGHT_RESPONSE)
mock_bridge.mock_group_responses.append(GROUP_RESPONSE)
await setup_bridge(hass, mock_bridge) await setup_bridge(hass, mock_bridge)
assert len(mock_bridge.mock_requests) == 1 assert len(mock_bridge.mock_requests) == 2
assert len(hass.states.async_all()) == 2 assert len(hass.states.async_all()) == 2
lamp_2 = hass.states.get("light.hue_lamp_2") lamp_2 = hass.states.get("light.hue_lamp_2")
@ -526,8 +539,8 @@ async def test_other_light_update(hass, mock_bridge):
await hass.services.async_call( await hass.services.async_call(
"light", "turn_on", {"entity_id": "light.hue_lamp_1"}, blocking=True "light", "turn_on", {"entity_id": "light.hue_lamp_1"}, blocking=True
) )
# 2x light update, 1 turn on request # 2x light update, 1 group update, 1 turn on request
assert len(mock_bridge.mock_requests) == 3 assert len(mock_bridge.mock_requests) == 4
assert len(hass.states.async_all()) == 2 assert len(hass.states.async_all()) == 2
lamp_2 = hass.states.get("light.hue_lamp_2") lamp_2 = hass.states.get("light.hue_lamp_2")
@ -549,7 +562,6 @@ async def test_update_timeout(hass, mock_bridge):
async def test_update_unauthorized(hass, mock_bridge): async def test_update_unauthorized(hass, mock_bridge):
"""Test bridge marked as not authorized if unauthorized during update.""" """Test bridge marked as not authorized if unauthorized during update."""
mock_bridge.api.lights.update = Mock(side_effect=aiohue.Unauthorized) mock_bridge.api.lights.update = Mock(side_effect=aiohue.Unauthorized)
mock_bridge.api.groups.update = Mock(side_effect=aiohue.Unauthorized)
await setup_bridge(hass, mock_bridge) await setup_bridge(hass, mock_bridge)
assert len(mock_bridge.mock_requests) == 0 assert len(mock_bridge.mock_requests) == 0
assert len(hass.states.async_all()) == 0 assert len(hass.states.async_all()) == 0
@ -559,6 +571,8 @@ async def test_update_unauthorized(hass, mock_bridge):
async def test_light_turn_on_service(hass, mock_bridge): async def test_light_turn_on_service(hass, mock_bridge):
"""Test calling the turn on service on a light.""" """Test calling the turn on service on a light."""
mock_bridge.mock_light_responses.append(LIGHT_RESPONSE) mock_bridge.mock_light_responses.append(LIGHT_RESPONSE)
mock_bridge.mock_group_responses.append(GROUP_RESPONSE)
await setup_bridge(hass, mock_bridge) await setup_bridge(hass, mock_bridge)
light = hass.states.get("light.hue_lamp_2") light = hass.states.get("light.hue_lamp_2")
assert light is not None assert light is not None
@ -575,10 +589,10 @@ async def test_light_turn_on_service(hass, mock_bridge):
{"entity_id": "light.hue_lamp_2", "brightness": 100, "color_temp": 300}, {"entity_id": "light.hue_lamp_2", "brightness": 100, "color_temp": 300},
blocking=True, blocking=True,
) )
# 2x light update, 1 turn on request # 2x light update, 1 group update, 1 turn on request
assert len(mock_bridge.mock_requests) == 3 assert len(mock_bridge.mock_requests) == 4
assert mock_bridge.mock_requests[1]["json"] == { assert mock_bridge.mock_requests[2]["json"] == {
"bri": 100, "bri": 100,
"on": True, "on": True,
"ct": 300, "ct": 300,
@ -599,9 +613,9 @@ async def test_light_turn_on_service(hass, mock_bridge):
blocking=True, blocking=True,
) )
assert len(mock_bridge.mock_requests) == 5 assert len(mock_bridge.mock_requests) == 6
assert mock_bridge.mock_requests[3]["json"] == { assert mock_bridge.mock_requests[4]["json"] == {
"on": True, "on": True,
"xy": (0.138, 0.08), "xy": (0.138, 0.08),
"alert": "none", "alert": "none",
@ -611,6 +625,8 @@ async def test_light_turn_on_service(hass, mock_bridge):
async def test_light_turn_off_service(hass, mock_bridge): async def test_light_turn_off_service(hass, mock_bridge):
"""Test calling the turn on service on a light.""" """Test calling the turn on service on a light."""
mock_bridge.mock_light_responses.append(LIGHT_RESPONSE) mock_bridge.mock_light_responses.append(LIGHT_RESPONSE)
mock_bridge.mock_group_responses.append(GROUP_RESPONSE)
await setup_bridge(hass, mock_bridge) await setup_bridge(hass, mock_bridge)
light = hass.states.get("light.hue_lamp_1") light = hass.states.get("light.hue_lamp_1")
assert light is not None assert light is not None
@ -624,10 +640,11 @@ async def test_light_turn_off_service(hass, mock_bridge):
await hass.services.async_call( await hass.services.async_call(
"light", "turn_off", {"entity_id": "light.hue_lamp_1"}, blocking=True "light", "turn_off", {"entity_id": "light.hue_lamp_1"}, blocking=True
) )
# 2x light update, 1 turn on request
assert len(mock_bridge.mock_requests) == 3
assert mock_bridge.mock_requests[1]["json"] == {"on": False, "alert": "none"} # 2x light update, 1 for group update, 1 turn on request
assert len(mock_bridge.mock_requests) == 4
assert mock_bridge.mock_requests[2]["json"] == {"on": False, "alert": "none"}
assert len(hass.states.async_all()) == 2 assert len(hass.states.async_all()) == 2
@ -649,6 +666,7 @@ def test_available():
bridge=Mock(allow_unreachable=False), bridge=Mock(allow_unreachable=False),
is_group=False, is_group=False,
supported_features=hue_light.SUPPORT_HUE_EXTENDED, supported_features=hue_light.SUPPORT_HUE_EXTENDED,
rooms={},
) )
assert light.available is False assert light.available is False
@ -664,6 +682,7 @@ def test_available():
bridge=Mock(allow_unreachable=True), bridge=Mock(allow_unreachable=True),
is_group=False, is_group=False,
supported_features=hue_light.SUPPORT_HUE_EXTENDED, supported_features=hue_light.SUPPORT_HUE_EXTENDED,
rooms={},
) )
assert light.available is True assert light.available is True
@ -679,6 +698,7 @@ def test_available():
bridge=Mock(allow_unreachable=False), bridge=Mock(allow_unreachable=False),
is_group=True, is_group=True,
supported_features=hue_light.SUPPORT_HUE_EXTENDED, supported_features=hue_light.SUPPORT_HUE_EXTENDED,
rooms={},
) )
assert light.available is True assert light.available is True
@ -697,6 +717,7 @@ def test_hs_color():
bridge=Mock(), bridge=Mock(),
is_group=False, is_group=False,
supported_features=hue_light.SUPPORT_HUE_EXTENDED, supported_features=hue_light.SUPPORT_HUE_EXTENDED,
rooms={},
) )
assert light.hs_color is None assert light.hs_color is None
@ -712,6 +733,7 @@ def test_hs_color():
bridge=Mock(), bridge=Mock(),
is_group=False, is_group=False,
supported_features=hue_light.SUPPORT_HUE_EXTENDED, supported_features=hue_light.SUPPORT_HUE_EXTENDED,
rooms={},
) )
assert light.hs_color is None assert light.hs_color is None
@ -727,6 +749,7 @@ def test_hs_color():
bridge=Mock(), bridge=Mock(),
is_group=False, is_group=False,
supported_features=hue_light.SUPPORT_HUE_EXTENDED, supported_features=hue_light.SUPPORT_HUE_EXTENDED,
rooms={},
) )
assert light.hs_color == color.color_xy_to_hs(0.4, 0.5, LIGHT_GAMUT) assert light.hs_color == color.color_xy_to_hs(0.4, 0.5, LIGHT_GAMUT)
@ -742,7 +765,7 @@ async def test_group_features(hass, mock_bridge):
"1": { "1": {
"name": "Group 1", "name": "Group 1",
"lights": ["1", "2"], "lights": ["1", "2"],
"type": "Room", "type": "LightGroup",
"action": { "action": {
"on": True, "on": True,
"bri": 254, "bri": 254,
@ -757,8 +780,8 @@ async def test_group_features(hass, mock_bridge):
"state": {"any_on": True, "all_on": False}, "state": {"any_on": True, "all_on": False},
}, },
"2": { "2": {
"name": "Group 2", "name": "Living Room",
"lights": ["3", "4"], "lights": ["2", "3"],
"type": "Room", "type": "Room",
"action": { "action": {
"on": True, "on": True,
@ -774,8 +797,8 @@ async def test_group_features(hass, mock_bridge):
"state": {"any_on": True, "all_on": False}, "state": {"any_on": True, "all_on": False},
}, },
"3": { "3": {
"name": "Group 3", "name": "Dining Room",
"lights": ["1", "3"], "lights": ["4"],
"type": "Room", "type": "Room",
"action": { "action": {
"on": True, "on": True,
@ -900,6 +923,7 @@ async def test_group_features(hass, mock_bridge):
mock_bridge.mock_light_responses.append(light_response) mock_bridge.mock_light_responses.append(light_response)
mock_bridge.mock_group_responses.append(group_response) mock_bridge.mock_group_responses.append(group_response)
await setup_bridge(hass, mock_bridge) await setup_bridge(hass, mock_bridge)
assert len(mock_bridge.mock_requests) == 2
color_temp_feature = hue_light.SUPPORT_HUE["Color temperature light"] color_temp_feature = hue_light.SUPPORT_HUE["Color temperature light"]
extended_color_feature = hue_light.SUPPORT_HUE["Extended color light"] extended_color_feature = hue_light.SUPPORT_HUE["Extended color light"]
@ -907,8 +931,27 @@ async def test_group_features(hass, mock_bridge):
group_1 = hass.states.get("light.group_1") group_1 = hass.states.get("light.group_1")
assert group_1.attributes["supported_features"] == color_temp_feature assert group_1.attributes["supported_features"] == color_temp_feature
group_2 = hass.states.get("light.group_2") group_2 = hass.states.get("light.living_room")
assert group_2.attributes["supported_features"] == extended_color_feature assert group_2.attributes["supported_features"] == extended_color_feature
group_3 = hass.states.get("light.group_3") group_3 = hass.states.get("light.dining_room")
assert group_3.attributes["supported_features"] == extended_color_feature assert group_3.attributes["supported_features"] == extended_color_feature
entity_registry = await async_get_entity_registry(hass)
device_registry = await async_get_device_registry(hass)
entry = entity_registry.async_get("light.hue_lamp_1")
device_entry = device_registry.async_get(entry.device_id)
assert device_entry.suggested_area is None
entry = entity_registry.async_get("light.hue_lamp_2")
device_entry = device_registry.async_get(entry.device_id)
assert device_entry.suggested_area == "Living Room"
entry = entity_registry.async_get("light.hue_lamp_3")
device_entry = device_registry.async_get(entry.device_id)
assert device_entry.suggested_area == "Living Room"
entry = entity_registry.async_get("light.hue_lamp_4")
device_entry = device_registry.async_get(entry.device_id)
assert device_entry.suggested_area == "Dining Room"