Rewrite tuya config flow (#57043)

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
Co-authored-by: Franck Nijhof <git@frenck.dev>
This commit is contained in:
Joakim Sørensen 2021-10-04 17:27:24 +02:00 committed by GitHub
parent 8567aa9e13
commit 745298408a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 168 additions and 339 deletions

View File

@ -1,10 +1,12 @@
#!/usr/bin/env python3
"""Config flow for Tuya.""" """Config flow for Tuya."""
from __future__ import annotations
import logging import logging
from typing import Any
from tuya_iot import ProjectType, TuyaOpenAPI from tuya_iot import ProjectType, TuyaOpenAPI
import voluptuous as vol import voluptuous as vol
from voluptuous.schema_builder import UNDEFINED
from homeassistant import config_entries from homeassistant import config_entries
@ -16,131 +18,123 @@ from .const import (
CONF_ENDPOINT, CONF_ENDPOINT,
CONF_PASSWORD, CONF_PASSWORD,
CONF_PROJECT_TYPE, CONF_PROJECT_TYPE,
CONF_REGION,
CONF_USERNAME, CONF_USERNAME,
DOMAIN, DOMAIN,
TUYA_APP_TYPE, SMARTLIFE_APP,
TUYA_ENDPOINT, TUYA_REGIONS,
TUYA_PROJECT_TYPE, TUYA_RESPONSE_CODE,
TUYA_RESPONSE_MSG,
TUYA_RESPONSE_PLATFROM_URL,
TUYA_RESPONSE_RESULT,
TUYA_RESPONSE_SUCCESS,
TUYA_SMART_APP,
) )
RESULT_SINGLE_INSTANCE = "single_instance_allowed"
RESULT_AUTH_FAILED = "invalid_auth"
TUYA_ENDPOINT_BASE = "https://openapi.tuyacn.com"
TUYA_ENDPOINT_OTHER = "https://openapi.tuyaus.com"
COUNTRY_CODE_CHINA = ["86", "+86", "China"]
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
# Project Type
DATA_SCHEMA_PROJECT_TYPE = vol.Schema(
{vol.Required(CONF_PROJECT_TYPE, default=0): vol.In(TUYA_PROJECT_TYPE)}
)
# INDUSTY_SOLUTIONS Schema
DATA_SCHEMA_INDUSTRY_SOLUTIONS = vol.Schema(
{
vol.Required(CONF_ENDPOINT): vol.In(TUYA_ENDPOINT),
vol.Required(CONF_ACCESS_ID): str,
vol.Required(CONF_ACCESS_SECRET): str,
vol.Required(CONF_USERNAME): str,
vol.Required(CONF_PASSWORD): str,
}
)
# SMART_HOME Schema
DATA_SCHEMA_SMART_HOME = vol.Schema(
{
vol.Required(CONF_ACCESS_ID): str,
vol.Required(CONF_ACCESS_SECRET): str,
vol.Required(CONF_APP_TYPE): vol.In(TUYA_APP_TYPE),
vol.Required(CONF_COUNTRY_CODE): str,
vol.Required(CONF_USERNAME): str,
vol.Required(CONF_PASSWORD): str,
}
)
class TuyaConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): class TuyaConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
"""Tuya Config Flow.""" """Tuya Config Flow."""
def __init__(self) -> None:
"""Init tuya config flow."""
super().__init__()
self.conf_project_type = None
@staticmethod @staticmethod
def _try_login(user_input): def _try_login(user_input: dict[str, Any]) -> tuple[dict[Any, Any], dict[str, Any]]:
project_type = ProjectType(user_input[CONF_PROJECT_TYPE]) """Try login."""
api = TuyaOpenAPI( response = {}
user_input[CONF_ENDPOINT]
if project_type == ProjectType.INDUSTY_SOLUTIONS
else "",
user_input[CONF_ACCESS_ID],
user_input[CONF_ACCESS_SECRET],
project_type,
)
api.set_dev_channel("hass")
if project_type == ProjectType.INDUSTY_SOLUTIONS: data = {
response = api.login(user_input[CONF_USERNAME], user_input[CONF_PASSWORD]) CONF_ENDPOINT: TUYA_REGIONS[user_input[CONF_REGION]],
else: CONF_PROJECT_TYPE: ProjectType.INDUSTY_SOLUTIONS,
if user_input[CONF_COUNTRY_CODE] in COUNTRY_CODE_CHINA: CONF_ACCESS_ID: user_input[CONF_ACCESS_ID],
api.endpoint = TUYA_ENDPOINT_BASE CONF_ACCESS_SECRET: user_input[CONF_ACCESS_SECRET],
CONF_USERNAME: user_input[CONF_USERNAME],
CONF_PASSWORD: user_input[CONF_PASSWORD],
CONF_COUNTRY_CODE: user_input[CONF_REGION],
}
for app_type in ("", TUYA_SMART_APP, SMARTLIFE_APP):
data[CONF_APP_TYPE] = app_type
if data[CONF_APP_TYPE] == "":
data[CONF_PROJECT_TYPE] = ProjectType.INDUSTY_SOLUTIONS
else: else:
api.endpoint = TUYA_ENDPOINT_OTHER data[CONF_PROJECT_TYPE] = ProjectType.SMART_HOME
api = TuyaOpenAPI(
endpoint=data[CONF_ENDPOINT],
access_id=data[CONF_ACCESS_ID],
access_secret=data[CONF_ACCESS_SECRET],
project_type=data[CONF_PROJECT_TYPE],
)
api.set_dev_channel("hass")
response = api.login( response = api.login(
user_input[CONF_USERNAME], username=data[CONF_USERNAME],
user_input[CONF_PASSWORD], password=data[CONF_PASSWORD],
user_input[CONF_COUNTRY_CODE], country_code=data[CONF_COUNTRY_CODE],
user_input[CONF_APP_TYPE], schema=data[CONF_APP_TYPE],
) )
if response.get("success", False) and isinstance(
api.token_info.platform_url, str
):
api.endpoint = api.token_info.platform_url
user_input[CONF_ENDPOINT] = api.token_info.platform_url
_LOGGER.debug("TuyaConfigFlow._try_login finish, response:, %s", response) _LOGGER.debug("Response %s", response)
return response
if response.get(TUYA_RESPONSE_SUCCESS, False):
break
return response, data
async def async_step_user(self, user_input=None): async def async_step_user(self, user_input=None):
"""Step user.""" """Step user."""
if user_input is None:
return self.async_show_form(
step_id="user", data_schema=DATA_SCHEMA_PROJECT_TYPE
)
self.conf_project_type = user_input[CONF_PROJECT_TYPE]
return await self.async_step_login()
async def async_step_login(self, user_input=None):
"""Step login."""
errors = {} errors = {}
if user_input is not None: placeholders = {}
assert self.conf_project_type is not None
user_input[CONF_PROJECT_TYPE] = self.conf_project_type
response = await self.hass.async_add_executor_job( if user_input is not None:
response, data = await self.hass.async_add_executor_job(
self._try_login, user_input self._try_login, user_input
) )
if response.get("success", False): if response.get(TUYA_RESPONSE_SUCCESS, False):
_LOGGER.debug("TuyaConfigFlow.async_step_user login success") if endpoint := response.get(TUYA_RESPONSE_RESULT, {}).get(
TUYA_RESPONSE_PLATFROM_URL
):
data[CONF_ENDPOINT] = endpoint
data[CONF_PROJECT_TYPE] = data[CONF_PROJECT_TYPE].value
return self.async_create_entry( return self.async_create_entry(
title=user_input[CONF_USERNAME], title=user_input[CONF_USERNAME],
data=user_input, data=data,
) )
errors["base"] = RESULT_AUTH_FAILED errors["base"] = "login_error"
placeholders = {
TUYA_RESPONSE_CODE: response.get(TUYA_RESPONSE_CODE),
TUYA_RESPONSE_MSG: response.get(TUYA_RESPONSE_MSG),
}
if ProjectType(self.conf_project_type) == ProjectType.SMART_HOME: def _schema_default(key: str) -> str | UNDEFINED:
return self.async_show_form( if not user_input:
step_id="login", data_schema=DATA_SCHEMA_SMART_HOME, errors=errors return UNDEFINED
) return user_input[key]
return self.async_show_form( return self.async_show_form(
step_id="login", step_id="user",
data_schema=DATA_SCHEMA_INDUSTRY_SOLUTIONS, data_schema=vol.Schema(
{
vol.Required(
CONF_REGION, default=_schema_default(CONF_REGION)
): vol.In(TUYA_REGIONS.keys()),
vol.Required(
CONF_ACCESS_ID, default=_schema_default(CONF_ACCESS_ID)
): str,
vol.Required(
CONF_ACCESS_SECRET, default=_schema_default(CONF_ACCESS_SECRET)
): str,
vol.Required(
CONF_USERNAME, default=_schema_default(CONF_USERNAME)
): str,
vol.Required(
CONF_PASSWORD, default=_schema_default(CONF_PASSWORD)
): str,
}
),
errors=errors, errors=errors,
description_placeholders=placeholders,
) )

