"""Philips Hue lights platform tests for V2 bridge/api.""" from homeassistant.components.light import ColorMode from homeassistant.helpers import entity_registry as er from .conftest import setup_platform from .const import FAKE_DEVICE, FAKE_LIGHT, FAKE_ZIGBEE_CONNECTIVITY async def test_lights(hass, mock_bridge_v2, v2_resources_test_data): """Test if all v2 lights get created with correct features.""" await mock_bridge_v2.api.load_test_data(v2_resources_test_data) await setup_platform(hass, mock_bridge_v2, "light") # there shouldn't have been any requests at this point assert len(mock_bridge_v2.mock_requests) == 0 # 8 entities should be created from test data assert len(hass.states.async_all()) == 8 # test light which supports color and color temperature light_1 = hass.states.get("light.hue_light_with_color_and_color_temperature_1") assert light_1 is not None assert ( light_1.attributes["friendly_name"] == "Hue light with color and color temperature 1" ) assert light_1.state == "on" assert light_1.attributes["brightness"] == int(46.85 / 100 * 255) assert light_1.attributes["mode"] == "normal" assert light_1.attributes["color_mode"] == ColorMode.XY assert set(light_1.attributes["supported_color_modes"]) == { ColorMode.COLOR_TEMP, ColorMode.XY, } assert light_1.attributes["xy_color"] == (0.5614, 0.4058) assert light_1.attributes["min_mireds"] == 153 assert light_1.attributes["max_mireds"] == 500 assert light_1.attributes["dynamics"] == "dynamic_palette" assert light_1.attributes["effect_list"] == ["None", "candle", "fire"] assert light_1.attributes["effect"] == "None" # test light which supports color temperature only light_2 = hass.states.get("light.hue_light_with_color_temperature_only") assert light_2 is not None assert ( light_2.attributes["friendly_name"] == "Hue light with color temperature only" ) assert light_2.state == "off" assert light_2.attributes["mode"] == "normal" assert light_2.attributes["supported_color_modes"] == [ColorMode.COLOR_TEMP] assert light_2.attributes["min_mireds"] == 153 assert light_2.attributes["max_mireds"] == 454 assert light_2.attributes["dynamics"] == "none" assert light_2.attributes["effect_list"] == ["None", "candle", "sunrise"] # test light which supports color only light_3 = hass.states.get("light.hue_light_with_color_only") assert light_3 is not None assert light_3.attributes["friendly_name"] == "Hue light with color only" assert light_3.state == "on" assert light_3.attributes["brightness"] == 128 assert light_3.attributes["mode"] == "normal" assert light_3.attributes["supported_color_modes"] == [ColorMode.XY] assert light_3.attributes["color_mode"] == ColorMode.XY assert light_3.attributes["dynamics"] == "dynamic_palette" # test light which supports on/off only light_4 = hass.states.get("light.hue_on_off_light") assert light_4 is not None assert light_4.attributes["friendly_name"] == "Hue on/off light" assert light_4.state == "off" assert light_4.attributes["mode"] == "normal" assert light_4.attributes["supported_color_modes"] == [] async def test_light_turn_on_service(hass, mock_bridge_v2, v2_resources_test_data): """Test calling the turn on service on a light.""" await mock_bridge_v2.api.load_test_data(v2_resources_test_data) await setup_platform(hass, mock_bridge_v2, "light") test_light_id = "light.hue_light_with_color_temperature_only" # verify the light is off before we start assert hass.states.get(test_light_id).state == "off" # now call the HA turn_on service await hass.services.async_call( "light", "turn_on", {"entity_id": test_light_id, "brightness_pct": 100, "color_temp": 300}, blocking=True, ) # PUT request should have been sent to device with correct params assert len(mock_bridge_v2.mock_requests) == 1 assert mock_bridge_v2.mock_requests[0]["method"] == "put" assert mock_bridge_v2.mock_requests[0]["json"]["on"]["on"] is True assert mock_bridge_v2.mock_requests[0]["json"]["dimming"]["brightness"] == 100 assert mock_bridge_v2.mock_requests[0]["json"]["color_temperature"]["mirek"] == 300 # Now generate update event by emitting the json we've sent as incoming event event = { "id": "3a6710fa-4474-4eba-b533-5e6e72968feb", "type": "light", **mock_bridge_v2.mock_requests[0]["json"], } mock_bridge_v2.api.emit_event("update", event) await hass.async_block_till_done() # the light should now be on test_light = hass.states.get(test_light_id) assert test_light is not None assert test_light.state == "on" assert test_light.attributes["mode"] == "normal" assert test_light.attributes["supported_color_modes"] == [ColorMode.COLOR_TEMP] assert test_light.attributes["color_mode"] == ColorMode.COLOR_TEMP assert test_light.attributes["brightness"] == 255 # test again with sending transition with 250ms which should round up to 200ms await hass.services.async_call( "light", "turn_on", {"entity_id": test_light_id, "brightness_pct": 50, "transition": 0.25}, blocking=True, ) assert len(mock_bridge_v2.mock_requests) == 2 assert mock_bridge_v2.mock_requests[1]["json"]["on"]["on"] is True assert mock_bridge_v2.mock_requests[1]["json"]["dynamics"]["duration"] == 200 # test again with sending long flash await hass.services.async_call( "light", "turn_on", {"entity_id": test_light_id, "flash": "long"}, blocking=True, ) assert len(mock_bridge_v2.mock_requests) == 3 assert mock_bridge_v2.mock_requests[2]["json"]["alert"]["action"] == "breathe" # test again with sending short flash await hass.services.async_call( "light", "turn_on", {"entity_id": test_light_id, "flash": "short"}, blocking=True, ) assert len(mock_bridge_v2.mock_requests) == 4 assert mock_bridge_v2.mock_requests[3]["json"]["identify"]["action"] == "identify" # test again with sending a colortemperature which is out of range # which should be normalized to the upper/lower bounds Hue can handle await hass.services.async_call( "light", "turn_on", {"entity_id": test_light_id, "color_temp": 50}, blocking=True, ) assert len(mock_bridge_v2.mock_requests) == 5 assert mock_bridge_v2.mock_requests[4]["json"]["color_temperature"]["mirek"] == 153 await hass.services.async_call( "light", "turn_on", {"entity_id": test_light_id, "color_temp": 550}, blocking=True, ) assert len(mock_bridge_v2.mock_requests) == 6 assert mock_bridge_v2.mock_requests[5]["json"]["color_temperature"]["mirek"] == 500 # test enable effect await hass.services.async_call( "light", "turn_on", {"entity_id": test_light_id, "effect": "candle"}, blocking=True, ) assert len(mock_bridge_v2.mock_requests) == 7 assert mock_bridge_v2.mock_requests[6]["json"]["effects"]["effect"] == "candle" # test disable effect await hass.services.async_call( "light", "turn_on", {"entity_id": test_light_id, "effect": "None"}, blocking=True, ) assert len(mock_bridge_v2.mock_requests) == 8 assert mock_bridge_v2.mock_requests[7]["json"]["effects"]["effect"] == "no_effect" # test timed effect await hass.services.async_call( "light", "turn_on", {"entity_id": test_light_id, "effect": "sunrise", "transition": 6}, blocking=True, ) assert len(mock_bridge_v2.mock_requests) == 9 assert ( mock_bridge_v2.mock_requests[8]["json"]["timed_effects"]["effect"] == "sunrise" ) assert mock_bridge_v2.mock_requests[8]["json"]["timed_effects"]["duration"] == 6000 async def test_light_turn_off_service(hass, mock_bridge_v2, v2_resources_test_data): """Test calling the turn off service on a light.""" await mock_bridge_v2.api.load_test_data(v2_resources_test_data) await setup_platform(hass, mock_bridge_v2, "light") test_light_id = "light.hue_light_with_color_and_color_temperature_1" # verify the light is on before we start assert hass.states.get(test_light_id).state == "on" # now call the HA turn_off service await hass.services.async_call( "light", "turn_off", {"entity_id": test_light_id}, blocking=True, ) # PUT request should have been sent to device with correct params assert len(mock_bridge_v2.mock_requests) == 1 assert mock_bridge_v2.mock_requests[0]["method"] == "put" assert mock_bridge_v2.mock_requests[0]["json"]["on"]["on"] is False # Now generate update event by emitting the json we've sent as incoming event event = { "id": "02cba059-9c2c-4d45-97e4-4f79b1bfbaa1", "type": "light", **mock_bridge_v2.mock_requests[0]["json"], } mock_bridge_v2.api.emit_event("update", event) await hass.async_block_till_done() # the light should now be off test_light = hass.states.get(test_light_id) assert test_light is not None assert test_light.state == "off" # test again with sending transition await hass.services.async_call( "light", "turn_off", {"entity_id": test_light_id, "transition": 0.25}, blocking=True, ) assert len(mock_bridge_v2.mock_requests) == 2 assert mock_bridge_v2.mock_requests[1]["json"]["on"]["on"] is False assert mock_bridge_v2.mock_requests[1]["json"]["dynamics"]["duration"] == 200 # test again with sending long flash await hass.services.async_call( "light", "turn_off", {"entity_id": test_light_id, "flash": "long"}, blocking=True, ) assert len(mock_bridge_v2.mock_requests) == 3 assert mock_bridge_v2.mock_requests[2]["json"]["alert"]["action"] == "breathe" # test again with sending short flash await hass.services.async_call( "light", "turn_off", {"entity_id": test_light_id, "flash": "short"}, blocking=True, ) assert len(mock_bridge_v2.mock_requests) == 4 assert mock_bridge_v2.mock_requests[3]["json"]["identify"]["action"] == "identify" async def test_light_added(hass, mock_bridge_v2): """Test new light added to bridge.""" await mock_bridge_v2.api.load_test_data([FAKE_DEVICE, FAKE_ZIGBEE_CONNECTIVITY]) await setup_platform(hass, mock_bridge_v2, "light") test_entity_id = "light.hue_fake_light" # verify entity does not exist before we start assert hass.states.get(test_entity_id) is None # Add new fake entity (and attached device and zigbee_connectivity) by emitting events mock_bridge_v2.api.emit_event("add", FAKE_LIGHT) await hass.async_block_till_done() # the entity should now be available test_entity = hass.states.get(test_entity_id) assert test_entity is not None assert test_entity.state == "off" assert test_entity.attributes["friendly_name"] == FAKE_LIGHT["metadata"]["name"] async def test_light_availability(hass, mock_bridge_v2, v2_resources_test_data): """Test light availability property.""" await mock_bridge_v2.api.load_test_data(v2_resources_test_data) await setup_platform(hass, mock_bridge_v2, "light") test_light_id = "light.hue_light_with_color_and_color_temperature_1" # verify entity does exist and is available before we start test_light = hass.states.get(test_light_id) assert test_light is not None assert test_light.state == "on" # Change availability by modififying the zigbee_connectivity status for status in ("connectivity_issue", "disconnected", "connected"): mock_bridge_v2.api.emit_event( "update", { "id": "1987ba66-c21d-48d0-98fb-121d939a71f3", "status": status, "type": "zigbee_connectivity", }, ) await hass.async_block_till_done() # the entity should now be available only when zigbee is connected test_light = hass.states.get(test_light_id) assert test_light.state == "on" if status == "connected" else "unavailable" async def test_grouped_lights(hass, mock_bridge_v2, v2_resources_test_data): """Test if all v2 grouped lights get created with correct features.""" await mock_bridge_v2.api.load_test_data(v2_resources_test_data) await setup_platform(hass, mock_bridge_v2, "light") # test if entities for hue groups are created and enabled by default for entity_id in ("light.test_zone", "light.test_room"): ent_reg = er.async_get(hass) entity_entry = ent_reg.async_get(entity_id) assert entity_entry # scene entities should have be assigned to the room/zone device/service assert entity_entry.device_id is not None # test light created for hue zone test_entity = hass.states.get("light.test_zone") assert test_entity is not None assert test_entity.attributes["friendly_name"] == "Test Zone" assert test_entity.state == "on" assert test_entity.attributes["brightness"] == 119 assert test_entity.attributes["color_mode"] == ColorMode.XY assert set(test_entity.attributes["supported_color_modes"]) == { ColorMode.COLOR_TEMP, ColorMode.XY, } assert test_entity.attributes["min_mireds"] == 153 assert test_entity.attributes["max_mireds"] == 500 assert test_entity.attributes["is_hue_group"] is True assert test_entity.attributes["hue_scenes"] == {"Dynamic Test Scene"} assert test_entity.attributes["hue_type"] == "zone" assert test_entity.attributes["lights"] == { "Hue light with color and color temperature 1", "Hue light with color and color temperature gradient", "Hue light with color and color temperature 2", } # test light created for hue room test_entity = hass.states.get("light.test_room") assert test_entity is not None assert test_entity.attributes["friendly_name"] == "Test Room" assert test_entity.state == "off" assert test_entity.attributes["supported_color_modes"] == [ColorMode.COLOR_TEMP] assert test_entity.attributes["min_mireds"] == 153 assert test_entity.attributes["max_mireds"] == 454 assert test_entity.attributes["is_hue_group"] is True assert test_entity.attributes["hue_scenes"] == {"Regular Test Scene"} assert test_entity.attributes["hue_type"] == "room" assert test_entity.attributes["lights"] == { "Hue on/off light", "Hue light with color temperature only", } # Test calling the turn on service on a grouped light test_light_id = "light.test_zone" await hass.services.async_call( "light", "turn_on", { "entity_id": test_light_id, "brightness_pct": 100, "xy_color": (0.123, 0.123), "transition": 0.25, }, blocking=True, ) # PUT request should have been sent to group_light with correct params assert len(mock_bridge_v2.mock_requests) == 1 assert mock_bridge_v2.mock_requests[0]["json"]["on"]["on"] is True assert mock_bridge_v2.mock_requests[0]["json"]["dimming"]["brightness"] == 100 assert mock_bridge_v2.mock_requests[0]["json"]["color"]["xy"]["x"] == 0.123 assert mock_bridge_v2.mock_requests[0]["json"]["color"]["xy"]["y"] == 0.123 assert mock_bridge_v2.mock_requests[0]["json"]["dynamics"]["duration"] == 200 # Now generate update events by emitting the json we've sent as incoming events for light_id in [ "02cba059-9c2c-4d45-97e4-4f79b1bfbaa1", "b3fe71ef-d0ef-48de-9355-d9e604377df0", "8015b17f-8336-415b-966a-b364bd082397", ]: event = { "id": light_id, "type": "light", **mock_bridge_v2.mock_requests[0]["json"], } mock_bridge_v2.api.emit_event("update", event) await hass.async_block_till_done() await hass.async_block_till_done() # the light should now be on and have the properties we've set test_light = hass.states.get(test_light_id) assert test_light is not None assert test_light.state == "on" assert test_light.attributes["color_mode"] == ColorMode.XY assert test_light.attributes["brightness"] == 255 assert test_light.attributes["xy_color"] == (0.123, 0.123) # Test calling the turn off service on a grouped light. mock_bridge_v2.mock_requests.clear() await hass.services.async_call( "light", "turn_off", {"entity_id": test_light_id}, blocking=True, ) # PUT request should have been sent to ONLY the grouped_light resource with correct params assert len(mock_bridge_v2.mock_requests) == 1 assert mock_bridge_v2.mock_requests[0]["method"] == "put" assert mock_bridge_v2.mock_requests[0]["json"]["on"]["on"] is False # Now generate update event by emitting the json we've sent as incoming event event = { "id": "f2416154-9607-43ab-a684-4453108a200e", "type": "grouped_light", **mock_bridge_v2.mock_requests[0]["json"], } mock_bridge_v2.api.emit_event("update", event) mock_bridge_v2.api.emit_event("update", mock_bridge_v2.mock_requests[0]["json"]) await hass.async_block_till_done() # the light should now be off test_light = hass.states.get(test_light_id) assert test_light is not None assert test_light.state == "off" # Test calling the turn off service on a grouped light with transition mock_bridge_v2.mock_requests.clear() test_light_id = "light.test_zone" await hass.services.async_call( "light", "turn_off", { "entity_id": test_light_id, "transition": 0.25, }, blocking=True, ) # PUT request should have been sent to group_light with correct params assert len(mock_bridge_v2.mock_requests) == 1 assert mock_bridge_v2.mock_requests[0]["json"]["on"]["on"] is False assert mock_bridge_v2.mock_requests[0]["json"]["dynamics"]["duration"] == 200 # Test sending short flash effect to a grouped light mock_bridge_v2.mock_requests.clear() test_light_id = "light.test_zone" await hass.services.async_call( "light", "turn_on", { "entity_id": test_light_id, "flash": "short", }, blocking=True, ) # PUT request should have been sent to ALL group lights with correct params assert len(mock_bridge_v2.mock_requests) == 3 for index in range(0, 3): assert ( mock_bridge_v2.mock_requests[index]["json"]["identify"]["action"] == "identify" ) # Test sending long flash effect to a grouped light mock_bridge_v2.mock_requests.clear() test_light_id = "light.test_zone" await hass.services.async_call( "light", "turn_on", { "entity_id": test_light_id, "flash": "long", }, blocking=True, ) # PUT request should have been sent to grouped_light with correct params assert len(mock_bridge_v2.mock_requests) == 1 assert mock_bridge_v2.mock_requests[0]["json"]["alert"]["action"] == "breathe" # Test sending flash effect in turn_off call mock_bridge_v2.mock_requests.clear() test_light_id = "light.test_zone" await hass.services.async_call( "light", "turn_off", { "entity_id": test_light_id, "flash": "short", }, blocking=True, ) # PUT request should have been sent to ALL group lights with correct params assert len(mock_bridge_v2.mock_requests) == 3 for index in range(0, 3): assert ( mock_bridge_v2.mock_requests[index]["json"]["identify"]["action"] == "identify" )