Remove Xiaomi Miio YAML import (#78995)
* Deprecate YAML import * Add logging for unexpected errors * remove unused import * fix tests * unused import * fix tests * fix snake_case * Do not add to standard key string
This commit is contained in:
parent
3aa24afad8
commit
a2080492de
5 changed files with 70 additions and 58 deletions
|
@ -383,10 +383,6 @@ async def async_setup_gateway_entry(hass: HomeAssistant, entry: ConfigEntry) ->
|
||||||
|
|
||||||
assert gateway_id
|
assert gateway_id
|
||||||
|
|
||||||
# For backwards compat
|
|
||||||
if gateway_id.endswith("-gateway"):
|
|
||||||
hass.config_entries.async_update_entry(entry, unique_id=entry.data["mac"])
|
|
||||||
|
|
||||||
# Connect to gateway
|
# Connect to gateway
|
||||||
gateway = ConnectXiaomiGateway(hass, entry)
|
gateway = ConnectXiaomiGateway(hass, entry)
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -13,7 +13,7 @@ import voluptuous as vol
|
||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
from homeassistant.components import zeroconf
|
from homeassistant.components import zeroconf
|
||||||
from homeassistant.config_entries import SOURCE_REAUTH, ConfigEntry
|
from homeassistant.config_entries import SOURCE_REAUTH, ConfigEntry
|
||||||
from homeassistant.const import CONF_HOST, CONF_MODEL, CONF_NAME, CONF_TOKEN
|
from homeassistant.const import CONF_HOST, CONF_MODEL, CONF_TOKEN
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
from homeassistant.data_entry_flow import FlowResult
|
from homeassistant.data_entry_flow import FlowResult
|
||||||
from homeassistant.helpers.device_registry import format_mac
|
from homeassistant.helpers.device_registry import format_mac
|
||||||
|
@ -145,18 +145,6 @@ class XiaomiMiioFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
return await self.async_step_cloud()
|
return await self.async_step_cloud()
|
||||||
return self.async_show_form(step_id="reauth_confirm")
|
return self.async_show_form(step_id="reauth_confirm")
|
||||||
|
|
||||||
async def async_step_import(self, conf: dict[str, Any]) -> FlowResult:
|
|
||||||
"""Import a configuration from config.yaml."""
|
|
||||||
self.host = conf[CONF_HOST]
|
|
||||||
self.token = conf[CONF_TOKEN]
|
|
||||||
self.name = conf.get(CONF_NAME)
|
|
||||||
self.model = conf.get(CONF_MODEL)
|
|
||||||
|
|
||||||
self.context.update(
|
|
||||||
{"title_placeholders": {"name": f"YAML import {self.host}"}}
|
|
||||||
)
|
|
||||||
return await self.async_step_connect()
|
|
||||||
|
|
||||||
async def async_step_user(
|
async def async_step_user(
|
||||||
self, user_input: dict[str, Any] | None = None
|
self, user_input: dict[str, Any] | None = None
|
||||||
) -> FlowResult:
|
) -> FlowResult:
|
||||||
|
@ -250,15 +238,22 @@ class XiaomiMiioFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
errors["base"] = "cloud_login_error"
|
errors["base"] = "cloud_login_error"
|
||||||
except MiCloudAccessDenied:
|
except MiCloudAccessDenied:
|
||||||
errors["base"] = "cloud_login_error"
|
errors["base"] = "cloud_login_error"
|
||||||
|
except Exception: # pylint: disable=broad-except
|
||||||
|
_LOGGER.exception("Unexpected exception in Miio cloud login")
|
||||||
|
return self.async_abort(reason="unknown")
|
||||||
|
|
||||||
if errors:
|
if errors:
|
||||||
return self.async_show_form(
|
return self.async_show_form(
|
||||||
step_id="cloud", data_schema=DEVICE_CLOUD_CONFIG, errors=errors
|
step_id="cloud", data_schema=DEVICE_CLOUD_CONFIG, errors=errors
|
||||||
)
|
)
|
||||||
|
|
||||||
devices_raw = await self.hass.async_add_executor_job(
|
try:
|
||||||
miio_cloud.get_devices, cloud_country
|
devices_raw = await self.hass.async_add_executor_job(
|
||||||
)
|
miio_cloud.get_devices, cloud_country
|
||||||
|
)
|
||||||
|
except Exception: # pylint: disable=broad-except
|
||||||
|
_LOGGER.exception("Unexpected exception in Miio cloud get devices")
|
||||||
|
return self.async_abort(reason="unknown")
|
||||||
|
|
||||||
if not devices_raw:
|
if not devices_raw:
|
||||||
errors["base"] = "cloud_no_devices"
|
errors["base"] = "cloud_no_devices"
|
||||||
|
@ -353,6 +348,9 @@ class XiaomiMiioFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
except SetupException:
|
except SetupException:
|
||||||
if self.model is None:
|
if self.model is None:
|
||||||
errors["base"] = "cannot_connect"
|
errors["base"] = "cannot_connect"
|
||||||
|
except Exception: # pylint: disable=broad-except
|
||||||
|
_LOGGER.exception("Unexpected exception in connect Xiaomi device")
|
||||||
|
return self.async_abort(reason="unknown")
|
||||||
|
|
||||||
device_info = connect_device_class.device_info
|
device_info = connect_device_class.device_info
|
||||||
|
|
||||||
|
@ -386,8 +384,8 @@ class XiaomiMiioFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
data[CONF_CLOUD_USERNAME] = self.cloud_username
|
data[CONF_CLOUD_USERNAME] = self.cloud_username
|
||||||
data[CONF_CLOUD_PASSWORD] = self.cloud_password
|
data[CONF_CLOUD_PASSWORD] = self.cloud_password
|
||||||
data[CONF_CLOUD_COUNTRY] = self.cloud_country
|
data[CONF_CLOUD_COUNTRY] = self.cloud_country
|
||||||
self.hass.config_entries.async_update_entry(existing_entry, data=data)
|
if self.hass.config_entries.async_update_entry(existing_entry, data=data):
|
||||||
await self.hass.config_entries.async_reload(existing_entry.entry_id)
|
await self.hass.config_entries.async_reload(existing_entry.entry_id)
|
||||||
return self.async_abort(reason="reauth_successful")
|
return self.async_abort(reason="reauth_successful")
|
||||||
|
|
||||||
if self.name is None:
|
if self.name is None:
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
|
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
|
||||||
"already_in_progress": "[%key:common::config_flow::abort::already_in_progress%]",
|
"already_in_progress": "[%key:common::config_flow::abort::already_in_progress%]",
|
||||||
"incomplete_info": "Incomplete information to setup device, no host or token supplied.",
|
"incomplete_info": "Incomplete information to setup device, no host or token supplied.",
|
||||||
"not_xiaomi_miio": "Device is not (yet) supported by Xiaomi Miio."
|
"not_xiaomi_miio": "Device is not (yet) supported by Xiaomi Miio.",
|
||||||
|
"unknown": "[%key:common::config_flow::error::unknown%]"
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
|
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
"already_in_progress": "Configuration flow is already in progress",
|
"already_in_progress": "Configuration flow is already in progress",
|
||||||
"incomplete_info": "Incomplete information to setup device, no host or token supplied.",
|
"incomplete_info": "Incomplete information to setup device, no host or token supplied.",
|
||||||
"not_xiaomi_miio": "Device is not (yet) supported by Xiaomi Miio.",
|
"not_xiaomi_miio": "Device is not (yet) supported by Xiaomi Miio.",
|
||||||
"reauth_successful": "Re-authentication was successful"
|
"reauth_successful": "Re-authentication was successful",
|
||||||
|
"unknown": "Unexpected error"
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"cannot_connect": "Failed to connect",
|
"cannot_connect": "Failed to connect",
|
||||||
|
|
|
@ -9,7 +9,7 @@ import pytest
|
||||||
from homeassistant import config_entries, data_entry_flow
|
from homeassistant import config_entries, data_entry_flow
|
||||||
from homeassistant.components import zeroconf
|
from homeassistant.components import zeroconf
|
||||||
from homeassistant.components.xiaomi_miio import const
|
from homeassistant.components.xiaomi_miio import const
|
||||||
from homeassistant.const import CONF_HOST, CONF_MODEL, CONF_NAME, CONF_TOKEN
|
from homeassistant.const import CONF_HOST, CONF_MODEL, CONF_TOKEN
|
||||||
|
|
||||||
from . import TEST_MAC
|
from . import TEST_MAC
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ TEST_CLOUD_DEVICES_2 = [
|
||||||
|
|
||||||
@pytest.fixture(name="xiaomi_miio_connect", autouse=True)
|
@pytest.fixture(name="xiaomi_miio_connect", autouse=True)
|
||||||
def xiaomi_miio_connect_fixture():
|
def xiaomi_miio_connect_fixture():
|
||||||
"""Mock denonavr connection and entry setup."""
|
"""Mock miio connection and entry setup."""
|
||||||
mock_info = get_mock_info()
|
mock_info = get_mock_info()
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
|
@ -320,6 +320,22 @@ async def test_config_flow_gateway_cloud_login_error(hass):
|
||||||
assert result["step_id"] == "cloud"
|
assert result["step_id"] == "cloud"
|
||||||
assert result["errors"] == {"base": "cloud_login_error"}
|
assert result["errors"] == {"base": "cloud_login_error"}
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.xiaomi_miio.config_flow.MiCloud.login",
|
||||||
|
side_effect=Exception({}),
|
||||||
|
):
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"],
|
||||||
|
{
|
||||||
|
const.CONF_CLOUD_USERNAME: TEST_CLOUD_USER,
|
||||||
|
const.CONF_CLOUD_PASSWORD: TEST_CLOUD_PASS,
|
||||||
|
const.CONF_CLOUD_COUNTRY: TEST_CLOUD_COUNTRY,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] == "abort"
|
||||||
|
assert result["reason"] == "unknown"
|
||||||
|
|
||||||
|
|
||||||
async def test_config_flow_gateway_cloud_no_devices(hass):
|
async def test_config_flow_gateway_cloud_no_devices(hass):
|
||||||
"""Test a failed config flow using cloud with no devices."""
|
"""Test a failed config flow using cloud with no devices."""
|
||||||
|
@ -348,6 +364,22 @@ async def test_config_flow_gateway_cloud_no_devices(hass):
|
||||||
assert result["step_id"] == "cloud"
|
assert result["step_id"] == "cloud"
|
||||||
assert result["errors"] == {"base": "cloud_no_devices"}
|
assert result["errors"] == {"base": "cloud_no_devices"}
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.xiaomi_miio.config_flow.MiCloud.get_devices",
|
||||||
|
side_effect=Exception({}),
|
||||||
|
):
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"],
|
||||||
|
{
|
||||||
|
const.CONF_CLOUD_USERNAME: TEST_CLOUD_USER,
|
||||||
|
const.CONF_CLOUD_PASSWORD: TEST_CLOUD_PASS,
|
||||||
|
const.CONF_CLOUD_COUNTRY: TEST_CLOUD_COUNTRY,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] == "abort"
|
||||||
|
assert result["reason"] == "unknown"
|
||||||
|
|
||||||
|
|
||||||
async def test_config_flow_gateway_cloud_missing_token(hass):
|
async def test_config_flow_gateway_cloud_missing_token(hass):
|
||||||
"""Test a failed config flow using cloud with a missing token."""
|
"""Test a failed config flow using cloud with a missing token."""
|
||||||
|
@ -558,34 +590,6 @@ async def test_config_flow_step_unknown_device(hass):
|
||||||
assert result["errors"] == {"base": "unknown_device"}
|
assert result["errors"] == {"base": "unknown_device"}
|
||||||
|
|
||||||
|
|
||||||
async def test_import_flow_success(hass):
|
|
||||||
"""Test a successful import form yaml for a device."""
|
|
||||||
mock_info = get_mock_info(model=const.MODELS_SWITCH[0])
|
|
||||||
|
|
||||||
with patch(
|
|
||||||
"homeassistant.components.xiaomi_miio.device.Device.info",
|
|
||||||
return_value=mock_info,
|
|
||||||
):
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
|
||||||
const.DOMAIN,
|
|
||||||
context={"source": config_entries.SOURCE_IMPORT},
|
|
||||||
data={CONF_NAME: TEST_NAME, CONF_HOST: TEST_HOST, CONF_TOKEN: TEST_TOKEN},
|
|
||||||
)
|
|
||||||
|
|
||||||
assert result["type"] == "create_entry"
|
|
||||||
assert result["title"] == TEST_NAME
|
|
||||||
assert result["data"] == {
|
|
||||||
const.CONF_FLOW_TYPE: const.CONF_DEVICE,
|
|
||||||
const.CONF_CLOUD_USERNAME: None,
|
|
||||||
const.CONF_CLOUD_PASSWORD: None,
|
|
||||||
const.CONF_CLOUD_COUNTRY: None,
|
|
||||||
CONF_HOST: TEST_HOST,
|
|
||||||
CONF_TOKEN: TEST_TOKEN,
|
|
||||||
CONF_MODEL: const.MODELS_SWITCH[0],
|
|
||||||
const.CONF_MAC: TEST_MAC,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async def test_config_flow_step_device_manual_model_error(hass):
|
async def test_config_flow_step_device_manual_model_error(hass):
|
||||||
"""Test config flow, device connection error, model None."""
|
"""Test config flow, device connection error, model None."""
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
@ -618,6 +622,18 @@ async def test_config_flow_step_device_manual_model_error(hass):
|
||||||
assert result["step_id"] == "connect"
|
assert result["step_id"] == "connect"
|
||||||
assert result["errors"] == {"base": "cannot_connect"}
|
assert result["errors"] == {"base": "cannot_connect"}
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.xiaomi_miio.device.Device.info",
|
||||||
|
side_effect=Exception({}),
|
||||||
|
):
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"],
|
||||||
|
{CONF_MODEL: TEST_MODEL},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] == "abort"
|
||||||
|
assert result["reason"] == "unknown"
|
||||||
|
|
||||||
|
|
||||||
async def test_config_flow_step_device_manual_model_succes(hass):
|
async def test_config_flow_step_device_manual_model_succes(hass):
|
||||||
"""Test config flow, device connection error, manual model."""
|
"""Test config flow, device connection error, manual model."""
|
||||||
|
@ -724,7 +740,7 @@ async def config_flow_device_success(hass, model_to_test):
|
||||||
|
|
||||||
async def config_flow_generic_roborock(hass):
|
async def config_flow_generic_roborock(hass):
|
||||||
"""Test a successful config flow for a generic roborock vacuum."""
|
"""Test a successful config flow for a generic roborock vacuum."""
|
||||||
DUMMY_MODEL = "roborock.vacuum.dummy"
|
dummy_model = "roborock.vacuum.dummy"
|
||||||
|
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
const.DOMAIN, context={"source": config_entries.SOURCE_USER}
|
const.DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||||
|
@ -743,7 +759,7 @@ async def config_flow_generic_roborock(hass):
|
||||||
assert result["step_id"] == "manual"
|
assert result["step_id"] == "manual"
|
||||||
assert result["errors"] == {}
|
assert result["errors"] == {}
|
||||||
|
|
||||||
mock_info = get_mock_info(model=DUMMY_MODEL)
|
mock_info = get_mock_info(model=dummy_model)
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.xiaomi_miio.device.Device.info",
|
"homeassistant.components.xiaomi_miio.device.Device.info",
|
||||||
|
@ -755,7 +771,7 @@ async def config_flow_generic_roborock(hass):
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result["type"] == "create_entry"
|
assert result["type"] == "create_entry"
|
||||||
assert result["title"] == DUMMY_MODEL
|
assert result["title"] == dummy_model
|
||||||
assert result["data"] == {
|
assert result["data"] == {
|
||||||
const.CONF_FLOW_TYPE: const.CONF_DEVICE,
|
const.CONF_FLOW_TYPE: const.CONF_DEVICE,
|
||||||
const.CONF_CLOUD_USERNAME: None,
|
const.CONF_CLOUD_USERNAME: None,
|
||||||
|
@ -763,7 +779,7 @@ async def config_flow_generic_roborock(hass):
|
||||||
const.CONF_CLOUD_COUNTRY: None,
|
const.CONF_CLOUD_COUNTRY: None,
|
||||||
CONF_HOST: TEST_HOST,
|
CONF_HOST: TEST_HOST,
|
||||||
CONF_TOKEN: TEST_TOKEN,
|
CONF_TOKEN: TEST_TOKEN,
|
||||||
CONF_MODEL: DUMMY_MODEL,
|
CONF_MODEL: dummy_model,
|
||||||
const.CONF_MAC: TEST_MAC,
|
const.CONF_MAC: TEST_MAC,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue