Allow resetting time in google_travel_time (#88256)

Co-authored-by: Robert Resch <robert@resch.dev>
This commit is contained in:
Kevin Stillhammer 2023-10-11 09:46:02 +02:00 committed by GitHub
parent 39fd5897cb
commit 7d1105228b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 282 additions and 50 deletions

View File

@ -8,12 +8,17 @@ from homeassistant.const import CONF_API_KEY, CONF_MODE, CONF_NAME
from homeassistant.core import HomeAssistant, callback
from homeassistant.data_entry_flow import FlowResult
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.selector import (
SelectSelector,
SelectSelectorConfig,
SelectSelectorMode,
)
from homeassistant.util.unit_system import US_CUSTOMARY_SYSTEM
from .const import (
ALL_LANGUAGES,
ARRIVAL_TIME,
AVOID,
AVOID_OPTIONS,
CONF_ARRIVAL_TIME,
CONF_AVOID,
CONF_DEPARTURE_TIME,
@ -30,18 +35,87 @@ from .const import (
DEPARTURE_TIME,
DOMAIN,
TIME_TYPES,
TRAFFIC_MODELS,
TRANSIT_PREFS,
TRANSPORT_TYPE,
TRAVEL_MODE,
TRAVEL_MODEL,
TRANSPORT_TYPES,
TRAVEL_MODES,
UNITS,
UNITS_IMPERIAL,
UNITS_METRIC,
)
from .helpers import InvalidApiKeyException, UnknownException, validate_config_entry
OPTIONS_SCHEMA = vol.Schema(
{
vol.Required(CONF_MODE): SelectSelector(
SelectSelectorConfig(
options=TRAVEL_MODES,
sort=True,
mode=SelectSelectorMode.DROPDOWN,
translation_key=CONF_MODE,
)
),
vol.Optional(CONF_LANGUAGE): SelectSelector(
SelectSelectorConfig(
options=sorted(ALL_LANGUAGES),
mode=SelectSelectorMode.DROPDOWN,
translation_key=CONF_LANGUAGE,
)
),
vol.Optional(CONF_AVOID): SelectSelector(
SelectSelectorConfig(
options=AVOID_OPTIONS,
sort=True,
mode=SelectSelectorMode.DROPDOWN,
translation_key=CONF_AVOID,
)
),
vol.Required(CONF_UNITS): SelectSelector(
SelectSelectorConfig(
options=UNITS,
sort=True,
mode=SelectSelectorMode.DROPDOWN,
translation_key=CONF_UNITS,
)
),
vol.Required(CONF_TIME_TYPE): SelectSelector(
SelectSelectorConfig(
options=TIME_TYPES,
sort=True,
mode=SelectSelectorMode.DROPDOWN,
translation_key=CONF_TIME_TYPE,
)
),
vol.Optional(CONF_TIME, default=""): cv.string,
vol.Optional(CONF_TRAFFIC_MODEL): SelectSelector(
SelectSelectorConfig(
options=TRAFFIC_MODELS,
sort=True,
mode=SelectSelectorMode.DROPDOWN,
translation_key=CONF_TRAFFIC_MODEL,
)
),
vol.Optional(CONF_TRANSIT_MODE): SelectSelector(
SelectSelectorConfig(
options=TRANSPORT_TYPES,
sort=True,
mode=SelectSelectorMode.DROPDOWN,
translation_key=CONF_TRANSIT_MODE,
)
),
vol.Optional(CONF_TRANSIT_ROUTING_PREFERENCE): SelectSelector(
SelectSelectorConfig(
options=TRANSIT_PREFS,
sort=True,
mode=SelectSelectorMode.DROPDOWN,
translation_key=CONF_TRANSIT_ROUTING_PREFERENCE,
)
),
}
)
def default_options(hass: HomeAssistant) -> dict[str, str | None]:
def default_options(hass: HomeAssistant) -> dict[str, str]:
"""Get the default options."""
return {
CONF_MODE: "driving",
@ -69,53 +143,20 @@ class GoogleOptionsFlow(config_entries.OptionsFlow):
user_input[CONF_DEPARTURE_TIME] = time
return self.async_create_entry(
title="",
data={k: v for k, v in user_input.items() if v not in (None, "")},
data=user_input,
)
options = self.config_entry.options.copy()
if CONF_ARRIVAL_TIME in self.config_entry.options:
default_time_type = ARRIVAL_TIME
default_time = self.config_entry.options[CONF_ARRIVAL_TIME]
options[CONF_TIME_TYPE] = ARRIVAL_TIME
options[CONF_TIME] = self.config_entry.options[CONF_ARRIVAL_TIME]
else:
default_time_type = DEPARTURE_TIME
default_time = self.config_entry.options.get(CONF_DEPARTURE_TIME, "")
options[CONF_TIME_TYPE] = DEPARTURE_TIME
options[CONF_TIME] = self.config_entry.options.get(CONF_DEPARTURE_TIME, "")
return self.async_show_form(
step_id="init",
data_schema=vol.Schema(
{
vol.Optional(
CONF_MODE, default=self.config_entry.options[CONF_MODE]
): vol.In(TRAVEL_MODE),
vol.Optional(
CONF_LANGUAGE,
default=self.config_entry.options.get(CONF_LANGUAGE),
): vol.In([None, *ALL_LANGUAGES]),
vol.Optional(
CONF_AVOID, default=self.config_entry.options.get(CONF_AVOID)
): vol.In([None, *AVOID]),
vol.Optional(
CONF_UNITS, default=self.config_entry.options[CONF_UNITS]
): vol.In(UNITS),
vol.Optional(CONF_TIME_TYPE, default=default_time_type): vol.In(
TIME_TYPES
),
vol.Optional(CONF_TIME, default=default_time): cv.string,
vol.Optional(
CONF_TRAFFIC_MODEL,
default=self.config_entry.options.get(CONF_TRAFFIC_MODEL),
): vol.In([None, *TRAVEL_MODEL]),
vol.Optional(
CONF_TRANSIT_MODE,
default=self.config_entry.options.get(CONF_TRANSIT_MODE),
): vol.In([None, *TRANSPORT_TYPE]),
vol.Optional(
CONF_TRANSIT_ROUTING_PREFERENCE,
default=self.config_entry.options.get(
CONF_TRANSIT_ROUTING_PREFERENCE
),
): vol.In([None, *TRANSIT_PREFS]),
}
),
data_schema=self.add_suggested_values_to_schema(OPTIONS_SCHEMA, options),
)

View File

@ -77,11 +77,11 @@ ALL_LANGUAGES = [
"zh-TW",
]
AVOID = ["tolls", "highways", "ferries", "indoor"]
AVOID_OPTIONS = ["tolls", "highways", "ferries", "indoor"]
TRANSIT_PREFS = ["less_walking", "fewer_transfers"]
TRANSPORT_TYPE = ["bus", "subway", "train", "tram", "rail"]
TRAVEL_MODE = ["driving", "walking", "bicycling", "transit"]
TRAVEL_MODEL = ["best_guess", "pessimistic", "optimistic"]
TRANSPORT_TYPES = ["bus", "subway", "train", "tram", "rail"]
TRAVEL_MODES = ["driving", "walking", "bicycling", "transit"]
TRAFFIC_MODELS = ["best_guess", "pessimistic", "optimistic"]
# googlemaps library uses "metric" or "imperial" terminology in distance_matrix
UNITS_METRIC = "metric"

View File

@ -30,12 +30,65 @@
"time_type": "Time Type",
"time": "Time",
"avoid": "Avoid",
"traffic_mode": "Traffic Mode",
"traffic_model": "Traffic Model",
"transit_mode": "Transit Mode",
"transit_routing_preference": "Transit Routing Preference",
"units": "Units"
}
}
}
},
"selector": {
"mode": {
"options": {
"driving": "Driving",
"walking": "Walking",
"bicycling": "Bicycling",
"transit": "Transit"
}
},
"avoid": {
"options": {
"none": "Avoid nothing",
"tolls": "Tolls",
"highways": "Highways",
"ferries": "Ferries",
"indoor": "Indoor"
}
},
"units": {
"options": {
"metric": "Metric System",
"imperial": "Imperial System"
}
},
"time_type": {
"options": {
"arrival_time": "Arrival Time",
"departure_time": "Departure Time"
}
},
"traffic_model": {
"options": {
"best_guess": "Best Guess",
"pessimistic": "Pessimistic",
"optimistic": "Optimistic"
}
},
"transit_mode": {
"options": {
"bus": "Bus",
"subway": "Subway",
"train": "Train",
"tram": "Tram",
"rail": "Rail"
}
},
"transit_routing_preference": {
"options": {
"less_walking": "Less Walking",
"fewer_transfers": "Fewer Transfers"
}
}
}
}

View File

@ -257,6 +257,144 @@ async def test_options_flow_departure_time(hass: HomeAssistant, mock_config) ->
}
@pytest.mark.parametrize(
("data", "options"),
[
(
MOCK_CONFIG,
{
CONF_MODE: "driving",
CONF_UNITS: UNITS_IMPERIAL,
CONF_DEPARTURE_TIME: "test",
},
),
(
MOCK_CONFIG,
{
CONF_MODE: "driving",
CONF_UNITS: UNITS_IMPERIAL,
CONF_ARRIVAL_TIME: "test",
},
),
],
)
@pytest.mark.usefixtures("validate_config_entry")
async def test_reset_departure_time(hass: HomeAssistant, mock_config) -> None:
"""Test resetting departure time."""
result = await hass.config_entries.options.async_init(
mock_config.entry_id, data=None
)
assert result["type"] == data_entry_flow.FlowResultType.FORM
assert result["step_id"] == "init"
result = await hass.config_entries.options.async_configure(
result["flow_id"],
user_input={
CONF_MODE: "driving",
CONF_UNITS: UNITS_IMPERIAL,
CONF_TIME_TYPE: DEPARTURE_TIME,
},
)
assert mock_config.options == {
CONF_MODE: "driving",
CONF_UNITS: UNITS_IMPERIAL,
}
@pytest.mark.parametrize(
("data", "options"),
[
(
MOCK_CONFIG,
{
CONF_MODE: "driving",
CONF_UNITS: UNITS_IMPERIAL,
CONF_ARRIVAL_TIME: "test",
},
),
(
MOCK_CONFIG,
{
CONF_MODE: "driving",
CONF_UNITS: UNITS_IMPERIAL,
CONF_DEPARTURE_TIME: "test",
},
),
],
)
@pytest.mark.usefixtures("validate_config_entry")
async def test_reset_arrival_time(hass: HomeAssistant, mock_config) -> None:
"""Test resetting arrival time."""
result = await hass.config_entries.options.async_init(
mock_config.entry_id, data=None
)
assert result["type"] == data_entry_flow.FlowResultType.FORM
assert result["step_id"] == "init"
result = await hass.config_entries.options.async_configure(
result["flow_id"],
user_input={
CONF_MODE: "driving",
CONF_UNITS: UNITS_IMPERIAL,
CONF_TIME_TYPE: ARRIVAL_TIME,
},
)
assert mock_config.options == {
CONF_MODE: "driving",
CONF_UNITS: UNITS_IMPERIAL,
}
@pytest.mark.parametrize(
("data", "options"),
[
(
MOCK_CONFIG,
{
CONF_MODE: "driving",
CONF_LANGUAGE: "en",
CONF_AVOID: "tolls",
CONF_UNITS: UNITS_IMPERIAL,
CONF_TIME_TYPE: ARRIVAL_TIME,
CONF_TIME: "test",
CONF_TRAFFIC_MODEL: "best_guess",
CONF_TRANSIT_MODE: "train",
CONF_TRANSIT_ROUTING_PREFERENCE: "less_walking",
},
)
],
)
@pytest.mark.usefixtures("validate_config_entry")
async def test_reset_options_flow_fields(hass: HomeAssistant, mock_config) -> None:
"""Test resetting options flow fields that are not time related to None."""
result = await hass.config_entries.options.async_init(
mock_config.entry_id, data=None
)
assert result["type"] == data_entry_flow.FlowResultType.FORM
assert result["step_id"] == "init"
result = await hass.config_entries.options.async_configure(
result["flow_id"],
user_input={
CONF_MODE: "driving",
CONF_UNITS: UNITS_IMPERIAL,
CONF_TIME_TYPE: ARRIVAL_TIME,
CONF_TIME: "test",
},
)
assert mock_config.options == {
CONF_MODE: "driving",
CONF_UNITS: UNITS_IMPERIAL,
CONF_ARRIVAL_TIME: "test",
}
@pytest.mark.usefixtures("validate_config_entry", "bypass_setup")
async def test_dupe(hass: HomeAssistant) -> None:
"""Test setting up the same entry data twice is OK."""