Skip to content

Commit

Permalink
split the config flow
Browse files Browse the repository at this point in the history
  • Loading branch information
miaucl committed Oct 22, 2024
1 parent 2f8ffd1 commit 12f60d2
Show file tree
Hide file tree
Showing 4 changed files with 260 additions and 81 deletions.
135 changes: 103 additions & 32 deletions homeassistant/components/swiss_public_transport/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.selector import (
DurationSelector,
SelectSelector,
SelectSelectorConfig,
SelectSelectorMode,
TextSelector,
TextSelectorConfig,
TextSelectorType,
Expand All @@ -26,19 +29,22 @@
CONF_IS_ARRIVAL,
CONF_START,
CONF_TIME,
CONF_TIME_MODE,
CONF_TIME_OFFSET,
CONF_VIA,
DEFAULT_TIME_MODE,
DOMAIN,
MAX_VIA,
PLACEHOLDERS,
TIME_MODE_OPTIONS,
)
from .helper import (
dict_duration_to_str_duration,
offset_opendata,
unique_id_from_config,
)

DATA_SCHEMA = vol.Schema(
USER_DATA_SCHEMA = vol.Schema(
{
vol.Required(CONF_START): cv.string,
vol.Optional(CONF_VIA): TextSelector(
Expand All @@ -48,11 +54,19 @@
),
),
vol.Required(CONF_DESTINATION): cv.string,
vol.Optional(CONF_TIME): TimeSelector(),
vol.Optional(CONF_TIME_OFFSET): DurationSelector(),
vol.Optional(CONF_IS_ARRIVAL): bool,
vol.Optional(CONF_TIME_MODE): SelectSelector(
SelectSelectorConfig(
options=TIME_MODE_OPTIONS,
mode=SelectSelectorMode.DROPDOWN,
translation_key="time_mode",
),
),
}
)
ADVANCED_TIME_DATA_SCHEMA = {vol.Optional(CONF_TIME): TimeSelector()}
ADVANCED_TIME_OFFSET_DATA_SCHEMA = {vol.Optional(CONF_TIME_OFFSET): DurationSelector()}


_LOGGER = logging.getLogger(__name__)

Expand All @@ -63,57 +77,114 @@ class SwissPublicTransportConfigFlow(ConfigFlow, domain=DOMAIN):
VERSION = 3
MINOR_VERSION = 1

user_input: dict[str, Any]

