Add Xiaomi Miio EU gateway support (#47955)

* Add EU gateway support

* add options flow translations

* fix options flow

* fix missing import

* try to fix async_add_executor_job

* try to fix async_add_executor_job

* fix unload

* check for login succes

* fix not reloading

* use cloud option

* fix styling

* Return after if

Co-authored-by: Nathan Tilley <nathan@tilley.xyz>

* cleanup

* add options flow tests

* fix new tests

* fix typo in docstring

* add missing blank line

* Use async_on_unload

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

* Use async_on_unload

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

* Use async_setup_platforms

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

* Use async_unload_platforms

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

* Update homeassistant/components/xiaomi_miio/__init__.py

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

* Update homeassistant/components/xiaomi_miio/const.py

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

* default use_cloud False

* add options flow checks

* fix styling

* fix issort

* add MiCloud check tests

* fix indent

* fix styling

* fix tests

* fix tests

* fix black

* re-write config flow

* add explicit return type

* update strings.json

* black formatting

* fix config flow

Tested the config flow and it is now fully working

* fix styling

* Fix current tests

* Add missing tests

* fix styling

* add re-auth flow

* fix styling

* fix reauth flow

* Add reauth flow test

* use ConfigEntryAuthFailed

* also trigger reauth @ login error

* fix styling

* remove unused import

* fix spelling

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

* Fix spelling

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

* fix spelling

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

* remove unessesary .keys()

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>

* combine async_add_executor_job calls

* remove async_step_model

* fix wrong indent

* fix gatway.py

* fix tests

Co-authored-by: Nathan Tilley <nathan@tilley.xyz>
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
starkillerOG 2021-06-15 00:05:40 +02:00 committed by GitHub
parent 8705168fe6
commit 3a2d50fe23
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 1050 additions and 198 deletions

View file

@ -2,27 +2,86 @@
from unittest.mock import Mock, patch
from miio import DeviceException
import pytest
from homeassistant import config_entries
from homeassistant import config_entries, data_entry_flow
from homeassistant.components.xiaomi_miio import const
from homeassistant.components.xiaomi_miio.config_flow import DEFAULT_GATEWAY_NAME
from homeassistant.const import CONF_HOST, CONF_NAME, CONF_TOKEN
from tests.common import MockConfigEntry
ZEROCONF_NAME = "name"
ZEROCONF_PROP = "properties"
ZEROCONF_MAC = "mac"
TEST_HOST = "1.2.3.4"
TEST_HOST2 = "5.6.7.8"
TEST_CLOUD_USER = "username"
TEST_CLOUD_PASS = "password"
TEST_CLOUD_COUNTRY = "cn"
TEST_TOKEN = "12345678901234567890123456789012"
TEST_NAME = "Test_Gateway"
TEST_NAME2 = "Test_Gateway_2"
TEST_MODEL = const.MODELS_GATEWAY[0]
TEST_MAC = "ab:cd:ef:gh:ij:kl"
TEST_MAC2 = "mn:op:qr:st:uv:wx"
TEST_MAC_DEVICE = "abcdefghijkl"
TEST_MAC_DEVICE2 = "mnopqrstuvwx"
TEST_GATEWAY_ID = TEST_MAC
TEST_HARDWARE_VERSION = "AB123"
TEST_FIRMWARE_VERSION = "1.2.3_456"
TEST_ZEROCONF_NAME = "lumi-gateway-v3_miio12345678._miio._udp.local."
TEST_SUB_DEVICE_LIST = []
TEST_CLOUD_DEVICES_1 = [
{
"parent_id": None,
"name": TEST_NAME,
"model": TEST_MODEL,
"localip": TEST_HOST,
"mac": TEST_MAC_DEVICE,
"token": TEST_TOKEN,
}
]
TEST_CLOUD_DEVICES_2 = [
{
"parent_id": None,
"name": TEST_NAME,
"model": TEST_MODEL,
"localip": TEST_HOST,
"mac": TEST_MAC_DEVICE,
"token": TEST_TOKEN,
},
{
"parent_id": None,
"name": TEST_NAME2,
"model": TEST_MODEL,
"localip": TEST_HOST2,
"mac": TEST_MAC_DEVICE2,
"token": TEST_TOKEN,
},
]
@pytest.fixture(name="xiaomi_miio_connect", autouse=True)
def xiaomi_miio_connect_fixture():
"""Mock denonavr connection and entry setup."""
mock_info = get_mock_info()
with patch(
"homeassistant.components.xiaomi_miio.device.Device.info",
return_value=mock_info,
), patch(
"homeassistant.components.xiaomi_miio.config_flow.MiCloud.login",
return_value=True,
), patch(
"homeassistant.components.xiaomi_miio.config_flow.MiCloud.get_devices",
return_value=TEST_CLOUD_DEVICES_1,
), patch(
"homeassistant.components.xiaomi_miio.async_setup_entry", return_value=True
), patch(
"homeassistant.components.xiaomi_miio.async_unload_entry", return_value=True
):
yield
def get_mock_info(
@ -48,7 +107,16 @@ async def test_config_flow_step_gateway_connect_error(hass):
)
assert result["type"] == "form"
assert result["step_id"] == "device"
assert result["step_id"] == "cloud"
assert result["errors"] == {}
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{const.CONF_MANUAL: True},
)
assert result["type"] == "form"
assert result["step_id"] == "manual"
assert result["errors"] == {}
with patch(
@ -61,7 +129,7 @@ async def test_config_flow_step_gateway_connect_error(hass):
)
assert result["type"] == "form"
assert result["step_id"] == "device"
assert result["step_id"] == "connect"
assert result["errors"] == {"base": "cannot_connect"}
@ -72,26 +140,30 @@ async def test_config_flow_gateway_success(hass):
)
assert result["type"] == "form"
assert result["step_id"] == "device"
assert result["step_id"] == "cloud"
assert result["errors"] == {}
mock_info = get_mock_info()
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{const.CONF_MANUAL: True},
)
with patch(
"homeassistant.components.xiaomi_miio.device.Device.info",
return_value=mock_info,
), patch(
"homeassistant.components.xiaomi_miio.async_setup_entry", return_value=True
):
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{CONF_HOST: TEST_HOST, CONF_TOKEN: TEST_TOKEN},
)
assert result["type"] == "form"
assert result["step_id"] == "manual"
assert result["errors"] == {}
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{CONF_HOST: TEST_HOST, CONF_TOKEN: TEST_TOKEN},
)
assert result["type"] == "create_entry"
assert result["title"] == DEFAULT_GATEWAY_NAME
assert result["title"] == TEST_MODEL
assert result["data"] == {
const.CONF_FLOW_TYPE: const.CONF_GATEWAY,
const.CONF_CLOUD_USERNAME: None,
const.CONF_CLOUD_PASSWORD: None,
const.CONF_CLOUD_COUNTRY: None,
CONF_HOST: TEST_HOST,
CONF_TOKEN: TEST_TOKEN,
const.CONF_MODEL: TEST_MODEL,
@ -99,6 +171,202 @@ async def test_config_flow_gateway_success(hass):
}
async def test_config_flow_gateway_cloud_success(hass):
"""Test a successful config flow using cloud."""
result = await hass.config_entries.flow.async_init(
const.DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] == "form"
assert result["step_id"] == "cloud"
assert result["errors"] == {}
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"] == "create_entry"
assert result["title"] == TEST_NAME
assert result["data"] == {
const.CONF_FLOW_TYPE: const.CONF_GATEWAY,
const.CONF_CLOUD_USERNAME: TEST_CLOUD_USER,
const.CONF_CLOUD_PASSWORD: TEST_CLOUD_PASS,
const.CONF_CLOUD_COUNTRY: TEST_CLOUD_COUNTRY,
CONF_HOST: TEST_HOST,
CONF_TOKEN: TEST_TOKEN,
const.CONF_MODEL: TEST_MODEL,
const.CONF_MAC: TEST_MAC,
}
async def test_config_flow_gateway_cloud_multiple_success(hass):
"""Test a successful config flow using cloud with multiple devices."""
result = await hass.config_entries.flow.async_init(
const.DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] == "form"
assert result["step_id"] == "cloud"
assert result["errors"] == {}
with patch(
"homeassistant.components.xiaomi_miio.config_flow.MiCloud.get_devices",
return_value=TEST_CLOUD_DEVICES_2,
):
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"] == "form"
assert result["step_id"] == "select"
assert result["errors"] == {}
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{"select_device": f"{TEST_NAME2} - {TEST_MODEL}"},
)
assert result["type"] == "create_entry"
assert result["title"] == TEST_NAME2
assert result["data"] == {
const.CONF_FLOW_TYPE: const.CONF_GATEWAY,
const.CONF_CLOUD_USERNAME: TEST_CLOUD_USER,
const.CONF_CLOUD_PASSWORD: TEST_CLOUD_PASS,
const.CONF_CLOUD_COUNTRY: TEST_CLOUD_COUNTRY,
CONF_HOST: TEST_HOST2,
CONF_TOKEN: TEST_TOKEN,
const.CONF_MODEL: TEST_MODEL,
const.CONF_MAC: TEST_MAC2,
}
async def test_config_flow_gateway_cloud_incomplete(hass):
"""Test a failed config flow using incomplete cloud credentials."""
result = await hass.config_entries.flow.async_init(
const.DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] == "form"
assert result["step_id"] == "cloud"
assert result["errors"] == {}
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
const.CONF_CLOUD_USERNAME: TEST_CLOUD_USER,
const.CONF_CLOUD_COUNTRY: TEST_CLOUD_COUNTRY,
},
)
assert result["type"] == "form"
assert result["step_id"] == "cloud"
assert result["errors"] == {"base": "cloud_credentials_incomplete"}
async def test_config_flow_gateway_cloud_login_error(hass):
"""Test a failed config flow using cloud login error."""
result = await hass.config_entries.flow.async_init(
const.DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] == "form"
assert result["step_id"] == "cloud"
assert result["errors"] == {}
with patch(
"homeassistant.components.xiaomi_miio.config_flow.MiCloud.login",
return_value=False,
):
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"] == "form"
assert result["step_id"] == "cloud"
assert result["errors"] == {"base": "cloud_login_error"}
async def test_config_flow_gateway_cloud_no_devices(hass):
"""Test a failed config flow using cloud with no devices."""
result = await hass.config_entries.flow.async_init(
const.DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] == "form"
assert result["step_id"] == "cloud"
assert result["errors"] == {}
with patch(
"homeassistant.components.xiaomi_miio.config_flow.MiCloud.get_devices",
return_value=[],
):
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"] == "form"
assert result["step_id"] == "cloud"
assert result["errors"] == {"base": "cloud_no_devices"}
async def test_config_flow_gateway_cloud_missing_token(hass):
"""Test a failed config flow using cloud with a missing token."""
result = await hass.config_entries.flow.async_init(
const.DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] == "form"
assert result["step_id"] == "cloud"
assert result["errors"] == {}
cloud_device = [
{
"parent_id": None,
"name": TEST_NAME,
"model": TEST_MODEL,
"localip": TEST_HOST,
"mac": TEST_MAC_DEVICE,
"token": None,
}
]
with patch(
"homeassistant.components.xiaomi_miio.config_flow.MiCloud.get_devices",
return_value=cloud_device,
):
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"] == "incomplete_info"
async def test_zeroconf_gateway_success(hass):
"""Test a successful zeroconf discovery of a gateway."""
result = await hass.config_entries.flow.async_init(
@ -112,26 +380,25 @@ async def test_zeroconf_gateway_success(hass):
)
assert result["type"] == "form"
assert result["step_id"] == "device"
assert result["step_id"] == "cloud"
assert result["errors"] == {}
mock_info = get_mock_info()
with patch(
"homeassistant.components.xiaomi_miio.device.Device.info",
return_value=mock_info,
), patch(
"homeassistant.components.xiaomi_miio.async_setup_entry", return_value=True
):
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{CONF_TOKEN: TEST_TOKEN},
)
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"] == "create_entry"
assert result["title"] == DEFAULT_GATEWAY_NAME
assert result["title"] == TEST_NAME
assert result["data"] == {
const.CONF_FLOW_TYPE: const.CONF_GATEWAY,
const.CONF_CLOUD_USERNAME: TEST_CLOUD_USER,
const.CONF_CLOUD_PASSWORD: TEST_CLOUD_PASS,
const.CONF_CLOUD_COUNTRY: TEST_CLOUD_COUNTRY,
CONF_HOST: TEST_HOST,
CONF_TOKEN: TEST_TOKEN,
const.CONF_MODEL: TEST_MODEL,
@ -184,7 +451,16 @@ async def test_config_flow_step_device_connect_error(hass):
)
assert result["type"] == "form"
assert result["step_id"] == "device"
assert result["step_id"] == "cloud"
assert result["errors"] == {}
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{const.CONF_MANUAL: True},
)
assert result["type"] == "form"
assert result["step_id"] == "manual"
assert result["errors"] == {}
with patch(
@ -197,7 +473,7 @@ async def test_config_flow_step_device_connect_error(hass):
)
assert result["type"] == "form"
assert result["step_id"] == "device"
assert result["step_id"] == "connect"
assert result["errors"] == {"base": "cannot_connect"}
@ -208,7 +484,16 @@ async def test_config_flow_step_unknown_device(hass):
)
assert result["type"] == "form"
assert result["step_id"] == "device"
assert result["step_id"] == "cloud"
assert result["errors"] == {}
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{const.CONF_MANUAL: True},
)
assert result["type"] == "form"
assert result["step_id"] == "manual"
assert result["errors"] == {}
mock_info = get_mock_info(model="UNKNOWN")
@ -223,7 +508,7 @@ async def test_config_flow_step_unknown_device(hass):
)
assert result["type"] == "form"
assert result["step_id"] == "device"
assert result["step_id"] == "connect"
assert result["errors"] == {"base": "unknown_device"}
@ -234,8 +519,6 @@ async def test_import_flow_success(hass):
with patch(
"homeassistant.components.xiaomi_miio.device.Device.info",
return_value=mock_info,
), patch(
"homeassistant.components.xiaomi_miio.async_setup_entry", return_value=True
):
result = await hass.config_entries.flow.async_init(
const.DOMAIN,
@ -247,6 +530,9 @@ async def test_import_flow_success(hass):
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,
const.CONF_MODEL: const.MODELS_SWITCH[0],
@ -261,7 +547,16 @@ async def test_config_flow_step_device_manual_model_succes(hass):
)
assert result["type"] == "form"
assert result["step_id"] == "device"
assert result["step_id"] == "cloud"
assert result["errors"] == {}
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{const.CONF_MANUAL: True},
)
assert result["type"] == "form"
assert result["step_id"] == "manual"
assert result["errors"] == {}
with patch(
@ -274,7 +569,7 @@ async def test_config_flow_step_device_manual_model_succes(hass):
)
assert result["type"] == "form"
assert result["step_id"] == "device"
assert result["step_id"] == "connect"
assert result["errors"] == {"base": "cannot_connect"}
overwrite_model = const.MODELS_VACUUM[0]
@ -282,18 +577,19 @@ async def test_config_flow_step_device_manual_model_succes(hass):
with patch(
"homeassistant.components.xiaomi_miio.device.Device.info",
side_effect=DeviceException({}),
), patch(
"homeassistant.components.xiaomi_miio.async_setup_entry", return_value=True
):
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{CONF_TOKEN: TEST_TOKEN, const.CONF_MODEL: overwrite_model},
{const.CONF_MODEL: overwrite_model},
)
assert result["type"] == "create_entry"
assert result["title"] == overwrite_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,
const.CONF_MODEL: overwrite_model,
@ -308,7 +604,16 @@ async def config_flow_device_success(hass, model_to_test):
)
assert result["type"] == "form"
assert result["step_id"] == "device"
assert result["step_id"] == "cloud"
assert result["errors"] == {}
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{const.CONF_MANUAL: True},
)
assert result["type"] == "form"
assert result["step_id"] == "manual"
assert result["errors"] == {}
mock_info = get_mock_info(model=model_to_test)
@ -316,8 +621,6 @@ async def config_flow_device_success(hass, model_to_test):
with patch(
"homeassistant.components.xiaomi_miio.device.Device.info",
return_value=mock_info,
), patch(
"homeassistant.components.xiaomi_miio.async_setup_entry", return_value=True
):
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
@ -328,6 +631,9 @@ async def config_flow_device_success(hass, model_to_test):
assert result["title"] == model_to_test
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,
const.CONF_MODEL: model_to_test,
@ -348,7 +654,16 @@ async def zeroconf_device_success(hass, zeroconf_name_to_test, model_to_test):
)
assert result["type"] == "form"
assert result["step_id"] == "device"
assert result["step_id"] == "cloud"
assert result["errors"] == {}
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{const.CONF_MANUAL: True},
)
assert result["type"] == "form"
assert result["step_id"] == "manual"
assert result["errors"] == {}
mock_info = get_mock_info(model=model_to_test)
@ -356,8 +671,6 @@ async def zeroconf_device_success(hass, zeroconf_name_to_test, model_to_test):
with patch(
"homeassistant.components.xiaomi_miio.device.Device.info",
return_value=mock_info,
), patch(
"homeassistant.components.xiaomi_miio.async_setup_entry", return_value=True
):
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
@ -368,6 +681,9 @@ async def zeroconf_device_success(hass, zeroconf_name_to_test, model_to_test):
assert result["title"] == model_to_test
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,
const.CONF_MODEL: model_to_test,
@ -399,3 +715,147 @@ async def test_zeroconf_vacuum_success(hass):
test_vacuum_model = const.MODELS_VACUUM[0]
test_zeroconf_name = const.MODELS_VACUUM[0].replace(".", "-")
await zeroconf_device_success(hass, test_zeroconf_name, test_vacuum_model)
async def test_options_flow(hass):
"""Test specifying non default settings using options flow."""
config_entry = MockConfigEntry(
domain=const.DOMAIN,
unique_id=TEST_GATEWAY_ID,
data={
const.CONF_CLOUD_USERNAME: TEST_CLOUD_USER,
const.CONF_CLOUD_PASSWORD: TEST_CLOUD_PASS,
const.CONF_CLOUD_COUNTRY: TEST_CLOUD_COUNTRY,
const.CONF_FLOW_TYPE: const.CONF_GATEWAY,
CONF_HOST: TEST_HOST,
CONF_TOKEN: TEST_TOKEN,
const.CONF_MODEL: TEST_MODEL,
const.CONF_MAC: TEST_MAC,
},
title=TEST_NAME,
)
config_entry.add_to_hass(hass)
assert 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
assert result["step_id"] == "init"
result = await hass.config_entries.options.async_configure(
result["flow_id"],
user_input={
const.CONF_CLOUD_SUBDEVICES: True,
},
)
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert config_entry.options == {
const.CONF_CLOUD_SUBDEVICES: True,
}
async def test_options_flow_incomplete(hass):
"""Test specifying incomplete settings using options flow."""
config_entry = MockConfigEntry(
domain=const.DOMAIN,
unique_id=TEST_GATEWAY_ID,
data={
const.CONF_CLOUD_USERNAME: None,
const.CONF_CLOUD_PASSWORD: None,
const.CONF_CLOUD_COUNTRY: None,
const.CONF_FLOW_TYPE: const.CONF_GATEWAY,
CONF_HOST: TEST_HOST,
CONF_TOKEN: TEST_TOKEN,
const.CONF_MODEL: TEST_MODEL,
const.CONF_MAC: TEST_MAC,
},
title=TEST_NAME,
)
config_entry.add_to_hass(hass)
assert 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
assert result["step_id"] == "init"
result = await hass.config_entries.options.async_configure(
result["flow_id"],
user_input={
const.CONF_CLOUD_SUBDEVICES: True,
},
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "init"
assert result["errors"] == {"base": "cloud_credentials_incomplete"}
async def test_reauth(hass):
"""Test a reauth flow."""
# await setup.async_setup_component(hass, "persistent_notification", {})
config_entry = MockConfigEntry(
domain=const.DOMAIN,
unique_id=TEST_GATEWAY_ID,
data={
const.CONF_CLOUD_USERNAME: None,
const.CONF_CLOUD_PASSWORD: None,
const.CONF_CLOUD_COUNTRY: None,
const.CONF_FLOW_TYPE: const.CONF_GATEWAY,
CONF_HOST: TEST_HOST,
CONF_TOKEN: TEST_TOKEN,
const.CONF_MODEL: TEST_MODEL,
const.CONF_MAC: TEST_MAC,
},
title=TEST_NAME,
)
config_entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
result = await hass.config_entries.flow.async_init(
const.DOMAIN,
context={"source": config_entries.SOURCE_REAUTH},
data=config_entry.data,
)
assert result["type"] == "form"
assert result["step_id"] == "reauth_confirm"
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
{},
)
assert result["type"] == "form"
assert result["step_id"] == "cloud"
assert result["errors"] == {}
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"] == "reauth_successful"
config_data = config_entry.data.copy()
assert config_data == {
const.CONF_FLOW_TYPE: const.CONF_GATEWAY,
const.CONF_CLOUD_USERNAME: TEST_CLOUD_USER,
const.CONF_CLOUD_PASSWORD: TEST_CLOUD_PASS,
const.CONF_CLOUD_COUNTRY: TEST_CLOUD_COUNTRY,
CONF_HOST: TEST_HOST,
CONF_TOKEN: TEST_TOKEN,
const.CONF_MODEL: TEST_MODEL,
const.CONF_MAC: TEST_MAC,
}