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.core import HomeAssistant, callback
from homeassistant.data_entry_flow import FlowResult from homeassistant.data_entry_flow import FlowResult
import homeassistant.helpers.config_validation as cv 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 homeassistant.util.unit_system import US_CUSTOMARY_SYSTEM
from .const import ( from .const import (
ALL_LANGUAGES, ALL_LANGUAGES,
ARRIVAL_TIME, ARRIVAL_TIME,
AVOID, AVOID_OPTIONS,
CONF_ARRIVAL_TIME, CONF_ARRIVAL_TIME,
CONF_AVOID, CONF_AVOID,
CONF_DEPARTURE_TIME, CONF_DEPARTURE_TIME,
@ -30,18 +35,87 @@ from .const import (
DEPARTURE_TIME, DEPARTURE_TIME,
DOMAIN, DOMAIN,
TIME_TYPES, TIME_TYPES,
TRAFFIC_MODELS,
TRANSIT_PREFS, TRANSIT_PREFS,
TRANSPORT_TYPE, TRANSPORT_TYPES,
TRAVEL_MODE, TRAVEL_MODES,
TRAVEL_MODEL,
UNITS, UNITS,
UNITS_IMPERIAL, UNITS_IMPERIAL,
UNITS_METRIC, UNITS_METRIC,
) )
from .helpers import InvalidApiKeyException, UnknownException, validate_config_entry 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.""" """Get the default options."""
return { return {
CONF_MODE: "driving", CONF_MODE: "driving",
@ -69,53 +143,20 @@ class GoogleOptionsFlow(config_entries.OptionsFlow):
user_input[CONF_DEPARTURE_TIME] = time user_input[CONF_DEPARTURE_TIME] = time
return self.async_create_entry( return self.async_create_entry(
title="", 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: if CONF_ARRIVAL_TIME in self.config_entry.options:
default_time_type = ARRIVAL_TIME options[CONF_TIME_TYPE] = ARRIVAL_TIME
default_time = self.config_entry.options[CONF_ARRIVAL_TIME] options[CONF_TIME] = self.config_entry.options[CONF_ARRIVAL_TIME]
else: else:
default_time_type = DEPARTURE_TIME options[CONF_TIME_TYPE] = DEPARTURE_TIME
default_time = self.config_entry.options.get(CONF_DEPARTURE_TIME, "") options[CONF_TIME] = self.config_entry.options.get(CONF_DEPARTURE_TIME, "")
return self.async_show_form( return self.async_show_form(
step_id="init", step_id="init",
data_schema=vol.Schema( data_schema=self.add_suggested_values_to_schema(OPTIONS_SCHEMA, options),
{
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]),
}
),
) )

View File

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

View File

@ -30,12 +30,65 @@
"time_type": "Time Type", "time_type": "Time Type",
"time": "Time", "time": "Time",
"avoid": "Avoid", "avoid": "Avoid",
"traffic_mode": "Traffic Mode", "traffic_model": "Traffic Model",
"transit_mode": "Transit Mode", "transit_mode": "Transit Mode",
"transit_routing_preference": "Transit Routing Preference", "transit_routing_preference": "Transit Routing Preference",
"units": "Units" "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") @pytest.mark.usefixtures("validate_config_entry", "bypass_setup")
async def test_dupe(hass: HomeAssistant) -> None: async def test_dupe(hass: HomeAssistant) -> None:
"""Test setting up the same entry data twice is OK.""" """Test setting up the same entry data twice is OK."""