mirror of
https://github.com/home-assistant/core.git
synced 2025-07-18 18:57:06 +00:00
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:
parent
8567aa9e13
commit
745298408a
@ -1,10 +1,12 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Config flow for Tuya."""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from tuya_iot import ProjectType, TuyaOpenAPI
|
||||
import voluptuous as vol
|
||||
from voluptuous.schema_builder import UNDEFINED
|
||||
|
||||
from homeassistant import config_entries
|
||||
|
||||
@ -16,131 +18,123 @@ from .const import (
|
||||
CONF_ENDPOINT,
|
||||
CONF_PASSWORD,
|
||||
CONF_PROJECT_TYPE,
|
||||
CONF_REGION,
|
||||
CONF_USERNAME,
|
||||
DOMAIN,
|
||||
TUYA_APP_TYPE,
|
||||
TUYA_ENDPOINT,
|
||||
TUYA_PROJECT_TYPE,
|
||||
SMARTLIFE_APP,
|
||||
TUYA_REGIONS,
|
||||
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__)
|
||||
|
||||
# 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):
|
||||
"""Tuya Config Flow."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
"""Init tuya config flow."""
|
||||
super().__init__()
|
||||
self.conf_project_type = None
|
||||
|
||||
@staticmethod
|
||||
def _try_login(user_input):
|
||||
project_type = ProjectType(user_input[CONF_PROJECT_TYPE])
|
||||
api = TuyaOpenAPI(
|
||||
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")
|
||||
def _try_login(user_input: dict[str, Any]) -> tuple[dict[Any, Any], dict[str, Any]]:
|
||||
"""Try login."""
|
||||
response = {}
|
||||
|
||||
if project_type == ProjectType.INDUSTY_SOLUTIONS:
|
||||
response = api.login(user_input[CONF_USERNAME], user_input[CONF_PASSWORD])
|
||||
else:
|
||||
if user_input[CONF_COUNTRY_CODE] in COUNTRY_CODE_CHINA:
|
||||
api.endpoint = TUYA_ENDPOINT_BASE
|
||||
data = {
|
||||
CONF_ENDPOINT: TUYA_REGIONS[user_input[CONF_REGION]],
|
||||
CONF_PROJECT_TYPE: ProjectType.INDUSTY_SOLUTIONS,
|
||||
CONF_ACCESS_ID: user_input[CONF_ACCESS_ID],
|
||||
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:
|
||||
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(
|
||||
user_input[CONF_USERNAME],
|
||||
user_input[CONF_PASSWORD],
|
||||
user_input[CONF_COUNTRY_CODE],
|
||||
user_input[CONF_APP_TYPE],
|
||||
username=data[CONF_USERNAME],
|
||||
password=data[CONF_PASSWORD],
|
||||
country_code=data[CONF_COUNTRY_CODE],
|
||||
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)
|
||||
return response
|
||||
_LOGGER.debug("Response %s", response)
|
||||
|
||||
if response.get(TUYA_RESPONSE_SUCCESS, False):
|
||||
break
|
||||
|
||||
return response, data
|
||||
|
||||
async def async_step_user(self, user_input=None):
|
||||
"""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 = {}
|
||||
if user_input is not None:
|
||||
assert self.conf_project_type is not None
|
||||
user_input[CONF_PROJECT_TYPE] = self.conf_project_type
|
||||
placeholders = {}
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
if response.get("success", False):
|
||||
_LOGGER.debug("TuyaConfigFlow.async_step_user login success")
|
||||
if response.get(TUYA_RESPONSE_SUCCESS, False):
|
||||
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(
|
||||
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:
|
||||
return self.async_show_form(
|
||||
step_id="login", data_schema=DATA_SCHEMA_SMART_HOME, errors=errors
|
||||
)
|
||||
def _schema_default(key: str) -> str | UNDEFINED:
|
||||
if not user_input:
|
||||
return UNDEFINED
|
||||
return user_input[key]
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="login",
|
||||
data_schema=DATA_SCHEMA_INDUSTRY_SOLUTIONS,
|
||||
step_id="user",
|
||||
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,
|
||||
description_placeholders=placeholders,
|
||||
)
|
||||
|
@ -9,6 +9,7 @@ CONF_ACCESS_ID = "access_id"
|
||||
CONF_ACCESS_SECRET = "access_secret"
|
||||
CONF_USERNAME = "username"
|
||||
CONF_PASSWORD = "password"
|
||||
CONF_REGION = "region"
|
||||
CONF_COUNTRY_CODE = "country_code"
|
||||
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_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_ENDPOINT = {
|
||||
"https://openapi.tuyaus.com": "America",
|
||||
"https://openapi.tuyacn.com": "China",
|
||||
"https://openapi.tuyaeu.com": "Europe",
|
||||
"https://openapi.tuyain.com": "India",
|
||||
"https://openapi-ueaz.tuyaus.com": "EasternAmerica",
|
||||
"https://openapi-weaz.tuyaeu.com": "WesternEurope",
|
||||
TUYA_SMART_APP = "tuyaSmart"
|
||||
SMARTLIFE_APP = "smartlife"
|
||||
|
||||
TUYA_REGIONS = {
|
||||
"America": "https://openapi.tuyaus.com",
|
||||
"China": "https://openapi.tuyacn.com",
|
||||
"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"]
|
||||
|
@ -1,29 +1,20 @@
|
||||
{
|
||||
"config": {
|
||||
"flow_title": "Tuya configuration",
|
||||
"step": {
|
||||
"user":{
|
||||
"title":"Tuya Integration",
|
||||
"data":{
|
||||
"tuya_project_type": "Tuya cloud project type"
|
||||
}
|
||||
},
|
||||
"login": {
|
||||
"title": "Tuya",
|
||||
"description": "Enter your Tuya credential",
|
||||
"user": {
|
||||
"description": "Enter your Tuya credentials",
|
||||
"data": {
|
||||
"endpoint": "Availability Zone",
|
||||
"access_id": "Access ID",
|
||||
"access_secret": "Access Secret",
|
||||
"tuya_app_type": "Mobile App",
|
||||
"country_code": "Country Code",
|
||||
"region": "Region",
|
||||
"access_id": "Tuya IoT Access ID",
|
||||
"access_secret": "Tuya IoT Access Secret",
|
||||
"username": "Account",
|
||||
"password": "Password"
|
||||
"password": "[%key:common::config_flow::data::password%]"
|
||||
}
|
||||
}
|
||||
},
|
||||
"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}"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,78 +1,19 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"cannot_connect": "Failed to connect",
|
||||
"invalid_auth": "Invalid authentication",
|
||||
"single_instance_allowed": "Already configured. Only a single configuration possible."
|
||||
},
|
||||
"error": {
|
||||
"invalid_auth": "Invalid authentication"
|
||||
"invalid_auth": "Invalid authentication",
|
||||
"login_error": "Login error ({code}): {msg}"
|
||||
},
|
||||
"flow_title": "Tuya configuration",
|
||||
"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": {
|
||||
"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",
|
||||
"platform": "The app where your account is registered",
|
||||
"tuya_project_type": "Tuya cloud project type",
|
||||
"username": "Username"
|
||||
"region": "Region",
|
||||
"username": "Account"
|
||||
},
|
||||
"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"
|
||||
"description": "Enter your Tuya credentials"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,93 +1,84 @@
|
||||
"""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
|
||||
|
||||
from homeassistant import config_entries, data_entry_flow
|
||||
from homeassistant.components.tuya.config_flow import RESULT_AUTH_FAILED
|
||||
from homeassistant.components.tuya.const import (
|
||||
CONF_ACCESS_ID,
|
||||
CONF_ACCESS_SECRET,
|
||||
CONF_APP_TYPE,
|
||||
CONF_COUNTRY_CODE,
|
||||
CONF_ENDPOINT,
|
||||
CONF_PASSWORD,
|
||||
CONF_PROJECT_TYPE,
|
||||
CONF_REGION,
|
||||
CONF_USERNAME,
|
||||
DOMAIN,
|
||||
SMARTLIFE_APP,
|
||||
TUYA_REGIONS,
|
||||
TUYA_SMART_APP,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
MOCK_SMART_HOME_PROJECT_TYPE = 0
|
||||
MOCK_INDUSTRY_PROJECT_TYPE = 1
|
||||
|
||||
MOCK_REGION = "Europe"
|
||||
MOCK_ACCESS_ID = "myAccessId"
|
||||
MOCK_ACCESS_SECRET = "myAccessSecret"
|
||||
MOCK_USERNAME = "myUsername"
|
||||
MOCK_PASSWORD = "myPassword"
|
||||
MOCK_COUNTRY_CODE_BASE = "86"
|
||||
MOCK_COUNTRY_CODE_OTHER = "1"
|
||||
MOCK_APP_TYPE = "smartlife"
|
||||
MOCK_ENDPOINT = "https://openapi-ueaz.tuyaus.com"
|
||||
|
||||
TUYA_SMART_HOME_PROJECT_DATA = {
|
||||
CONF_PROJECT_TYPE: MOCK_SMART_HOME_PROJECT_TYPE,
|
||||
}
|
||||
TUYA_INDUSTRY_PROJECT_DATA = {
|
||||
CONF_PROJECT_TYPE: MOCK_INDUSTRY_PROJECT_TYPE,
|
||||
}
|
||||
|
||||
TUYA_INPUT_INDUSTRY_DATA = {
|
||||
CONF_ENDPOINT: MOCK_ENDPOINT,
|
||||
TUYA_INPUT_DATA = {
|
||||
CONF_REGION: MOCK_REGION,
|
||||
CONF_ACCESS_ID: MOCK_ACCESS_ID,
|
||||
CONF_ACCESS_SECRET: MOCK_ACCESS_SECRET,
|
||||
CONF_USERNAME: MOCK_USERNAME,
|
||||
CONF_PASSWORD: MOCK_PASSWORD,
|
||||
}
|
||||
|
||||
TUYA_IMPORT_SMART_HOME_DATA_BASE = {
|
||||
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_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_SUCCESS = {
|
||||
"success": True,
|
||||
"code": 1024,
|
||||
"result": {"platform_url": MOCK_ENDPOINT},
|
||||
}
|
||||
RESPONSE_ERROR = {"success": False, "code": 123, "msg": "Error"}
|
||||
|
||||
|
||||
@pytest.fixture(name="tuya")
|
||||
def tuya_fixture() -> Mock:
|
||||
def tuya_fixture() -> MagicMock:
|
||||
"""Patch libraries."""
|
||||
with patch("homeassistant.components.tuya.config_flow.TuyaOpenAPI") as tuya:
|
||||
yield tuya
|
||||
|
||||
|
||||
@pytest.fixture(name="tuya_setup", autouse=True)
|
||||
def tuya_setup_fixture():
|
||||
def tuya_setup_fixture() -> None:
|
||||
"""Mock tuya entry setup."""
|
||||
with patch("homeassistant.components.tuya.async_setup_entry", return_value=True):
|
||||
yield
|
||||
|
||||
|
||||
async def test_industry_user(hass, tuya):
|
||||
"""Test industry user config."""
|
||||
@pytest.mark.parametrize(
|
||||
"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(
|
||||
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["step_id"] == "user"
|
||||
|
||||
tuya().login = MagicMock(side_effect=side_effects)
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], user_input=TUYA_INDUSTRY_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": True, "errorCode": 1024})
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"], user_input=TUYA_INPUT_INDUSTRY_DATA
|
||||
result["flow_id"], user_input=TUYA_INPUT_DATA
|
||||
)
|
||||
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_USERNAME] == MOCK_USERNAME
|
||||
assert result["data"][CONF_PASSWORD] == MOCK_PASSWORD
|
||||
assert not result["result"].unique_id
|
||||
|
||||
|
||||
async def test_smart_home_user_base(hass, tuya):
|
||||
"""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 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
|
||||
assert result["data"][CONF_PROJECT_TYPE] == project_type
|
||||
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["step_id"] == "user"
|
||||
|
||||
tuya().login = MagicMock(return_value=RESPONSE_ERROR)
|
||||
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": 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
|
||||
assert result["errors"]["base"] == "login_error"
|
||||
assert result["description_placeholders"]["code"] == RESPONSE_ERROR["code"]
|
||||
assert result["description_placeholders"]["msg"] == RESPONSE_ERROR["msg"]
|
||||
|
Loading…
x
Reference in New Issue
Block a user