View File

@ -9,6 +9,7 @@ CONF_ACCESS_ID = "access_id"
CONF_ACCESS_SECRET = "access_secret" CONF_ACCESS_SECRET = "access_secret"
CONF_USERNAME = "username" CONF_USERNAME = "username"
CONF_PASSWORD = "password" CONF_PASSWORD = "password"
CONF_REGION = "region"
CONF_COUNTRY_CODE = "country_code" CONF_COUNTRY_CODE = "country_code"
CONF_APP_TYPE = "tuya_app_type" CONF_APP_TYPE = "tuya_app_type"
@ -19,19 +20,24 @@ TUYA_MQTT_LISTENER = "tuya_mqtt_listener"
TUYA_HA_TUYA_MAP = "tuya_ha_tuya_map" TUYA_HA_TUYA_MAP = "tuya_ha_tuya_map"
TUYA_HA_DEVICES = "tuya_ha_devices" TUYA_HA_DEVICES = "tuya_ha_devices"
TUYA_RESPONSE_CODE = "code"
TUYA_RESPONSE_RESULT = "result"
TUYA_RESPONSE_MSG = "msg"
TUYA_RESPONSE_SUCCESS = "success"
TUYA_RESPONSE_PLATFROM_URL = "platform_url"
TUYA_HA_SIGNAL_UPDATE_ENTITY = "tuya_entry_update" TUYA_HA_SIGNAL_UPDATE_ENTITY = "tuya_entry_update"
TUYA_ENDPOINT = { TUYA_SMART_APP = "tuyaSmart"
"https://openapi.tuyaus.com": "America", SMARTLIFE_APP = "smartlife"
"https://openapi.tuyacn.com": "China",
"https://openapi.tuyaeu.com": "Europe", TUYA_REGIONS = {
"https://openapi.tuyain.com": "India", "America": "https://openapi.tuyaus.com",
"https://openapi-ueaz.tuyaus.com": "EasternAmerica", "China": "https://openapi.tuyacn.com",
"https://openapi-weaz.tuyaeu.com": "WesternEurope", "Eastern America": "https://openapi-ueaz.tuyaus.com",
"Europe": "https://openapi.tuyaeu.com",
"India": "https://openapi.tuyain.com",
"Western Europe": "https://openapi-weaz.tuyaeu.com",
} }
TUYA_PROJECT_TYPE = {1: "Custom Development", 0: "Smart Home PaaS"}
TUYA_APP_TYPE = {"tuyaSmart": "TuyaSmart", "smartlife": "Smart Life"}
PLATFORMS = ["climate", "fan", "light", "scene", "switch"] PLATFORMS = ["climate", "fan", "light", "scene", "switch"]

