mirror of
https://github.com/home-assistant/core.git
synced 2025-12-24 12:59:34 +00:00
Improve Growatt Server config flow with region dropdown (#159329)
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -16,6 +16,7 @@ from homeassistant.const import (
|
|||||||
CONF_USERNAME,
|
CONF_USERNAME,
|
||||||
)
|
)
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
|
from homeassistant.helpers.selector import SelectSelector, SelectSelectorConfig
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
ABORT_NO_PLANTS,
|
ABORT_NO_PLANTS,
|
||||||
@@ -23,12 +24,13 @@ from .const import (
|
|||||||
AUTH_PASSWORD,
|
AUTH_PASSWORD,
|
||||||
CONF_AUTH_TYPE,
|
CONF_AUTH_TYPE,
|
||||||
CONF_PLANT_ID,
|
CONF_PLANT_ID,
|
||||||
|
CONF_REGION,
|
||||||
DEFAULT_URL,
|
DEFAULT_URL,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
ERROR_CANNOT_CONNECT,
|
ERROR_CANNOT_CONNECT,
|
||||||
ERROR_INVALID_AUTH,
|
ERROR_INVALID_AUTH,
|
||||||
LOGIN_INVALID_AUTH_CODE,
|
LOGIN_INVALID_AUTH_CODE,
|
||||||
SERVER_URLS,
|
SERVER_URLS_NAMES,
|
||||||
)
|
)
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
@@ -67,10 +69,13 @@ class GrowattServerConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
self.auth_type = AUTH_PASSWORD
|
self.auth_type = AUTH_PASSWORD
|
||||||
|
|
||||||
# Traditional username/password authentication
|
# Traditional username/password authentication
|
||||||
|
# Convert region name to URL - guaranteed to exist since vol.In validates it
|
||||||
|
server_url = SERVER_URLS_NAMES[user_input[CONF_REGION]]
|
||||||
|
|
||||||
self.api = growattServer.GrowattApi(
|
self.api = growattServer.GrowattApi(
|
||||||
add_random_user_id=True, agent_identifier=user_input[CONF_USERNAME]
|
add_random_user_id=True, agent_identifier=user_input[CONF_USERNAME]
|
||||||
)
|
)
|
||||||
self.api.server_url = user_input[CONF_URL]
|
self.api.server_url = server_url
|
||||||
|
|
||||||
try:
|
try:
|
||||||
login_response = await self.hass.async_add_executor_job(
|
login_response = await self.hass.async_add_executor_job(
|
||||||
@@ -91,6 +96,8 @@ class GrowattServerConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
|
|
||||||
self.user_id = login_response["user"]["id"]
|
self.user_id = login_response["user"]["id"]
|
||||||
self.data = user_input
|
self.data = user_input
|
||||||
|
# Store the actual URL, not the region name
|
||||||
|
self.data[CONF_URL] = server_url
|
||||||
self.data[CONF_AUTH_TYPE] = self.auth_type
|
self.data[CONF_AUTH_TYPE] = self.auth_type
|
||||||
return await self.async_step_plant()
|
return await self.async_step_plant()
|
||||||
|
|
||||||
@@ -104,8 +111,11 @@ class GrowattServerConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
self.auth_type = AUTH_API_TOKEN
|
self.auth_type = AUTH_API_TOKEN
|
||||||
|
|
||||||
# Using token authentication
|
# Using token authentication
|
||||||
token = user_input[CONF_TOKEN]
|
# Convert region name to URL - guaranteed to exist since vol.In validates it
|
||||||
self.api = growattServer.OpenApiV1(token=token)
|
server_url = SERVER_URLS_NAMES[user_input[CONF_REGION]]
|
||||||
|
|
||||||
|
self.api = growattServer.OpenApiV1(token=user_input[CONF_TOKEN])
|
||||||
|
self.api.server_url = server_url
|
||||||
|
|
||||||
# Verify token by fetching plant list
|
# Verify token by fetching plant list
|
||||||
try:
|
try:
|
||||||
@@ -127,6 +137,8 @@ class GrowattServerConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
)
|
)
|
||||||
return self._async_show_token_form({"base": ERROR_CANNOT_CONNECT})
|
return self._async_show_token_form({"base": ERROR_CANNOT_CONNECT})
|
||||||
self.data = user_input
|
self.data = user_input
|
||||||
|
# Store the actual URL, not the region name
|
||||||
|
self.data[CONF_URL] = server_url
|
||||||
self.data[CONF_AUTH_TYPE] = self.auth_type
|
self.data[CONF_AUTH_TYPE] = self.auth_type
|
||||||
return await self.async_step_plant()
|
return await self.async_step_plant()
|
||||||
|
|
||||||
@@ -139,7 +151,12 @@ class GrowattServerConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
{
|
{
|
||||||
vol.Required(CONF_USERNAME): str,
|
vol.Required(CONF_USERNAME): str,
|
||||||
vol.Required(CONF_PASSWORD): str,
|
vol.Required(CONF_PASSWORD): str,
|
||||||
vol.Required(CONF_URL, default=DEFAULT_URL): vol.In(SERVER_URLS),
|
vol.Required(CONF_REGION, default=DEFAULT_URL): SelectSelector(
|
||||||
|
SelectSelectorConfig(
|
||||||
|
options=list(SERVER_URLS_NAMES.keys()),
|
||||||
|
translation_key="region",
|
||||||
|
)
|
||||||
|
),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -155,6 +172,12 @@ class GrowattServerConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||||||
data_schema = vol.Schema(
|
data_schema = vol.Schema(
|
||||||
{
|
{
|
||||||
vol.Required(CONF_TOKEN): str,
|
vol.Required(CONF_TOKEN): str,
|
||||||
|
vol.Required(CONF_REGION, default=DEFAULT_URL): SelectSelector(
|
||||||
|
SelectSelectorConfig(
|
||||||
|
options=list(SERVER_URLS_NAMES.keys()),
|
||||||
|
translation_key="region",
|
||||||
|
)
|
||||||
|
),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
from homeassistant.const import Platform
|
from homeassistant.const import Platform
|
||||||
|
|
||||||
CONF_PLANT_ID = "plant_id"
|
CONF_PLANT_ID = "plant_id"
|
||||||
|
CONF_REGION = "region"
|
||||||
|
|
||||||
|
|
||||||
# API key support
|
# API key support
|
||||||
@@ -18,13 +19,14 @@ DEFAULT_PLANT_ID = "0"
|
|||||||
|
|
||||||
DEFAULT_NAME = "Growatt"
|
DEFAULT_NAME = "Growatt"
|
||||||
|
|
||||||
SERVER_URLS = [
|
SERVER_URLS_NAMES = {
|
||||||
"https://openapi.growatt.com/", # Other regional server
|
"north_america": "https://openapi-us.growatt.com/",
|
||||||
"https://openapi-cn.growatt.com/", # Chinese server
|
"australia_new_zealand": "https://openapi-au.growatt.com/",
|
||||||
"https://openapi-us.growatt.com/", # North American server
|
"china": "https://openapi-cn.growatt.com/",
|
||||||
"https://openapi-au.growatt.com/", # Australia Server
|
"other_regions": "https://openapi.growatt.com/",
|
||||||
"http://server.smten.com/", # smten server
|
"smten_server": "http://server.smten.com/",
|
||||||
]
|
"era_server": "http://ess-server.atesspower.com/",
|
||||||
|
}
|
||||||
|
|
||||||
DEPRECATED_URLS = [
|
DEPRECATED_URLS = [
|
||||||
"https://server.growatt.com/",
|
"https://server.growatt.com/",
|
||||||
@@ -32,7 +34,7 @@ DEPRECATED_URLS = [
|
|||||||
"https://server-us.growatt.com/",
|
"https://server-us.growatt.com/",
|
||||||
]
|
]
|
||||||
|
|
||||||
DEFAULT_URL = SERVER_URLS[0]
|
DEFAULT_URL = "other_regions"
|
||||||
|
|
||||||
DOMAIN = "growatt_server"
|
DOMAIN = "growatt_server"
|
||||||
|
|
||||||
|
|||||||
@@ -24,9 +24,7 @@ rules:
|
|||||||
# Silver
|
# Silver
|
||||||
action-exceptions: done
|
action-exceptions: done
|
||||||
config-entry-unloading: done
|
config-entry-unloading: done
|
||||||
docs-configuration-parameters:
|
docs-configuration-parameters: done
|
||||||
status: todo
|
|
||||||
comment: Update server URL dropdown to show regional descriptions (e.g., 'China', 'United States') instead of raw URLs.
|
|
||||||
docs-installation-parameters: todo
|
docs-installation-parameters: todo
|
||||||
entity-unavailable: done
|
entity-unavailable: done
|
||||||
integration-owner: done
|
integration-owner: done
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
"password_auth": {
|
"password_auth": {
|
||||||
"data": {
|
"data": {
|
||||||
"password": "[%key:common::config_flow::data::password%]",
|
"password": "[%key:common::config_flow::data::password%]",
|
||||||
"url": "[%key:common::config_flow::data::url%]",
|
"url": "Server region",
|
||||||
"username": "[%key:common::config_flow::data::username%]"
|
"username": "[%key:common::config_flow::data::username%]"
|
||||||
},
|
},
|
||||||
"title": "Enter your Growatt login credentials"
|
"title": "Enter your Growatt login credentials"
|
||||||
@@ -26,7 +26,8 @@
|
|||||||
},
|
},
|
||||||
"token_auth": {
|
"token_auth": {
|
||||||
"data": {
|
"data": {
|
||||||
"token": "API Token"
|
"token": "API Token",
|
||||||
|
"url": "Server region"
|
||||||
},
|
},
|
||||||
"description": "Token authentication is only supported for MIN/TLX devices. For other device types, please use username/password authentication.",
|
"description": "Token authentication is only supported for MIN/TLX devices. For other device types, please use username/password authentication.",
|
||||||
"title": "Enter your API token"
|
"title": "Enter your API token"
|
||||||
@@ -530,6 +531,16 @@
|
|||||||
"grid_first": "Grid first",
|
"grid_first": "Grid first",
|
||||||
"load_first": "Load first"
|
"load_first": "Load first"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"region": {
|
||||||
|
"options": {
|
||||||
|
"australia_new_zealand": "Australia and New Zealand",
|
||||||
|
"china": "China",
|
||||||
|
"era_server": "Era server (Atess Power)",
|
||||||
|
"north_america": "North America",
|
||||||
|
"other_regions": "Other regions",
|
||||||
|
"smten_server": "SMTEN server"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"services": {
|
"services": {
|
||||||
|
|||||||
@@ -13,19 +13,14 @@ from homeassistant.components.growatt_server.const import (
|
|||||||
AUTH_PASSWORD,
|
AUTH_PASSWORD,
|
||||||
CONF_AUTH_TYPE,
|
CONF_AUTH_TYPE,
|
||||||
CONF_PLANT_ID,
|
CONF_PLANT_ID,
|
||||||
|
CONF_REGION,
|
||||||
DEFAULT_URL,
|
DEFAULT_URL,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
ERROR_CANNOT_CONNECT,
|
ERROR_CANNOT_CONNECT,
|
||||||
ERROR_INVALID_AUTH,
|
ERROR_INVALID_AUTH,
|
||||||
LOGIN_INVALID_AUTH_CODE,
|
LOGIN_INVALID_AUTH_CODE,
|
||||||
)
|
)
|
||||||
from homeassistant.const import (
|
from homeassistant.const import CONF_NAME, CONF_PASSWORD, CONF_TOKEN, CONF_USERNAME
|
||||||
CONF_NAME,
|
|
||||||
CONF_PASSWORD,
|
|
||||||
CONF_TOKEN,
|
|
||||||
CONF_URL,
|
|
||||||
CONF_USERNAME,
|
|
||||||
)
|
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.data_entry_flow import FlowResultType
|
from homeassistant.data_entry_flow import FlowResultType
|
||||||
|
|
||||||
@@ -34,11 +29,12 @@ from tests.common import MockConfigEntry
|
|||||||
FIXTURE_USER_INPUT_PASSWORD = {
|
FIXTURE_USER_INPUT_PASSWORD = {
|
||||||
CONF_USERNAME: "username",
|
CONF_USERNAME: "username",
|
||||||
CONF_PASSWORD: "password",
|
CONF_PASSWORD: "password",
|
||||||
CONF_URL: DEFAULT_URL,
|
CONF_REGION: DEFAULT_URL,
|
||||||
}
|
}
|
||||||
|
|
||||||
FIXTURE_USER_INPUT_TOKEN = {
|
FIXTURE_USER_INPUT_TOKEN = {
|
||||||
CONF_TOKEN: "test_api_token_12345",
|
CONF_TOKEN: "test_api_token_12345",
|
||||||
|
CONF_REGION: DEFAULT_URL,
|
||||||
}
|
}
|
||||||
|
|
||||||
GROWATT_PLANT_LIST_RESPONSE = {
|
GROWATT_PLANT_LIST_RESPONSE = {
|
||||||
@@ -109,8 +105,8 @@ async def test_show_auth_menu(hass: HomeAssistant) -> None:
|
|||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
("auth_type", "expected_fields"),
|
("auth_type", "expected_fields"),
|
||||||
[
|
[
|
||||||
("password_auth", [CONF_USERNAME, CONF_PASSWORD, CONF_URL]),
|
("password_auth", [CONF_USERNAME, CONF_PASSWORD, CONF_REGION]),
|
||||||
("token_auth", [CONF_TOKEN]),
|
("token_auth", [CONF_TOKEN, CONF_REGION]),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_auth_form_display(
|
async def test_auth_form_display(
|
||||||
|
|||||||
Reference in New Issue
Block a user