diff --git a/homeassistant/components/hyperion/config_flow.py b/homeassistant/components/hyperion/config_flow.py index 97e97cd835d..52c4647f11c 100644 --- a/homeassistant/components/hyperion/config_flow.py +++ b/homeassistant/components/hyperion/config_flow.py @@ -447,7 +447,7 @@ class HyperionOptionsFlow(OptionsFlow): ) -> FlowResult: """Manage the options.""" - effects = {source: source for source in const.KEY_COMPONENTID_EXTERNAL_SOURCES} + effects = {} async with self._create_client() as hyperion_client: if not hyperion_client: return self.async_abort(reason="cannot_connect") diff --git a/homeassistant/components/hyperion/const.py b/homeassistant/components/hyperion/const.py index e7e4e7f70a4..4585b8bedaa 100644 --- a/homeassistant/components/hyperion/const.py +++ b/homeassistant/components/hyperion/const.py @@ -21,8 +21,6 @@ HYPERION_MODEL_NAME = f"{HYPERION_MANUFACTURER_NAME}-NG" HYPERION_RELEASES_URL = "https://github.com/hyperion-project/hyperion.ng/releases" HYPERION_VERSION_WARN_CUTOFF = "2.0.0-alpha.9" -NAME_SUFFIX_HYPERION_LIGHT = "" -NAME_SUFFIX_HYPERION_PRIORITY_LIGHT = "Priority" NAME_SUFFIX_HYPERION_COMPONENT_SWITCH = "Component" NAME_SUFFIX_HYPERION_CAMERA = "" @@ -32,5 +30,4 @@ SIGNAL_ENTITY_REMOVE = f"{DOMAIN}_entity_remove_signal.{{}}" TYPE_HYPERION_CAMERA = "hyperion_camera" TYPE_HYPERION_LIGHT = "hyperion_light" -TYPE_HYPERION_PRIORITY_LIGHT = "hyperion_priority_light" TYPE_HYPERION_COMPONENT_SWITCH_BASE = "hyperion_component_switch" diff --git a/homeassistant/components/hyperion/light.py b/homeassistant/components/hyperion/light.py index d44688b3bed..e14c395315e 100644 --- a/homeassistant/components/hyperion/light.py +++ b/homeassistant/components/hyperion/light.py @@ -41,24 +41,19 @@ from .const import ( DOMAIN, HYPERION_MANUFACTURER_NAME, HYPERION_MODEL_NAME, - NAME_SUFFIX_HYPERION_LIGHT, - NAME_SUFFIX_HYPERION_PRIORITY_LIGHT, SIGNAL_ENTITY_REMOVE, TYPE_HYPERION_LIGHT, - TYPE_HYPERION_PRIORITY_LIGHT, ) _LOGGER = logging.getLogger(__name__) -COLOR_BLACK = color_util.COLORS["black"] - CONF_DEFAULT_COLOR = "default_color" CONF_HDMI_PRIORITY = "hdmi_priority" CONF_EFFECT_LIST = "effect_list" # As we want to preserve brightness control for effects (e.g. to reduce the -# brightness for V4L), we need to persist the effect that is in flight, so -# subsequent calls to turn_on will know the keep the effect enabled. +# brightness), we need to persist the effect that is in flight, so +# subsequent calls to turn_on will know to keep the effect enabled. # Unfortunately the Home Assistant UI does not easily expose a way to remove a # selected effect (there is no 'No Effect' option by default). Instead, we # create a new fake effect ("Solid") that is always selected by default for @@ -75,7 +70,6 @@ DEFAULT_EFFECT_LIST: list[str] = [] ICON_LIGHTBULB = "mdi:lightbulb" ICON_EFFECT = "mdi:lava-lamp" -ICON_EXTERNAL_SOURCE = "mdi:television-ambient-light" async def async_setup_entry( @@ -102,7 +96,6 @@ async def async_setup_entry( async_add_entities( [ HyperionLight(*args), - HyperionPriorityLight(*args), ] ) @@ -110,19 +103,18 @@ async def async_setup_entry( def instance_remove(instance_num: int) -> None: """Remove entities for an old Hyperion instance.""" assert server_id - for light_type in LIGHT_TYPES: - async_dispatcher_send( - hass, - SIGNAL_ENTITY_REMOVE.format( - get_hyperion_unique_id(server_id, instance_num, light_type) - ), - ) + async_dispatcher_send( + hass, + SIGNAL_ENTITY_REMOVE.format( + get_hyperion_unique_id(server_id, instance_num, TYPE_HYPERION_LIGHT) + ), + ) listen_for_instance_updates(hass, config_entry, instance_add, instance_remove) -class HyperionBaseLight(LightEntity): - """A Hyperion light base class.""" +class HyperionLight(LightEntity): + """A Hyperion light that acts as a client for the configured priority.""" _attr_color_mode = ColorMode.HS _attr_should_poll = False @@ -151,11 +143,6 @@ class HyperionBaseLight(LightEntity): self._effect: str = KEY_EFFECT_SOLID self._static_effect_list: list[str] = [KEY_EFFECT_SOLID] - if self._support_external_effects: - self._static_effect_list += [ - const.KEY_COMPONENTID_TO_NAME[component] - for component in const.KEY_COMPONENTID_EXTERNAL_SOURCES - ] self._effect_list: list[str] = self._static_effect_list[:] self._client_callbacks: Mapping[str, Callable[[dict[str, Any]], None]] = { @@ -168,11 +155,11 @@ class HyperionBaseLight(LightEntity): def _compute_unique_id(self, server_id: str, instance_num: int) -> str: """Compute a unique id for this instance.""" - raise NotImplementedError + return get_hyperion_unique_id(server_id, instance_num, TYPE_HYPERION_LIGHT) def _compute_name(self, instance_name: str) -> str: """Compute the name of the light.""" - raise NotImplementedError + return f"{instance_name}".strip() @property def entity_registry_enabled_default(self) -> bool: @@ -198,12 +185,6 @@ class HyperionBaseLight(LightEntity): def icon(self) -> str: """Return state specific icon.""" if self.is_on: - if ( - self.effect in const.KEY_COMPONENTID_FROM_NAME - and const.KEY_COMPONENTID_FROM_NAME[self.effect] - in const.KEY_COMPONENTID_EXTERNAL_SOURCES - ): - return ICON_EXTERNAL_SOURCE if self.effect != KEY_EFFECT_SOLID: return ICON_EFFECT return ICON_LIGHTBULB @@ -247,6 +228,11 @@ class HyperionBaseLight(LightEntity): } return self._options.get(key, defaults[key]) + @property + def is_on(self) -> bool: + """Return true if light is on. Light is considered on when there is a source at the configured HA priority.""" + return self._get_priority_entry_that_dictates_state() is not None + async def async_turn_on(self, **kwargs: Any) -> None: """Turn on the light.""" # == Get key parameters == @@ -279,55 +265,8 @@ class HyperionBaseLight(LightEntity): ): return - # == Set an external source - if ( - effect - and self._support_external_effects - and ( - effect in const.KEY_COMPONENTID_EXTERNAL_SOURCES - or effect in const.KEY_COMPONENTID_FROM_NAME - ) - ): - if effect in const.KEY_COMPONENTID_FROM_NAME: - component = const.KEY_COMPONENTID_FROM_NAME[effect] - else: - _LOGGER.warning( - ( - "Use of Hyperion effect '%s' is deprecated and will be removed " - "in a future release. Please use '%s' instead" - ), - effect, - const.KEY_COMPONENTID_TO_NAME[effect], - ) - component = effect - - # Clear any color/effect. - if not await self._client.async_send_clear( - **{const.KEY_PRIORITY: self._get_option(CONF_PRIORITY)} - ): - return - - # Turn off all external sources, except the intended. - for key in const.KEY_COMPONENTID_EXTERNAL_SOURCES: - if not await self._client.async_send_set_component( - **{ - const.KEY_COMPONENTSTATE: { - const.KEY_COMPONENT: key, - const.KEY_STATE: component == key, - } - } - ): - return - # == Set an effect - elif effect and effect != KEY_EFFECT_SOLID: - # This call should not be necessary, but without it there is no priorities-update issued: - # https://github.com/hyperion-project/hyperion.ng/issues/992 - if not await self._client.async_send_clear( - **{const.KEY_PRIORITY: self._get_option(CONF_PRIORITY)} - ): - return - + if effect and effect != KEY_EFFECT_SOLID: if not await self._client.async_send_set_effect( **{ const.KEY_PRIORITY: self._get_option(CONF_PRIORITY), @@ -336,6 +275,7 @@ class HyperionBaseLight(LightEntity): } ): return + # == Set a color elif not await self._client.async_send_set_color( **{ @@ -346,6 +286,13 @@ class HyperionBaseLight(LightEntity): ): return + async def async_turn_off(self, **kwargs: Any) -> None: + """Turn off the light i.e. clear the configured priority.""" + if not await self._client.async_send_clear( + **{const.KEY_PRIORITY: self._get_option(CONF_PRIORITY)} + ): + return + def _set_internal_state( self, brightness: int | None = None, @@ -383,24 +330,15 @@ class HyperionBaseLight(LightEntity): def _update_priorities(self, _: dict[str, Any] | None = None) -> None: """Update Hyperion priorities.""" priority = self._get_priority_entry_that_dictates_state() - if priority and self._allow_priority_update(priority): - componentid = priority.get(const.KEY_COMPONENTID) - if ( - self._support_external_effects - and componentid in const.KEY_COMPONENTID_EXTERNAL_SOURCES - and componentid in const.KEY_COMPONENTID_TO_NAME - ): - self._set_internal_state( - rgb_color=DEFAULT_COLOR, - effect=const.KEY_COMPONENTID_TO_NAME[componentid], - ) - elif componentid == const.KEY_COMPONENTID_EFFECT: + if priority: + component_id = priority.get(const.KEY_COMPONENTID) + if component_id == const.KEY_COMPONENTID_EFFECT: # Owner is the effect name. # See: https://docs.hyperion-project.org/en/json/ServerInfo.html#priorities self._set_internal_state( rgb_color=DEFAULT_COLOR, effect=priority[const.KEY_OWNER] ) - elif componentid == const.KEY_COMPONENTID_COLOR: + elif component_id == const.KEY_COMPONENTID_COLOR: self._set_internal_state( rgb_color=priority[const.KEY_VALUE][const.KEY_RGB], effect=KEY_EFFECT_SOLID, @@ -469,172 +407,10 @@ class HyperionBaseLight(LightEntity): """Cleanup prior to hass removal.""" self._client.remove_callbacks(self._client_callbacks) - @property - def _support_external_effects(self) -> bool: - """Whether or not to support setting external effects from the light entity.""" - return True - def _get_priority_entry_that_dictates_state(self) -> dict[str, Any] | None: """Get the relevant Hyperion priority entry to consider.""" - # Return the visible priority (whether or not it is the HA priority). - - # Explicit type specifier to ensure this works when the underlying (typed) - # library is installed along with the tests. Casts would trigger a - # redundant-cast warning in this case. - priority: dict[str, Any] | None = self._client.visible_priority - return priority - - def _allow_priority_update(self, priority: dict[str, Any] | None = None) -> bool: - """Determine whether to allow a priority to update internal state.""" - return True - - -class HyperionLight(HyperionBaseLight): - """A Hyperion light that acts in absolute (vs priority) manner. - - Light state is the absolute Hyperion component state (e.g. LED device on/off) rather - than color based at a particular priority, and the 'winning' priority determines - shown state rather than exclusively the HA priority. - """ - - def _compute_unique_id(self, server_id: str, instance_num: int) -> str: - """Compute a unique id for this instance.""" - return get_hyperion_unique_id(server_id, instance_num, TYPE_HYPERION_LIGHT) - - def _compute_name(self, instance_name: str) -> str: - """Compute the name of the light.""" - return f"{instance_name} {NAME_SUFFIX_HYPERION_LIGHT}".strip() - - @property - def is_on(self) -> bool: - """Return true if light is on.""" - return ( - bool(self._client.is_on()) - and self._get_priority_entry_that_dictates_state() is not None - ) - - async def async_turn_on(self, **kwargs: Any) -> None: - """Turn on the light.""" - # == Turn device on == - # Turn on both ALL (Hyperion itself) and LEDDEVICE. It would be - # preferable to enable LEDDEVICE after the settings (e.g. brightness, - # color, effect), but this is not possible due to: - # https://github.com/hyperion-project/hyperion.ng/issues/967 - if not bool(self._client.is_on()): - for component in ( - const.KEY_COMPONENTID_ALL, - const.KEY_COMPONENTID_LEDDEVICE, - ): - if not await self._client.async_send_set_component( - **{ - const.KEY_COMPONENTSTATE: { - const.KEY_COMPONENT: component, - const.KEY_STATE: True, - } - } - ): - return - - # Turn on the relevant Hyperion priority as usual. - await super().async_turn_on(**kwargs) - - async def async_turn_off(self, **kwargs: Any) -> None: - """Turn off the light.""" - if not await self._client.async_send_set_component( - **{ - const.KEY_COMPONENTSTATE: { - const.KEY_COMPONENT: const.KEY_COMPONENTID_LEDDEVICE, - const.KEY_STATE: False, - } - } - ): - return - - -class HyperionPriorityLight(HyperionBaseLight): - """A Hyperion light that only acts on a single Hyperion priority.""" - - def _compute_unique_id(self, server_id: str, instance_num: int) -> str: - """Compute a unique id for this instance.""" - return get_hyperion_unique_id( - server_id, instance_num, TYPE_HYPERION_PRIORITY_LIGHT - ) - - def _compute_name(self, instance_name: str) -> str: - """Compute the name of the light.""" - return f"{instance_name} {NAME_SUFFIX_HYPERION_PRIORITY_LIGHT}".strip() - - @property - def entity_registry_enabled_default(self) -> bool: - """Whether or not the entity is enabled by default.""" - return False - - @property - def is_on(self) -> bool: - """Return true if light is on.""" - priority = self._get_priority_entry_that_dictates_state() - return ( - priority is not None - and not HyperionPriorityLight._is_priority_entry_black(priority) - ) - - async def async_turn_off(self, **kwargs: Any) -> None: - """Turn off the light.""" - if not await self._client.async_send_clear( - **{const.KEY_PRIORITY: self._get_option(CONF_PRIORITY)} - ): - return - await self._client.async_send_set_color( - **{ - const.KEY_PRIORITY: self._get_option(CONF_PRIORITY), - const.KEY_COLOR: COLOR_BLACK, - const.KEY_ORIGIN: DEFAULT_ORIGIN, - } - ) - - @property - def _support_external_effects(self) -> bool: - """Whether or not to support setting external effects from the light entity.""" - return False - - def _get_priority_entry_that_dictates_state(self) -> dict[str, Any] | None: - """Get the relevant Hyperion priority entry to consider.""" - # Return the active priority (if any) at the configured HA priority. - for candidate in self._client.priorities or []: - if const.KEY_PRIORITY not in candidate: - continue - if candidate[const.KEY_PRIORITY] == self._get_option( - CONF_PRIORITY - ) and candidate.get(const.KEY_ACTIVE, False): - # Explicit type specifier to ensure this works when the underlying - # (typed) library is installed along with the tests. Casts would trigger - # a redundant-cast warning in this case. - output: dict[str, Any] = candidate - return output + # Return whether or not the HA priority is among the active priorities. + for priority in self._client.priorities or []: + if priority.get(const.KEY_PRIORITY) == self._get_option(CONF_PRIORITY): + return priority return None - - @classmethod - def _is_priority_entry_black(cls, priority: dict[str, Any] | None) -> bool: - """Determine if a given priority entry is the color black.""" - if ( - priority - and priority.get(const.KEY_COMPONENTID) == const.KEY_COMPONENTID_COLOR - ): - rgb_color = priority.get(const.KEY_VALUE, {}).get(const.KEY_RGB) - if rgb_color is not None and tuple(rgb_color) == COLOR_BLACK: - return True - return False - - def _allow_priority_update(self, priority: dict[str, Any] | None = None) -> bool: - """Determine whether to allow a Hyperion priority to update entity attributes.""" - # Black is treated as 'off' (and Home Assistant does not support selecting black - # from the color selector). Do not set our internal attributes if the priority is - # 'off' (i.e. if black is active). Do this to ensure it seamlessly turns back on - # at the correct prior color on the next 'on' call. - return not HyperionPriorityLight._is_priority_entry_black(priority) - - -LIGHT_TYPES = { - TYPE_HYPERION_LIGHT: HyperionLight, - TYPE_HYPERION_PRIORITY_LIGHT: HyperionPriorityLight, -} diff --git a/tests/components/hyperion/__init__.py b/tests/components/hyperion/__init__.py index 80a585f9740..382a168bc44 100644 --- a/tests/components/hyperion/__init__.py +++ b/tests/components/hyperion/__init__.py @@ -27,7 +27,6 @@ TEST_PRIORITY = 180 TEST_ENTITY_ID_1 = "light.test_instance_1" TEST_ENTITY_ID_2 = "light.test_instance_2" TEST_ENTITY_ID_3 = "light.test_instance_3" -TEST_PRIORITY_LIGHT_ENTITY_ID_1 = "light.test_instance_1_priority" TEST_TITLE = f"{TEST_HOST}:{TEST_PORT}" TEST_TOKEN = "sekr1t" diff --git a/tests/components/hyperion/test_config_flow.py b/tests/components/hyperion/test_config_flow.py index 635fd24a795..f9cef677ead 100644 --- a/tests/components/hyperion/test_config_flow.py +++ b/tests/components/hyperion/test_config_flow.py @@ -795,10 +795,8 @@ async def test_options_effect_show_list(hass: HomeAssistant) -> None: await hass.async_block_till_done() assert result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY - # effect1 and effect3 only, so effect2 & external sources are hidden. - assert result["data"][CONF_EFFECT_HIDE_LIST] == sorted( - ["effect2"] + const.KEY_COMPONENTID_EXTERNAL_SOURCES - ) + # effect1 and effect3 only, so effect2 is hidden. + assert result["data"][CONF_EFFECT_HIDE_LIST] == ["effect2"] async def test_options_effect_hide_list_cannot_connect(hass: HomeAssistant) -> None: diff --git a/tests/components/hyperion/test_light.py b/tests/components/hyperion/test_light.py index 33f6acf995f..667c73a20ac 100644 --- a/tests/components/hyperion/test_light.py +++ b/tests/components/hyperion/test_light.py @@ -1,7 +1,6 @@ """Tests for the Hyperion integration.""" from __future__ import annotations -from datetime import timedelta from unittest.mock import AsyncMock, Mock, call, patch from hyperion import const @@ -17,7 +16,6 @@ from homeassistant.components.hyperion.const import ( DOMAIN, HYPERION_MANUFACTURER_NAME, HYPERION_MODEL_NAME, - TYPE_HYPERION_PRIORITY_LIGHT, ) from homeassistant.components.light import ( ATTR_BRIGHTNESS, @@ -27,12 +25,7 @@ from homeassistant.components.light import ( ColorMode, LightEntityFeature, ) -from homeassistant.config_entries import ( - RELOAD_AFTER_UPDATE_DELAY, - SOURCE_REAUTH, - ConfigEntry, - ConfigEntryState, -) +from homeassistant.config_entries import SOURCE_REAUTH, ConfigEntry, ConfigEntryState from homeassistant.const import ( ATTR_ENTITY_ID, CONF_HOST, @@ -44,8 +37,6 @@ from homeassistant.const import ( ) from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr, entity_registry as er -from homeassistant.util import dt as dt_util -import homeassistant.util.color as color_util from . import ( TEST_AUTH_NOT_REQUIRED_RESP, @@ -62,19 +53,13 @@ from . import ( TEST_INSTANCE_3, TEST_PORT, TEST_PRIORITY, - TEST_PRIORITY_LIGHT_ENTITY_ID_1, TEST_SYSINFO_ID, add_test_config_entry, call_registered_callback, create_mock_client, - register_test_entity, setup_test_config_entry, ) -from tests.common import async_fire_time_changed - -COLOR_BLACK = color_util.COLORS["black"] - def _get_config_entry_from_unique_id( hass: HomeAssistant, unique_id: str @@ -247,6 +232,7 @@ async def test_setup_config_entry_dynamic_instances(hass: HomeAssistant) -> None async def test_light_basic_properties(hass: HomeAssistant) -> None: """Test the basic properties.""" client = create_mock_client() + client.priorities = [{const.KEY_PRIORITY: TEST_PRIORITY}] await setup_test_config_entry(hass, hyperion_client=client) entity_state = hass.states.get(TEST_ENTITY_ID_1) @@ -257,8 +243,8 @@ async def test_light_basic_properties(hass: HomeAssistant) -> None: assert entity_state.attributes["icon"] == hyperion_light.ICON_LIGHTBULB assert entity_state.attributes["effect"] == hyperion_light.KEY_EFFECT_SOLID - # By default the effect list is the 3 external sources + 'Solid'. - assert len(entity_state.attributes["effect_list"]) == 4 + # By default the effect list contains only 'Solid'. + assert len(entity_state.attributes["effect_list"]) == 1 assert entity_state.attributes["color_mode"] == ColorMode.HS assert entity_state.attributes["supported_color_modes"] == [ColorMode.HS] @@ -268,6 +254,7 @@ async def test_light_basic_properties(hass: HomeAssistant) -> None: async def test_light_async_turn_on(hass: HomeAssistant) -> None: """Test turning the light on.""" client = create_mock_client() + client.priorities = [{const.KEY_PRIORITY: TEST_PRIORITY}] await setup_test_config_entry(hass, hyperion_client=client) # On (=), 100% (=), solid (=), [255,255,255] (=) @@ -345,10 +332,13 @@ async def test_light_async_turn_on(hass: HomeAssistant) -> None: ) # Simulate a state callback from Hyperion. - client.visible_priority = { - const.KEY_COMPONENTID: const.KEY_COMPONENTID_COLOR, - const.KEY_VALUE: {const.KEY_RGB: (0, 255, 255)}, - } + client.priorities = [ + { + const.KEY_PRIORITY: TEST_PRIORITY, + const.KEY_COMPONENTID: const.KEY_COMPONENTID_COLOR, + const.KEY_VALUE: {const.KEY_RGB: (0, 255, 255)}, + } + ] call_registered_callback(client, "priorities-update") entity_state = hass.states.get(TEST_ENTITY_ID_1) @@ -385,54 +375,6 @@ async def test_light_async_turn_on(hass: HomeAssistant) -> None: assert entity_state assert entity_state.attributes["brightness"] == brightness - # On (=), 100% (=), "USB Capture (!), [0,255,255] (=) - component = "V4L" - effect = const.KEY_COMPONENTID_TO_NAME[component] - client.async_send_clear = AsyncMock(return_value=True) - client.async_send_set_component = AsyncMock(return_value=True) - await hass.services.async_call( - LIGHT_DOMAIN, - SERVICE_TURN_ON, - {ATTR_ENTITY_ID: TEST_ENTITY_ID_1, ATTR_EFFECT: effect}, - blocking=True, - ) - - assert client.async_send_clear.call_args == call( - **{const.KEY_PRIORITY: TEST_PRIORITY} - ) - assert client.async_send_set_component.call_args_list == [ - call( - **{ - const.KEY_COMPONENTSTATE: { - const.KEY_COMPONENT: const.KEY_COMPONENTID_EXTERNAL_SOURCES[0], - const.KEY_STATE: False, - } - } - ), - call( - **{ - const.KEY_COMPONENTSTATE: { - const.KEY_COMPONENT: const.KEY_COMPONENTID_EXTERNAL_SOURCES[1], - const.KEY_STATE: False, - } - } - ), - call( - **{ - const.KEY_COMPONENTSTATE: { - const.KEY_COMPONENT: const.KEY_COMPONENTID_EXTERNAL_SOURCES[2], - const.KEY_STATE: True, - } - } - ), - ] - client.visible_priority = {const.KEY_COMPONENTID: component} - call_registered_callback(client, "priorities-update") - entity_state = hass.states.get(TEST_ENTITY_ID_1) - assert entity_state - assert entity_state.attributes["icon"] == hyperion_light.ICON_EXTERNAL_SOURCE - assert entity_state.attributes["effect"] == effect - # On (=), 100% (=), "Warm Blobs" (!), [0,255,255] (=) effect = "Warm Blobs" client.async_send_clear = AsyncMock(return_value=True) @@ -445,9 +387,6 @@ async def test_light_async_turn_on(hass: HomeAssistant) -> None: blocking=True, ) - assert client.async_send_clear.call_args == call( - **{const.KEY_PRIORITY: TEST_PRIORITY} - ) assert client.async_send_set_effect.call_args == call( **{ const.KEY_PRIORITY: TEST_PRIORITY, @@ -455,10 +394,13 @@ async def test_light_async_turn_on(hass: HomeAssistant) -> None: const.KEY_ORIGIN: DEFAULT_ORIGIN, } ) - client.visible_priority = { - const.KEY_COMPONENTID: const.KEY_COMPONENTID_EFFECT, - const.KEY_OWNER: effect, - } + client.priorities = [ + { + const.KEY_PRIORITY: TEST_PRIORITY, + const.KEY_COMPONENTID: const.KEY_COMPONENTID_EFFECT, + const.KEY_OWNER: effect, + } + ] call_registered_callback(client, "priorities-update") entity_state = hass.states.get(TEST_ENTITY_ID_1) assert entity_state @@ -484,10 +426,13 @@ async def test_light_async_turn_on(hass: HomeAssistant) -> None: } ) # Simulate a state callback from Hyperion. - client.visible_priority = { - const.KEY_COMPONENTID: const.KEY_COMPONENTID_COLOR, - const.KEY_VALUE: {const.KEY_RGB: (0, 0, 255)}, - } + client.priorities = [ + { + const.KEY_PRIORITY: TEST_PRIORITY, + const.KEY_COMPONENTID: const.KEY_COMPONENTID_COLOR, + const.KEY_VALUE: {const.KEY_RGB: (0, 0, 255)}, + } + ] call_registered_callback(client, "priorities-update") entity_state = hass.states.get(TEST_ENTITY_ID_1) assert entity_state @@ -509,82 +454,6 @@ async def test_light_async_turn_on(hass: HomeAssistant) -> None: assert not client.async_send_set_effect.called -async def test_light_async_turn_on_fail_async_send_set_component( - hass: HomeAssistant, -) -> None: - """Test set_component failure when turning the light on.""" - client = create_mock_client() - client.async_send_set_component = AsyncMock(return_value=False) - client.is_on = Mock(return_value=False) - await setup_test_config_entry(hass, hyperion_client=client) - await hass.services.async_call( - LIGHT_DOMAIN, SERVICE_TURN_ON, {ATTR_ENTITY_ID: TEST_ENTITY_ID_1}, blocking=True - ) - assert client.method_calls[-1] == call.async_send_set_component( - componentstate={"component": "ALL", "state": True} - ) - - -async def test_light_async_turn_on_fail_async_send_set_component_source( - hass: HomeAssistant, -) -> None: - """Test async_send_set_component failure when selecting the source.""" - client = create_mock_client() - client.async_send_clear = AsyncMock(return_value=True) - client.async_send_set_component = AsyncMock(return_value=False) - client.is_on = Mock(return_value=True) - await setup_test_config_entry(hass, hyperion_client=client) - await hass.services.async_call( - LIGHT_DOMAIN, - SERVICE_TURN_ON, - { - ATTR_ENTITY_ID: TEST_ENTITY_ID_1, - ATTR_EFFECT: const.KEY_COMPONENTID_TO_NAME["V4L"], - }, - blocking=True, - ) - assert client.method_calls[-1] == call.async_send_set_component( - componentstate={"component": "BOBLIGHTSERVER", "state": False} - ) - - -async def test_light_async_turn_on_fail_async_send_clear_source( - hass: HomeAssistant, -) -> None: - """Test async_send_clear failure when turning the light on.""" - client = create_mock_client() - client.is_on = Mock(return_value=True) - client.async_send_clear = AsyncMock(return_value=False) - await setup_test_config_entry(hass, hyperion_client=client) - await hass.services.async_call( - LIGHT_DOMAIN, - SERVICE_TURN_ON, - { - ATTR_ENTITY_ID: TEST_ENTITY_ID_1, - ATTR_EFFECT: const.KEY_COMPONENTID_TO_NAME["V4L"], - }, - blocking=True, - ) - assert client.method_calls[-1] == call.async_send_clear(priority=180) - - -async def test_light_async_turn_on_fail_async_send_clear_effect( - hass: HomeAssistant, -) -> None: - """Test async_send_clear failure when turning on an effect.""" - client = create_mock_client() - client.is_on = Mock(return_value=True) - client.async_send_clear = AsyncMock(return_value=False) - await setup_test_config_entry(hass, hyperion_client=client) - await hass.services.async_call( - LIGHT_DOMAIN, - SERVICE_TURN_ON, - {ATTR_ENTITY_ID: TEST_ENTITY_ID_1, ATTR_EFFECT: "Warm Mood Blobs"}, - blocking=True, - ) - assert client.method_calls[-1] == call.async_send_clear(priority=180) - - async def test_light_async_turn_on_fail_async_send_set_effect( hass: HomeAssistant, ) -> None: @@ -625,12 +494,12 @@ async def test_light_async_turn_on_fail_async_send_set_color( ) -async def test_light_async_turn_off_fail_async_send_set_component( +async def test_light_async_turn_off_fail_async_send_send_clear( hass: HomeAssistant, ) -> None: - """Test async_send_set_component failure when turning off the light.""" + """Test async_send_clear failure when turning off the light.""" client = create_mock_client() - client.async_send_set_component = AsyncMock(return_value=False) + client.async_send_clear = AsyncMock(return_value=False) await setup_test_config_entry(hass, hyperion_client=client) await hass.services.async_call( @@ -639,30 +508,7 @@ async def test_light_async_turn_off_fail_async_send_set_component( {ATTR_ENTITY_ID: TEST_ENTITY_ID_1}, blocking=True, ) - assert client.method_calls[-1] == call.async_send_set_component( - componentstate={"component": "LEDDEVICE", "state": False} - ) - - -async def test_priority_light_async_turn_off_fail_async_send_clear( - hass: HomeAssistant, -) -> None: - """Test async_send_clear failure when turning off a priority light.""" - client = create_mock_client() - client.async_send_clear = AsyncMock(return_value=False) - with patch( - "homeassistant.components.hyperion.light.HyperionPriorityLight.entity_registry_enabled_default" - ) as enabled_by_default_mock: - enabled_by_default_mock.return_value = True - await setup_test_config_entry(hass, hyperion_client=client) - - await hass.services.async_call( - LIGHT_DOMAIN, - SERVICE_TURN_OFF, - {ATTR_ENTITY_ID: TEST_PRIORITY_LIGHT_ENTITY_ID_1}, - blocking=True, - ) - assert client.method_calls[-1] == call.async_send_clear(priority=180) + assert client.method_calls[-1] == call.async_send_clear(priority=TEST_PRIORITY) async def test_light_async_turn_off(hass: HomeAssistant) -> None: @@ -670,7 +516,7 @@ async def test_light_async_turn_off(hass: HomeAssistant) -> None: client = create_mock_client() await setup_test_config_entry(hass, hyperion_client=client) - client.async_send_set_component = AsyncMock(return_value=True) + client.async_send_clear = AsyncMock(return_value=True) await hass.services.async_call( LIGHT_DOMAIN, SERVICE_TURN_OFF, @@ -678,40 +524,18 @@ async def test_light_async_turn_off(hass: HomeAssistant) -> None: blocking=True, ) - assert client.async_send_set_component.call_args == call( - **{ - const.KEY_COMPONENTSTATE: { - const.KEY_COMPONENT: const.KEY_COMPONENTID_LEDDEVICE, - const.KEY_STATE: False, - } - } + assert client.async_send_clear.called + assert client.async_send_clear.call_args == call( + **{const.KEY_PRIORITY: TEST_PRIORITY} ) - call_registered_callback(client, "components-update") - entity_state = hass.states.get(TEST_ENTITY_ID_1) - assert entity_state - assert entity_state.attributes["icon"] == hyperion_light.ICON_LIGHTBULB - - # No calls if no state loaded. - client.has_loaded_state = False - client.async_send_set_component = AsyncMock(return_value=True) - call_registered_callback(client, "client-update", {"loaded-state": False}) - - await hass.services.async_call( - LIGHT_DOMAIN, - SERVICE_TURN_OFF, - {ATTR_ENTITY_ID: TEST_ENTITY_ID_1}, - blocking=True, - ) - - assert not client.async_send_set_component.called - async def test_light_async_updates_from_hyperion_client( hass: HomeAssistant, ) -> None: """Test receiving a variety of Hyperion client callbacks.""" client = create_mock_client() + client.priorities = [{const.KEY_PRIORITY: TEST_PRIORITY}] await setup_test_config_entry(hass, hyperion_client=client) # Bright change gets accepted. @@ -720,6 +544,7 @@ async def test_light_async_updates_from_hyperion_client( call_registered_callback(client, "adjustment-update") entity_state = hass.states.get(TEST_ENTITY_ID_1) assert entity_state + assert entity_state.state == "on" assert entity_state.attributes["brightness"] == round(255 * (brightness / 100.0)) # Broken brightness value is ignored. @@ -728,40 +553,18 @@ async def test_light_async_updates_from_hyperion_client( call_registered_callback(client, "adjustment-update") entity_state = hass.states.get(TEST_ENTITY_ID_1) assert entity_state - assert entity_state.attributes["brightness"] == round(255 * (brightness / 100.0)) - - # Update components. - client.is_on.return_value = True - call_registered_callback(client, "components-update") - entity_state = hass.states.get(TEST_ENTITY_ID_1) - assert entity_state assert entity_state.state == "on" - - client.is_on.return_value = False - call_registered_callback(client, "components-update") - entity_state = hass.states.get(TEST_ENTITY_ID_1) - assert entity_state - assert entity_state.state == "off" - - # Update priorities (V4L) - client.is_on.return_value = True - client.visible_priority = {const.KEY_COMPONENTID: const.KEY_COMPONENTID_V4L} - call_registered_callback(client, "priorities-update") - entity_state = hass.states.get(TEST_ENTITY_ID_1) - assert entity_state - assert entity_state.attributes["icon"] == hyperion_light.ICON_EXTERNAL_SOURCE - assert entity_state.attributes["hs_color"] == (0.0, 0.0) - assert ( - entity_state.attributes["effect"] - == const.KEY_COMPONENTID_TO_NAME[const.KEY_COMPONENTID_V4L] - ) + assert entity_state.attributes["brightness"] == round(255 * (brightness / 100.0)) # Update priorities (Effect) effect = "foo" - client.visible_priority = { - const.KEY_COMPONENTID: const.KEY_COMPONENTID_EFFECT, - const.KEY_OWNER: effect, - } + client.priorities = [ + { + const.KEY_PRIORITY: TEST_PRIORITY, + const.KEY_COMPONENTID: const.KEY_COMPONENTID_EFFECT, + const.KEY_OWNER: effect, + } + ] call_registered_callback(client, "priorities-update") entity_state = hass.states.get(TEST_ENTITY_ID_1) @@ -772,10 +575,13 @@ async def test_light_async_updates_from_hyperion_client( # Update priorities (Color) rgb = (0, 100, 100) - client.visible_priority = { - const.KEY_COMPONENTID: const.KEY_COMPONENTID_COLOR, - const.KEY_VALUE: {const.KEY_RGB: rgb}, - } + client.priorities = [ + { + const.KEY_PRIORITY: TEST_PRIORITY, + const.KEY_COMPONENTID: const.KEY_COMPONENTID_COLOR, + const.KEY_VALUE: {const.KEY_RGB: rgb}, + } + ] call_registered_callback(client, "priorities-update") entity_state = hass.states.get(TEST_ENTITY_ID_1) @@ -785,7 +591,7 @@ async def test_light_async_updates_from_hyperion_client( assert entity_state.attributes["hs_color"] == (180.0, 100.0) # Update priorities (None) - client.visible_priority = None + client.priorities = [] call_registered_callback(client, "priorities-update") entity_state = hass.states.get(TEST_ENTITY_ID_1) @@ -800,12 +606,7 @@ async def test_light_async_updates_from_hyperion_client( assert entity_state assert entity_state.attributes["effect_list"] == [ hyperion_light.KEY_EFFECT_SOLID - ] + [ - const.KEY_COMPONENTID_TO_NAME[component] - for component in const.KEY_COMPONENTID_EXTERNAL_SOURCES - ] + [ - effect[const.KEY_NAME] for effect in effects - ] + ] + [effect[const.KEY_NAME] for effect in effects] # Update connection status (e.g. disconnection). @@ -818,10 +619,13 @@ async def test_light_async_updates_from_hyperion_client( # Update connection status (e.g. re-connection) client.has_loaded_state = True - client.visible_priority = { - const.KEY_COMPONENTID: const.KEY_COMPONENTID_COLOR, - const.KEY_VALUE: {const.KEY_RGB: rgb}, - } + client.priorities = [ + { + const.KEY_PRIORITY: TEST_PRIORITY, + const.KEY_COMPONENTID: const.KEY_COMPONENTID_COLOR, + const.KEY_VALUE: {const.KEY_RGB: rgb}, + } + ] call_registered_callback(client, "client-update", {"loaded-state": True}) entity_state = hass.states.get(TEST_ENTITY_ID_1) assert entity_state @@ -835,10 +639,13 @@ async def test_full_state_loaded_on_start(hass: HomeAssistant) -> None: # Update full state (should call all update methods). brightness = 25 client.adjustment = [{const.KEY_BRIGHTNESS: brightness}] - client.visible_priority = { - const.KEY_COMPONENTID: const.KEY_COMPONENTID_COLOR, - const.KEY_VALUE: {const.KEY_RGB: (0, 100, 100)}, - } + client.priorities = [ + { + const.KEY_PRIORITY: TEST_PRIORITY, + const.KEY_COMPONENTID: const.KEY_COMPONENTID_COLOR, + const.KEY_VALUE: {const.KEY_RGB: (0, 100, 100)}, + } + ] client.effects = [{const.KEY_NAME: "One"}, {const.KEY_NAME: "Two"}] await setup_test_config_entry(hass, hyperion_client=client) @@ -940,358 +747,6 @@ async def test_setup_entry_bad_token_reauth(hass: HomeAssistant) -> None: assert config_entry.state is ConfigEntryState.SETUP_ERROR -async def test_priority_light_async_updates( - hass: HomeAssistant, -) -> None: - """Test receiving a variety of Hyperion client callbacks to a HyperionPriorityLight.""" - priority_template = { - const.KEY_ACTIVE: True, - const.KEY_VISIBLE: True, - const.KEY_PRIORITY: TEST_PRIORITY, - const.KEY_COMPONENTID: const.KEY_COMPONENTID_COLOR, - const.KEY_VALUE: {const.KEY_RGB: (100, 100, 100)}, - } - - client = create_mock_client() - client.priorities = [{**priority_template}] - - register_test_entity( - hass, - LIGHT_DOMAIN, - TYPE_HYPERION_PRIORITY_LIGHT, - TEST_PRIORITY_LIGHT_ENTITY_ID_1, - ) - await setup_test_config_entry(hass, hyperion_client=client) - - # == Scenario: Color at HA priority will show light as on. - entity_state = hass.states.get(TEST_PRIORITY_LIGHT_ENTITY_ID_1) - assert entity_state - assert entity_state.state == "on" - assert entity_state.attributes["hs_color"] == (0.0, 0.0) - - # == Scenario: Color going to black shows the light as off. - client.priorities = [ - { - **priority_template, - const.KEY_VALUE: {const.KEY_RGB: COLOR_BLACK}, - } - ] - client.visible_priority = client.priorities[0] - - call_registered_callback(client, "priorities-update") - entity_state = hass.states.get(TEST_PRIORITY_LIGHT_ENTITY_ID_1) - assert entity_state - assert entity_state.state == "off" - - # == Scenario: Lower priority than HA priority should have no impact on what HA - # shows when the HA priority is present. - client.priorities = [ - {**priority_template, const.KEY_PRIORITY: TEST_PRIORITY - 1}, - { - **priority_template, - const.KEY_VALUE: {const.KEY_RGB: COLOR_BLACK}, - }, - ] - client.visible_priority = client.priorities[0] - - call_registered_callback(client, "priorities-update") - entity_state = hass.states.get(TEST_PRIORITY_LIGHT_ENTITY_ID_1) - assert entity_state - assert entity_state.state == "off" - - # == Scenario: Fresh color at HA priority should turn HA entity on (even though - # there's a lower priority enabled/visible in Hyperion). - client.priorities = [ - {**priority_template, const.KEY_PRIORITY: TEST_PRIORITY - 1}, - { - **priority_template, - const.KEY_PRIORITY: TEST_PRIORITY, - const.KEY_VALUE: {const.KEY_RGB: (100, 100, 150)}, - }, - ] - client.visible_priority = client.priorities[0] - - call_registered_callback(client, "priorities-update") - entity_state = hass.states.get(TEST_PRIORITY_LIGHT_ENTITY_ID_1) - assert entity_state - assert entity_state.state == "on" - assert entity_state.attributes["hs_color"] == (240.0, 33.333) - - # == Scenario: V4L at a higher priority, with no other HA priority at all, should - # have no effect. - - # Emulate HA turning the light off with black at the HA priority. - client.priorities = [] - client.visible_priority = None - - call_registered_callback(client, "priorities-update") - entity_state = hass.states.get(TEST_PRIORITY_LIGHT_ENTITY_ID_1) - assert entity_state - assert entity_state.state == "off" - - # Emulate V4L turning on. - client.priorities = [ - { - **priority_template, - const.KEY_PRIORITY: 240, - const.KEY_COMPONENTID: const.KEY_COMPONENTID_V4L, - const.KEY_VALUE: {const.KEY_RGB: (100, 100, 150)}, - }, - ] - client.visible_priority = client.priorities[0] - - call_registered_callback(client, "priorities-update") - entity_state = hass.states.get(TEST_PRIORITY_LIGHT_ENTITY_ID_1) - assert entity_state - assert entity_state.state == "off" - - # == Scenario: A lower priority input (lower priority than HA) should have no effect. - - client.priorities = [ - { - **priority_template, - const.KEY_VISIBLE: True, - const.KEY_PRIORITY: TEST_PRIORITY - 1, - const.KEY_COMPONENTID: const.KEY_COMPONENTID_COLOR, - const.KEY_VALUE: {const.KEY_RGB: (255, 0, 0)}, - }, - { - **priority_template, - const.KEY_PRIORITY: 240, - const.KEY_COMPONENTID: const.KEY_COMPONENTID_V4L, - const.KEY_VALUE: {const.KEY_RGB: (100, 100, 150)}, - const.KEY_VISIBLE: False, - }, - ] - - client.visible_priority = client.priorities[0] - call_registered_callback(client, "priorities-update") - entity_state = hass.states.get(TEST_PRIORITY_LIGHT_ENTITY_ID_1) - assert entity_state - assert entity_state.state == "off" - - # == Scenario: A non-active priority is ignored. - client.priorities = [ - { - const.KEY_ACTIVE: False, - const.KEY_VISIBLE: False, - const.KEY_PRIORITY: TEST_PRIORITY, - const.KEY_COMPONENTID: const.KEY_COMPONENTID_COLOR, - const.KEY_VALUE: {const.KEY_RGB: (100, 100, 100)}, - } - ] - client.visible_priority = None - call_registered_callback(client, "priorities-update") - entity_state = hass.states.get(TEST_PRIORITY_LIGHT_ENTITY_ID_1) - assert entity_state - assert entity_state.state == "off" - - # == Scenario: A priority with no ... priority ... is ignored. - client.priorities = [ - { - const.KEY_ACTIVE: True, - const.KEY_VISIBLE: True, - const.KEY_COMPONENTID: const.KEY_COMPONENTID_COLOR, - const.KEY_VALUE: {const.KEY_RGB: (100, 100, 100)}, - } - ] - client.visible_priority = None - call_registered_callback(client, "priorities-update") - entity_state = hass.states.get(TEST_PRIORITY_LIGHT_ENTITY_ID_1) - assert entity_state - assert entity_state.state == "off" - - -async def test_priority_light_async_updates_off_sets_black( - hass: HomeAssistant, -) -> None: - """Test turning the HyperionPriorityLight off.""" - client = create_mock_client() - client.priorities = [ - { - const.KEY_ACTIVE: True, - const.KEY_VISIBLE: True, - const.KEY_PRIORITY: TEST_PRIORITY, - const.KEY_COMPONENTID: const.KEY_COMPONENTID_COLOR, - const.KEY_VALUE: {const.KEY_RGB: (100, 100, 100)}, - } - ] - - register_test_entity( - hass, - LIGHT_DOMAIN, - TYPE_HYPERION_PRIORITY_LIGHT, - TEST_PRIORITY_LIGHT_ENTITY_ID_1, - ) - await setup_test_config_entry(hass, hyperion_client=client) - - client.async_send_clear = AsyncMock(return_value=True) - client.async_send_set_color = AsyncMock(return_value=True) - - await hass.services.async_call( - LIGHT_DOMAIN, - SERVICE_TURN_OFF, - {ATTR_ENTITY_ID: TEST_PRIORITY_LIGHT_ENTITY_ID_1}, - blocking=True, - ) - - assert client.async_send_clear.call_args == call( - **{ - const.KEY_PRIORITY: TEST_PRIORITY, - } - ) - - assert client.async_send_set_color.call_args == call( - **{ - const.KEY_PRIORITY: TEST_PRIORITY, - const.KEY_COLOR: COLOR_BLACK, - const.KEY_ORIGIN: DEFAULT_ORIGIN, - } - ) - - -async def test_priority_light_prior_color_preserved_after_black( - hass: HomeAssistant, -) -> None: - """Test that color is preserved in an on->off->on cycle for a HyperionPriorityLight. - - For a HyperionPriorityLight the color black is used to indicate off. This test - ensures that a cycle through 'off' will preserve the original color. - """ - priority_template = { - const.KEY_ACTIVE: True, - const.KEY_VISIBLE: True, - const.KEY_PRIORITY: TEST_PRIORITY, - const.KEY_COMPONENTID: const.KEY_COMPONENTID_COLOR, - } - - client = create_mock_client() - client.async_send_set_color = AsyncMock(return_value=True) - client.async_send_clear = AsyncMock(return_value=True) - client.priorities = [] - client.visible_priority = None - - register_test_entity( - hass, - LIGHT_DOMAIN, - TYPE_HYPERION_PRIORITY_LIGHT, - TEST_PRIORITY_LIGHT_ENTITY_ID_1, - ) - await setup_test_config_entry(hass, hyperion_client=client) - - # Turn the light on full green... - # On (=), 100% (=), solid (=), [0,0,255] (=) - hs_color = (240.0, 100.0) - rgb_color = (0, 0, 255) - - await hass.services.async_call( - LIGHT_DOMAIN, - SERVICE_TURN_ON, - {ATTR_ENTITY_ID: TEST_PRIORITY_LIGHT_ENTITY_ID_1, ATTR_HS_COLOR: hs_color}, - blocking=True, - ) - - assert client.async_send_set_color.call_args == call( - **{ - const.KEY_PRIORITY: TEST_PRIORITY, - const.KEY_COLOR: rgb_color, - const.KEY_ORIGIN: DEFAULT_ORIGIN, - } - ) - - client.priorities = [ - { - **priority_template, - const.KEY_VALUE: {const.KEY_RGB: rgb_color}, - } - ] - client.visible_priority = client.priorities[0] - call_registered_callback(client, "priorities-update") - - entity_state = hass.states.get(TEST_PRIORITY_LIGHT_ENTITY_ID_1) - assert entity_state - assert entity_state.state == "on" - assert entity_state.attributes["hs_color"] == hs_color - - # Then turn it off. - await hass.services.async_call( - LIGHT_DOMAIN, - SERVICE_TURN_OFF, - {ATTR_ENTITY_ID: TEST_PRIORITY_LIGHT_ENTITY_ID_1}, - blocking=True, - ) - - assert client.async_send_set_color.call_args == call( - **{ - const.KEY_PRIORITY: TEST_PRIORITY, - const.KEY_COLOR: COLOR_BLACK, - const.KEY_ORIGIN: DEFAULT_ORIGIN, - } - ) - - client.priorities = [ - { - **priority_template, - const.KEY_VALUE: {const.KEY_RGB: COLOR_BLACK}, - } - ] - client.visible_priority = client.priorities[0] - call_registered_callback(client, "priorities-update") - - entity_state = hass.states.get(TEST_PRIORITY_LIGHT_ENTITY_ID_1) - assert entity_state - assert entity_state.state == "off" - - # Then turn it back on and ensure it's still green. - # On (=), 100% (=), solid (=), [0,0,255] (=) - await hass.services.async_call( - LIGHT_DOMAIN, - SERVICE_TURN_ON, - {ATTR_ENTITY_ID: TEST_PRIORITY_LIGHT_ENTITY_ID_1}, - blocking=True, - ) - - assert client.async_send_set_color.call_args == call( - **{ - const.KEY_PRIORITY: TEST_PRIORITY, - const.KEY_COLOR: rgb_color, - const.KEY_ORIGIN: DEFAULT_ORIGIN, - } - ) - - client.priorities = [ - { - **priority_template, - const.KEY_VALUE: {const.KEY_RGB: rgb_color}, - } - ] - client.visible_priority = client.priorities[0] - call_registered_callback(client, "priorities-update") - - entity_state = hass.states.get(TEST_PRIORITY_LIGHT_ENTITY_ID_1) - assert entity_state - assert entity_state.state == "on" - assert entity_state.attributes["hs_color"] == hs_color - - -async def test_priority_light_has_no_external_sources(hass: HomeAssistant) -> None: - """Ensure a HyperionPriorityLight does not list external sources.""" - client = create_mock_client() - client.priorities = [] - - register_test_entity( - hass, - LIGHT_DOMAIN, - TYPE_HYPERION_PRIORITY_LIGHT, - TEST_PRIORITY_LIGHT_ENTITY_ID_1, - ) - await setup_test_config_entry(hass, hyperion_client=client) - - entity_state = hass.states.get(TEST_PRIORITY_LIGHT_ENTITY_ID_1) - assert entity_state - assert entity_state.attributes["effect_list"] == [hyperion_light.KEY_EFFECT_SOLID] - - async def test_light_option_effect_hide_list(hass: HomeAssistant) -> None: """Test the effect_hide_list option.""" client = create_mock_client() @@ -1300,15 +755,13 @@ async def test_light_option_effect_hide_list(hass: HomeAssistant) -> None: await setup_test_config_entry( hass, hyperion_client=client, - options={CONF_EFFECT_HIDE_LIST: ["Two", "USB Capture"]}, + options={CONF_EFFECT_HIDE_LIST: ["Two", "Three"]}, ) entity_state = hass.states.get(TEST_ENTITY_ID_1) assert entity_state assert entity_state.attributes["effect_list"] == [ "Solid", - "Boblight Server", - "Platform Capture", "One", ] @@ -1317,12 +770,6 @@ async def test_device_info(hass: HomeAssistant) -> None: """Verify device information includes expected details.""" client = create_mock_client() - register_test_entity( - hass, - LIGHT_DOMAIN, - TYPE_HYPERION_PRIORITY_LIGHT, - TEST_PRIORITY_LIGHT_ENTITY_ID_1, - ) await setup_test_config_entry(hass, hyperion_client=client) device_id = get_hyperion_device_id(TEST_SYSINFO_ID, TEST_INSTANCE) @@ -1341,82 +788,4 @@ async def test_device_info(hass: HomeAssistant) -> None: entry.entity_id for entry in er.async_entries_for_device(entity_registry, device.id) ] - assert TEST_PRIORITY_LIGHT_ENTITY_ID_1 in entities_from_device assert TEST_ENTITY_ID_1 in entities_from_device - - -async def test_lights_can_be_enabled(hass: HomeAssistant) -> None: - """Verify lights can be enabled.""" - client = create_mock_client() - await setup_test_config_entry(hass, hyperion_client=client) - - entity_registry = er.async_get(hass) - entry = entity_registry.async_get(TEST_PRIORITY_LIGHT_ENTITY_ID_1) - assert entry - assert entry.disabled - assert entry.disabled_by is er.RegistryEntryDisabler.INTEGRATION - entity_state = hass.states.get(TEST_PRIORITY_LIGHT_ENTITY_ID_1) - assert not entity_state - - with patch( - "homeassistant.components.hyperion.client.HyperionClient", - return_value=client, - ): - updated_entry = entity_registry.async_update_entity( - TEST_PRIORITY_LIGHT_ENTITY_ID_1, disabled_by=None - ) - assert not updated_entry.disabled - await hass.async_block_till_done() - - async_fire_time_changed( - hass, - dt_util.utcnow() + timedelta(seconds=RELOAD_AFTER_UPDATE_DELAY + 1), - ) - await hass.async_block_till_done() - - entity_state = hass.states.get(TEST_PRIORITY_LIGHT_ENTITY_ID_1) - assert entity_state - - -async def test_deprecated_effect_names( - caplog: pytest.LogCaptureFixture, hass: HomeAssistant -) -> None: - """Test deprecated effects function and issue a warning.""" - client = create_mock_client() - client.async_send_clear = AsyncMock(return_value=True) - client.async_send_set_component = AsyncMock(return_value=True) - - await setup_test_config_entry(hass, hyperion_client=client) - - for component in const.KEY_COMPONENTID_EXTERNAL_SOURCES: - await hass.services.async_call( - LIGHT_DOMAIN, - SERVICE_TURN_ON, - {ATTR_ENTITY_ID: TEST_ENTITY_ID_1, ATTR_EFFECT: component}, - blocking=True, - ) - assert f"Use of Hyperion effect '{component}' is deprecated" in caplog.text - - # Simulate a state callback from Hyperion. - client.visible_priority = { - const.KEY_COMPONENTID: component, - } - call_registered_callback(client, "priorities-update") - - entity_state = hass.states.get(TEST_ENTITY_ID_1) - assert entity_state - assert ( - entity_state.attributes["effect"] - == const.KEY_COMPONENTID_TO_NAME[component] - ) - - -async def test_deprecated_effect_names_not_in_effect_list( - hass: HomeAssistant, -) -> None: - """Test deprecated effects are not in shown effect list.""" - await setup_test_config_entry(hass) - entity_state = hass.states.get(TEST_ENTITY_ID_1) - assert entity_state - for component in const.KEY_COMPONENTID_EXTERNAL_SOURCES: - assert component not in entity_state.attributes["effect_list"]