View File

@ -1,29 +1,20 @@
{ {
"config": { "config": {
"flow_title": "Tuya configuration",
"step": { "step": {
"user":{ "user": {
"title":"Tuya Integration", "description": "Enter your Tuya credentials",
"data":{
"tuya_project_type": "Tuya cloud project type"
}
},
"login": {
"title": "Tuya",
"description": "Enter your Tuya credential",
"data": { "data": {
"endpoint": "Availability Zone", "region": "Region",
"access_id": "Access ID", "access_id": "Tuya IoT Access ID",
"access_secret": "Access Secret", "access_secret": "Tuya IoT Access Secret",
"tuya_app_type": "Mobile App",
"country_code": "Country Code",
"username": "Account", "username": "Account",
"password": "Password" "password": "[%key:common::config_flow::data::password%]"
} }
} }
}, },
"error": { "error": {
"invalid_auth": "[%key:common::config_flow::error::invalid_auth%]" "invalid_auth": "[%key:common::config_flow::error::invalid_auth%]",
"login_error": "Login error ({code}): {msg}"
} }
} }
} }

View File

@ -1,78 +1,19 @@
{ {
"config": { "config": {
"abort": {
"cannot_connect": "Failed to connect",
"invalid_auth": "Invalid authentication",
"single_instance_allowed": "Already configured. Only a single configuration possible."
},
"error": { "error": {
"invalid_auth": "Invalid authentication" "invalid_auth": "Invalid authentication",
"login_error": "Login error ({code}): {msg}"
}, },
"flow_title": "Tuya configuration",
"step": { "step": {
"login": {
"data": {
"access_id": "Access ID",
"access_secret": "Access Secret",
"country_code": "Country Code",
"endpoint": "Availability Zone",
"password": "Password",
"tuya_app_type": "Mobile App",
"username": "Account"
},
"description": "Enter your Tuya credential",
"title": "Tuya"
},
"user": { "user": {
"data": { "data": {
"country_code": "Your account country code (e.g., 1 for USA or 86 for China)", "access_id": "Tuya IoT Access ID",
"access_secret": "Tuya IoT Access Secret",
"password": "Password", "password": "Password",
"platform": "The app where your account is registered", "region": "Region",
"tuya_project_type": "Tuya cloud project type", "username": "Account"
"username": "Username"
}, },
"description": "Enter your Tuya credentials.", "description": "Enter your Tuya credentials"
"title": "Tuya Integration"
}
}
},
"options": {
"abort": {
"cannot_connect": "Failed to connect"
},
"error": {
"dev_multi_type": "Multiple selected devices to configure must be of the same type",
"dev_not_config": "Device type not configurable",
"dev_not_found": "Device not found"
},
"step": {
"device": {
"data": {
"brightness_range_mode": "Brightness range used by device",
"curr_temp_divider": "Current Temperature value divider (0 = use default)",
"max_kelvin": "Max color temperature supported in kelvin",
"max_temp": "Max target temperature (use min and max = 0 for default)",
"min_kelvin": "Min color temperature supported in kelvin",
"min_temp": "Min target temperature (use min and max = 0 for default)",
"set_temp_divided": "Use divided Temperature value for set temperature command",
"support_color": "Force color support",
"temp_divider": "Temperature values divider (0 = use default)",
"temp_step_override": "Target Temperature step",
"tuya_max_coltemp": "Max color temperature reported by device",
"unit_of_measurement": "Temperature unit used by device"
},
"description": "Configure options to adjust displayed information for {device_type} device `{device_name}`",
"title": "Configure Tuya Device"
},
"init": {
"data": {
"discovery_interval": "Discovery device polling interval in seconds",
"list_devices": "Select the devices to configure or leave empty to save configuration",
"query_device": "Select device that will use query method for faster status update",
"query_interval": "Query device polling interval in seconds"
},
"description": "Do not set pollings interval values too low or the calls will fail generating error message in the log",
"title": "Configure Tuya Options"
} }
} }
} }

View File

@ -1,93 +1,84 @@
"""Tests for the Tuya config flow.""" """Tests for the Tuya config flow."""
from unittest.mock import MagicMock, Mock, patch from __future__ import annotations
from typing import Any
from unittest.mock import MagicMock, patch
import pytest import pytest
from homeassistant import config_entries, data_entry_flow from homeassistant import config_entries, data_entry_flow
from homeassistant.components.tuya.config_flow import RESULT_AUTH_FAILED
from homeassistant.components.tuya.const import ( from homeassistant.components.tuya.const import (
CONF_ACCESS_ID, CONF_ACCESS_ID,
CONF_ACCESS_SECRET, CONF_ACCESS_SECRET,
CONF_APP_TYPE, CONF_APP_TYPE,
CONF_COUNTRY_CODE,
CONF_ENDPOINT, CONF_ENDPOINT,
CONF_PASSWORD, CONF_PASSWORD,
CONF_PROJECT_TYPE, CONF_PROJECT_TYPE,
CONF_REGION,
CONF_USERNAME, CONF_USERNAME,
DOMAIN, DOMAIN,
SMARTLIFE_APP,
TUYA_REGIONS,
TUYA_SMART_APP,
) )
from homeassistant.core import HomeAssistant
MOCK_SMART_HOME_PROJECT_TYPE = 0 MOCK_SMART_HOME_PROJECT_TYPE = 0
MOCK_INDUSTRY_PROJECT_TYPE = 1 MOCK_INDUSTRY_PROJECT_TYPE = 1
MOCK_REGION = "Europe"
MOCK_ACCESS_ID = "myAccessId" MOCK_ACCESS_ID = "myAccessId"
MOCK_ACCESS_SECRET = "myAccessSecret" MOCK_ACCESS_SECRET = "myAccessSecret"
MOCK_USERNAME = "myUsername" MOCK_USERNAME = "myUsername"
MOCK_PASSWORD = "myPassword" MOCK_PASSWORD = "myPassword"
MOCK_COUNTRY_CODE_BASE = "86"
MOCK_COUNTRY_CODE_OTHER = "1"
MOCK_APP_TYPE = "smartlife"
MOCK_ENDPOINT = "https://openapi-ueaz.tuyaus.com" MOCK_ENDPOINT = "https://openapi-ueaz.tuyaus.com"
TUYA_SMART_HOME_PROJECT_DATA = { TUYA_INPUT_DATA = {
CONF_PROJECT_TYPE: MOCK_SMART_HOME_PROJECT_TYPE, CONF_REGION: MOCK_REGION,
}
TUYA_INDUSTRY_PROJECT_DATA = {
CONF_PROJECT_TYPE: MOCK_INDUSTRY_PROJECT_TYPE,
}
TUYA_INPUT_INDUSTRY_DATA = {
CONF_ENDPOINT: MOCK_ENDPOINT,
CONF_ACCESS_ID: MOCK_ACCESS_ID, CONF_ACCESS_ID: MOCK_ACCESS_ID,
CONF_ACCESS_SECRET: MOCK_ACCESS_SECRET, CONF_ACCESS_SECRET: MOCK_ACCESS_SECRET,
CONF_USERNAME: MOCK_USERNAME, CONF_USERNAME: MOCK_USERNAME,
CONF_PASSWORD: MOCK_PASSWORD, CONF_PASSWORD: MOCK_PASSWORD,
} }
TUYA_IMPORT_SMART_HOME_DATA_BASE = { RESPONSE_SUCCESS = {
CONF_ACCESS_ID: MOCK_ACCESS_ID, "success": True,
CONF_ACCESS_SECRET: MOCK_ACCESS_SECRET, "code": 1024,
CONF_USERNAME: MOCK_USERNAME, "result": {"platform_url": MOCK_ENDPOINT},
CONF_PASSWORD: MOCK_PASSWORD,
CONF_COUNTRY_CODE: MOCK_COUNTRY_CODE_BASE,
CONF_APP_TYPE: MOCK_APP_TYPE,
}
TUYA_IMPORT_SMART_HOME_DATA_OTHER = {
CONF_ACCESS_ID: MOCK_ACCESS_ID,
CONF_ACCESS_SECRET: MOCK_ACCESS_SECRET,
CONF_USERNAME: MOCK_USERNAME,
CONF_PASSWORD: MOCK_PASSWORD,
CONF_COUNTRY_CODE: MOCK_COUNTRY_CODE_OTHER,
CONF_APP_TYPE: MOCK_APP_TYPE,
}
TUYA_IMPORT_INDUSTRY_DATA = {
CONF_PROJECT_TYPE: MOCK_SMART_HOME_PROJECT_TYPE,
CONF_ENDPOINT: MOCK_ENDPOINT,
CONF_ACCESS_ID: MOCK_ACCESS_ID,
CONF_ACCESS_SECRET: MOCK_ACCESS_SECRET,
CONF_USERNAME: MOCK_USERNAME,
CONF_PASSWORD: MOCK_PASSWORD,
} }
RESPONSE_ERROR = {"success": False, "code": 123, "msg": "Error"}
@pytest.fixture(name="tuya") @pytest.fixture(name="tuya")
def tuya_fixture() -> Mock: def tuya_fixture() -> MagicMock:
"""Patch libraries.""" """Patch libraries."""
with patch("homeassistant.components.tuya.config_flow.TuyaOpenAPI") as tuya: with patch("homeassistant.components.tuya.config_flow.TuyaOpenAPI") as tuya:
yield tuya yield tuya
@pytest.fixture(name="tuya_setup", autouse=True) @pytest.fixture(name="tuya_setup", autouse=True)
def tuya_setup_fixture(): def tuya_setup_fixture() -> None:
"""Mock tuya entry setup.""" """Mock tuya entry setup."""
with patch("homeassistant.components.tuya.async_setup_entry", return_value=True): with patch("homeassistant.components.tuya.async_setup_entry", return_value=True):
yield yield
async def test_industry_user(hass, tuya): @pytest.mark.parametrize(
"""Test industry user config.""" "app_type,side_effects, project_type",
[
("", [RESPONSE_SUCCESS], 1),
(TUYA_SMART_APP, [RESPONSE_ERROR, RESPONSE_SUCCESS], 0),
(SMARTLIFE_APP, [RESPONSE_ERROR, RESPONSE_ERROR, RESPONSE_SUCCESS], 0),
],
)
async def test_user_flow(
hass: HomeAssistant,
tuya: MagicMock,
app_type: str,
side_effects: list[dict[str, Any]],
project_type: int,
):
"""Test user flow."""
result = await hass.config_entries.flow.async_init( result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER} DOMAIN, context={"source": config_entries.SOURCE_USER}
) )
@ -95,17 +86,9 @@ async def test_industry_user(hass, tuya):
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "user" assert result["step_id"] == "user"
tuya().login = MagicMock(side_effect=side_effects)
result = await hass.config_entries.flow.async_configure( result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input=TUYA_INDUSTRY_PROJECT_DATA result["flow_id"], user_input=TUYA_INPUT_DATA
)
await hass.async_block_till_done()
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "login"
tuya().login = MagicMock(return_value={"success": True, "errorCode": 1024})
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input=TUYA_INPUT_INDUSTRY_DATA
) )
await hass.async_block_till_done() await hass.async_block_till_done()
@ -115,90 +98,10 @@ async def test_industry_user(hass, tuya):
assert result["data"][CONF_ACCESS_SECRET] == MOCK_ACCESS_SECRET assert result["data"][CONF_ACCESS_SECRET] == MOCK_ACCESS_SECRET
assert result["data"][CONF_USERNAME] == MOCK_USERNAME assert result["data"][CONF_USERNAME] == MOCK_USERNAME
assert result["data"][CONF_PASSWORD] == MOCK_PASSWORD assert result["data"][CONF_PASSWORD] == MOCK_PASSWORD
assert not result["result"].unique_id assert result["data"][CONF_ENDPOINT] == MOCK_ENDPOINT
assert result["data"][CONF_ENDPOINT] != TUYA_REGIONS[TUYA_INPUT_DATA[CONF_REGION]]
assert result["data"][CONF_APP_TYPE] == app_type
async def test_smart_home_user_base(hass, tuya): assert result["data"][CONF_PROJECT_TYPE] == project_type
"""Test smart home user config base."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "user"
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input=TUYA_SMART_HOME_PROJECT_DATA
)
await hass.async_block_till_done()
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "login"
tuya().login = MagicMock(return_value={"success": False, "errorCode": 1024})
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input=TUYA_IMPORT_SMART_HOME_DATA_BASE
)
await hass.async_block_till_done()
assert result["errors"]["base"] == RESULT_AUTH_FAILED
tuya().login = MagicMock(return_value={"success": True, "errorCode": 1024})
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input=TUYA_IMPORT_SMART_HOME_DATA_BASE
)
await hass.async_block_till_done()
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert result["title"] == MOCK_USERNAME
assert result["data"][CONF_ACCESS_ID] == MOCK_ACCESS_ID
assert result["data"][CONF_ACCESS_SECRET] == MOCK_ACCESS_SECRET
assert result["data"][CONF_USERNAME] == MOCK_USERNAME
assert result["data"][CONF_PASSWORD] == MOCK_PASSWORD
assert result["data"][CONF_COUNTRY_CODE] == MOCK_COUNTRY_CODE_BASE
assert result["data"][CONF_APP_TYPE] == MOCK_APP_TYPE
assert not result["result"].unique_id
async def test_smart_home_user_other(hass, tuya):
"""Test smart home user config other."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": config_entries.SOURCE_USER}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "user"
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input=TUYA_SMART_HOME_PROJECT_DATA
)
await hass.async_block_till_done()
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "login"
tuya().login = MagicMock(return_value={"success": False, "errorCode": 1024})
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input=TUYA_IMPORT_SMART_HOME_DATA_OTHER
)
await hass.async_block_till_done()
assert result["errors"]["base"] == RESULT_AUTH_FAILED
tuya().login = MagicMock(return_value={"success": True, "errorCode": 1024})
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input=TUYA_IMPORT_SMART_HOME_DATA_OTHER
)
await hass.async_block_till_done()
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert result["title"] == MOCK_USERNAME
assert result["data"][CONF_ACCESS_ID] == MOCK_ACCESS_ID
assert result["data"][CONF_ACCESS_SECRET] == MOCK_ACCESS_SECRET
assert result["data"][CONF_USERNAME] == MOCK_USERNAME
assert result["data"][CONF_PASSWORD] == MOCK_PASSWORD
assert result["data"][CONF_COUNTRY_CODE] == MOCK_COUNTRY_CODE_OTHER
assert result["data"][CONF_APP_TYPE] == MOCK_APP_TYPE
assert not result["result"].unique_id assert not result["result"].unique_id
@ -212,18 +115,12 @@ async def test_error_on_invalid_credentials(hass, tuya):
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
assert result["step_id"] == "user" assert result["step_id"] == "user"
tuya().login = MagicMock(return_value=RESPONSE_ERROR)
result = await hass.config_entries.flow.async_configure( result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input=TUYA_INDUSTRY_PROJECT_DATA result["flow_id"], user_input=TUYA_INPUT_DATA
) )
await hass.async_block_till_done() await hass.async_block_till_done()
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM assert result["errors"]["base"] == "login_error"
assert result["step_id"] == "login" assert result["description_placeholders"]["code"] == RESPONSE_ERROR["code"]
assert result["description_placeholders"]["msg"] == RESPONSE_ERROR["msg"]
tuya().login = MagicMock(return_value={"success": False, "errorCode": 1024})
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input=TUYA_INPUT_INDUSTRY_DATA
)
await hass.async_block_till_done()
assert result["errors"]["base"] == RESULT_AUTH_FAILED