Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove Xiaomi Miio YAML import #78995

Merged
merged 8 commits into from
Oct 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions homeassistant/components/xiaomi_miio/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -383,10 +383,6 @@ async def async_setup_gateway_entry(hass: HomeAssistant, entry: ConfigEntry) ->

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
gateway = ConnectXiaomiGateway(hass, entry)
try:
Expand Down
34 changes: 16 additions & 18 deletions homeassistant/components/xiaomi_miio/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from homeassistant import config_entries
from homeassistant.components import zeroconf
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.data_entry_flow import FlowResult
from homeassistant.helpers.device_registry import format_mac
Expand Down Expand Up @@ -145,18 +145,6 @@ async def async_step_reauth_confirm(
return await self.async_step_cloud()
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(
self, user_input: dict[str, Any] | None = None
) -> FlowResult:
Expand Down Expand Up @@ -250,15 +238,22 @@ async def async_step_cloud(
errors["base"] = "cloud_login_error"
except MiCloudAccessDenied:
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:
return self.async_show_form(
step_id="cloud", data_schema=DEVICE_CLOUD_CONFIG, errors=errors
)

devices_raw = await self.hass.async_add_executor_job(
miio_cloud.get_devices, cloud_country
)
try:
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:
errors["base"] = "cloud_no_devices"
Expand Down Expand Up @@ -353,6 +348,9 @@ async def async_step_connect(
except SetupException:
if self.model is None:
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

Expand Down Expand Up @@ -386,8 +384,8 @@ async def async_step_connect(
data[CONF_CLOUD_USERNAME] = self.cloud_username
data[CONF_CLOUD_PASSWORD] = self.cloud_password
data[CONF_CLOUD_COUNTRY] = self.cloud_country
self.hass.config_entries.async_update_entry(existing_entry, data=data)
await self.hass.config_entries.async_reload(existing_entry.entry_id)
if self.hass.config_entries.async_update_entry(existing_entry, data=data):
await self.hass.config_entries.async_reload(existing_entry.entry_id)
return self.async_abort(reason="reauth_successful")

if self.name is None:
Expand Down
3 changes: 2 additions & 1 deletion homeassistant/components/xiaomi_miio/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
"already_in_progress": "[%key:common::config_flow::abort::already_in_progress%]",
"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": {
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
Expand Down
3 changes: 2 additions & 1 deletion homeassistant/components/xiaomi_miio/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"already_in_progress": "Configuration flow is already in progress",
"incomplete_info": "Incomplete information to setup device, no host or token supplied.",
"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": {
"cannot_connect": "Failed to connect",
Expand Down
84 changes: 50 additions & 34 deletions tests/components/xiaomi_miio/test_config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from homeassistant import config_entries, data_entry_flow
from homeassistant.components import zeroconf
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

Expand Down Expand Up @@ -67,7 +67,7 @@

@pytest.fixture(name="xiaomi_miio_connect", autouse=True)
def xiaomi_miio_connect_fixture():
"""Mock denonavr connection and entry setup."""
"""Mock miio connection and entry setup."""
mock_info = get_mock_info()

with patch(
Expand Down Expand Up @@ -320,6 +320,22 @@ async def test_config_flow_gateway_cloud_login_error(hass):
assert result["step_id"] == "cloud"
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):
"""Test a failed config flow using cloud with no devices."""
Expand Down Expand Up @@ -348,6 +364,22 @@ async def test_config_flow_gateway_cloud_no_devices(hass):
assert result["step_id"] == "cloud"
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):
"""Test a failed config flow using cloud with a missing token."""
Expand Down Expand Up @@ -558,34 +590,6 @@ async def test_config_flow_step_unknown_device(hass):
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):
"""Test config flow, device connection error, model None."""
result = await hass.config_entries.flow.async_init(
Expand Down Expand Up @@ -618,6 +622,18 @@ async def test_config_flow_step_device_manual_model_error(hass):
assert result["step_id"] == "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):
"""Test config flow, device connection error, manual model."""
Expand Down Expand Up @@ -724,7 +740,7 @@ async def config_flow_device_success(hass, model_to_test):

async def config_flow_generic_roborock(hass):
"""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(
const.DOMAIN, context={"source": config_entries.SOURCE_USER}
Expand All @@ -743,7 +759,7 @@ async def config_flow_generic_roborock(hass):
assert result["step_id"] == "manual"
assert result["errors"] == {}

mock_info = get_mock_info(model=DUMMY_MODEL)
mock_info = get_mock_info(model=dummy_model)

with patch(
"homeassistant.components.xiaomi_miio.device.Device.info",
Expand All @@ -755,15 +771,15 @@ async def config_flow_generic_roborock(hass):
)

assert result["type"] == "create_entry"
assert result["title"] == DUMMY_MODEL
assert result["title"] == dummy_model
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: DUMMY_MODEL,
CONF_MODEL: dummy_model,
const.CONF_MAC: TEST_MAC,
}

Expand Down