Files
Garbage-Collection-fr/custom_components/garbage_collection/config_flow.py
T

282 lines
10 KiB
Python

"""Adds config flow for GarbageCollection."""
from __future__ import annotations
import logging
# import uuid
from collections.abc import Mapping
from typing import Any, Dict, cast
import voluptuous as vol
from homeassistant.const import ATTR_HIDDEN, CONF_ENTITIES, CONF_NAME
from homeassistant.core import callback
from homeassistant.helpers import selector
from homeassistant.helpers.schema_config_entry_flow import (
SchemaConfigFlowHandler,
SchemaFlowError,
SchemaFlowFormStep,
SchemaFlowMenuStep,
SchemaOptionsFlowHandler,
)
from . import const, helpers
_LOGGER = logging.getLogger(__name__)
async def _validate_config(
_: SchemaConfigFlowHandler | SchemaOptionsFlowHandler, data: Any
) -> Any:
"""Validate config."""
if const.CONF_DATE in data:
try:
helpers.month_day_text(data[const.CONF_DATE])
except vol.Invalid as exc:
raise SchemaFlowError("month_day") from exc
return data
def required(
key: str, options: Dict[str, Any], default: Any | None = None
) -> vol.Required:
"""Return vol.Required."""
if isinstance(options, dict) and key in options:
suggested_value = options[key]
elif default is not None:
suggested_value = default
else:
return vol.Required(key)
return vol.Required(key, description={"suggested_value": suggested_value})
def optional(
key: str, options: Dict[str, Any], default: Any | None = None
) -> vol.Optional:
"""Return vol.Optional."""
if isinstance(options, dict) and key in options:
suggested_value = options[key]
elif default is not None:
suggested_value = default
else:
return vol.Optional(key)
return vol.Optional(key, description={"suggested_value": suggested_value})
async def general_config_schema(
handler: SchemaConfigFlowHandler | SchemaOptionsFlowHandler,
) -> vol.Schema:
"""Generate config schema."""
return vol.Schema(
{
optional(CONF_NAME, handler.options): selector.TextSelector(),
required(
const.CONF_FREQUENCY, handler.options, const.DEFAULT_FREQUENCY
): selector.SelectSelector(
selector.SelectSelectorConfig(options=const.FREQUENCY_OPTIONS)
),
optional(
const.CONF_ICON_NORMAL, handler.options, const.DEFAULT_ICON_NORMAL
): selector.IconSelector(),
optional(
const.CONF_ICON_TODAY, handler.options, const.DEFAULT_ICON_TODAY
): selector.IconSelector(),
optional(
const.CONF_ICON_TOMORROW, handler.options, const.DEFAULT_ICON_TOMORROW
): selector.IconSelector(),
optional(const.CONF_EXPIRE_AFTER, handler.options): selector.TimeSelector(),
optional(
const.CONF_VERBOSE_STATE, handler.options, const.DEFAULT_VERBOSE_STATE
): bool,
optional(ATTR_HIDDEN, handler.options, False): bool,
optional(const.CONF_MANUAL, handler.options, False): bool,
optional(
const.CONF_MOVE_COUNTRY_HOLIDAYS,
handler.options,
const.DEFAULT_HOLIDAY_IN_WEEK_MOVE,
): bool,
optional(
const.CONF_HOLIDAY_DATES,
handler.options,
const.DEFAULT_HOLIDAY_DATES,
): selector.TextSelector(),
}
)
async def general_options_schema(
handler: SchemaConfigFlowHandler | SchemaOptionsFlowHandler,
) -> vol.Schema:
"""Generate options schema."""
return vol.Schema(
{
required(
const.CONF_FREQUENCY, handler.options, const.DEFAULT_FREQUENCY
): selector.SelectSelector(
selector.SelectSelectorConfig(options=const.FREQUENCY_OPTIONS)
),
optional(
const.CONF_ICON_NORMAL, handler.options, const.DEFAULT_ICON_NORMAL
): selector.IconSelector(),
optional(
const.CONF_ICON_TODAY, handler.options, const.DEFAULT_ICON_TODAY
): selector.IconSelector(),
optional(
const.CONF_ICON_TOMORROW, handler.options, const.DEFAULT_ICON_TOMORROW
): selector.IconSelector(),
optional(const.CONF_EXPIRE_AFTER, handler.options): selector.TimeSelector(),
optional(
const.CONF_VERBOSE_STATE, handler.options, const.DEFAULT_VERBOSE_STATE
): bool,
optional(ATTR_HIDDEN, handler.options, False): bool,
optional(const.CONF_MANUAL, handler.options, False): bool,
optional(
const.CONF_MOVE_COUNTRY_HOLIDAYS,
handler.options,
const.DEFAULT_HOLIDAY_IN_WEEK_MOVE,
): bool,
optional(
const.CONF_HOLIDAY_DATES,
handler.options,
const.DEFAULT_HOLIDAY_DATES,
): selector.TextSelector(),
}
)
async def detail_config_schema(
handler: SchemaConfigFlowHandler | SchemaOptionsFlowHandler,
) -> vol.Schema:
"""Generate options schema."""
options_schema: Dict[vol.Optional | vol.Required, Any] = {}
if handler.options[const.CONF_FREQUENCY] in const.ANNUAL_FREQUENCY:
# "annual"
options_schema[
required(const.CONF_DATE, handler.options)
] = selector.TextSelector()
elif handler.options[const.CONF_FREQUENCY] in const.GROUP_FREQUENCY:
# "group"
options_schema[
required(CONF_ENTITIES, handler.options)
] = selector.EntitySelector(
selector.EntitySelectorConfig(
domain="sensor", integration=const.DOMAIN, multiple=True
),
)
elif handler.options[const.CONF_FREQUENCY] not in const.BLANK_FREQUENCY:
# everything else except "blank" and every-n-days
if handler.options[const.CONF_FREQUENCY] not in const.DAILY_FREQUENCY:
options_schema[
required(const.CONF_COLLECTION_DAYS, handler.options)
] = selector.SelectSelector(
selector.SelectSelectorConfig(
options=const.WEEKDAY_OPTIONS,
multiple=True,
mode=selector.SelectSelectorMode.LIST,
)
)
# everything else except "blank"
options_schema[
optional(const.CONF_FIRST_MONTH, handler.options, const.DEFAULT_FIRST_MONTH)
] = selector.SelectSelector(
selector.SelectSelectorConfig(options=const.MONTH_OPTIONS)
)
options_schema[
optional(const.CONF_LAST_MONTH, handler.options, const.DEFAULT_LAST_MONTH)
] = selector.SelectSelector(
selector.SelectSelectorConfig(options=const.MONTH_OPTIONS)
)
if handler.options[const.CONF_FREQUENCY] in const.MONTHLY_FREQUENCY:
# "monthly"
options_schema[
optional(const.CONF_WEEKDAY_ORDER_NUMBER, handler.options)
] = selector.SelectSelector(
selector.SelectSelectorConfig(
options=const.ORDER_OPTIONS,
multiple=True,
mode=selector.SelectSelectorMode.LIST,
)
)
options_schema[
optional(const.CONF_FORCE_WEEK_NUMBERS, handler.options)
] = selector.BooleanSelector()
if handler.options[const.CONF_FREQUENCY] in const.WEEKLY_DAILY_MONTHLY:
# "every-n-weeks", "every-n-days", "monthly"
uom = {"every-n-weeks": "weeks", "every-n-days": "days", "monthly": "month"}
options_schema[
required(const.CONF_PERIOD, handler.options)
] = selector.NumberSelector(
selector.NumberSelectorConfig(
min=1,
max=1000,
mode=selector.NumberSelectorMode.BOX,
unit_of_measurement=uom[handler.options[const.CONF_FREQUENCY]],
)
)
if handler.options[const.CONF_FREQUENCY] in const.WEEKLY_FREQUENCY_X:
# every-n-weeks
options_schema[
required(
const.CONF_FIRST_WEEK, handler.options, const.DEFAULT_FIRST_WEEK
)
] = selector.NumberSelector(
selector.NumberSelectorConfig(
min=1,
max=52,
mode=selector.NumberSelectorMode.BOX,
unit_of_measurement="weeks",
)
)
if handler.options[const.CONF_FREQUENCY] in const.DAILY_FREQUENCY:
# every-n-days
options_schema[
required(const.CONF_FIRST_DATE, handler.options, helpers.now().date())
] = selector.DateSelector()
if handler.options.get(const.CONF_VERBOSE_STATE, False):
# "verbose_state"
options_schema[
required(
const.CONF_VERBOSE_FORMAT, handler.options, const.DEFAULT_VERBOSE_FORMAT
)
] = selector.TextSelector()
options_schema[
required(const.CONF_DATE_FORMAT, handler.options, const.DEFAULT_DATE_FORMAT)
] = selector.TextSelector()
return vol.Schema(options_schema)
async def choose_details_step(_: dict[str, Any]) -> str:
"""Return next step_id for options flow."""
return "detail"
CONFIG_FLOW: Dict[str, SchemaFlowFormStep | SchemaFlowMenuStep] = {
"user": SchemaFlowFormStep(general_config_schema, next_step=choose_details_step),
"detail": SchemaFlowFormStep(
detail_config_schema, validate_user_input=_validate_config
),
}
OPTIONS_FLOW: Dict[str, SchemaFlowFormStep | SchemaFlowMenuStep] = {
"init": SchemaFlowFormStep(general_options_schema, next_step=choose_details_step),
"detail": SchemaFlowFormStep(
detail_config_schema, validate_user_input=_validate_config
),
}
# mypy: ignore-errors
class GarbageCollectionConfigFlowHandler(SchemaConfigFlowHandler, domain=const.DOMAIN):
"""Handle a config or options flow for GarbageCollection."""
config_flow = CONFIG_FLOW
options_flow = OPTIONS_FLOW
VERSION = const.CONFIG_VERSION
@callback
def async_config_entry_title(self, options: Mapping[str, Any]) -> str:
"""Return config entry title.
The options parameter contains config entry options, which is the union of user
input from the config flow steps.
"""
return cast(str, options["name"]) if "name" in options else ""