Improve config flow for GIOS (#139935)

* Initial commit

* Use TYPE_CHECKING

* Update strings

* Remove default value

* Improve tests
This commit is contained in:
Maciej Bieniek 2025-03-11 12:52:40 +01:00 committed by GitHub
parent d3a96ba688
commit 98cf936ff5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 79 additions and 46 deletions

View File

@ -3,7 +3,7 @@
from __future__ import annotations
import asyncio
from typing import Any
from typing import TYPE_CHECKING, Any
from aiohttp.client_exceptions import ClientConnectorError
from gios import ApiError, Gios, InvalidSensorsDataError, NoStationError
@ -12,6 +12,12 @@ import voluptuous as vol
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
from homeassistant.const import CONF_NAME
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.selector import (
SelectOptionDict,
SelectSelector,
SelectSelectorConfig,
SelectSelectorMode,
)
from .const import API_TIMEOUT, CONF_STATION_ID, DOMAIN
@ -27,40 +33,59 @@ class GiosFlowHandler(ConfigFlow, domain=DOMAIN):
"""Handle a flow initialized by the user."""
errors = {}
websession = async_get_clientsession(self.hass)
if user_input is not None:
station_id = user_input[CONF_STATION_ID]
try:
await self.async_set_unique_id(
str(user_input[CONF_STATION_ID]), raise_on_progress=False
)
await self.async_set_unique_id(station_id, raise_on_progress=False)
self._abort_if_unique_id_configured()
websession = async_get_clientsession(self.hass)
async with asyncio.timeout(API_TIMEOUT):
gios = await Gios.create(websession, user_input[CONF_STATION_ID])
gios = await Gios.create(websession, int(station_id))
await gios.async_update()
assert gios.station_name is not None
# GIOS treats station ID as int
user_input[CONF_STATION_ID] = int(station_id)
if TYPE_CHECKING:
assert gios.station_name is not None
return self.async_create_entry(
title=gios.station_name,
data=user_input,
)
except (ApiError, ClientConnectorError, TimeoutError):
errors["base"] = "cannot_connect"
except NoStationError:
errors[CONF_STATION_ID] = "wrong_station_id"
except InvalidSensorsDataError:
errors[CONF_STATION_ID] = "invalid_sensors_data"
try:
gios = await Gios.create(websession)
except (ApiError, ClientConnectorError, NoStationError):
return self.async_abort(reason="cannot_connect")
options: list[SelectOptionDict] = [
SelectOptionDict(value=str(station.id), label=station.name)
for station in gios.measurement_stations.values()
]
schema: vol.Schema = vol.Schema(
{
vol.Required(CONF_STATION_ID): SelectSelector(
SelectSelectorConfig(
options=options,
sort=True,
mode=SelectSelectorMode.DROPDOWN,
),
),
vol.Optional(CONF_NAME, default=self.hass.config.location_name): str,
}
)
return self.async_show_form(
step_id="user",
data_schema=vol.Schema(
{
vol.Required(CONF_STATION_ID): int,
vol.Optional(
CONF_NAME, default=self.hass.config.location_name
): str,
}
),
data_schema=schema,
errors=errors,
)

View File

@ -5,17 +5,17 @@
"title": "GIO\u015a (Polish Chief Inspectorate Of Environmental Protection)",
"data": {
"name": "[%key:common::config_flow::data::name%]",
"station_id": "ID of the measuring station"
"station_id": "Measuring station"
}
}
},
"error": {
"wrong_station_id": "ID of the measuring station is not correct.",
"invalid_sensors_data": "Invalid sensors' data for this measuring station.",
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]"
},
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_location%]"
"already_configured": "[%key:common::config_flow::abort::already_configured_location%]",
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]"
}
},
"system_health": {

View File

@ -6,7 +6,8 @@ from unittest.mock import patch
from gios import ApiError
from homeassistant.components.gios import config_flow
from homeassistant.components.gios.const import CONF_STATION_ID
from homeassistant.components.gios.const import CONF_STATION_ID, DOMAIN
from homeassistant.config_entries import SOURCE_USER
from homeassistant.const import CONF_NAME
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType
@ -17,36 +18,35 @@ from tests.common import load_fixture
CONFIG = {
CONF_NAME: "Foo",
CONF_STATION_ID: 123,
CONF_STATION_ID: "123",
}
async def test_show_form(hass: HomeAssistant) -> None:
"""Test that the form is served with no input."""
flow = config_flow.GiosFlowHandler()
flow.hass = hass
result = await flow.async_step_user(user_input=None)
with patch(
"homeassistant.components.gios.coordinator.Gios._get_stations",
return_value=STATIONS,
):
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "user"
async def test_invalid_station_id(hass: HomeAssistant) -> None:
"""Test that errors are shown when measuring station ID is invalid."""
async def test_form_with_api_error(hass: HomeAssistant) -> None:
"""Test the form is aborted because of API error."""
with patch(
"homeassistant.components.gios.coordinator.Gios._get_stations",
return_value=STATIONS,
side_effect=ApiError("error"),
):
flow = config_flow.GiosFlowHandler()
flow.hass = hass
flow.context = {}
result = await flow.async_step_user(
user_input={CONF_NAME: "Foo", CONF_STATION_ID: 0}
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
assert result["errors"] == {CONF_STATION_ID: "wrong_station_id"}
assert result["type"] is FlowResultType.ABORT
async def test_invalid_sensor_data(hass: HomeAssistant) -> None:
@ -76,17 +76,25 @@ async def test_invalid_sensor_data(hass: HomeAssistant) -> None:
async def test_cannot_connect(hass: HomeAssistant) -> None:
"""Test that errors are shown when cannot connect to GIOS server."""
with patch(
"homeassistant.components.gios.coordinator.Gios._async_get",
side_effect=ApiError("error"),
with (
patch(
"homeassistant.components.gios.coordinator.Gios._get_stations",
return_value=STATIONS,
),
patch(
"homeassistant.components.gios.coordinator.Gios._async_get",
side_effect=ApiError("error"),
),
):
flow = config_flow.GiosFlowHandler()
flow.hass = hass
flow.context = {}
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
result = await hass.config_entries.flow.async_configure(
result["flow_id"], CONFIG
)
await hass.async_block_till_done()
result = await flow.async_step_user(user_input=CONFIG)
assert result["errors"] == {"base": "cannot_connect"}
assert result["errors"] == {"base": "cannot_connect"}
async def test_create_entry(hass: HomeAssistant) -> None: