Reinstate asking for country in Tuya flow (#57142)

This commit is contained in:
Paulus Schoutsen 2021-10-05 13:32:48 -07:00 committed by GitHub
parent f76cb12945
commit 34544da449
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 312 additions and 100 deletions

View File

@ -44,7 +44,10 @@ _LOGGER = logging.getLogger(__name__)
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Async setup hass config entry."""
hass.data[DOMAIN] = {entry.entry_id: {TUYA_HA_TUYA_MAP: {}, TUYA_HA_DEVICES: set()}}
hass.data.setdefault(DOMAIN, {})[entry.entry_id] = {
TUYA_HA_TUYA_MAP: {},
TUYA_HA_DEVICES: set(),
}
# Project type has been renamed to auth type in the upstream Tuya IoT SDK.
# This migrates existing config entries to reflect that name change.
@ -54,6 +57,13 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
hass.config_entries.async_update_entry(entry, data=data)
success = await _init_tuya_sdk(hass, entry)
if not success:
hass.data[DOMAIN].pop(entry.entry_id)
if not hass.data[DOMAIN]:
hass.data.pop(DOMAIN)
return bool(success)
@ -143,6 +153,9 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
hass.data[DOMAIN][entry.entry_id][TUYA_MQTT_LISTENER]
)
hass.data[DOMAIN].pop(entry.entry_id)
if not hass.data[DOMAIN]:
hass.data.pop(DOMAIN)
return unload

View File

@ -6,7 +6,6 @@ from typing import Any
from tuya_iot import AuthType, TuyaOpenAPI
import voluptuous as vol
from voluptuous.schema_builder import UNDEFINED
from homeassistant import config_entries
@ -18,11 +17,10 @@ from .const import (
CONF_COUNTRY_CODE,
CONF_ENDPOINT,
CONF_PASSWORD,
CONF_REGION,
CONF_USERNAME,
DOMAIN,
SMARTLIFE_APP,
TUYA_REGIONS,
TUYA_COUNTRIES,
TUYA_RESPONSE_CODE,
TUYA_RESPONSE_MSG,
TUYA_RESPONSE_PLATFROM_URL,
@ -42,14 +40,20 @@ class TuyaConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
"""Try login."""
response = {}
country = [
country
for country in TUYA_COUNTRIES
if country.name == user_input[CONF_COUNTRY_CODE]
][0]
data = {
CONF_ENDPOINT: TUYA_REGIONS[user_input[CONF_REGION]],
CONF_ENDPOINT: country.endpoint,
CONF_AUTH_TYPE: AuthType.CUSTOM,
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],
CONF_COUNTRY_CODE: country.country_code,
}
for app_type in ("", TUYA_SMART_APP, SMARTLIFE_APP):
@ -109,29 +113,32 @@ class TuyaConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
TUYA_RESPONSE_MSG: response.get(TUYA_RESPONSE_MSG),
}
def _schema_default(key: str) -> str | UNDEFINED:
if not user_input:
return UNDEFINED
return user_input[key]
if user_input is None:
user_input = {}
return self.async_show_form(
step_id="user",
data_schema=vol.Schema(
{
vol.Required(
CONF_REGION, default=_schema_default(CONF_REGION)
): vol.In(TUYA_REGIONS.keys()),
CONF_COUNTRY_CODE,
default=user_input.get(CONF_COUNTRY_CODE, "United States"),
): vol.In(
# We don't pass a dict {code:name} because country codes can be duplicate.
[country.name for country in TUYA_COUNTRIES]
),
vol.Required(
CONF_ACCESS_ID, default=_schema_default(CONF_ACCESS_ID)
CONF_ACCESS_ID, default=user_input.get(CONF_ACCESS_ID, "")
): str,
vol.Required(
CONF_ACCESS_SECRET, default=_schema_default(CONF_ACCESS_SECRET)
CONF_ACCESS_SECRET,
default=user_input.get(CONF_ACCESS_SECRET, ""),
): str,
vol.Required(
CONF_USERNAME, default=_schema_default(CONF_USERNAME)
CONF_USERNAME, default=user_input.get(CONF_USERNAME, "")
): str,
vol.Required(
CONF_PASSWORD, default=_schema_default(CONF_PASSWORD)
CONF_PASSWORD, default=user_input.get(CONF_PASSWORD, "")
): str,
}
),

View File

@ -1,4 +1,5 @@
"""Constants for the Tuya integration."""
from dataclasses import dataclass
DOMAIN = "tuya"
@ -9,7 +10,6 @@ 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"
@ -31,13 +31,265 @@ TUYA_HA_SIGNAL_UPDATE_ENTITY = "tuya_entry_update"
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",
}
ENDPOINT_AMERICA = "https://openapi.tuyaus.com"
ENDPOINT_CHINA = "https://openapi.tuyacn.com"
ENDPOINT_EASTERN_AMERICA = "https://openapi-ueaz.tuyaus.com"
ENDPOINT_EUROPE = "https://openapi.tuyaeu.com"
ENDPOINT_INDIA = "https://openapi.tuyain.com"
ENDPOINT_WESTERN_EUROPE = "https://openapi-weaz.tuyaeu.com"
PLATFORMS = ["climate", "fan", "light", "scene", "switch"]
@dataclass
class Country:
"""Describe a supported country."""
name: str
country_code: str
endpoint: str = ENDPOINT_AMERICA
# https://developer.tuya.com/en/docs/iot/oem-app-data-center-distributed?id=Kafi0ku9l07qb#title-4-China%20Data%20Center
TUYA_COUNTRIES = [
Country("Afghanistan", "93"),
Country("Albania", "355"),
Country("Algeria", "213"),
Country("American Samoa", "1-684"),
Country("Andorra", "376"),
Country("Angola", "244"),
Country("Anguilla", "1-264"),
Country("Antarctica", "672"),
Country("Antigua and Barbuda", "1-268"),
Country("Argentina", "54", ENDPOINT_EUROPE),
Country("Armenia", "374"),
Country("Aruba", "297"),
Country("Australia", "61"),
Country("Austria", "43", ENDPOINT_EUROPE),
Country("Azerbaijan", "994"),
Country("Bahamas", "1-242"),
Country("Bahrain", "973"),
Country("Bangladesh", "880"),
Country("Barbados", "1-246"),
Country("Belarus", "375"),
Country("Belgium", "32", ENDPOINT_EUROPE),
Country("Belize", "501"),
Country("Benin", "229"),
Country("Bermuda", "1-441"),
Country("Bhutan", "975"),
Country("Bolivia", "591"),
Country("Bosnia and Herzegovina", "387"),
Country("Botswana", "267"),
Country("Brazil", "55", ENDPOINT_EUROPE),
Country("British Indian Ocean Territory", "246"),
Country("British Virgin Islands", "1-284"),
Country("Brunei", "673"),
Country("Bulgaria", "359"),
Country("Burkina Faso", "226"),
Country("Burundi", "257"),
Country("Cambodia", "855"),
Country("Cameroon", "237"),
Country("Canada", "1", ENDPOINT_AMERICA),
Country("Cape Verde", "238"),
Country("Cayman Islands", "1-345"),
Country("Central African Republic", "236"),
Country("Chad", "235"),
Country("Chile", "56"),
Country("China", "86", ENDPOINT_CHINA),
Country("Christmas Island", "61"),
Country("Cocos Islands", "61"),
Country("Colombia", "57"),
Country("Comoros", "269"),
Country("Cook Islands", "682"),
Country("Costa Rica", "506"),
Country("Croatia", "385", ENDPOINT_EUROPE),
Country("Cuba", "53"),
Country("Curacao", "599"),
Country("Cyprus", "357", ENDPOINT_EUROPE),
Country("Czech Republic", "420", ENDPOINT_EUROPE),
Country("Democratic Republic of the Congo", "243"),
Country("Denmark", "45", ENDPOINT_EUROPE),
Country("Djibouti", "253"),
Country("Dominica", "1-767"),
Country("Dominican Republic", "1-809"),
Country("East Timor", "670"),
Country("Ecuador", "593"),
Country("Egypt", "20"),
Country("El Salvador", "503"),
Country("Equatorial Guinea", "240"),
Country("Eritrea", "291"),
Country("Estonia", "372", ENDPOINT_EUROPE),
Country("Ethiopia", "251"),
Country("Falkland Islands", "500"),
Country("Faroe Islands", "298"),
Country("Fiji", "679"),
Country("Finland", "358", ENDPOINT_EUROPE),
Country("France", "33", ENDPOINT_EUROPE),
Country("French Polynesia", "689"),
Country("Gabon", "241"),
Country("Gambia", "220"),
Country("Georgia", "995"),
Country("Germany", "49", ENDPOINT_EUROPE),
Country("Ghana", "233"),
Country("Gibraltar", "350"),
Country("Greece", "30", ENDPOINT_EUROPE),
Country("Greenland", "299"),
Country("Grenada", "1-473"),
Country("Guam", "1-671"),
Country("Guatemala", "502"),
Country("Guernsey", "44-1481"),
Country("Guinea", "224"),
Country("Guinea-Bissau", "245"),
Country("Guyana", "592"),
Country("Haiti", "509"),
Country("Honduras", "504"),
Country("Hong Kong", "852"),
Country("Hungary", "36", ENDPOINT_EUROPE),
Country("Iceland", "354", ENDPOINT_EUROPE),
Country("India", "91", ENDPOINT_INDIA),
Country("Indonesia", "62"),
Country("Iran", "98"),
Country("Iraq", "964"),
Country("Ireland", "353", ENDPOINT_EUROPE),
Country("Isle of Man", "44-1624"),
Country("Israel", "972"),
Country("Italy", "39", ENDPOINT_EUROPE),
Country("Ivory Coast", "225"),
Country("Jamaica", "1-876"),
Country("Japan", "81", ENDPOINT_EUROPE),
Country("Jersey", "44-1534"),
Country("Jordan", "962"),
Country("Kazakhstan", "7"),
Country("Kenya", "254"),
Country("Kiribati", "686"),
Country("Kosovo", "383"),
Country("Kuwait", "965"),
Country("Kyrgyzstan", "996"),
Country("Laos", "856"),
Country("Latvia", "371", ENDPOINT_EUROPE),
Country("Lebanon", "961"),
Country("Lesotho", "266"),
Country("Liberia", "231"),
Country("Libya", "218"),
Country("Liechtenstein", "423", ENDPOINT_EUROPE),
Country("Lithuania", "370", ENDPOINT_EUROPE),
Country("Luxembourg", "352", ENDPOINT_EUROPE),
Country("Macau", "853"),
Country("Macedonia", "389"),
Country("Madagascar", "261"),
Country("Malawi", "265"),
Country("Malaysia", "60"),
Country("Maldives", "960"),
Country("Mali", "223"),
Country("Malta", "356", ENDPOINT_EUROPE),
Country("Marshall Islands", "692"),
Country("Mauritania", "222"),
Country("Mauritius", "230"),
Country("Mayotte", "262"),
Country("Mexico", "52"),
Country("Micronesia", "691"),
Country("Moldova", "373"),
Country("Monaco", "377"),
Country("Mongolia", "976"),
Country("Montenegro", "382"),
Country("Montserrat", "1-664"),
Country("Morocco", "212"),
Country("Mozambique", "258"),
Country("Myanmar", "95"),
Country("Namibia", "264"),
Country("Nauru", "674"),
Country("Nepal", "977"),
Country("Netherlands", "31", ENDPOINT_EUROPE),
Country("Netherlands Antilles", "599"),
Country("New Caledonia", "687"),
Country("New Zealand", "64"),
Country("Nicaragua", "505"),
Country("Niger", "227"),
Country("Nigeria", "234"),
Country("Niue", "683"),
Country("North Korea", "850"),
Country("Northern Mariana Islands", "1-670"),
Country("Norway", "47"),
Country("Oman", "968"),
Country("Pakistan", "92"),
Country("Palau", "680"),
Country("Palestine", "970"),
Country("Panama", "507"),
Country("Papua New Guinea", "675"),
Country("Paraguay", "595"),
Country("Peru", "51"),
Country("Philippines", "63"),
Country("Pitcairn", "64"),
Country("Poland", "48", ENDPOINT_EUROPE),
Country("Portugal", "351", ENDPOINT_EUROPE),
Country("Puerto Rico", "1-787, 1-939"),
Country("Qatar", "974"),
Country("Republic of the Congo", "242"),
Country("Reunion", "262"),
Country("Romania", "40", ENDPOINT_EUROPE),
Country("Russia", "7", ENDPOINT_EUROPE),
Country("Rwanda", "250"),
Country("Saint Barthelemy", "590"),
Country("Saint Helena", "290"),
Country("Saint Kitts and Nevis", "1-869"),
Country("Saint Lucia", "1-758"),
Country("Saint Martin", "590"),
Country("Saint Pierre and Miquelon", "508"),
Country("Saint Vincent and the Grenadines", "1-784"),
Country("Samoa", "685"),
Country("San Marino", "378"),
Country("Sao Tome and Principe", "239"),
Country("Saudi Arabia", "966"),
Country("Senegal", "221"),
Country("Serbia", "381"),
Country("Seychelles", "248"),
Country("Sierra Leone", "232"),
Country("Singapore", "65"),
Country("Sint Maarten", "1-721"),
Country("Slovakia", "421", ENDPOINT_EUROPE),
Country("Slovenia", "386", ENDPOINT_EUROPE),
Country("Solomon Islands", "677"),
Country("Somalia", "252"),
Country("South Africa", "27"),
Country("South Korea", "82"),
Country("South Sudan", "211"),
Country("Spain", "34", ENDPOINT_EUROPE),
Country("Sri Lanka", "94"),
Country("Sudan", "249"),
Country("Suriname", "597"),
Country("Svalbard and Jan Mayen", "47", ENDPOINT_EUROPE),
Country("Swaziland", "268"),
Country("Sweden", "46", ENDPOINT_EUROPE),
Country("Switzerland", "41"),
Country("Syria", "963"),
Country("Taiwan", "886"),
Country("Tajikistan", "992"),
Country("Tanzania", "255"),
Country("Thailand", "66"),
Country("Togo", "228"),
Country("Tokelau", "690"),
Country("Tonga", "676"),
Country("Trinidad and Tobago", "1-868"),
Country("Tunisia", "216"),
Country("Turkey", "90"),
Country("Turkmenistan", "993"),
Country("Turks and Caicos Islands", "1-649"),
Country("Tuvalu", "688"),
Country("U.S. Virgin Islands", "1-340"),
Country("Uganda", "256"),
Country("Ukraine", "380"),
Country("United Arab Emirates", "971"),
Country("United Kingdom", "44", ENDPOINT_EUROPE),
Country("United States", "1", ENDPOINT_AMERICA),
Country("Uruguay", "598"),
Country("Uzbekistan", "998"),
Country("Vanuatu", "678"),
Country("Vatican", "379"),
Country("Venezuela", "58"),
Country("Vietnam", "84"),
Country("Wallis and Futuna", "681"),
Country("Western Sahara", "212"),
Country("Yemen", "967"),
Country("Zambia", "260"),
Country("Zimbabwe", "263"),
]

View File

@ -4,7 +4,7 @@
"user": {
"description": "Enter your Tuya credentials",
"data": {
"region": "Region",
"country_code": "Country",
"access_id": "Tuya IoT Access ID",
"access_secret": "Tuya IoT Access Secret",
"username": "Account",

View File

@ -1,82 +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",
"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": {
"access_id": "Tuya IoT Access ID",
"access_secret": "Tuya IoT Access Secret",
"country_code": "Your account country code (e.g., 1 for USA or 86 for China)",
"country_code": "Country",
"password": "Password",
"platform": "The app where your account is registered",
"region": "Region",
"tuya_project_type": "Tuya cloud project type",
"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"
}
}
}

View File

@ -12,13 +12,14 @@ from homeassistant.components.tuya.const import (
CONF_ACCESS_SECRET,
CONF_APP_TYPE,
CONF_AUTH_TYPE,
CONF_COUNTRY_CODE,
CONF_ENDPOINT,
CONF_PASSWORD,
CONF_REGION,
CONF_USERNAME,
DOMAIN,
ENDPOINT_INDIA,
SMARTLIFE_APP,
TUYA_REGIONS,
TUYA_COUNTRIES,
TUYA_SMART_APP,
)
from homeassistant.core import HomeAssistant
@ -26,15 +27,15 @@ from homeassistant.core import HomeAssistant
MOCK_SMART_HOME_PROJECT_TYPE = 0
MOCK_INDUSTRY_PROJECT_TYPE = 1
MOCK_REGION = "Europe"
MOCK_COUNTRY = "India"
MOCK_ACCESS_ID = "myAccessId"
MOCK_ACCESS_SECRET = "myAccessSecret"
MOCK_USERNAME = "myUsername"
MOCK_PASSWORD = "myPassword"
MOCK_ENDPOINT = "https://openapi-ueaz.tuyaus.com"
MOCK_ENDPOINT = ENDPOINT_INDIA
TUYA_INPUT_DATA = {
CONF_REGION: MOCK_REGION,
CONF_COUNTRY_CODE: MOCK_COUNTRY,
CONF_ACCESS_ID: MOCK_ACCESS_ID,
CONF_ACCESS_SECRET: MOCK_ACCESS_SECRET,
CONF_USERNAME: MOCK_USERNAME,
@ -92,16 +93,18 @@ async def test_user_flow(
)
await hass.async_block_till_done()
country = [country for country in TUYA_COUNTRIES if country.name == MOCK_COUNTRY][0]
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_ENDPOINT] == MOCK_ENDPOINT
assert result["data"][CONF_ENDPOINT] != TUYA_REGIONS[TUYA_INPUT_DATA[CONF_REGION]]
assert result["data"][CONF_ENDPOINT] == country.endpoint
assert result["data"][CONF_APP_TYPE] == app_type
assert result["data"][CONF_AUTH_TYPE] == project_type
assert result["data"][CONF_COUNTRY_CODE] == country.country_code
assert not result["result"].unique_id