Remove YAML import from homeworks (#120171)
This commit is contained in:
parent
9b341f5b67
commit
f06bd1b66f
4 changed files with 6 additions and 304 deletions
|
@ -11,7 +11,7 @@ from typing import Any
|
|||
from pyhomeworks.pyhomeworks import HW_BUTTON_PRESSED, HW_BUTTON_RELEASED, Homeworks
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
CONF_HOST,
|
||||
CONF_ID,
|
||||
|
@ -29,14 +29,7 @@ from homeassistant.helpers.entity import Entity
|
|||
from homeassistant.helpers.typing import ConfigType
|
||||
from homeassistant.util import slugify
|
||||
|
||||
from .const import (
|
||||
CONF_ADDR,
|
||||
CONF_CONTROLLER_ID,
|
||||
CONF_DIMMERS,
|
||||
CONF_KEYPADS,
|
||||
CONF_RATE,
|
||||
DOMAIN,
|
||||
)
|
||||
from .const import CONF_ADDR, CONF_CONTROLLER_ID, CONF_KEYPADS, DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -51,35 +44,7 @@ DEFAULT_FADE_RATE = 1.0
|
|||
|
||||
KEYPAD_LEDSTATE_POLL_COOLDOWN = 1.0
|
||||
|
||||
CV_FADE_RATE = vol.All(vol.Coerce(float), vol.Range(min=0, max=20))
|
||||
|
||||
DIMMER_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_ADDR): cv.string,
|
||||
vol.Required(CONF_NAME): cv.string,
|
||||
vol.Optional(CONF_RATE, default=DEFAULT_FADE_RATE): CV_FADE_RATE,
|
||||
}
|
||||
)
|
||||
|
||||
KEYPAD_SCHEMA = vol.Schema(
|
||||
{vol.Required(CONF_ADDR): cv.string, vol.Required(CONF_NAME): cv.string}
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema(
|
||||
{
|
||||
DOMAIN: vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_HOST): cv.string,
|
||||
vol.Required(CONF_PORT): cv.port,
|
||||
vol.Required(CONF_DIMMERS): vol.All(cv.ensure_list, [DIMMER_SCHEMA]),
|
||||
vol.Optional(CONF_KEYPADS, default=[]): vol.All(
|
||||
cv.ensure_list, [KEYPAD_SCHEMA]
|
||||
),
|
||||
}
|
||||
)
|
||||
},
|
||||
extra=vol.ALLOW_EXTRA,
|
||||
)
|
||||
CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)
|
||||
|
||||
SERVICE_SEND_COMMAND_SCHEMA = vol.Schema(
|
||||
{
|
||||
|
@ -157,14 +122,6 @@ async def async_send_command(hass: HomeAssistant, data: Mapping[str, Any]) -> No
|
|||
|
||||
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||
"""Start Homeworks controller."""
|
||||
|
||||
if DOMAIN in config:
|
||||
hass.async_create_task(
|
||||
hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": SOURCE_IMPORT}, data=config[DOMAIN]
|
||||
)
|
||||
)
|
||||
|
||||
async_setup_services(hass)
|
||||
|
||||
return True
|
||||
|
|
|
@ -14,17 +14,11 @@ from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN
|
|||
from homeassistant.components.light import DOMAIN as LIGHT_DOMAIN
|
||||
from homeassistant.config_entries import ConfigEntry, ConfigFlow, ConfigFlowResult
|
||||
from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PORT
|
||||
from homeassistant.core import (
|
||||
DOMAIN as HOMEASSISTANT_DOMAIN,
|
||||
HomeAssistant,
|
||||
async_get_hass,
|
||||
callback,
|
||||
)
|
||||
from homeassistant.core import async_get_hass, callback
|
||||
from homeassistant.data_entry_flow import AbortFlow
|
||||
from homeassistant.helpers import (
|
||||
config_validation as cv,
|
||||
entity_registry as er,
|
||||
issue_registry as ir,
|
||||
selector,
|
||||
)
|
||||
from homeassistant.helpers.schema_config_entry_flow import (
|
||||
|
@ -148,24 +142,6 @@ async def _try_connection(user_input: dict[str, Any]) -> None:
|
|||
raise SchemaFlowError("unknown_error") from err
|
||||
|
||||
|
||||
def _create_import_issue(hass: HomeAssistant) -> None:
|
||||
"""Create a repair issue asking the user to remove YAML."""
|
||||
ir.async_create_issue(
|
||||
hass,
|
||||
HOMEASSISTANT_DOMAIN,
|
||||
f"deprecated_yaml_{DOMAIN}",
|
||||
breaks_in_ha_version="2024.6.0",
|
||||
is_fixable=False,
|
||||
issue_domain=DOMAIN,
|
||||
severity=ir.IssueSeverity.WARNING,
|
||||
translation_key="deprecated_yaml",
|
||||
translation_placeholders={
|
||||
"domain": DOMAIN,
|
||||
"integration_title": "Lutron Homeworks",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def _validate_address(handler: SchemaCommonFlowHandler, addr: str) -> None:
|
||||
"""Validate address."""
|
||||
try:
|
||||
|
@ -547,100 +523,6 @@ OPTIONS_FLOW = {
|
|||
class HomeworksConfigFlowHandler(ConfigFlow, domain=DOMAIN):
|
||||
"""Config flow for Lutron Homeworks."""
|
||||
|
||||
import_config: dict[str, Any]
|
||||
|
||||
async def async_step_import(self, config: dict[str, Any]) -> ConfigFlowResult:
|
||||
"""Start importing configuration from yaml."""
|
||||
self.import_config = {
|
||||
CONF_HOST: config[CONF_HOST],
|
||||
CONF_PORT: config[CONF_PORT],
|
||||
CONF_DIMMERS: [
|
||||
{
|
||||
CONF_ADDR: light[CONF_ADDR],
|
||||
CONF_NAME: light[CONF_NAME],
|
||||
CONF_RATE: light[CONF_RATE],
|
||||
}
|
||||
for light in config[CONF_DIMMERS]
|
||||
],
|
||||
CONF_KEYPADS: [
|
||||
{
|
||||
CONF_ADDR: keypad[CONF_ADDR],
|
||||
CONF_BUTTONS: [],
|
||||
CONF_NAME: keypad[CONF_NAME],
|
||||
}
|
||||
for keypad in config[CONF_KEYPADS]
|
||||
],
|
||||
}
|
||||
return await self.async_step_import_controller_name()
|
||||
|
||||
async def async_step_import_controller_name(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> ConfigFlowResult:
|
||||
"""Ask user to set a name of the controller."""
|
||||
errors = {}
|
||||
try:
|
||||
self._async_abort_entries_match(
|
||||
{
|
||||
CONF_HOST: self.import_config[CONF_HOST],
|
||||
CONF_PORT: self.import_config[CONF_PORT],
|
||||
}
|
||||
)
|
||||
except AbortFlow:
|
||||
_create_import_issue(self.hass)
|
||||
raise
|
||||
|
||||
if user_input:
|
||||
try:
|
||||
user_input[CONF_CONTROLLER_ID] = slugify(user_input[CONF_NAME])
|
||||
self._async_abort_entries_match(
|
||||
{CONF_CONTROLLER_ID: user_input[CONF_CONTROLLER_ID]}
|
||||
)
|
||||
except AbortFlow:
|
||||
errors["base"] = "duplicated_controller_id"
|
||||
else:
|
||||
self.import_config |= user_input
|
||||
return await self.async_step_import_finish()
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="import_controller_name",
|
||||
data_schema=vol.Schema(
|
||||
{
|
||||
vol.Required(
|
||||
CONF_NAME, description={"suggested_value": "Lutron Homeworks"}
|
||||
): selector.TextSelector(),
|
||||
}
|
||||
),
|
||||
errors=errors,
|
||||
)
|
||||
|
||||
async def async_step_import_finish(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> ConfigFlowResult:
|
||||
"""Ask user to remove YAML configuration."""
|
||||
|
||||
if user_input is not None:
|
||||
entity_registry = er.async_get(self.hass)
|
||||
config = self.import_config
|
||||
for light in config[CONF_DIMMERS]:
|
||||
addr = light[CONF_ADDR]
|
||||
if entity_id := entity_registry.async_get_entity_id(
|
||||
LIGHT_DOMAIN, DOMAIN, f"homeworks.{addr}"
|
||||
):
|
||||
entity_registry.async_update_entity(
|
||||
entity_id,
|
||||
new_unique_id=calculate_unique_id(
|
||||
config[CONF_CONTROLLER_ID], addr, 0
|
||||
),
|
||||
)
|
||||
name = config.pop(CONF_NAME)
|
||||
return self.async_create_entry(
|
||||
title=name,
|
||||
data={},
|
||||
options=config,
|
||||
)
|
||||
|
||||
return self.async_show_form(step_id="import_finish", data_schema=vol.Schema({}))
|
||||
|
||||
async def _validate_edit_controller(
|
||||
self, user_input: dict[str, Any]
|
||||
) -> dict[str, Any]:
|
||||
|
|
|
@ -9,21 +9,17 @@ from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAI
|
|||
from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN
|
||||
from homeassistant.components.homeworks.const import (
|
||||
CONF_ADDR,
|
||||
CONF_DIMMERS,
|
||||
CONF_INDEX,
|
||||
CONF_KEYPADS,
|
||||
CONF_LED,
|
||||
CONF_NUMBER,
|
||||
CONF_RATE,
|
||||
CONF_RELEASE_DELAY,
|
||||
DOMAIN,
|
||||
)
|
||||
from homeassistant.components.light import DOMAIN as LIGHT_DOMAIN
|
||||
from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_RECONFIGURE, SOURCE_USER
|
||||
from homeassistant.config_entries import SOURCE_RECONFIGURE, SOURCE_USER
|
||||
from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PORT
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.data_entry_flow import FlowResultType
|
||||
from homeassistant.helpers import entity_registry as er, issue_registry as ir
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
@ -129,114 +125,6 @@ async def test_user_flow_cannot_connect(
|
|||
assert result["step_id"] == "user"
|
||||
|
||||
|
||||
async def test_import_flow(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
issue_registry: ir.IssueRegistry,
|
||||
mock_homeworks: MagicMock,
|
||||
mock_setup_entry,
|
||||
) -> None:
|
||||
"""Test importing yaml config."""
|
||||
entry = entity_registry.async_get_or_create(
|
||||
LIGHT_DOMAIN, DOMAIN, "homeworks.[02:08:01:01]"
|
||||
)
|
||||
|
||||
mock_controller = MagicMock()
|
||||
mock_homeworks.return_value = mock_controller
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": SOURCE_IMPORT},
|
||||
data={
|
||||
CONF_HOST: "192.168.0.1",
|
||||
CONF_PORT: 1234,
|
||||
CONF_DIMMERS: [
|
||||
{
|
||||
CONF_ADDR: "[02:08:01:01]",
|
||||
CONF_NAME: "Foyer Sconces",
|
||||
CONF_RATE: 1.0,
|
||||
}
|
||||
],
|
||||
CONF_KEYPADS: [
|
||||
{
|
||||
CONF_ADDR: "[02:08:02:01]",
|
||||
CONF_NAME: "Foyer Keypad",
|
||||
}
|
||||
],
|
||||
},
|
||||
)
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert result["step_id"] == "import_controller_name"
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], user_input={CONF_NAME: "Main controller"}
|
||||
)
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert result["step_id"] == "import_finish"
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], user_input={}
|
||||
)
|
||||
assert result["type"] is FlowResultType.CREATE_ENTRY
|
||||
assert result["title"] == "Main controller"
|
||||
assert result["data"] == {}
|
||||
assert result["options"] == {
|
||||
"controller_id": "main_controller",
|
||||
"dimmers": [{"addr": "[02:08:01:01]", "name": "Foyer Sconces", "rate": 1.0}],
|
||||
"host": "192.168.0.1",
|
||||
"keypads": [
|
||||
{
|
||||
"addr": "[02:08:02:01]",
|
||||
"buttons": [],
|
||||
"name": "Foyer Keypad",
|
||||
}
|
||||
],
|
||||
"port": 1234,
|
||||
}
|
||||
assert len(issue_registry.issues) == 0
|
||||
|
||||
# Check unique ID is updated in entity registry
|
||||
entry = entity_registry.async_get(entry.id)
|
||||
assert entry.unique_id == "homeworks.main_controller.[02:08:01:01].0"
|
||||
|
||||
|
||||
async def test_import_flow_already_exists(
|
||||
hass: HomeAssistant,
|
||||
issue_registry: ir.IssueRegistry,
|
||||
mock_empty_config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test importing yaml config where entry already exists."""
|
||||
mock_empty_config_entry.add_to_hass(hass)
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": SOURCE_IMPORT},
|
||||
data={"host": "192.168.0.1", "port": 1234, CONF_DIMMERS: [], CONF_KEYPADS: []},
|
||||
)
|
||||
assert result["type"] is FlowResultType.ABORT
|
||||
assert result["reason"] == "already_configured"
|
||||
assert len(issue_registry.issues) == 1
|
||||
|
||||
|
||||
async def test_import_flow_controller_id_exists(
|
||||
hass: HomeAssistant, mock_empty_config_entry: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test importing yaml config where entry already exists."""
|
||||
mock_empty_config_entry.add_to_hass(hass)
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": SOURCE_IMPORT},
|
||||
data={"host": "192.168.0.2", "port": 1234, CONF_DIMMERS: [], CONF_KEYPADS: []},
|
||||
)
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert result["step_id"] == "import_controller_name"
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], user_input={CONF_NAME: "Main controller"}
|
||||
)
|
||||
assert result["type"] is FlowResultType.FORM
|
||||
assert result["step_id"] == "import_controller_name"
|
||||
assert result["errors"] == {"base": "duplicated_controller_id"}
|
||||
|
||||
|
||||
async def test_reconfigure_flow(
|
||||
hass: HomeAssistant, mock_config_entry: MockConfigEntry, mock_homeworks: MagicMock
|
||||
) -> None:
|
||||
|
|
|
@ -6,39 +6,14 @@ from pyhomeworks.pyhomeworks import HW_BUTTON_PRESSED, HW_BUTTON_RELEASED
|
|||
import pytest
|
||||
|
||||
from homeassistant.components.homeworks import EVENT_BUTTON_PRESS, EVENT_BUTTON_RELEASE
|
||||
from homeassistant.components.homeworks.const import CONF_DIMMERS, CONF_KEYPADS, DOMAIN
|
||||
from homeassistant.components.homeworks.const import DOMAIN
|
||||
from homeassistant.config_entries import ConfigEntryState
|
||||
from homeassistant.const import CONF_HOST, CONF_PORT
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ServiceValidationError
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from tests.common import MockConfigEntry, async_capture_events
|
||||
|
||||
|
||||
async def test_import(
|
||||
hass: HomeAssistant,
|
||||
mock_homeworks: MagicMock,
|
||||
) -> None:
|
||||
"""Test the Homeworks YAML import."""
|
||||
await async_setup_component(
|
||||
hass,
|
||||
DOMAIN,
|
||||
{
|
||||
DOMAIN: {
|
||||
CONF_HOST: "192.168.0.1",
|
||||
CONF_PORT: 1234,
|
||||
CONF_DIMMERS: [],
|
||||
CONF_KEYPADS: [],
|
||||
}
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(hass.config_entries.flow.async_progress()) == 1
|
||||
assert hass.config_entries.flow.async_progress()[0]["context"]["source"] == "import"
|
||||
|
||||
|
||||
async def test_load_unload_config_entry(
|
||||
hass: HomeAssistant,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
|
|
Loading…
Add table
Reference in a new issue