mirror of
https://github.com/home-assistant/core.git
synced 2025-07-21 12:17:07 +00:00
Add an option to hide selected Hyperion effects (#45689)
This commit is contained in:
parent
286217f771
commit
781084880b
@ -26,6 +26,7 @@ from homeassistant.const import (
|
|||||||
CONF_TOKEN,
|
CONF_TOKEN,
|
||||||
)
|
)
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.typing import ConfigType
|
from homeassistant.helpers.typing import ConfigType
|
||||||
|
|
||||||
from . import create_hyperion_client
|
from . import create_hyperion_client
|
||||||
@ -34,6 +35,8 @@ from . import create_hyperion_client
|
|||||||
from .const import (
|
from .const import (
|
||||||
CONF_AUTH_ID,
|
CONF_AUTH_ID,
|
||||||
CONF_CREATE_TOKEN,
|
CONF_CREATE_TOKEN,
|
||||||
|
CONF_EFFECT_HIDE_LIST,
|
||||||
|
CONF_EFFECT_SHOW_LIST,
|
||||||
CONF_PRIORITY,
|
CONF_PRIORITY,
|
||||||
DEFAULT_ORIGIN,
|
DEFAULT_ORIGIN,
|
||||||
DEFAULT_PRIORITY,
|
DEFAULT_PRIORITY,
|
||||||
@ -439,13 +442,44 @@ class HyperionOptionsFlow(OptionsFlow):
|
|||||||
"""Initialize a Hyperion options flow."""
|
"""Initialize a Hyperion options flow."""
|
||||||
self._config_entry = config_entry
|
self._config_entry = config_entry
|
||||||
|
|
||||||
|
def _create_client(self) -> client.HyperionClient:
|
||||||
|
"""Create and connect a client instance."""
|
||||||
|
return create_hyperion_client(
|
||||||
|
self._config_entry.data[CONF_HOST],
|
||||||
|
self._config_entry.data[CONF_PORT],
|
||||||
|
token=self._config_entry.data.get(CONF_TOKEN),
|
||||||
|
)
|
||||||
|
|
||||||
async def async_step_init(
|
async def async_step_init(
|
||||||
self, user_input: dict[str, Any] | None = None
|
self, user_input: dict[str, Any] | None = None
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
"""Manage the options."""
|
"""Manage the options."""
|
||||||
|
|
||||||
|
effects = {source: source for source in const.KEY_COMPONENTID_EXTERNAL_SOURCES}
|
||||||
|
async with self._create_client() as hyperion_client:
|
||||||
|
if not hyperion_client:
|
||||||
|
return self.async_abort(reason="cannot_connect")
|
||||||
|
for effect in hyperion_client.effects or []:
|
||||||
|
if const.KEY_NAME in effect:
|
||||||
|
effects[effect[const.KEY_NAME]] = effect[const.KEY_NAME]
|
||||||
|
|
||||||
|
# If a new effect is added to Hyperion, we always want it to show by default. So
|
||||||
|
# rather than store a 'show list' in the config entry, we store a 'hide list'.
|
||||||
|
# However, it's more intuitive to ask the user to select which effects to show,
|
||||||
|
# so we inverse the meaning prior to storage.
|
||||||
|
|
||||||
if user_input is not None:
|
if user_input is not None:
|
||||||
|
effect_show_list = user_input.pop(CONF_EFFECT_SHOW_LIST)
|
||||||
|
user_input[CONF_EFFECT_HIDE_LIST] = sorted(
|
||||||
|
set(effects) - set(effect_show_list)
|
||||||
|
)
|
||||||
return self.async_create_entry(title="", data=user_input)
|
return self.async_create_entry(title="", data=user_input)
|
||||||
|
|
||||||
|
default_effect_show_list = list(
|
||||||
|
set(effects)
|
||||||
|
- set(self._config_entry.options.get(CONF_EFFECT_HIDE_LIST, []))
|
||||||
|
)
|
||||||
|
|
||||||
return self.async_show_form(
|
return self.async_show_form(
|
||||||
step_id="init",
|
step_id="init",
|
||||||
data_schema=vol.Schema(
|
data_schema=vol.Schema(
|
||||||
@ -456,6 +490,10 @@ class HyperionOptionsFlow(OptionsFlow):
|
|||||||
CONF_PRIORITY, DEFAULT_PRIORITY
|
CONF_PRIORITY, DEFAULT_PRIORITY
|
||||||
),
|
),
|
||||||
): vol.All(vol.Coerce(int), vol.Range(min=0, max=255)),
|
): vol.All(vol.Coerce(int), vol.Range(min=0, max=255)),
|
||||||
|
vol.Optional(
|
||||||
|
CONF_EFFECT_SHOW_LIST,
|
||||||
|
default=default_effect_show_list,
|
||||||
|
): cv.multi_select(effects),
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -31,6 +31,8 @@ CONF_INSTANCE_CLIENTS = "INSTANCE_CLIENTS"
|
|||||||
CONF_ON_UNLOAD = "ON_UNLOAD"
|
CONF_ON_UNLOAD = "ON_UNLOAD"
|
||||||
CONF_PRIORITY = "priority"
|
CONF_PRIORITY = "priority"
|
||||||
CONF_ROOT_CLIENT = "ROOT_CLIENT"
|
CONF_ROOT_CLIENT = "ROOT_CLIENT"
|
||||||
|
CONF_EFFECT_HIDE_LIST = "effect_hide_list"
|
||||||
|
CONF_EFFECT_SHOW_LIST = "effect_show_list"
|
||||||
|
|
||||||
DEFAULT_NAME = "Hyperion"
|
DEFAULT_NAME = "Hyperion"
|
||||||
DEFAULT_ORIGIN = "Home Assistant"
|
DEFAULT_ORIGIN = "Home Assistant"
|
||||||
|
@ -28,6 +28,7 @@ import homeassistant.util.color as color_util
|
|||||||
|
|
||||||
from . import get_hyperion_unique_id, listen_for_instance_updates
|
from . import get_hyperion_unique_id, listen_for_instance_updates
|
||||||
from .const import (
|
from .const import (
|
||||||
|
CONF_EFFECT_HIDE_LIST,
|
||||||
CONF_INSTANCE_CLIENTS,
|
CONF_INSTANCE_CLIENTS,
|
||||||
CONF_PRIORITY,
|
CONF_PRIORITY,
|
||||||
DEFAULT_ORIGIN,
|
DEFAULT_ORIGIN,
|
||||||
@ -217,7 +218,10 @@ class HyperionBaseLight(LightEntity):
|
|||||||
|
|
||||||
def _get_option(self, key: str) -> Any:
|
def _get_option(self, key: str) -> Any:
|
||||||
"""Get a value from the provided options."""
|
"""Get a value from the provided options."""
|
||||||
defaults = {CONF_PRIORITY: DEFAULT_PRIORITY}
|
defaults = {
|
||||||
|
CONF_PRIORITY: DEFAULT_PRIORITY,
|
||||||
|
CONF_EFFECT_HIDE_LIST: [],
|
||||||
|
}
|
||||||
return self._options.get(key, defaults[key])
|
return self._options.get(key, defaults[key])
|
||||||
|
|
||||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||||
@ -366,11 +370,17 @@ class HyperionBaseLight(LightEntity):
|
|||||||
if not self._client.effects:
|
if not self._client.effects:
|
||||||
return
|
return
|
||||||
effect_list: list[str] = []
|
effect_list: list[str] = []
|
||||||
|
hide_effects = self._get_option(CONF_EFFECT_HIDE_LIST)
|
||||||
|
|
||||||
for effect in self._client.effects or []:
|
for effect in self._client.effects or []:
|
||||||
if const.KEY_NAME in effect:
|
if const.KEY_NAME in effect:
|
||||||
effect_list.append(effect[const.KEY_NAME])
|
effect_name = effect[const.KEY_NAME]
|
||||||
if effect_list:
|
if effect_name not in hide_effects:
|
||||||
self._effect_list = self._static_effect_list + effect_list
|
effect_list.append(effect_name)
|
||||||
|
|
||||||
|
self._effect_list = [
|
||||||
|
effect for effect in self._static_effect_list if effect not in hide_effects
|
||||||
|
] + effect_list
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
|
@ -45,7 +45,8 @@
|
|||||||
"step": {
|
"step": {
|
||||||
"init": {
|
"init": {
|
||||||
"data": {
|
"data": {
|
||||||
"priority": "Hyperion priority to use for colors and effects"
|
"priority": "Hyperion priority to use for colors and effects",
|
||||||
|
"effect_show_list": "Hyperion effects to show"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,7 +118,9 @@ def create_mock_client() -> Mock:
|
|||||||
|
|
||||||
|
|
||||||
def add_test_config_entry(
|
def add_test_config_entry(
|
||||||
hass: HomeAssistantType, data: dict[str, Any] | None = None
|
hass: HomeAssistantType,
|
||||||
|
data: dict[str, Any] | None = None,
|
||||||
|
options: dict[str, Any] | None = None,
|
||||||
) -> ConfigEntry:
|
) -> ConfigEntry:
|
||||||
"""Add a test config entry."""
|
"""Add a test config entry."""
|
||||||
config_entry: MockConfigEntry = MockConfigEntry( # type: ignore[no-untyped-call]
|
config_entry: MockConfigEntry = MockConfigEntry( # type: ignore[no-untyped-call]
|
||||||
@ -131,7 +133,7 @@ def add_test_config_entry(
|
|||||||
},
|
},
|
||||||
title=f"Hyperion {TEST_SYSINFO_ID}",
|
title=f"Hyperion {TEST_SYSINFO_ID}",
|
||||||
unique_id=TEST_SYSINFO_ID,
|
unique_id=TEST_SYSINFO_ID,
|
||||||
options=TEST_CONFIG_ENTRY_OPTIONS,
|
options=options or TEST_CONFIG_ENTRY_OPTIONS,
|
||||||
)
|
)
|
||||||
config_entry.add_to_hass(hass) # type: ignore[no-untyped-call]
|
config_entry.add_to_hass(hass) # type: ignore[no-untyped-call]
|
||||||
return config_entry
|
return config_entry
|
||||||
@ -141,9 +143,10 @@ async def setup_test_config_entry(
|
|||||||
hass: HomeAssistantType,
|
hass: HomeAssistantType,
|
||||||
config_entry: ConfigEntry | None = None,
|
config_entry: ConfigEntry | None = None,
|
||||||
hyperion_client: Mock | None = None,
|
hyperion_client: Mock | None = None,
|
||||||
|
options: dict[str, Any] | None = None,
|
||||||
) -> ConfigEntry:
|
) -> ConfigEntry:
|
||||||
"""Add a test Hyperion entity to hass."""
|
"""Add a test Hyperion entity to hass."""
|
||||||
config_entry = config_entry or add_test_config_entry(hass)
|
config_entry = config_entry or add_test_config_entry(hass, options=options)
|
||||||
|
|
||||||
hyperion_client = hyperion_client or create_mock_client()
|
hyperion_client = hyperion_client or create_mock_client()
|
||||||
# pylint: disable=attribute-defined-outside-init
|
# pylint: disable=attribute-defined-outside-init
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
"""Tests for the Hyperion config flow."""
|
"""Tests for the Hyperion config flow."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import asyncio
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from unittest.mock import AsyncMock, patch
|
from unittest.mock import AsyncMock, Mock, patch
|
||||||
|
|
||||||
from hyperion import const
|
from hyperion import const
|
||||||
|
|
||||||
@ -10,6 +11,8 @@ from homeassistant import data_entry_flow
|
|||||||
from homeassistant.components.hyperion.const import (
|
from homeassistant.components.hyperion.const import (
|
||||||
CONF_AUTH_ID,
|
CONF_AUTH_ID,
|
||||||
CONF_CREATE_TOKEN,
|
CONF_CREATE_TOKEN,
|
||||||
|
CONF_EFFECT_HIDE_LIST,
|
||||||
|
CONF_EFFECT_SHOW_LIST,
|
||||||
CONF_PRIORITY,
|
CONF_PRIORITY,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
)
|
)
|
||||||
@ -309,23 +312,42 @@ async def test_auth_static_token_success(hass: HomeAssistantType) -> None:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async def test_auth_static_token_login_fail(hass: HomeAssistantType) -> None:
|
async def test_auth_static_token_login_connect_fail(hass: HomeAssistantType) -> None:
|
||||||
"""Test correct behavior with a bad static token."""
|
"""Test correct behavior with a static token that cannot connect."""
|
||||||
result = await _init_flow(hass)
|
result = await _init_flow(hass)
|
||||||
assert result["step_id"] == "user"
|
assert result["step_id"] == "user"
|
||||||
|
|
||||||
client = create_mock_client()
|
client = create_mock_client()
|
||||||
client.async_is_auth_required = AsyncMock(return_value=TEST_AUTH_REQUIRED_RESP)
|
client.async_is_auth_required = AsyncMock(return_value=TEST_AUTH_REQUIRED_RESP)
|
||||||
|
|
||||||
# Fail the login call.
|
with patch(
|
||||||
client.async_login = AsyncMock(
|
"homeassistant.components.hyperion.client.HyperionClient", return_value=client
|
||||||
return_value={"command": "authorize-login", "success": False, "tan": 0}
|
):
|
||||||
|
result = await _configure_flow(hass, result, user_input=TEST_HOST_PORT)
|
||||||
|
client.async_client_connect = AsyncMock(return_value=False)
|
||||||
|
result = await _configure_flow(
|
||||||
|
hass, result, user_input={CONF_CREATE_TOKEN: False, CONF_TOKEN: TEST_TOKEN}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
|
||||||
|
assert result["reason"] == "cannot_connect"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_auth_static_token_login_fail(hass: HomeAssistantType) -> None:
|
||||||
|
"""Test correct behavior with a static token that cannot login."""
|
||||||
|
result = await _init_flow(hass)
|
||||||
|
assert result["step_id"] == "user"
|
||||||
|
|
||||||
|
client = create_mock_client()
|
||||||
|
client.async_is_auth_required = AsyncMock(return_value=TEST_AUTH_REQUIRED_RESP)
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.hyperion.client.HyperionClient", return_value=client
|
"homeassistant.components.hyperion.client.HyperionClient", return_value=client
|
||||||
):
|
):
|
||||||
result = await _configure_flow(hass, result, user_input=TEST_HOST_PORT)
|
result = await _configure_flow(hass, result, user_input=TEST_HOST_PORT)
|
||||||
|
client.async_login = AsyncMock(
|
||||||
|
return_value={"command": "authorize-login", "success": False, "tan": 0}
|
||||||
|
)
|
||||||
result = await _configure_flow(
|
result = await _configure_flow(
|
||||||
hass, result, user_input={CONF_CREATE_TOKEN: False, CONF_TOKEN: TEST_TOKEN}
|
hass, result, user_input={CONF_CREATE_TOKEN: False, CONF_TOKEN: TEST_TOKEN}
|
||||||
)
|
)
|
||||||
@ -377,6 +399,66 @@ async def test_auth_create_token_approval_declined(hass: HomeAssistantType) -> N
|
|||||||
assert result["reason"] == "auth_new_token_not_granted_error"
|
assert result["reason"] == "auth_new_token_not_granted_error"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_auth_create_token_approval_declined_task_canceled(
|
||||||
|
hass: HomeAssistantType,
|
||||||
|
) -> None:
|
||||||
|
"""Verify correct behaviour when a token request is declined."""
|
||||||
|
result = await _init_flow(hass)
|
||||||
|
|
||||||
|
client = create_mock_client()
|
||||||
|
client.async_is_auth_required = AsyncMock(return_value=TEST_AUTH_REQUIRED_RESP)
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.hyperion.client.HyperionClient", return_value=client
|
||||||
|
):
|
||||||
|
result = await _configure_flow(hass, result, user_input=TEST_HOST_PORT)
|
||||||
|
assert result["step_id"] == "auth"
|
||||||
|
|
||||||
|
client.async_request_token = AsyncMock(return_value=TEST_REQUEST_TOKEN_FAIL)
|
||||||
|
|
||||||
|
class CanceledAwaitableMock(AsyncMock):
|
||||||
|
"""A canceled awaitable mock."""
|
||||||
|
|
||||||
|
def __await__(self):
|
||||||
|
raise asyncio.CancelledError
|
||||||
|
|
||||||
|
mock_task = CanceledAwaitableMock()
|
||||||
|
task_coro = None
|
||||||
|
|
||||||
|
def create_task(arg):
|
||||||
|
nonlocal task_coro
|
||||||
|
task_coro = arg
|
||||||
|
return mock_task
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.hyperion.client.HyperionClient", return_value=client
|
||||||
|
), patch(
|
||||||
|
"homeassistant.components.hyperion.config_flow.client.generate_random_auth_id",
|
||||||
|
return_value=TEST_AUTH_ID,
|
||||||
|
), patch.object(
|
||||||
|
hass, "async_create_task", side_effect=create_task
|
||||||
|
):
|
||||||
|
result = await _configure_flow(
|
||||||
|
hass, result, user_input={CONF_CREATE_TOKEN: True}
|
||||||
|
)
|
||||||
|
assert result["step_id"] == "create_token"
|
||||||
|
|
||||||
|
result = await _configure_flow(hass, result)
|
||||||
|
assert result["step_id"] == "create_token_external"
|
||||||
|
|
||||||
|
# Leave the task running, to ensure it is canceled.
|
||||||
|
mock_task.done = Mock(return_value=False)
|
||||||
|
mock_task.cancel = Mock()
|
||||||
|
|
||||||
|
result = await _configure_flow(hass, result)
|
||||||
|
|
||||||
|
# This await will advance to the next step.
|
||||||
|
await task_coro
|
||||||
|
|
||||||
|
# Assert that cancel is called on the task.
|
||||||
|
assert mock_task.cancel.called
|
||||||
|
|
||||||
|
|
||||||
async def test_auth_create_token_when_issued_token_fails(
|
async def test_auth_create_token_when_issued_token_fails(
|
||||||
hass: HomeAssistantType,
|
hass: HomeAssistantType,
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -468,6 +550,47 @@ async def test_auth_create_token_success(hass: HomeAssistantType) -> None:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def test_auth_create_token_success_but_login_fail(
|
||||||
|
hass: HomeAssistantType,
|
||||||
|
) -> None:
|
||||||
|
"""Verify correct behaviour when a token is successfully created but the login fails."""
|
||||||
|
result = await _init_flow(hass)
|
||||||
|
|
||||||
|
client = create_mock_client()
|
||||||
|
client.async_is_auth_required = AsyncMock(return_value=TEST_AUTH_REQUIRED_RESP)
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.hyperion.client.HyperionClient", return_value=client
|
||||||
|
):
|
||||||
|
result = await _configure_flow(hass, result, user_input=TEST_HOST_PORT)
|
||||||
|
assert result["step_id"] == "auth"
|
||||||
|
|
||||||
|
client.async_request_token = AsyncMock(return_value=TEST_REQUEST_TOKEN_SUCCESS)
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.hyperion.client.HyperionClient", return_value=client
|
||||||
|
), patch(
|
||||||
|
"homeassistant.components.hyperion.config_flow.client.generate_random_auth_id",
|
||||||
|
return_value=TEST_AUTH_ID,
|
||||||
|
):
|
||||||
|
result = await _configure_flow(
|
||||||
|
hass, result, user_input={CONF_CREATE_TOKEN: True}
|
||||||
|
)
|
||||||
|
assert result["step_id"] == "create_token"
|
||||||
|
|
||||||
|
result = await _configure_flow(hass, result)
|
||||||
|
assert result["step_id"] == "create_token_external"
|
||||||
|
|
||||||
|
client.async_login = AsyncMock(
|
||||||
|
return_value={"command": "authorize-login", "success": False, "tan": 0}
|
||||||
|
)
|
||||||
|
|
||||||
|
# The flow will be automatically advanced by the auth token response.
|
||||||
|
result = await _configure_flow(hass, result)
|
||||||
|
|
||||||
|
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
|
||||||
|
assert result["reason"] == "auth_new_token_not_work_error"
|
||||||
|
|
||||||
|
|
||||||
async def test_ssdp_success(hass: HomeAssistantType) -> None:
|
async def test_ssdp_success(hass: HomeAssistantType) -> None:
|
||||||
"""Check an SSDP flow."""
|
"""Check an SSDP flow."""
|
||||||
|
|
||||||
@ -599,8 +722,8 @@ async def test_ssdp_abort_duplicates(hass: HomeAssistantType) -> None:
|
|||||||
assert result_2["reason"] == "already_in_progress"
|
assert result_2["reason"] == "already_in_progress"
|
||||||
|
|
||||||
|
|
||||||
async def test_options(hass: HomeAssistantType) -> None:
|
async def test_options_priority(hass: HomeAssistantType) -> None:
|
||||||
"""Check an options flow."""
|
"""Check an options flow priority option."""
|
||||||
|
|
||||||
config_entry = add_test_config_entry(hass)
|
config_entry = add_test_config_entry(hass)
|
||||||
|
|
||||||
@ -618,11 +741,12 @@ async def test_options(hass: HomeAssistantType) -> None:
|
|||||||
|
|
||||||
new_priority = 1
|
new_priority = 1
|
||||||
result = await hass.config_entries.options.async_configure(
|
result = await hass.config_entries.options.async_configure(
|
||||||
result["flow_id"], user_input={CONF_PRIORITY: new_priority}
|
result["flow_id"],
|
||||||
|
user_input={CONF_PRIORITY: new_priority},
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||||
assert result["data"] == {CONF_PRIORITY: new_priority}
|
assert result["data"][CONF_PRIORITY] == new_priority
|
||||||
|
|
||||||
# Turn the light on and ensure the new priority is used.
|
# Turn the light on and ensure the new priority is used.
|
||||||
client.async_send_set_color = AsyncMock(return_value=True)
|
client.async_send_set_color = AsyncMock(return_value=True)
|
||||||
@ -636,6 +760,59 @@ async def test_options(hass: HomeAssistantType) -> None:
|
|||||||
assert client.async_send_set_color.call_args[1][CONF_PRIORITY] == new_priority
|
assert client.async_send_set_color.call_args[1][CONF_PRIORITY] == new_priority
|
||||||
|
|
||||||
|
|
||||||
|
async def test_options_effect_show_list(hass: HomeAssistantType) -> None:
|
||||||
|
"""Check an options flow effect show list."""
|
||||||
|
|
||||||
|
config_entry = add_test_config_entry(hass)
|
||||||
|
|
||||||
|
client = create_mock_client()
|
||||||
|
client.effects = [
|
||||||
|
{const.KEY_NAME: "effect1"},
|
||||||
|
{const.KEY_NAME: "effect2"},
|
||||||
|
{const.KEY_NAME: "effect3"},
|
||||||
|
]
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.hyperion.client.HyperionClient", return_value=client
|
||||||
|
):
|
||||||
|
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
result = await hass.config_entries.options.async_init(config_entry.entry_id)
|
||||||
|
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||||
|
|
||||||
|
result = await hass.config_entries.options.async_configure(
|
||||||
|
result["flow_id"],
|
||||||
|
user_input={CONF_EFFECT_SHOW_LIST: ["effect1", "effect3"]},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert result["type"] == data_entry_flow.RESULT_TYPE_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
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_options_effect_hide_list_cannot_connect(hass: HomeAssistantType) -> None:
|
||||||
|
"""Check an options flow effect hide list with a failed connection."""
|
||||||
|
|
||||||
|
config_entry = add_test_config_entry(hass)
|
||||||
|
client = create_mock_client()
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.hyperion.client.HyperionClient", return_value=client
|
||||||
|
):
|
||||||
|
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
client.async_client_connect = AsyncMock(return_value=False)
|
||||||
|
|
||||||
|
result = await hass.config_entries.options.async_init(config_entry.entry_id)
|
||||||
|
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
|
||||||
|
assert result["reason"] == "cannot_connect"
|
||||||
|
|
||||||
|
|
||||||
async def test_reauth_success(hass: HomeAssistantType) -> None:
|
async def test_reauth_success(hass: HomeAssistantType) -> None:
|
||||||
"""Check a reauth flow that succeeds."""
|
"""Check a reauth flow that succeeds."""
|
||||||
|
|
||||||
|
@ -6,7 +6,11 @@ from unittest.mock import AsyncMock, Mock, call, patch
|
|||||||
from hyperion import const
|
from hyperion import const
|
||||||
|
|
||||||
from homeassistant.components.hyperion import light as hyperion_light
|
from homeassistant.components.hyperion import light as hyperion_light
|
||||||
from homeassistant.components.hyperion.const import DEFAULT_ORIGIN, DOMAIN
|
from homeassistant.components.hyperion.const import (
|
||||||
|
CONF_EFFECT_HIDE_LIST,
|
||||||
|
DEFAULT_ORIGIN,
|
||||||
|
DOMAIN,
|
||||||
|
)
|
||||||
from homeassistant.components.light import (
|
from homeassistant.components.light import (
|
||||||
ATTR_BRIGHTNESS,
|
ATTR_BRIGHTNESS,
|
||||||
ATTR_EFFECT,
|
ATTR_EFFECT,
|
||||||
@ -1129,3 +1133,21 @@ async def test_priority_light_has_no_external_sources(hass: HomeAssistantType) -
|
|||||||
entity_state = hass.states.get(TEST_PRIORITY_LIGHT_ENTITY_ID_1)
|
entity_state = hass.states.get(TEST_PRIORITY_LIGHT_ENTITY_ID_1)
|
||||||
assert entity_state
|
assert entity_state
|
||||||
assert entity_state.attributes["effect_list"] == [hyperion_light.KEY_EFFECT_SOLID]
|
assert entity_state.attributes["effect_list"] == [hyperion_light.KEY_EFFECT_SOLID]
|
||||||
|
|
||||||
|
|
||||||
|
async def test_light_option_effect_hide_list(hass: HomeAssistantType) -> None:
|
||||||
|
"""Test the effect_hide_list option."""
|
||||||
|
client = create_mock_client()
|
||||||
|
client.effects = [{const.KEY_NAME: "One"}, {const.KEY_NAME: "Two"}]
|
||||||
|
|
||||||
|
await setup_test_config_entry(
|
||||||
|
hass, hyperion_client=client, options={CONF_EFFECT_HIDE_LIST: ["Two", "V4L"]}
|
||||||
|
)
|
||||||
|
|
||||||
|
entity_state = hass.states.get(TEST_ENTITY_ID_1)
|
||||||
|
assert entity_state.attributes["effect_list"] == [
|
||||||
|
"Solid",
|
||||||
|
"BOBLIGHTSERVER",
|
||||||
|
"GRABBER",
|
||||||
|
"One",
|
||||||
|
]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user