async def async_step_user(
self, user_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Async user step to set up the connection."""
errors: dict[str, str] = {}
if user_input is not None:
unique_id = unique_id_from_config(user_input)
await self.async_set_unique_id(unique_id)
self._abort_if_unique_id_configured()

if CONF_VIA in user_input and len(user_input[CONF_VIA]) > MAX_VIA:
errors["base"] = "too_many_via_stations"
elif CONF_TIME in user_input and CONF_TIME_OFFSET in user_input:
errors["base"] = "mutex_time_offset"
else:
session = async_get_clientsession(self.hass)
time_offset_dict: dict[str, int] | None = user_input.get(
CONF_TIME_OFFSET
)
time_offset = (
dict_duration_to_str_duration(time_offset_dict)
if CONF_TIME_OFFSET in user_input and time_offset_dict is not None
else None
)
opendata = OpendataTransport(
user_input[CONF_START],
user_input[CONF_DESTINATION],
session,
via=user_input.get(CONF_VIA),
time=user_input.get(CONF_TIME),
)
if time_offset:
offset_opendata(opendata, time_offset)
try:
await opendata.async_get_data()
except OpendataTransportConnectionError:
errors["base"] = "cannot_connect"
except OpendataTransportError:
errors["base"] = "bad_config"
except Exception: # pylint: disable=broad-except
_LOGGER.exception("Unknown error")
errors["base"] = "unknown"
err = await self.fetch_connections(opendata)
if err:
errors["base"] = err
else:
return self.async_create_entry(
title=unique_id,
data=user_input,
if user_input[CONF_TIME_MODE] == "now":
unique_id = unique_id_from_config(user_input)
await self.async_set_unique_id(unique_id)
self._abort_if_unique_id_configured()
return self.async_create_entry(
title=unique_id,
data=user_input,
)
self.user_input = user_input
return self.async_show_form(
step_id="advanced",
data_schema=self.build_advanced_schema(user_input),
errors=errors,
description_placeholders=PLACEHOLDERS,
)

return self.async_show_form(
step_id="user",
data_schema=DATA_SCHEMA,
data_schema=self.add_suggested_values_to_schema(
data_schema=USER_DATA_SCHEMA,
suggested_values=user_input or {CONF_TIME_MODE: DEFAULT_TIME_MODE},
),
errors=errors,
description_placeholders=PLACEHOLDERS,
)

async def async_step_advanced(
self, advanced_input: dict[str, Any] | None = None
) -> ConfigFlowResult:
"""Async advanced step to set up the connection."""
errors: dict[str, str] = {}
if advanced_input is not None:
unique_id = unique_id_from_config({**self.user_input, **advanced_input})
await self.async_set_unique_id(unique_id)
self._abort_if_unique_id_configured()

session = async_get_clientsession(self.hass)
time_offset_dict: dict[str, int] | None = advanced_input.get(
CONF_TIME_OFFSET
)
time_offset = (
dict_duration_to_str_duration(time_offset_dict)
if CONF_TIME_OFFSET in advanced_input and time_offset_dict is not None
else None
)
opendata = OpendataTransport(
self.user_input[CONF_START],
self.user_input[CONF_DESTINATION],
session,
via=self.user_input.get(CONF_VIA),
time=advanced_input.get(CONF_TIME),
)
if time_offset:
offset_opendata(opendata, time_offset)
err = await self.fetch_connections(opendata)
if err:
errors["base"] = err
else:
return self.async_create_entry(
title=unique_id,
data={**self.user_input, **advanced_input},
)

return self.async_show_form(
step_id="advanced",
data_schema=self.build_advanced_schema(self.user_input),
errors=errors,
description_placeholders=PLACEHOLDERS,
)

async def fetch_connections(self, opendata: OpendataTransport) -> str | None:
"""Fetch the connections and advancedly return an error."""
try:
await opendata.async_get_data()
except OpendataTransportConnectionError:
return "cannot_connect"
except OpendataTransportError:
return "bad_config"
except Exception: # pylint: disable=broad-except
_LOGGER.exception("Unknown error")
return "unknown"
return None

def build_advanced_schema(self, user_input: dict[str, Any]) -> vol.Schema:
"""Build the advanced schema."""
if user_input[CONF_TIME_MODE] == "fixed":
return vol.Schema(ADVANCED_TIME_DATA_SCHEMA)
return vol.Schema(ADVANCED_TIME_OFFSET_DATA_SCHEMA)
5 changes: 4 additions & 1 deletion homeassistant/components/swiss_public_transport/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,20 @@
CONF_DESTINATION: Final = "to"
CONF_START: Final = "from"
CONF_VIA: Final = "via"
CONF_IS_ARRIVAL: Final = "is_arrival"
CONF_TIME_MODE: Final = "time_mode"
CONF_TIME: Final = "time"
CONF_TIME_OFFSET: Final = "time_offset"
CONF_IS_ARRIVAL: Final = "is_arrival"

DEFAULT_NAME = "Next Destination"
DEFAULT_UPDATE_TIME = 90
DEFAULT_IS_ARRIVAL = False
DEFAULT_TIME_MODE = "now"

MAX_VIA = 5
CONNECTIONS_COUNT = 3
CONNECTIONS_MAX = 15
TIME_MODE_OPTIONS = ["now", "fixed", "offset"]


PLACEHOLDERS = {
Expand Down
23 changes: 19 additions & 4 deletions homeassistant/components/swiss_public_transport/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,17 @@
"from": "Start station",
"to": "End station",
"via": "List of up to 5 via stations",
"time": "Select a fixed time of day",
"time_offset": "Select a moving time offset",
"is_arrival": "Use arrival instead of departure for time and offset configuration"
"is_arrival": "Use arrival instead of departure",
"time_mode": "Select a time mode"
},
"description": "Provide start and end station for your connection,\nand optionally up to 5 via stations.\nOptionally, you can also configure connections at a specific time or moving offset.\n\nCheck the [stationboard]({stationboard_url}) for valid stations.",
"title": "Swiss Public Transport"
},
"optional": {
"data": {
"time": "Select the time of day",
"time_offset": "Select an offset duration"
},
"description": "Provide start and end station for your connection,\nand optionally up to 5 via stations.\nOptionally, you can also configure connections at a specific time or moving offset for departure or arrival.\n\nCheck the [stationboard]({stationboard_url}) for valid stations.",
"title": "Swiss Public Transport"
}
}
Expand Down Expand Up @@ -88,5 +94,14 @@
"config_entry_not_found": {
"message": "Swiss public transport integration instance \"{target}\" not found."
}
},
"selector": {
"time_mode": {
"options": {
"now": "Now",
"fixed": "At a fixed time of day",
"offset": "At an offset from now"
}
}
}
}
Loading

0 comments on commit 12f60d2

Please sign in to comment.