Remove YAML import from homeworks (#120171)

This commit is contained in:
G Johansson 2024-06-22 20:05:34 +02:00 committed by GitHub
parent 9b341f5b67
commit f06bd1b66f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 6 additions and 304 deletions

View file

@ -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

View file

@ -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]:

View file

@ -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:

View file

@ -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,